[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. Numa rede de computadores, quando pacotes de dados são enviados por um host, eles entram numa fila onde aguardam processamento pelo sistema operacional. O sistema operacional decide qual fila e quais pacotes nesta fila devem ser processados. A ordem em que o sistema operacional escolhe os pacotes a processar pode afetar a performance da rede. Por exemplo, imagine um usuário executando duas aplicações de rede: SSH e FTP. Em condiçoes 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 num 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 estas 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á muito lenta e com atrasos. Modificando a estratégia de enfileiramento utilizada, a largura de banda pode ser compartilhada entre diferentes aplicações, usuários e computadores.
Perceba que o enfileiramento é útil somente para pacotes saindo. Quando o pacote chega entrando numa 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 o host que recebeu o pacote está funcionado como roteador, habilitar enfileiramento na interface interna onde os pacotes saem do mesmo.
OpenBSD suporta mais dois escalonadores:
Filas CBQ são organizadas de forma hirárquica. No topo da hierarquia está a fila raiz que define a quantidade total de banda disponível. As outras filas 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 assim:
Neste caso, a largura de banda total disponível está definida para 2 megabits por segundo (Mbps). Esta banda é então dividida entre outras três filas.
A hierarquia pode ser expandida definindo-se filas dentro de filas. Para dividir a banda igualmente entre diferentes usuários e ainda classificar seu tráfego de forma que certos protocolos não ocupem a banda de outros, uma estrutura parecida com essa pode ser definida:
Perceba que a cada nível a soma do total de banda vinculado a cada fila nunca é maior que o valor da banda da fila raiz.
Uma fila pode ser configurada para emprestar banda de sua fila pai caso as outras filas dentro da fila pai não estejam usando sua porção e a banda esteja disponível. Considere a configuração a seguir:
Se o tráfego na fila ftp exceder os 900Kbps e o tráfego na fila UserA for menor que 1Mbps (por que a fila ssh está usando menos que 100Kbps), a fila ftp irá emprestar banda de UserA. Desta forma a fila ftp pode usar mais banda do que foi definido a princípio quando necessário. Quando o tráfego na fila ssh aumenta, a banda emprestada é devolvida.
CBQ atribui a cada fila um nível de prioridade. Filas com prioridade alta tem preferência sobre outras com menor prioridade em caso de congestionamento, contanto que estejam contidas na mesma fila pai (Em outras palavras contanto que estejam no mesmo nível na hierarquia). Filas com a mesma prioridade são processadas em sequência (round-robin). Por exemplo:
O CBQ irá processar as filas UserA e UserB em sequência -- nenhuma fila será preferida sobre a outra. Enquanto a fila UserA está sendo processada, o CBQ também irá processar suas subfilas. Neste 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 tem suas prioridades comparadas às filas UserA e UserB pelo fato de elas não estarem no mesmo nível na hierarquia.
Para um estudo mais detalhado sobre a teoria por trás do CBQ, por favor consulte Referências sobre CBQ.
A estrutura de enfileiramento no PRIQ é simples -- você não pode definir filas dentro de filas. A fila raiz é definida, onde é configurado o total de banda disponível, então subfilas são definidas sob a raiz. Considere o exemplo a seguir:
A fila raiz é definida possuindo 2Mbps de largura de banda disponível e três subfilas são definidas. A fila com maior prioridade (o maior número na prioridade) é servida primeiro. Quando todos pacotes nesta fila são processados, ou caso a fila esteja vazia, PRIQ vai para a próxima fila com prioridade mais alta. Dentro da fila, os pacotes são processados num sistema FIFO (First In First Out).
É importante notar quando estiver usando PRIQ que você deve planejar suas filas com muito cuidado. Como PRIQ sempre processa a fila com prioridade mais alta 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 pacotes constantemente.
O RED é útil porque evita uma situação conhecida como sincronização global e 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 num roteador 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 cairá severamente. Esta 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 é utilizada mais em todo seu potencial. RED evita esse cenário escolhendo aleatoriamente quais conexões terão pacotes descartados ao invés de escolher todas elas. Conexões usando muita largura de banda tem chances maiores de terem seus pacotes descartados. Desta forma, conexões que ocupam muita banda serão evitadas, o congestionamento será evitado, e sérias perdas nas taxas de transferência não ocorrerão. 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 táfego inesperado chegar, existirá 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 isto significa que RED deve ser usado para enfileirar tráfego TCP e nunca tráfego UDP ou ICMP.
Para uma discussão mais detalhada sobre a teoria por trás do RED, por favor consulte Referências sobre RED.
Para mais informações sobre ECN, por favor consulte a RFC 3168.
Pelo fato de ALTQ ter sido integrado ao PF, o PF deve estar habilitado para que o sistema funcione. Instruções de como habilitar o PF podem ser encontradas em Começando.
Filas são configuradas no arquivo pf.conf. Existem dois tipos de diretivas utilizadas para configuração de filas:
A sintaxe para a diretiva altq on é:
altq on interface scheduler bandwidth bw qlimit qlim \
tbrsize size queue { queue_list }
Por exemplo:
altq on fxp0 cbq bandwidth 2Mb queue { std, ssh, ftp }Isso habilitará o CBQ na interface fxp0. A largura de banda total disponível é configurada para 2Mbps. Três subfilas são definidas: std, ssh e ftp.
A sintaxe para a diretiva queue é:
queue name [on interface] bandwidth bw [priority pri] [qlimit qlim] \
scheduler ( sched_options ) { queue_list }
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 subfilas previamente definidas são configurados. A fila std possui largura de banda de 50% da fila raiz (ou 1Mbps) e está configurada como a fila padrão. A fila ssh possui 25% da banda da fila raiz (500kb) e também contém duas filas ssh_login e ssh_bulk. A fila ssh_login tem prioridade maior que ssh_bulk e ambas tem ECN habilitado. A banda atribuída à fila ftp é de 500Kbps com prioridade 3. Ela também pode tomar banda emprestada quando estiver disponível e também tem RED habilitado.
NOTA: Cada definição de fila tem sua banda especificada. Sem especificar a banda, o PF dará a fila 100% da banda da fila pai. Nesta situação, que causará um erro quando as regras são carregadas uma vez que existe uma fila com 100% da banda, nenhuma outra fila pode ser definida neste nível uma vez que não existe banda livre para alocar.
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 from any to any port 22
Pacotes que casarem com esta regra podem ser enviados para uma fila específica através do uso da palavra-chave queue:
pass out on fxp0 from any to any port 22 queue ssh
Ao usar a palavra queue com diretivas block, quaisquer pacotes TCP RST ou ICMP Unreachable resultantes serão enviados à fila especificada.
Note que as designações de filas podem ocorrer numa 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 from any to any port 21 queue ftp
Enfileiramento está habilitado em fxp0 mas a designação acontece em dc0. Se os pacotes combinando com a regra pass sairem pela interface fxp0, serão enfileirados na fila ftp. Este tipo de enfileiramento pode ser muito útil em roteadores.
Normalmente apenas um nome de fila é informado com a palavra queue, mas caso um segundo nome seja especificado a fila será usada para pacotes com um Type of Service (ToS) com pouco atraso e para pacotes TCP ACK sem payload de dados. Um bom exemplo disso pode ser obtido utilizando SSH. Sessões de login SSH irão definir o ToS para low-delay enquanto que sessões SCP e SFTP não. PF pode usar estas informações para enfileirar pacotes pertencentes a uma conexão de login numa fila diferente dos pacotes que não forem de conexões de login. Isso pode ser útil para priorizar os pacotes das conexões de login sobre pacotes de transferência de arquivos.
pass out on fxp0 from any to any port 22 queue(ssh_bulk, ssh_login)
Isto envia pacotes pertencentes a conexões de login SSH para a fila ssh_login e pacotes pertencentes a conexões SCP e SFTP para a fila ssh_bulk. Conexões de login SSH terão seus pacotes processados antes dos pacotes SCP e SFTP, porque a fila ssh_login tem 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. Numa conexão ADSL, se o canal de upload estiver sendo utilizado em sua capacidade máxima e um download é iniciado, o download irá sofrer porquê os pacotes TCP ACK que devem ser enviados entrarão num congestionamento quando tentarem passar pelo canal de upload. Testes tem mostrado que para atingir os melhores resultados, a largura de banda na fila de upload deve ser configurado 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 da fila raiz para um valor como 600Kbp deve resultar numa melhora de performance. Tentativas e erros mostrarão a melhor configuração de bandwidth.
Ao utilizar a palavra queue com regras que mantém o estado das conexões keep state como:
pass in on fxp0 proto tcp from any to any port 22 flags S/SA \
keep state queue ssh
O PF gravará uma entrada para fila na tabela de estado de forma que pacotes saindo pela fxp0 que combinem com a conexão stateful serão enviados para a fila ssh. Perceba que apesar da palavra queue estar sendo utilizada num regra filtrando tráfego entrante, o objetivo é especificar uma fila para o tráfego que sai; a regra acima não enfileira pacotes entrantes.
[ Alice ] [ Charlie ]
| | ADSL
---+-----+-------+------ dc0 [ OpenBSD ] fxp0 -------- ( Internet )
|
[ Bob ]
Neste exemplo, o OpenBSD está sendo usado num gateway 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 Internet é via linha ADSL rodando a 2Mbps down e 640Kbps up.
O política de filas para esta rede:
Abaixo segue o conjunto de regras adequado à política da rede. Perceba que somente diretivas pf.conf que se aplicam diretamente a política descrita acima estão presentes; nat, rdr, options, etc., não são mostradas.
# habilita enfileiramento na interface externa para controlar tráfego
# indo para Internet. usa o escalonador priq para controlar somente prioridades.
# define largura de banda para 610Kbps para obter melhor performance
# na 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 subfilas.
# std_out - a fila padrão. qualquer regra abaixo que não especifique
# explicitamente uma fila terá seu tráfego inserido nesta fila.
# ssh_im_out - SSH interativo e tráfego de várias mensagems instantâneas.
# dns_out - pesquisas DNS.
# tcp_ack_out - pacotes TCP ACK sem dados de payload.
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 enfileiramento na interface interna para controlar tráfego
# vindo da Internet. usa escalonador cbq para controlar a banda.
# 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 subfilas.
# std_in - a fila padrão. qualquer regra de filtragem abaixo que
# não expecifique explicitamente uma fila terá seu
# tráfego inserido nesta fila.
# ssh_im_in - SSH interativo e tráfego de várias mensagems instantâneas.
# dns_in - respostas DNS.
# bob_in - 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 entrada em fxp0
block in on fxp0 all
# regras de filtragem para saída em fxp0
block out on fxp0 all
pass out on fxp0 inet proto tcp from (fxp0) to any flags S/SA \
keep state queue(std_out, tcp_ack_out)
pass out on fxp0 inet proto { udp icmp } from (fxp0) to any keep state
pass out on fxp0 inet proto { tcp udp } from (fxp0) to any port domain \
keep state queue dns_out
pass out on fxp0 inet proto tcp from (fxp0) to any port $ssh_ports \
flags S/SA keep state queue(std_out, ssh_im_out)
pass out on fxp0 inet proto tcp from (fxp0) to any port $im_ports \
flags S/SA keep state queue(ssh_im_out, tcp_ack_out)
# regras de filtragem de entrada em dc0
block in on dc0 all
pass in on dc0 from $local_net
# regras de filtragem de saída em dc0
block out on dc0 all
pass out on dc0 from any to $local_net
pass out on dc0 proto { tcp udp } from any port domain to $local_net \
queue dns_in
pass out on dc0 proto tcp from any port $ssh_ports to $local_net \
queue(std_in, ssh_im_in)
pass out on dc0 proto tcp from any port $im_ports to $local_net \
queue ssh_im_in
pass out on dc0 from any to $bob queue bob_in
|
( IT Dept ) [ Boss's PC ]
| | T1
--+----+-----+---------- dc0 [ OpenBSD ] fxp0 -------- ( Internet )
| fxp1
[ COMP1 ] [ WWW ] /
| /
--+----------'
Neste 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 websites via FTP. O departamento de TI possui sua própria subrede conectada na rede principal, e o chefe tem um PC em sua mesa que é usado para ler email e navegar na Internet. A conexão com a Internet é via um linha T1 rodando a 1.5Mbps em ambas as direções. Todos os outros segmentos de rede utilizam Fast Ethernet (100Mbps).
O administrador de rede decidiu pela seguinte política:
Abaixo estão as regras que fazem a política desta rede. Perceba que somente diretivas pf.conf que se aplicam diretamente a política descrita acima estão presentes; nat, rdr, options, etc., não são mostradas.
# habilita enfileiramento na interface externa para pacotes
# saindo para a Internet. usa cbq para que o uso da banda por cada fila
# possa ser controlado. a largura máxima para tráfego saindo é de 1.5Mbps.
altq on fxp0 cbq bandwidth 1.5Mb queue { std_ext, www_ext, boss_ext }
# define os parâmetros para as subfilas.
# std_ext - a fila padrão. também para tráfego saindo via fxp0.
# www_ext - fila para tráfego WWW do servidor. limitada a 500Kbps.
# www_ext_http - fila para tráfego WWW do servidor; alta prioridade.
# www_ext_misc - todo tráfego difetente 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 enfileiramento na interface interna para controlar tráfego
# vindo da internet para DMZ. usa cbq para controlar a banda em cada
# fila. esta interface está configurada para largura máxima de banda.
# tráfego vindo da DMZ poderá usar toda a banda enquanto tráfego vindo
# da Internet será 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 subfilas.
# net_int - fila para tráfego vindo da Internet. banda de 1.0Mbps.
# std_int - a fila padrão. padrão também para tráfego
# saindo via dc0.
# it_int - tráfego para a rede do TI; reservar 500Kbps.
# boss_int - tráfego para o PC do chefe, designar alta prioridade.
# www_int - tráfego do servidor WWW na DMZ; velocicade 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)
# habilitar enfileiramento na interface da DMZ para controlar tráfego
# destinado ao servidor WWW. cbq é utilizado nesta interface já que
# controle preciso se faz necessário. a banda nesta interface está
# configurada para sua capacidade máxima. tráfego da rede interna poderá
# utilizar toda a banda, enquanto tráfego da Internet será limitado a
# 500Kbps.
altq on fxp1 cbq bandwidth 100% queue { internal_dmz, net_dmz }
# define os parâmetros para as subfilas.
# internal_dmz - tráfego da rede interna.
# net_dmz - tráfego da Internet.
# net_dmz_http - tráfego http; alta prioridade.
# net_dmz_misc - todo tráfego não-http. esta 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 of 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 entrada em fxp0
pass in on fxp0 proto tcp from any to $wwwserv port { 21, \
> 49151 } flags S/SA keep state queue www_ext_misc
pass in on fxp0 proto tcp from any to $wwwserv port 80 \
flags S/SA keep state queue www_ext_http
# regras de filtragem para saída em fxp0
pass out on fxp0 from $int_nets to any keep state
pass out on fxp0 from $boss to any keep state queue boss_ext
# regras de filtragem para entrada em dc0
pass in on dc0 from $int_nets to any keep state
pass in on dc0 from $it_net to any queue it_int
pass in on dc0 from $boss to any queue boss_int
pass in on dc0 proto tcp from $int_nets to $wwwserv port { 21, 80, \
> 49151 } flags S/SA keep state queue www_int
# regras de filtragem para saída em dc0
pass out on dc0 from dc0 to $int_nets
# regras de filtragem para entrada em fxp1
pass in on fxp1 proto { tcp, udp } from $wwwserv to any port 53 \
keep state
# regras de filtragem para saída em fxp1
pass out on fxp1 proto tcp from any to $wwwserv port { 21, \
> 49151 } flags S/SA keep state queue net_dmz_misc
pass out on fxp1 proto tcp from any to $wwwserv port 80 \
flags S/SA keep state queue net_dmz_http
pass out on fxp1 proto tcp from $int_nets to $wwwserv port { 80, \
21, > 49151 } flags S/SA keep state queue internal_dmz
|
[Anterior: Âncoras] [Conteúdo] [Próximo: Grupos de Endereços e Balanceamento de Carga]