O módulo multiportas iptables fornece um benefício de desempenho sobre várias regras separadas?

3

O módulo multiport de iptables fornece um benefício de desempenho em relação a várias regras separadas? Em outras palavras, é isso:

iptables -A INPUT -p tcp -m multiport --sports 1,2,3,4,5,6,7,8,9,10,11,12,13,14,80 -j ACCEPT

.. mais eficiente do que isso:

iptables -A INPUT -p tcp --sport 1 -j ACCEPT
iptables -A INPUT -p tcp --sport 2 -j ACCEPT
iptables -A INPUT -p tcp --sport 3 -j ACCEPT
iptables -A INPUT -p tcp --sport 4 -j ACCEPT
iptables -A INPUT -p tcp --sport 5 -j ACCEPT
iptables -A INPUT -p tcp --sport 6 -j ACCEPT
iptables -A INPUT -p tcp --sport 7 -j ACCEPT
iptables -A INPUT -p tcp --sport 8 -j ACCEPT
iptables -A INPUT -p tcp --sport 9 -j ACCEPT
iptables -A INPUT -p tcp --sport 10 -j ACCEPT
iptables -A INPUT -p tcp --sport 11 -j ACCEPT
iptables -A INPUT -p tcp --sport 12 -j ACCEPT
iptables -A INPUT -p tcp --sport 13 -j ACCEPT
iptables -A INPUT -p tcp --sport 14 -j ACCEPT
iptables -A INPUT -p tcp --sport 80 -j ACCEPT

No primeiro caso, os módulos tcp e multiport são verificados para cada pacote, mas há uma única regra. No segundo caso, 15 regras são verificadas para cada pacote, mas para cada regra apenas tcp module é processado.

Eu fiz uma topologia de rede simples:

server1[eth2] <--> [enp0s31f6]server2

Os dois eth2 em server1 e enp0s31f6 in server2 são adaptadores de rede 1GigE e estão conectados com o cabo Cat5e de 5m. Quando eu faço o download de um arquivo 10000 MiB de server1 para server2 sem nenhuma regra de firewall, a taxa de transferência é de 942Mbps. Então eu criei 4369 regras assim:

for i in {1..65535}; do if ((i%15 == 0)); then iptables -A INPUT -p tcp -m multiport --sports $p$i -j ACCEPT; p=; else p=$p$i,; fi; done

Isso significa que havia 4369% de regrasmultiport com 15 portas em cada regra. Por exemplo:

# iptables -L INPUT 1 -v -n --line-numbers 
1        0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            multiport sports 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
# iptables -L INPUT 4369 -v -n --line-numbers 
4369     0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            multiport sports 65521,65522,65523,65524,65525,65526,65527,65528,65529,65530,65531,65532,65533,65534,65535
# 

Agora, quando executei wget --report-speed=bits -4 -O /dev/null 10.10.10.1:65535 em server2 , então, para minha surpresa, a taxa de transferência ainda era de 942Mbps. Como próximo passo, descarreguei a cadeia INPUT e gerou 65535 regras como esta:

for i in {1..65535}; do iptables -A INPUT -p tcp --sport $i -j ACCEPT; done

Novamente, executei wget --report-speed=bits -4 -O /dev/null 10.10.10.1:65535 em server2 e agora a taxa de transferência caiu para 580Mbps. Então, estou certo de que, em casos extremos, a abordagem multiport é mais eficiente? No entanto, sob condições normais, sem dezenas de milhares de regras ou dezenas de Gbps de tráfego, não há diferença prática?

    
por Martin 23.03.2018 / 14:08

2 respostas

3

O iptables percorre todas as regras da tabela até que uma correspondência com um destino final seja encontrada, portanto, menos regras significam menos uso da CPU. Embora algumas regras rodem mais rápido do que outras, por exemplo, uma regra multiportas para 15 portas pode ser mais rápida que a regra set equivalente (como em answer ). Portanto, não apenas o número de regras é importante, mas o tipo delas também.

O código-fonte para tcp / udp , multiportas e conjunto extensões de correspondência oferece algumas regras práticas, mas porque é difícil prever onde as coisas estão lentas , eu recomendo comparar os possíveis conjuntos de regras iptables e ver qual deles é mais rápido. Por exemplo eu corro iperf3 com uma lista de apenas 3 portas, e o módulo tcp foi um pouco mais rápido que os módulos multiportas e set que ofereciam uma taxa de transferência semelhante.

Se você ainda curte microbenchmarks, contei os ciclos de CPU necessários para executar o ipt_do_table função do kernel usando este muito, muito rudimentar SystemTap :

global call_cycles = 0

probe kernel.function("ipt_do_table@net/ipv4/netfilter/ip_tables.c").call {
    call_cycles = get_cycles()
}

probe kernel.function("ipt_do_table@net/ipv4/netfilter/ip_tables.c").return {
    delta = get_cycles() - call_cycles
    printf(" <- delta = %d\n", delta)
}

Estes são os meus resultados para um pacote que atravessa todas as regras em uma máquina virtual executando o Linux 4.15:

Module    | Ports | Rules  | Run 1   | Run 2   | Run 3   | Run 4   | Run 5
----------+-------+--------+---------+---------+---------+---------+--------
tcp       |  4500 |   4500 |  973148 | 1032564 |  856528 |  410894 |  854708
multiport |  4500 |    300 |   89370 |  259250 |   99752 |  225275 |  182256
set       |  4500 |      1 |   28463 |   43494 |   28315 |   33589 |   40988
    
por 02.04.2018 / 18:14
1

Eu não sei como o Linux lida com as regras do Netfilter no nível do opcode. Mas a abordagem multiportas poderia fazer várias verificações com uma única operação.

Como 1Gb / s não é muito para uma CPU (mesmo que lenta), não é de se surpreender que você precise de casos extremos. Mas ambas as abordagens podem, mesmo com o mesmo rendimento, gerar cargas bastante diferentes. Como isso é coisa do kernel, provavelmente nem é mostrado em /proc/loadavg . Portanto, você teria que executar um aplicativo intenso da CPU no mesmo sistema e medir seu desempenho para ver a diferença real.

Mas eu acho que sua comparação é meio injusta, porque as multiportas verificam uma vez para -p tcp , enquanto que a multirule faz a mesma verificação 65536 vezes. Assim você faria algo assim:

iptables -N tcp_ports
iptables -A INPUT -p tcp -j tcp_ports
for ((i=1;i<65536;i++)); do iptables -A tcp_ports --sport $i ...

Acabei de perceber que você não pode deixar de fora a verificação TCP porque é um requisito para --dport . Mas esta é uma das razões pelas quais a abordagem de múltiplas regras é mais lenta.

Não tenho certeza se o multiport foi destinado a casos como o seu. Para grandes listas de comparação ipset foi criado. Então, isso pode ser o que você está realmente procurando.

ipset create foo bitmap:port range tcp:10000-19999
ipset add foo tcp:10000-19999
iptables -A INPUT -p tcp -m set --match-set foo dst
    
por 30.03.2018 / 21:43

Tags