Site menu Qualidade de serviço (QoS) na Internet

Qualidade de serviço (QoS) na Internet

O objetivo deste artigo é introduzir o tema "qualidade de serviço" (QoS) na Internet, com algum foco nas ferramentas de QoS do Linux. A documentação autoritativa sobre o assunto ainda é o velho LARTC HOWTO, porém ele está meio desatualizado. Este artigo da Comparitech tem algumas outras referências. Adicionei algumas novidades marcadas com [Update 2018] mais para o fim do texto; são novidades ainda não "sacramentados" no LARTC.

Afinal, existe QoS no TCP/IP e na Internet?

A resposta curta: "Não". A única coisa que você pode controlar na Internet é o ritmo dos pacotes que você envia.

Você nem sequer pode controlar os pacotes que recebe. Pode até ignorá-los, mas já é tarde, eles já ocuparam sua banda. Para sacanear o link de alguém, basta juntar uma meia dúzia de pessoas e fazer todas mandarem montes de pacotes para a vítima.

Além disso, o TCP tem a tendência natural de usar toda a banda disponível. Em tese, diversas conexões TCP em paralelo vão compartilhar a banda disponível, mas na prática é mais correto dizer que elas vão brigar pela banda. Em particular as conexões "novatas" vão sofrer muito para abrir caminho. Todo mundo que já tentou acessar um site ao mesmo tempo que baixa um ou dois pacotes grandes, sabe como é.

(Recado de 2016 para um artigo de 2004: hoje em dia até os roteadores de uso doméstico implementam um arremedo de QoS, e os links domésticos estão muito mais rápidos que em 2004, então o problema não é tão pronunciado. Mas o problema ainda pode se manifestar numa conexão 3G compartilhada.)

A aplicação pode em tese controlar o volume de dados, mas apenas uma minoria delas realmente faz isso. Como o TCP/IP não oferece mecanismos diretos para descobrir a velocidade do seu link, seria difícil a qualquer aplicativo auto-configurar-se para usar, digamos, apenas metade da banda disponível.

Para implementar qualidade de serviço na Internet, seria necessário que todos os roteadores suportassem o conceito, ou pelo menos os que estão num gargalo, como o link internacional do seu provedor de acesso à Internet. Se você fizer uma conexão TCP entre Brasil e Nova Zelândia e quiser uma banda mínima garantida de 100kbps, todos os roteadores do caminho têm de garantir 100kbps. Isto garante que a) nossos dados vão fluir; e b) a conexão TCP não vai monopolizar o link.

Implementar esse tipo de garantia seria perfeitamente possível. Já existe o protocolo (RSVP) e também os roteadores que o suportam, mas a coisa empaca numa simples pergunta: quem vai pagar a conta? Todo mundo quer QoS mas ninguém quer pagar a mais por isso. E se for de graça, será alvo de abuso.

Então, o que resta é construir estratégias de QoS baseadas unicamente na regulação da nossa própria transmissão de pacotes.

Mas a minha Internet funciona, que diferença faz?

Dadas as limitações e características do TCP/IP, eu fico sinceramente surpreso que, na maior parte do tempo, a coisa funciona. Mesmo serviços como VoIP e videoconferência são utilizados com sucesso por milhões ou bilhões de pessoas leigas ao redor do globo. Como é que pode?

Isto se deve, em primeiríssimo lugar, ao controle de congestionamento do TCP, que é o "antídoto" para a tendência de comer toda a banda. Ao primeiro sinal de perda de pacotes (ou do flag ECN em sistemas recentes), o TCP reduz bruscamente a taxa de envio.

Além de evitar o congestionamento generalizado da Internet, esta característica do TCP permite que usemos alguns truques para implementar QoS, conforme veremos.

Outro recurso pouco comentado do TCP/IP é o TOS (Type Of Service). É um pequeno mapa de bits do IP (abaixo do TCP), que sugere prioridade e tipo de tráfego. Há três bits de prioridade, três bits de tipo e dois bits que são hoje utilizados pelo ECN.

Embora nenhum roteador intermediário seja obrigado a prestar atenção a estes bits (até porque podem ser abusados), a maioria dos aplicativos, roteadores e sistemas operacionais respeita estes bits, e prioriza o tráfego de acordo. Lembrando novamente que isto só afeta o tráfego upstream, cuja fila o nosso roteador pode controlar e priorizar.

