[Anterior: Âncoras] [Conteúdo] [Próximo: Grupos de Endereços e Balanceamento de Carga]
Enfileirar algo é armazená-lo em algum lugar, de maneira organizada, enquanto aguarda processamento. Em uma rede de computadores, quando pacotes de dados são enviados por uma máquina eles entram em uma fila onde aguardam processamento pelo sistema operacional. O sistema operacional decide qual fila e qual(is) pacote(s) nessa fila deve(m) ser processado(s). A ordem em que o sistema operacional escolhe os pacotes para processar pode afetar o desempenho da rede. Por exemplo, imagine um usuário executando dois aplicativos de rede: SSH e FTP. Em condições ideais, os pacotes SSH devem ser processados antes dos pacotes FTP por causa da natureza sensível do tempo no SSH; quando uma tecla é acionada em um cliente SSH, uma resposta imediata é esperada, mas uma transferência FTP sendo atrasada por alguns segundos extras muito dificilmente será percebida. Mas o que acontece se o roteador manipulando essas conexões processar um grande número de pacotes da conexão FTP antes de processar a conexão SSH? Pacotes da conexão SSH permanecerão na fila (ou possivelmente serão descartados pelo roteador caso a fila não seja grande o suficiente para manter todos os pacotes) e a sessão SSH parecerá latente ou muito lenta. Ao modificar a estratégia de enfileiramento utilizada, a largura de banda pode ser compartilhada entre diferentes aplicativos, usuários e computadores.
Perceba que o enfileiramento é útil somente para pacotes que estão saindo. Quando o pacote chega na direção de entrada em uma interface, já é tarde demais para ser enfileirado -- ele já consumiu largura de banda ao chegar na interface que o recebeu. A única solução é habilitar enfileiramento no roteador adjacente ou, se a máquina que recebeu o pacote está funcionando como roteador, habilitar enfileiramento na interface interna por onde os pacotes saem dele.
OpenBSD suporta mais dois agendadores:
Filas CBQ são organizadas de forma hierárquica. No topo da hierarquia está a fila raiz que define a quantidade total de largura de banda disponível. As filas filhas são criadas sob a fila raiz, cada uma delas pode receber parte da largura de banda da fila raiz. Por exemplo, filas podem ser definidas da seguinte maneira:
Nesse caso, a largura de banda total disponível está definida como 2 megabits por segundo (Mbps). Essa largura de banda é então dividida entre outras três filas filhas.
A hierarquia pode ser expandida definindo-se filas dentro de filas. Para dividir a largura de banda igualmente entre diferentes usuários e ainda classificar seu tráfego de forma que certos protocolos não ocupem a largura de banda de outros, uma estrutura de enfileiramento parecida com esta pode ser definida:
Perceba que a cada nível a soma do total da largura de banda vinculada a cada fila nunca é maior que o valor da largura de banda da fila raiz.
Uma fila pode ser configurada para emprestar largura de banda de sua fila pai caso as outras filas dentro da fila pai não estejam usando sua porção e a largura de banda esteja disponível. Considere a configuração de enfileiramento a seguir:
Se o tráfego na fila ftp exceder os 900Kbps e o tráfego na fila UsuárioA for menor que 1Mbps (porque a fila ssh está usando menos que 100Kbps), a fila ftp empresta a largura de banda excedente de UsuárioA. Dessa forma a fila ftp pode usar mais largura de banda do que foi definido a princípio quando necessário. Quando o tráfego na fila ssh aumenta, a largura de banda emprestada é devolvida.
CBQ atribui a cada fila um nível de prioridade. Filas com prioridade alta têm preferência sobre outras com menor prioridade em caso de congestionamento, contanto que ambas as filas estejam contidas na mesma fila pai (em outras palavras, contanto que estejam no mesmo ramo na hierarquia). Filas com a mesma prioridade são processadas pelo método round robin. Por exemplo:
O CBQ processa as filas UsuárioA e UsuárioB através do método round robin -- nenhuma fila será preferida sobre a outra. Enquanto a fila UsuárioA está sendo processada, o CBQ também processa suas filas filhas. Nesse caso, a fila ssh tem prioridade maior e terá tratamento preferencial sobre a fila ftp caso a rede fique congestionada. Perceba como as filas ssh e ftp não têm suas prioridades comparadas às filas UsuárioA e UsuárioB pelo fato de elas não estarem no mesmo ramo na hierarquia.
Para um estudo mais detalhado sobre a teoria por trás do CBQ, por favor consulte as Referências sobre CBQ.
A estrutura de enfileiramento no PRIQ é plana -- você não pode definir filas dentro de filas. A fila raiz é definida, onde é configurado o total de largura de banda disponível, então subfilas são definidas sob a raiz. Considere o exemplo a seguir:
A fila raiz é definida como tendo 2Mbps de largura de banda disponível e três subfilas são definidas. A fila com maior prioridade (o maior número de prioridade) é servida primeiro. Quando todos os pacotes nessa fila são processados, ou caso a fila esteja vazia, PRIQ vai para a próxima fila com prioridade mais alta. Dentro de uma fila, os pacotes são processados através do método Primeiro a Entrar, Primeiro a Sair.
É importante notar que quando estiver usando PRIQ você deve planejar suas filas com muito cuidado. Como PRIQ sempre processa a fila com prioridade mais alta por primeiro, é possível que uma fila com alta prioridade faça com que pacotes destinados a outra fila com prioridade menor atrasem muito ou até mesmo sejam descartados caso a fila preferida esteja recebendo um fluxo constante de pacotes.
O RED é útil porque evita uma situação conhecida como sincronização global e porque pode acomodar aumentos repentinos no tráfego. Sincronização global refere-se a uma queda na capacidade de transferência devido aos pacotes descartados de várias conexões ao mesmo tempo. Por exemplo, caso o congestionamento ocorra em um roteador que está transmitindo tráfego para 10 conexões FTP, e pacotes de todas (ou quase todas) as conexões são descartados (como é o caso com enfileiramento FIFO), a capacidade média de transferência cai severamente. Essa não é uma situação ideal porque faz com que todas as conexões FTP reduzam sua taxa de transferência, e também significa que a rede não está mais sendo utilizada em todo seu potencial. RED evita esse cenário escolhendo aleatoriamente quais conexões terão pacotes descartados em vez de escolher todas elas. Conexões que utilizam muita largura de banda têm chances maiores de terem seus pacotes descartados. Dessa forma, conexões que ocupam muita largura de banda são evitadas, o congestionamento é evitado, e sérias perdas nas taxas de transferência não ocorrem. Além disso, RED pode responder a aumentos repentinos no tráfego pelo fato de começar a descartar pacotes antes da fila ficar cheia. Quando o tráfego inesperado chegar, existe espaço suficiente na fila para armazenar os novos pacotes.
RED deve ser usado apenas quando o protocolo de transporte for capaz de responder a indicadores de congestionamento da rede. Na maioria dos casos isso significa que RED deve ser usado para enfileirar tráfego TCP e não tráfego UDP ou ICMP.
Para uma discussão mais detalhada sobre a teoria por trás do RED, por favor consulte as Referências sobre RED.
Para mais informações sobre ECN, por favor consulte a RFC 3168.
Pelo fato do ALTQ ter sido integrado ao PF, o PF deve estar habilitado para que o enfileiramento funcione. Instruções sobre como habilitar o PF podem ser encontradas em Primeiros Passos.
O enfileiramento é configurado no arquivo pf.conf. Existem dois tipos de diretivas que são utilizadas para configurar o enfileiramento:
A sintaxe para a diretiva altq on é:
altq on interface agendador bandwidth larg_de_banda qlimit lim_da_fila \
tbrsize tamanho queue { lista_de_filas }
Por exemplo:
altq on fxp0 cbq bandwidth 2Mb queue { std, ssh, ftp }Isso habilita o CBQ na interface fxp0. A largura de banda total disponível é configurada para 2Mbps. Três filas filhas são definidas: std, ssh e ftp.
A sintaxe para a diretiva queue é:
queue nome [on interface] bandwidth lar_de_banda [priority prio] [qlimit lim_da_fila] \
agendador ( opções_do_agendador ) { lista_de_filas }
Continuando o exemplo acima:
queue std bandwidth 50% cbq(default)
queue ssh bandwidth 25% { ssh_login, ssh_bulk }
queue ssh_login bandwidth 25% priority 4 cbq(ecn)
queue ssh_bulk bandwidth 75% cbq(ecn)
queue ftp bandwidth 500Kb priority 3 cbq(borrow red)
Aqui os parâmetros das filas filhas, previamente definidas, são configurados. A fila std possui largura de banda de 50% da largura de banda da fila raiz (ou 1Mbps) e está configurada como a fila padrão. A fila ssh possui 25% da largura de banda da fila raiz (500kb) e também contém duas filas filhas, ssh_login e ssh_bulk. A fila ssh_login tem prioridade maior que a ssh_bulk, e ambas tem ECN habilitado. A largura de banda atribuída à fila ftp é de 500Kbps, com a prioridade 3. Ela também pode tomar largura de banda emprestada quando estiver disponível, e também tem RED habilitado.
NOTA: Cada definição de fila filha tem sua largura de banda especificada. Sem especificar a largura de banda, o PF dá à fila 100% da largura de banda da fila pai. Nessa situação, que causaria um erro quando as regras fossem carregadas, pois se já existe uma fila com 100% da largura de banda, nenhuma outra fila pode ser definida nesse nível, já que não existe largura de banda livre para ser alocada.
Para atribuir tráfego a uma fila, a palavra-chave queue é usada em conjunto com as regras de filtragem do PF. Por exemplo, considere um conjunto de regras de filtragem contendo uma linha como:
pass out on fxp0 proto tcp to port 22
Pacotes que corresponderam àquela regra podem ser atribuídos a uma fila específica através do uso da palavra-chave queue:
pass out on fxp0 proto tcp to port 22 queue ssh
Quando uma entrada na tabela de estados é criada por esta regra, o PF irá registrar a fila pertencente a esta entrada da tabela de estados; isso será utilizado por outros pacotes permitidos pela seguinte entrada:
pass in on fxp0 proto tcp to port 80 queue httpCom essa regra, pacotes pertencentes a conexões stateful e trafegando de volta por fxp0 que vão acabar na fila http. Percebe-se, então, que mesmo que a queue esteja sendo utilizada em uma regra de filtragem de tráfego de entrada, o objetivo é especificar uma fila para o tráfego de saída correspondente; a regra acima não adiciona pacotes de entrada a uma fila.
Ao usar a palavra-chave queue com diretivas block, quaisquer pacotes TCP RST ou ICMP de Inalcançável resultantes serão atribuídos à fila especificada.
Note que as designações de filas podem ocorrer em uma interface diferente da definida na diretiva altq on:
altq on fxp0 cbq bandwidth 2Mb queue { std, ftp }
queue std bandwidth 500Kb cbq(default)
queue ftp bandwidth 1.5Mb
pass in on dc0 proto tcp to port 21 queue ftp
O enfileiramento está habilitado em fxp0, mas a designação acontece em dc0. Se os pacotes que correspondem à regra pass (ou ao estado correspondente a esta regra) sairem pela interface fxp0, eles serão enfileirados na fila ftp. Esse tipo de enfileiramento pode ser muito útil em roteadores.
Normalmente apenas um nome de fila é informado com a palavra-chave queue, mas caso um segundo nome seja especificado, a fila será usada para pacotes com um Tipo de Serviço (ToS - "Type of Service") de baixo atraso e para pacotes TCP ACK sem carga útil de dados. Um bom exemplo disso é encontrado ao utilizar o SSH. Inícios de sessão SSH definem o ToS para baixo atraso enquanto que sessões SCP e SFTP não. O PF pode usar essas informações para enfileirar pacotes pertencentes a uma conexão de início de sessão em uma fila diferente dos pacotes que não forem de conexões de início de sessão. Isso pode ser útil para priorizar os pacotes das conexões de início de sessão sobre pacotes de transferência de arquivos.
pass out on fxp0 from any to any port 22 queue(ssh_bulk, ssh_login)
Isso atribui pacotes pertencentes à conexões de início de sessão SSH para a fila ssh_login, e pacotes pertencentes à conexões SCP e SFTP para a fila ssh_bulk. Conexões de início de sessão SSH terão seus pacotes processados antes dos pacotes SCP e SFTP porque a fila ssh_login tem uma prioridade maior.
Atribuir pacotes TCP ACK a uma fila de alta prioridade é útil em conexões assimétricas, isto é, conexões que possuem taxas de upload e download diferentes, como conexões ADSL, por exemplo. Em uma conexão ADSL, se o canal de upload estiver sendo utilizado em sua capacidade máxima e um download é iniciado, o download sofre porque os pacotes TCP ACK que devem ser enviados entram em um congestionamento quando tentam passar pelo canal de upload. Testes têm mostrado que para atingir os melhores resultados a largura de banda na fila de upload deve ser configurada para um valor menor do que a conexão realmente é capaz. Por exemplo, se uma conexão ADSL tem uma taxa máxima de upload de 640Kbps, configurar a bandwidth (largura de banda) da fila raiz para um valor como 600Kb deve resultar em uma melhora de desempenho. Tentativas e erros mostram a melhor configuração de bandwidth.
[ Alice ] [ Charlie ]
| | ADSL
---+-----+-------+------ dc0 [ OpenBSD ] fxp0 -------- ( Internet )
|
[ Bob ]
Nesse exemplo o OpenBSD está sendo usado em um gateway de Internet para uma pequena rede doméstica com três estações de trabalho. O gateway faz filtragem de pacotes e NAT. A conexão com a Internet é via linha ADSL funcionando a 2Mbps de download e 640Kbps de upload.
A política de enfileiramento para essa rede:
Abaixo o conjunto de regras adequado à política da rede. Perceba que somente diretivas pf.conf que se aplicam diretamente à política descrita acima estão presentes.
# Habilita o enfileiramento na interface externa para controlar o
# tráfego indo para Internet. Usa o agendador priq para controlar
# somente as prioridades. Define a largura de banda como 610Kbps para
# obter o melhor desempenho da fila TCP ACK.
altq on fxp0 priq bandwidth 610Kb queue { std_out, ssh_im_out, dns_out, \
tcp_ack_out }
# Define os parâmetros para as filas filhas.
# std_out - a fila padrão. Qualquer regra de filtragem abaixo que
# não especifique explicitamente uma fila terá seu
# tráfego adicionado a essa fila.
# ssh_im_out - SSH interativo e tráfego de várias mensagens
# instantâneas.
# dns_out - pesquisas DNS.
# tcp_ack_out - pacotes TCP ACK sem carga útil de dados.
queue std_out priq(default)
queue ssh_im_out priority 4 priq(red)
queue dns_out priority 5
queue tcp_ack_out priority 6
# Habilita o enfileiramento na interface interna para controlar o tráfego
# vindo da Internet. Usa o agendador cbq para controlar a largura de banda.
# A largura de banda máxima é 2Mbps.
altq on dc0 cbq bandwidth 2Mb queue { std_in, ssh_im_in, dns_in, bob_in }
# Define os parâmetros para as filas filhas.
# std_in - a fila padrão. Qualquer regra de filtragem abaixo que
# não especifique explicitamente uma fila terá seu
# tráfego adicionado a essa fila.
# ssh_im_in - SSH interativo e tráfego de várias mensagens
# instantâneas.
# dns_in - respostas DNS.
# bob_in - largura de banda reservada para a estação de trabalho de
# Bob. Permitir a ele emprestar banda dos outros.
queue std_in bandwidth 1.6Mb cbq(default)
queue ssh_im_in bandwidth 200Kb priority 4
queue dns_in bandwidth 120Kb priority 5
queue bob_in bandwidth 80Kb cbq(borrow)
# ... Na seção de filtragem do pf.conf ...
alice = "192.168.0.2"
bob = "192.168.0.3"
charlie = "192.168.0.4"
local_net = "192.168.0.0/24"
ssh_ports = "{ 22 2022 }"
im_ports = "{ 1863 5190 5222 }"
# Regras de filtragem para o tráfego de entrada em fxp0
block in on fxp0 all
# Regras de filtragem para o tráfego de saída em fxp0
block out on fxp0 all
pass out on fxp0 inet proto tcp from (fxp0) queue(std_out, tcp_ack_out)
pass out on fxp0 inet proto { udp icmp } from (fxp0)
pass out on fxp0 inet proto { tcp udp } from (fxp0) to port domain \
queue dns_out
pass out on fxp0 inet proto tcp from (fxp0) to port $ssh_ports \
queue(std_out, ssh_im_out)
pass out on fxp0 inet proto tcp from (fxp0) to port $im_ports \
queue(ssh_im_out, tcp_ack_out)
# Regras de filtragem para o tráfego de entrada em dc0
block in on dc0 all
pass in on dc0 from $local_net
# Regras de filtragem para o tráfego de saída em dc0
block out on dc0 all
pass out on dc0 to $local_net
pass out on dc0 proto { tcp udp } from port domain to $local_net \
queue dns_in
pass out on dc0 proto tcp from port $ssh_ports to $local_net \
queue(std_in, ssh_im_in)
pass out on dc0 proto tcp from port $im_ports to $local_net \
queue ssh_im_in
pass out on dc0 to $bob queue bob_in
|
( Dep. de TI ) [ PC do Chefe ]
| | T1
--+----+------+--------- dc0 [ OpenBSD ] fxp0 -------- ( Internet )
| fxp1
[ COMP1 ] [ WWW ] /
| /
--+----------'
Nesse exemplo a máquina OpenBSD funciona como firewall para a rede de uma empresa. A empresa roda um servidor WWW na porção DMZ de sua rede, onde os clientes fazem upload de seus sítios Web via FTP. O departamento de TI possui sua própria sub-rede conectada na rede principal, e o chefe tem um PC em sua mesa que é usado para acessar o correio eletrônico e navegar na Internet. A conexão com a Internet é via linha T1 funcionando a 1.5Mbps em ambas as direções. Todos os outros segmentos de rede utilizam Fast Ethernet (100Mbps).
O administrador da rede decidiu pela seguinte política:
Abaixo o conjunto de regras adequado à política da rede. Perceba que somente diretivas pf.conf que se aplicam diretamente à política descrita acima estão presentes; nat, rdr, opções, etc., não são mostradas.
# Habilita o enfileiramento na interface externa para enfileirar pacotes
# saindo para a Internet. Usa o agendador cbq de modo que o uso da
# largura de banda por cada fila possa ser controlado.
# A largura de banda máxima para tráfego de saída é de 1.5Mbps.
altq on fxp0 cbq bandwidth 1.5Mb queue { std_ext, www_ext, boss_ext }
# Define os parâmetros para as filas filhas.
# std_ext - a fila padrão. Também é a fila padrão para o tráfego
# de saída em fxp0.
# www_ext - fila contêiner para as filas do servidor WWW.
# Limitada a 500Kbps.
# www_ext_http - tráfego http do servidor WWW; alta prioridade.
# www_ext_misc - todo o tráfego diferente de http do servidor WWW.
# boss_ext - tráfego vindo do computador do chefe.
queue std_ext bandwidth 500Kb cbq(default borrow)
queue www_ext bandwidth 500Kb { www_ext_http, www_ext_misc }
queue www_ext_http bandwidth 50% priority 3 cbq(red borrow)
queue www_ext_misc bandwidth 50% priority 1 cbq(borrow)
queue boss_ext bandwidth 500Kb priority 3 cbq(borrow)
# Habilita o enfileiramento na interface interna para controlar o
# tráfego vindo da internet ou DMZ. Usa o agendador cbq para controlar a
# largura de banda de cada fila. Esta interface está configurada para a
# largura máxima de banda. Tráfego vindo da DMZ pode usar toda a
# largura de banda, enquanto tráfego vindo da Internet é limitado a
# 1.0Mbps (porque 0.5Mbps (500Kbps) está alocado para fxp1).
altq on dc0 cbq bandwidth 100% queue { net_int, www_int }
# Define os parâmetros para as filas filhas.
# net_int - fila contêiner para o tráfego da Internet.
# Largura de banda de 1.0Mbps.
# std_int - a fila padrão. Também é a fila padrão para o tráfego
# de saída em dc0.
# it_int - tráfego para a rede do departamento de TI; reserva
# a eles 500Kbps.
# boss_int - tráfego para o PC do chefe, designa alta prioridade.
# www_int - tráfego do servidor WWW na DMZ; velocidade máxima.
queue net_int bandwidth 1.0Mb { std_int, it_int, boss_int }
queue std_int bandwidth 250Kb cbq(default borrow)
queue it_int bandwidth 500Kb cbq(borrow)
queue boss_int bandwidth 250Kb priority 3 cbq(borrow)
queue www_int bandwidth 99Mb cbq(red borrow)
# Habilita o enfileiramento na interface da DMZ para controlar o tráfego
# destinado ao servidor WWW. cbq será utilizado nesta interface já que
# o controle preciso se faz necessário. A largura de banda nesta
# interface está configurada para o máximo. O tráfego da rede interna
# é capaz de utilizar toda a largura de banda, enquanto o tráfego da
# Internet é limitado a 500Kbps.
altq on fxp1 cbq bandwidth 100% queue { internal_dmz, net_dmz }
# Define os parâmetros para as filas filhas.
# internal_dmz - tráfego da rede interna.
# net_dmz - fila contêiner para o tráfego da Internet.
# net_dmz_http - tráfego http; alta prioridade.
# net_dmz_misc - todo tráfego não-http. Essa também é a fila padrão.
queue internal_dmz bandwidth 99Mb cbq(borrow)
queue net_dmz bandwidth 500Kb { net_dmz_http, net_dmz_misc }
queue net_dmz_http bandwidth 50% priority 3 cbq(red borrow)
queue net_dmz_misc bandwidth 50% priority 1 cbq(default borrow)
# ... Na seção de filtragem do pf.conf ...
main_net = "192.168.0.0/24"
it_net = "192.168.1.0/24"
int_nets = "{ 192.168.0.0/24, 192.168.1.0/24 }"
dmz_net = "10.0.0.0/24"
boss = "192.168.0.200"
wwwserv = "10.0.0.100"
# Negar por padrão
block on { fxp0, fxp1, dc0 } all
# Regras de filtragem para o tráfego de entrada em fxp0
pass in on fxp0 proto tcp from any to $wwwserv port { 21, \
> 49151 } queue www_ext_misc
pass in on fxp0 proto tcp from any to $wwwserv port 80 queue www_ext_http
# Regras de filtragem para o tráfego de saída em fxp0
pass out on fxp0 from $int_nets
pass out on fxp0 from $boss queue boss_ext
# Regras de filtragem para o tráfego de entrada em dc0
pass in on dc0 from $int_nets
pass in on dc0 from $it_net queue it_int
pass in on dc0 from $boss queue boss_int
pass in on dc0 proto tcp from $int_nets to $wwwserv port { 21, 80, \
> 49151 } queue www_int
# Regras de filtragem para o tráfego de saída em dc0
pass out on dc0 from dc0 to $int_nets
# Regras de filtragem para o tráfego de entrada em fxp1
pass in on fxp1 proto { tcp, udp } from $wwwserv to port 53
# Regras de filtragem para o tráfego de saída em fxp1
pass out on fxp1 proto tcp to $wwwserv port { 21, \
> 49151 } queue net_dmz_misc
pass out on fxp1 proto tcp to $wwwserv port 80 queue net_dmz_http
pass out on fxp1 proto tcp from $int_nets to $wwwserv port { 80, \
21, > 49151 } queue internal_dmz
|
[Anterior: Âncoras] [Conteúdo] [Próximo: Grupos de Endereços e Balanceamento de Carga]