Simule a conexão lenta entre duas máquinas servidores ubuntu


9

Quero simular o seguinte cenário: considerando que tenho 4 máquinas servidores ubuntu A, B, C e D. Quero reduzir a largura de banda da rede em 20% entre a máquina A e a máquina C e 10% entre A e B. fazer isso usando ferramentas de simulação / otimização de rede?


O iptables pode ter capacidade de limitação. Eu nunca usei, mas vale a pena investigar.
Michael Martinez

@MichaelMartinez Não, não. tcfaz quando usado com a marcação iptables.
Xavier Lucas

@XavierLucas bom saber!
Michael Martinez

Respostas:


15

Para fazer isso, você pode usar tcsozinho os u32filtros 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 tcferramenta 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 htbno Hierarchy Token Bucket (o qdisc padrão de um dispositivo é pfifoou pfifo_fastdepende 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:30classe.
  • 1:1será uma htbclasse que limita todo o tráfego do dispositivo a 10 Mbit / s.
  • 1:10será uma htbclasse que limita o tráfego de saída a 9 Mbit / s (90% de 10 Mbit / s).
  • 1:20será uma htbclasse que limita o tráfego de saída a 8 Mbit / s (80% de 10 Mbit / s).
  • 1:30será uma htbclasse que limita o tráfego a 10 Mbit / s (fallback).
  • :10, :20, :30são sfqqdisc 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:10classe e os pacotes IP com IP de destino igual a C passem para a 1:20classe:

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 tcregras 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 htbclasses, 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:20e 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

1
Muito obrigado pela sua resposta incrível. Se possível, você poderia adicionar os comandos para remover os filtros? caso alguém queira reverter essa configuração com segurança após a simulação.
Yehia Elshater

1
@YahiaZakaria Acabei de adicionar essas informações na parte final do meu post.
Xavier Lucas

0

O Ubuntu possui IPFW portado no FreeBSD e o IPFW possui o DUMMYNET que permite gerenciar vários parâmetros de rede - largura de banda, atraso, taxa de perda de pacotes, etc.


0

O melhor é usar as ferramentas tc com o módulo netem agora integrado (pelo menos no servidor Ubuntu). Você pode encontrar mais informações neste artigo em Stackoverflow .


O Netem trata de emulação rtt e de congestionamento, não de largura de banda.
Xavier Lucas

1
@XavierLucas, você está certo, quanto à largura de banda, você só precisa de tc, sem sequer netem.
Luc Stepniewski

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.