Mas afinal, o que é qualidade de serviço (QoS)?

Uma definição informal seria: vários serviços usando o mesmo link para acessar a Internet, cada um com requisitos diferentes, e todos conseguindo fazer o seu trabalho. Fazer download rápido, usar Skype sem "cortar" a voz e acessar o VNC remoto com baixo tempo de resposta, tudo ao mesmo tempo.

Alguns parâmetros de qualidade de serviço são:

BANDA: muitos serviços precisam de uma banda mínima para funcionar, como no caso de voz sobre IP ou videoconferência. E é óbvio que, quanto mais banda disponível houver, mais rápidos serão os downloads, aberturas de páginas Web, etc.

LATÊNCIA: é o tempo que o pacote leva para chegar ao destino. Alta latência prejudica muito jogos e VNC/ssh remoto, e também prejudica um pouco voz sobre IP. Quando muito alta, também causa demoras para abrir páginas Web, coisa bastante irritante.

Muitas vezes, um problema de latência é percebido como "falta de banda". As primeiras ADSL tinham apenas o dobro da banda dos modems discados, mas pareciam ter dez vezes mais, simplesmente porque sua latência é muito menor (RTT de 30ms para ADSL e 140ms para modem).

JITTER: é a variação da latência. Causa problemas mais visíveis na voz sobre IP, embora incomode qualquer conexão TCP, já que o TCP pressupõe que a latência de um link é mais ou menos constante. Um pacote que demora a chegar é considerado perdido, e o TCP reage fortemente à perda de pacotes.

No caso do VoIP, a aplicação tem a opção de implementar um "jitter buffer", que adiciona um atraso adicional fixo, para acomodar um eventual jitter. Isto permite o áudio tocar sem cortes, mas tem de ser usado judiciosamente, porque um atraso total (link+buffer) muito grande confunde os interlocutores. Uma pessoa fala, a outra demora a ouvir, e demora mais ainda para responder. Aí começa aquele "Alô?... alô?...".

JUSTIÇA: todas as conexões de mesma classe e prioridade deveriam receber uma fatia igual da banda.

Como infernizar os demais usuários da sua rede

Se não houver controle de QoS no acesso à Internet, basta colocar uns downloads bem grandes para baixar. As consequências serão as seguintes:

a) As conexões TCP de download aumentarão o ritmo até ocupar toda a banda disponível.

b) Como provavelmente o seu link com a Internet é o gargalo do caminho até o servidor dos arquivos, o roteador do seu provedor de acesso começará a enfileirar pacotes. No caso de links ADSL, esta fila pode ser muito longa, equivalente a até 5 segundos de tráfego.

c) Qualquer outro usuário que inicie uma outra conexão à Internet vai entrar lá no fim na fila na hora de receber a resposta. A conexão dele vai demorar 5 segundos para abrir, em vez dos usuais 0,03.

d) Se qualquer usuário tentar usar voz sobre IP, enfrentará a fila e verá que a voz do interlocutor demorará até 5 segundos para chegar, bem pior que uma ligação internacional.

e) O roteador do provedor vai finalmente começar a descartar pacotes, o que faz seu download "maneirar" momentaneamente no consumo da banda. Isto faz o tamanho da fila variar, portanto faz oscilar a latência, aumentando o jitter.

Se você abriu diversos downloads simultâneos, elas vão "brigar" entre si, o excesso de banda de uma causando a perda de pacotes de outra, fazendo o comprimento da fila variar ainda mais, estragando completamente a Internet dos seus colegas...

Neste cenário, apenas o download é prejudicado. O envio de pacotes para fora ainda está livre. Para "resolver" isto, você dispara um Torrent também, de preferência oferecendo conteúdo bastante popular, e sem configurar limites de banda. Aí vai acontecer que:

a) O Torrent vai começar a mandar pacotes upstream até ocupar toda a banda. O seu roteador local, ou access point, vai começar também a enfileirar pacotes;

b) Agora os demais usuários enfrentam duas filas: uma na saída (roteador local) e outra na entrada (roteador do provedor). A latência pode dobrar, e o jitter aumentar muito.

O Wally (do Dilbert) não poderia ter feito melhor. Internet "parada", todo mundo pode ficar bebendo café na copa e reclamando da chefia que "não abre a mão pra pagar um link mais rápido".

