Para fazer isso, você pode usar tc
sozinho os u32
filtros ou combiná- los com a marcação iptables (talvez mais direta se você não quiser aprender a sintaxe dos filtros complexos). No post a seguir, detalharei a solução anterior.
Simulando sua configuração
Como exemplo, vamos considerar A, B, C e D executando interfaces virtuais de 10 Mbit / s .
Você basicamente quer:
- A <==> B: 9 Mbit / s para a saída
- A <==> C: 8 Mbit / s moldando para saída
Para simular isso, criarei 4 namespaces de rede e interfaces Ethernet virtuais conectadas a uma ponte.
Obviamente, no seu caso, você trabalhará com placas de rede reais e a ponte será seu gateway ou um switch, dependendo da sua infraestrutura.
Portanto, na minha simulação, teremos a seguinte configuração, em uma rede 10.0.0.0/24:
10.0.0.254
+-------+
| |
| br0 |
| |
+---+---+
|
| veth{A..D}.peer
|
+------------+------+-----+------------+
| | | |
vethA | vethB | vethC | vethD |
+---+---+ +---+---+ +---+---+ +---+---+
| | | | | | | |
| A | | B | | C | | D |
| | | | | | | |
+-------+ +-------+ +-------+ +-------+
10.0.0.1 10.0.0.2 10.0.0.3 10.0.0.4
Primeiro, a fase de configuração é feita para que você possa entender do que é feito; pule se não estiver familiarizado com isso, não é grande coisa. No entanto, o que você deve saber é que o comando ip netns exec <namespace> <command>
permite executar um comando em um namespace de rede (ou seja, em uma das caixas do sorteio anterior). Isso também será usado na próxima seção.
# Create the bridge
ip link add br0 type bridge
# Create network namespaces and veth interfaces and plug them into the bridge
for host in {A..D} ; do
ip link netns add ${host}
ip link add veth${host} type veth peer name veth${host}.peer
ip link set dev veth${host}.peer master br0
ip link set dev veth${host} netns ${host}
ip netns exec ${host} ip link set veth${host} up
done
# Assign IPs
ip addr add 10.0.0.254/24 dev br0
ip netns exec A ip addr add 10.0.0.1/24 dev vethA
ip netns exec B ip addr add 10.0.0.2/24 dev vethB
ip netns exec C ip addr add 10.0.0.3/24 dev vethC
ip netns exec D ip addr add 10.0.0.4/24 dev vethD
Portanto, neste ponto, temos a configuração descrita anteriormente.
Modelando o tráfego
É hora de entrar no controle de tráfego para conseguir o que deseja. A tc
ferramenta permite adicionar disciplinas de enfileiramento:
- Para saída: uma vez que o kernel precise enviar pacotes e antes de acessar o driver da NIC.
- Para ingresso: depois de acessar o driver da NIC e antes das rotinas do kernel serem executadas nos pacotes recebidos.
Ele vem com 3 noções: qdisc , classes e filtros . Essas noções podem ser usadas para configurar o gerenciamento complexo de fluxo de pacotes e priorizar o tráfego com base em qualquer critério / critério que você desejar.
Em poucas palavras:
- Qdiscs são estruturas nas quais os pacotes serão enfileirados / desenfileirados no ambiente.
- Classes são contêineres para qdiscs agindo com comportamentos específicos.
- Os filtros são maneiras de rotear pacotes entre classes, várias delas podem ser definidas no mesmo ponto de entrada com prioridades durante o processamento.
Tudo isso geralmente funciona como uma árvore onde as folhas são qdiscs e as classes são nós. A raiz de uma árvore ou subárvore será declarada como <id>:
e os nós filhos serão declarados como <parent_id>:<children_id>
. Mantenha essa sintaxe em mente.
No seu caso, vamos pegar A e renderizar a árvore com a qual você deseja configurar tc
:
1:
|
|
|
1:1
/ | \
/ | \
/ | \
1:10 1:20 1:30
| | |
| | |
:10 :20 :30
Explicação:
1:
é o qdisc raiz anexado ao dispositivo vethA, será assumido explicitamente como htb
no Hierarchy Token Bucket (o qdisc padrão de um dispositivo é pfifo
ou pfifo_fast
depende do sistema operacional). É especificamente apropriado para gerenciamento de banda. Os pacotes que não correspondem aos filtros definidos neste nível irão para a 1:30
classe.
1:1
será uma htb
classe que limita todo o tráfego do dispositivo a 10 Mbit / s.
1:10
será uma htb
classe que limita o tráfego de saída a 9 Mbit / s (90% de 10 Mbit / s).
1:20
será uma htb
classe que limita o tráfego de saída a 8 Mbit / s (80% de 10 Mbit / s).
1:30
será uma htb
classe que limita o tráfego a 10 Mbit / s (fallback).
:10, :20, :30
são sfq
qdisc para enfileiramento estocástico de justiça. Em outras palavras, esses qdiscs garantirão justiça no agendamento da transmissão com base nos fluxos.
Essa coisa toda é configurada pelos seguintes comandos:
ip netns exec A tc qdisc add dev vethA root handle 1: htb default 30
ip netns exec A tc class add dev vethA parent 1: classid 1:1 htb rate 10mbit burst 15k
ip netns exec A tc class add dev vethA parent 1:1 classid 1:10 htb rate 9mbit burst 15k
ip netns exec A tc class add dev vethA parent 1:1 classid 1:20 htb rate 8mbit burst 15k
ip netns exec A tc class add dev vethA parent 1:1 classid 1:30 htb rate 10mbit burst 15k
ip netns exec A tc qdsic add dev vethA parent 1:10 handle 10: sfq perturb 10
ip netns exec A tc qdisc add dev vethA parent 1:20 handle 20: sfq perturb 10
ip netns exec A tc qdisc add dev vethA parent 1:30 handle 30: sfq perturb 10
A última coisa que precisamos é adicionar filtros para que os pacotes IP com IP de destino igual a B passem para a 1:10
classe e os pacotes IP com IP de destino igual a C passem para a 1:20
classe:
ip netns exec A tc filter add dev vethA parent 1: protocol ip prio 1 u32 match ip dst 10.0.0.2/32 flowid 1:10
ip netns exec A tc filter add dev vethA parent 1: protocol ip prio 2 u32 match ip dst 10.0.0.3/32 flowid 1:20
Agora que você entendeu, precisará adicionar tc
regras semelhantes às B e C para que as transmissões para A dessas plataformas também sejam modeladas.
Teste
Agora vamos testar. Para isso, estou acostumado a brincar pessoalmente iperf
, consiste simplesmente em um único binário que pode ser executado como cliente ou servidor e envia automaticamente o máximo de tráfego possível entre os dois hosts.
Entre A e B:
$ ip netns exec B iperf -s -p 8001
...
$ ip netns exec A iperf -c 10.0.0.2 -p 8001 -t 10 -i 2
------------------------------------------------------------
Client connecting to 10.0.0.2, TCP port 8001
TCP window size: 21.0 KByte (default)
------------------------------------------------------------
[ 5] local 10.0.0.1 port 58191 connected with 10.0.0.2 port 8001
[ ID] Interval Transfer Bandwidth
[ 5] 0.0- 2.0 sec 2.38 MBytes 9.96 Mbits/sec
[ 5] 2.0- 4.0 sec 2.12 MBytes 8.91 Mbits/sec
[ 5] 4.0- 6.0 sec 2.00 MBytes 8.39 Mbits/sec
[ 5] 6.0- 8.0 sec 2.12 MBytes 8.91 Mbits/sec
[ 5] 8.0-10.0 sec 2.00 MBytes 8.39 Mbits/sec
[ 5] 0.0-10.1 sec 10.8 MBytes 8.91 Mbits/sec
Obtemos nosso limite de 9 Mbit / s de largura de banda.
Entre A e C:
$ ip netns exec C iperf -s -p 8001
...
$ ip netns exec A iperf -c 10.0.0.3 -p 8001 -t 10 -i 2
------------------------------------------------------------
Client connecting to 10.0.0.3, TCP port 8001
TCP window size: 21.0 KByte (default)
------------------------------------------------------------
[ 5] local 10.0.0.1 port 58522 connected with 10.0.0.3 port 8001
[ ID] Interval Transfer Bandwidth
[ 5] 0.0- 2.0 sec 2.25 MBytes 9.44 Mbits/sec
[ 5] 2.0- 4.0 sec 1.75 MBytes 7.34 Mbits/sec
[ 5] 4.0- 6.0 sec 1.88 MBytes 7.86 Mbits/sec
[ 5] 6.0- 8.0 sec 1.88 MBytes 7.86 Mbits/sec
[ 5] 8.0-10.0 sec 1.75 MBytes 7.34 Mbits/sec
[ 5] 0.0-10.1 sec 9.62 MBytes 7.98 Mbits/sec
Obtemos nosso limite de 8 Mbit / s de largura de banda.
Entre A e D:
$ ip netns exec D iperf -s -p 8001
...
$ ip netns exec A iperf -c 10.0.0.4 -p 8001 -t 10 -i 2
------------------------------------------------------------
Client connecting to 10.0.0.4, TCP port 8001
TCP window size: 21.0 KByte (default)
------------------------------------------------------------
[ 5] local 10.0.0.1 port 40614 connected with 10.0.0.4 port 8001
[ ID] Interval Transfer Bandwidth
[ 5] 0.0- 2.0 sec 2.62 MBytes 11.0 Mbits/sec
[ 5] 2.0- 4.0 sec 2.25 MBytes 9.44 Mbits/sec
[ 5] 4.0- 6.0 sec 2.38 MBytes 9.96 Mbits/sec
[ 5] 6.0- 8.0 sec 2.25 MBytes 9.44 Mbits/sec
[ 5] 8.0-10.0 sec 2.38 MBytes 9.96 Mbits/sec
[ 5] 0.0-10.2 sec 12.0 MBytes 9.89 Mbits/sec
Aqui temos a velocidade máxima da interface virtual de 10 Mbit / s atingida.
Observe que o burst da primeira medida de cada execução pode ser melhor tratado nas htb
classes, ajustando o parâmetro adequado.
Limpando
Remover :
- O filtro de prioridade 1 em
1:
: tc filter del dev vethA parent 1: prio 1 u32
.
- Todos os filtros em
1:
: tc filter del dev vethA parent 1:
.
- Classe
1:20
e seus filhos: tc class del dev vethA parent 1:1 classid
1:20
.
- A árvore inteira:
tc qdisc del dev vethA
.
Para limpar o conjunto de simulação:
# Remove veth pairs and network namespaces
for host in {A..D} ; do
ip link del dev veth${host}.peer
ip netns del ${host}
done
# Remove the bridge
ip link del dev br0