Como evitar que um usuário acabe com o acesso à Internet

Ok, agora é a vez de jogar com as pretas: o administrador de rede ou o fabricante de roteadores contra-ataca.

A rigor, não há defesa perfeita contra um usuário decidido a entupir o acesso à Internet. Uma política simples e muito eficiente é simplesmente policiar o tráfego, usando alguma ferramenta tipo ntop, e puxar a orelha de quem estiver fazendo mau uso. Mas, às vezes, os usuários e os próprios sistemas usam mal a Internet sem a intenção. Então é preciso adotar algumas táticas proativas e automáticas.

Vamos imaginar uma rede bem simples com roteador NAT, que pode ser um simples access point:

rede local     +----------+
---------------|eth0      |
               | roteador |          +--------------+
	       |      ppp0|----------| roteador ISP |----> Internet
	       +----------+   ADSL   +--------------+

A principal coisa a fazer é: não deixar que se formem filas de pacotes nos rotedores. No sentido de upload, a fila está no nosso próprio roteador, pois o gargalo é o link ADSL. Já a fila de download está no roteador ISP, que não podemos controlar diretamente.

Para diminuir a chance de formar esta fila, o que podemos fazer é criar um gargalo artificial em eth0 no sentido de download, deixando passar uma banda menor que nosso link ADSL, e configurar nosso roteador para descartar pacotes em vez de enfileirá-los.

Isto fará as conexões TCP entrarem em controle de congestionamento, e diminuirem o ritmo. O objetivo final é que esta redução de ritmo "limpe" a fila do roteador ISP.

Não há garantias de que esta estratégia funcione, e nem que o efeito seja imediato, uma vez detectado o excesso de pacotes. Mas em geral funciona bem.

Escolher a banda de eth0 exige um pouco de experimentação. Quanto menor a banda de eth0, menor a chance de enfileiramento, e mais rápido o link se recupera de um eventual congestionamento. Seria ótimo ter um link de 100Mbps e limitar a banda a 50Mbps... mas então nosso link ficaria 50% ocioso.

Esta é uma característica inevitável do QoS sobre TCP/IP: para melhorar uma métrica de qualidade, precisamos dar alguma coisa em troca. Geralmente será um pouco de banda em troca de latência melhor.

No caso de um link de 2Mbps (que na verdade é menos, pois há o overhead do ATM e do PPPoE), uma limitação da banda a 1600kbps dá bons resultados, com uma perda na taxa de download de aproximadamente 12%.

Exemplo de configuração usando o controle de tráfego do Linux:

DOWN=1600
tc qdisc del dev eth0 root    2> /dev/null > /dev/null

# Disciplina downstream, feito na interface eth0
# Nem todo tráfego da eth0 deve ser disciplinado; apenas
# o que veio da Internet. Tráfego da rede local corre solto.

tc qdisc add dev eth0 root handle 1: htb r2q 100

# Classe com a capacidade downstream da ADSL 
tc class add dev eth0 parent 1: classid 1:20 htb \
	rate ${DOWN}kbit ceil ${DOWN}kbit

# Novamente usamos SFQ para justiça entre conexões
tc qdisc add dev eth0 parent 1:20 handle 20: sfq perturb 11

# Agora, marcamos o tráfego que deve ser controlado pela regra acima
# Critério: marcar os pacotes IP/IPv6 que vêm de interfaces expostas
# à Internet
iptables -t mangle -F PREROUTING
ip6tables -t mangle -F PREROUTING
iptables  -A PREROUTING -t mangle -i ppp0 -j MARK --set-mark 20
ip6tables -A PREROUTING -t mangle -i sixxs -j MARK --set-mark 20

# [Update 2018] O comando 'tc filter' agora exige
# que cada item tenha uma prioridade (prio) diferente.

tc filter add dev eth0 protocol ip parent 1:0 \
	prio 1 handle 20 fw flowid 1:20
tc filter add dev eth0 protocol ipv6 parent 1:0 \
	prio 2 handle 20 fw flowid 1:20

# Para ver estatísticas:
# tc -s -d qdisc show dev eth0
# tc -s -d class show dev eth0

Todo o script aí em cima destina-se unicamente a estrangular o download para a rede local. Ele não controla, por exemplo, o download destinado ao próprio roteador Linux. Note que o estrangulamento é feito na saída de eth0, não na entrada de ppp0. Lembre-se do mantra: não podemos controlar os pacotes que recebemos, só os que transmitimos.

A segunda coisa a fazer, que na verdade o script aí em cima já faz, é assegurar justiça entre conexões concorrentes. Conforme dissemos antes, as conexões TCP tendem sempre a monopolizar a banda. Mas, agora que criamos uma fila na interface de rede eth0, podemos usá-la para impedir que uma conexão monopolize a banda.

Vamos observar os dois comandos a seguir, que são o "coração" do script acima:

tc class add dev eth0 parent 1: classid 1:20 htb \
	rate ${DOWN}kbit ceil ${DOWN}kbit
tc qdisc add dev eth0 parent 1:20 handle 20: sfq perturb 11

A primeira linha cria uma CLASSE de tráfego, que é onde estrangulamos a banda. A segunda linha cria uma DISCIPLINA DE FILA. Utilizamos a disciplina SFQ, que distribui internamente as conexões em sub-filas e dá a cada sub-fila a chance de mandar um pacote.

Num computador rodando Linux sem QoS configurado, não há classe de tráfego, e cada interface tem apenas uma disciplina de fila: QFIFO_FAST, que leva em conta os bits TOS do TCP/IP. Ou seja, mesmo que não se faça configuração alguma, já existe algum controle de tráfego.

A estrutura interface-classe-disciplina é definida de cima para baixo, mas o pacote de rede na verdade flui de baixo para cima. O pacote vindo da Internet é encaixado numa disciplina de fila, e fica esperando. Pode haver várias filas; é o comando "tc filter" quem direciona o pacote à fila certa.

Quando a interface de rede está livre para enviar um pacote, ela requisita à classe "root", que por sua vez requisita à classe que criamos. Se a classe estiver pronta (o que só acontece se não tivermos extrapolado a banda configurada), ela requisita um pacote à fila (ou a uma sub-classe, se houver). A fila entrega o pacote, e ele sobe até a interface.

Bem, tratamos o problema no sentido de download. Agora vamos lidar com o upload. O script abaixo implementa este controle na interface ppp0:

UP=320
tc qdisc del dev ppp0 root
tc qdisc add dev ppp0 root handle 1: htb default 1 r2q 20
tc class add dev ppp0 parent 1: classid 1:1 htb rate ${UP}kbit \
	ceil ${UP}kbit
tc qdisc add dev ppp0 parent 1:1 handle 10: sfq perturb 10

Assim como fizemos para eth0, também definimos uma classe que limita a banda, e uma disciplina que assegura tratamento mais ou menos equitativo entre as diversas conexões.

Alguém poderia alegar que não precisamos limitar a banda, pois ela é naturalmente limitada pela velocidade da ADSL. O problema é que a interface de rede também tem sua própria fila, que é bastante longa (até 1000 pacotes) e fora do alcance do SFQ. Limitar a banda na classe garante que, quando uma classe libera um pacote, ele será imediatamente transmitido.

Mantendo os roteadores livres de filas longas, a latência fica baixa, o jitter também, e novas conexões são estabelecidas muito rapidamente.

A única coisa que falta agora é reservar banda para serviços que exigem banda garantida, como voz sobre IP. Fazemos isso adicionando sub-classes, algo que estou prometendo explicar neste artigo desde 2004 e provavelmente ficará pra o dia de São Nunca.

Quando nosso roteador Linux também roda serviços de rede, acessados a partir da Internet, como por exemplo um servidor Web ou FTP, temos de impor um controle adicional de banda, o "ingress":

DOWN_PRE=1750
tc qdisc del dev ppp0 ingress
tc qdisc add dev ppp0 handle ffff: ingress
tc filter add dev ppp0 parent ffff: protocol ip prio 50 \
	u32 match ip src \
  0.0.0.0/0 police rate ${DOWN_PRE}kbit burst 20k drop flowid :1

Os comandos acima implementam um controle grosseiro, baseado em "tc filter", que simplesmente descarta pacotes que ultrapassarem a banda de 1750kbps. É praticamente uma gambiarra. O Linux não permite fazer QoS diretamente sobre o tráfego entrante.

Note também que esta "pré-filtragem" deixa passar uma banda maior que os 1600kbps de eth0, tanto para compensar o overhead quanto para garantir que o pré-filtro não torne inútil o gargalo artificial que colocamos em eth0. Isto seria desastroso, porque o pré-filtro não faz "justiça" (não tem uma disciplina de tráfego SFQ).

Mas, como tudo nessa vida tem jeitinho (aliás, a brasileirada a-do-ra usar essas paradas de QoS para tirar leite de pedra da Internet), existe um truque para fazer QoS real sobre o tráfego entrante: criar uma interface de rede falsa por onde os pacotes "entram" e "saem" antes de serem consumidos. Assim, temos um ponto de saída onde podemos pendurar os comandos "tc".

Pelo menos dois módulos no Linux fazem isso: o IMQ e o IFB. O IMQ é mais antigo, existe desde o início dos anos 2000, porém nunca entrou no kernel padrão. O IMQ também exige patchear o iptables. Em resumo, é chatinho de instalar. Já o IFB é mais recente e está no kernel padrão.

[Update 2018] O IFB funciona, vou fornecer um exemplo ao final do artigo, mas ainda é uma gambiarra e ainda é meio chatinho acertar a configuração. O ideal é que o computador-roteador seja apenas um roteador, porque é mais fácil implementar QoS assim, e é mais seguro.

Miscelânea

Algumas coisas soltas que devo mencionar por completeza.

Podemos controlar banda de duas formas básicas: atrasando os pacotes ou descartando-os. Atrasar sem descartar é "work-conserving" ("conserva o trabalho"), ou seja, evita que um pacote perfeitamente válido tenha de ser novamente gerado e transmitido. A classe HTB que usamos nos exemplos é work-conserving na maior parte do tempo.

O HTB suporta o conceito de "borrowing" (empréstimo), onde diversas classes, cada uma com banda reservada, possa ceder banda a outras quando estiver ociosa. Normalmente é uma boa idéia permitir que isto aconteça.

HTB significa "hierachical token bucket". Token bucket é uma técnica de controle de banda, uma variação do "balde furado", que "vaza" a uma taxa fixa independente do volume de água dentro.

O Linux implementa outras classes, como o CBQ, onde a banda é controlada estabelecendo-se uma espera entre transmissão de pacotes. Assim, o CBQ obrigatoriamente conta pacotes e não bytes, e a estimativa do pacote médio tem de ser boa.

Quase sempre a disciplina de fila SFQ é a utilizada para "fechar" cada classe com justiça entre conexões, mas existem outras. Uma disciplina que alguns scripts usam é a PRIO, uma versão elaborada da PFIFO_FAST que baseia-se igualmente nos bits de TOS do pacote IP.

Script completo de exemplo de QoS para roteador

Este é o script da versão original do artigo. É possível que os comandos "tc filter" falhem porque cada um tem de ter uma prioridade diferente em versões mais recentes.

#!/bin/sh

UP=320
DOWN_PRE=1750
DOWN=1600

# Elimina velharias

tc qdisc del dev ppp0 root    2> /dev/null > /dev/null
tc qdisc del dev eth0 root    2> /dev/null > /dev/null
tc qdisc del dev ppp0 ingress 2> /dev/null > /dev/null

[ "$1" = "off" ] && exit 0

# Topo da disciplina para a interface ppp0

# r2q é escolhido de forma que
# banda / r2q fique apenas um pouco maior que o MTU
# No caso, 320kbits = 40kbytes / 20 = 2kbytes > 1500

tc qdisc add dev ppp0 root handle 1: htb default 1 r2q 20

# Classe 1:1, limita a taxa à capacidade do link upstream
tc class add dev ppp0 parent 1: classid 1:1 htb \
	rate ${UP}kbit ceil ${UP}kbit

# Para a classe 1:1, a disciplina de tráfego é SFQ,
# que assegura justiça entre as muitas conexões
tc qdisc add dev ppp0 parent 1:1 handle 10: sfq perturb 10

# Também fazemos um "shaping" prévio no downstream,
# embora o controle fino do downstream seja feito na eth0

tc qdisc add dev ppp0 handle ffff: ingress
tc filter add dev ppp0 parent ffff: protocol \
  ip prio 50 u32 match ip src \
  0.0.0.0/0 police rate ${DOWN_PRE}kbit burst 20k drop flowid :1

# Disciplina downstream, feito na interface eth0
# Nem todo tráfego da eth0 deve ser disciplinado; apenas
# o que veio da Internet. Tráfego da rede local corre solto.

tc qdisc add dev eth0 root handle 1: htb # r2q 100

# Classe com a capacidade downstream da ADSL 
tc class add dev eth0 parent 1: classid 1:20 htb \
	rate ${DOWN}kbit ceil ${DOWN}kbit

# Novamente usamos SFQ para justiça entre conexões
tc qdisc add dev eth0 parent 1:20 handle 20: sfq perturb 11

# Agora, marcamos o tráfego que deve ser controlado pela regra acima
# Critério: marcar os pacotes IP/IPv6 que vêm de interfaces expostas
# à Internet
iptables -t mangle -F PREROUTING
ip6tables -t mangle -F PREROUTING
iptables  -A PREROUTING -t mangle -i ppp0 -j MARK --set-mark 20
ip6tables -A PREROUTING -t mangle -i sixxs -j MARK --set-mark 20
tc filter add dev eth0 protocol ip parent 1:0 handle 20 fw flowid 1:20
tc filter add dev eth0 protocol ipv6 parent 1:0 handle 20 \
	fw flowid 1:20

# O tráfego não marcado não passará por classe nenhuma, e aparece
# apenas na estatística da disciplina "root".

# tc -s -d qdisc show dev ppp0
# tc -s -d class show dev ppp0

[Update 2018] Script de exemplo para um servidor

Este script não é para um roteador, mas sim para um servidor NAS. O objetivo é evitar que ele use toda a banda da Internet, mas a comunicação do NAS com a rede local deve fluir sem restrições.

Este script também faz uso de técnicas mais modernas, que não existiam em 2004: o IFB para controle de tráfego "entrante", suporte total a IPv6 na ferramenta "tc", e a marcação de pacotes com CONNMARK, de modo que a marcação do pacote seja mantida mesmo com o uso de IFB.

IF=eno1
UP=2000
DOWN=15000
# FIXME detectar prefixo automaticamente
IPV6_NET="2804:111:f230:a683::/64"

modprobe ifb numifbs=1
ip link set dev ifb0 up

iptables -t mangle -F
ip6tables -t mangle -F

# Restaura a marca do pacote
# (do contrário, apenas o pacote que abre a conexão ficaria marcado)

iptables -A POSTROUTING -t mangle -j CONNMARK --restore-mark
ip6tables -A POSTROUTING -t mangle -j CONNMARK --restore-mark
iptables -A PREROUTING -t mangle -j CONNMARK --restore-mark
ip6tables -A PREROUTING -t mangle -j CONNMARK --restore-mark

# Pacotes já marcados encerram o processamento cedo

ip6tables -A POSTROUTING -o $IF -t mangle -m mark --mark 5 -j ACCEPT
ip6tables -A POSTROUTING -o $IF -t mangle -m mark --mark 1 -j ACCEPT
ip6tables -A PREROUTING -i $IF -t mangle -m mark --mark 5 -j ACCEPT
ip6tables -A PREROUTING -i $IF -t mangle -m mark --mark 1 -j ACCEPT
iptables -A POSTROUTING -o $IF -t mangle -m mark --mark 5 -j ACCEPT
iptables -A POSTROUTING -o $IF -t mangle -m mark --mark 1 -j ACCEPT
iptables -A PREROUTING -i $IF -t mangle -m mark --mark 5 -j ACCEPT
iptables -A PREROUTING -i $IF -t mangle -m mark --mark 1 -j ACCEPT

# Pacotes recebidos da rede local: marca como "1"
# Pacotes vindos de fora: marca "5"

ip6tables -A PREROUTING -t mangle -i $IF -s $IPV6_NET \
	-j MARK --set-mark 1
ip6tables -A PREROUTING -t mangle -i $IF -s fe80::/64 \
	-j MARK --set-mark 1
ip6tables -A PREROUTING -t mangle -i $IF \
	-m mark ! --mark 1 -j MARK --set-mark 5

# Pacotes com destino à rede local: marca como "1"
# Pacotes transmitidos para a Internet: marca "5"

ip6tables -A POSTROUTING -t mangle -o $IF -d $IPV6_NET \
	-j MARK --set-mark 1
ip6tables -A POSTROUTING -t mangle -o $IF -d fe80::/64 \
	-j MARK --set-mark 1
ip6tables -A POSTROUTING -t mangle -o $IF \
	-m mark ! --mark 1 -j MARK --set-mark 5

# Mesmo tratamento pacotes recebidos IPv4

iptables -A PREROUTING -t mangle -i $IF -d 192.168.0.0/255.255.0.0 \
	-j MARK --set-mark 1
iptables -A PREROUTING -t mangle -i $IF -s 192.168.0.0/255.255.0.0 \
	-j MARK --set-mark 1
iptables -A PREROUTING -t mangle -i $IF -m mark ! --mark 1 \
	-j MARK --set-mark 5

# Mesmo tratamento pacotes transmitidos IPv4

iptables -A POSTROUTING -t mangle -o $IF -d 192.168.0.0/255.255.0.0 \
	-j MARK --set-mark 1
iptables -A POSTROUTING -t mangle -o $IF -s 192.168.0.0/255.255.0.0 \
	-j MARK --set-mark 1
iptables -A POSTROUTING -t mangle -o $IF -m mark ! --mark 1 \
	-j MARK --set-mark 5

# Salva a marca estampada há pouco

iptables -A POSTROUTING -t mangle -j CONNMARK --save-mark
iptables -A PREROUTING -t mangle -j CONNMARK --save-mark
ip6tables -A POSTROUTING -t mangle -j CONNMARK --save-mark
ip6tables -A PREROUTING -t mangle -j CONNMARK --save-mark

# O trecho a seguir limita o upload.
# Não é muito diferente dos exemplos anteriores.
# Os pacotes com a marca "5" têm banda limitada.

tc qdisc del dev $IF root    2> /dev/null > /dev/null
tc qdisc del dev $IF ingress 2> /dev/null > /dev/null
tc qdisc del dev ifb0 root    2> /dev/null > /dev/null
tc qdisc del dev ifb0 ingress 2> /dev/null > /dev/null

# r2q escolhido por tentativa e erro para evitar warning
# no dmesg. Tamanho 'ideal' tem a ver com a proporção entre
# as bandas das classes 1:20 e 1:30
tc qdisc add dev $IF root handle 1: htb default 30 r2q 200

tc class add dev $IF parent 1: classid 1:20 htb \
    rate ${UP}kbit ceil ${UP}kbit
tc qdisc add dev $IF parent 1:20 handle 20: sfq perturb 10

tc class add dev $IF parent 1: classid 1:30 htb \
    rate 90mbit ceil 90mbit
tc qdisc add dev $IF parent 1:30 handle 30: sfq perturb 10

tc filter add dev $IF parent 1: protocol ip prio 1 \
	handle 5 fw flowid 1:20
tc filter add dev $IF parent 1: protocol ipv6 prio 2 \
	handle 5 fw flowid 1:20

# Desta vez o "ingress" não vai limitar banda, mas sim
# jogar os pacotes entrantes pra ifb0. Note os parâmetros
# novos "connmark", "mirred", "egress".

tc qdisc add dev $IF handle ffff: ingress
tc filter add dev $IF parent ffff: protocol ip \
	prio 5 u32 match u32 0 0 \
	action connmark action mirred egress \
	redirect dev ifb0
tc filter add dev $IF parent ffff: protocol ipv6 \
	prio 6 u32 match u32 0 0 \
	action connmark action mirred egress \
	redirect dev ifb0

# Configuração do QoS para a falsa interface ifb0
# Ao limitar a banda de "transmissão" desta interface,
# estamos limitando o download de $IF. Novamente, os
# pacotes com marca "5" são direcionados para a classe
# com limite de banda.
    
tc qdisc add dev ifb0 root handle 2: htb default 30 r2q 200
    
tc class add dev ifb0 parent 2: classid 2:20 htb \
    rate ${DOWN}kbit ceil ${DOWN}kbit
tc class add dev ifb0 parent 2: classid 2:30 htb \
	rate 90mbit

tc qdisc add dev ifb0 parent 2:20 handle 20: sfq perturb 10
tc qdisc add dev ifb0 parent 2:30 handle 30: sfq perturb 10

tc filter add dev ifb0 parent 2: protocol ip prio 10 \
	handle 5 fw flowid 2:20
tc filter add dev ifb0 parent 2: protocol ipv6 prio 11 \
	handle 5 fw flowid 2:20