O iptables
módulo multiporta 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, ambos 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 o tcp
módulo é processado.
Eu fiz uma topologia de rede simples a seguir:
server1[eth2] <--> [enp0s31f6]server2
Ambos eth2
in server1
e enp0s31f6
in server2
são adaptadores de rede 1GigE e são conectados com cabo Cat5e de 5m. Quando eu baixei um arquivo de 10.000 MiB de server1
para server2
sem nenhuma regra de firewall, a taxa de transferência foi de 942 Mbps. Então eu gerei 4369 regras como esta:
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 multiport
regras 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
, para minha surpresa, a taxa de transferência ainda era de 942 Mbps. Como próximo passo, limpei a INPUT
cadeia e gerei 65535 regras como esta:
for i in {1..65535}; do iptables -A INPUT -p tcp --sport $i -j ACCEPT; done
Mais uma vez, executei e agora o throughput caiu wget --report-speed=bits -4 -O /dev/null 10.10.10.1:65535
para server2
580Mbps. Então, estou correto que, em casos extremos, a multiport
abordagem é mais eficiente? Porém, em condições normais sem dezenas de milhares de regras ou dezenas de Gbps de tráfego, não há diferença prática?
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 sejam executadas mais rapidamente do que outras, por exemplo, uma regra multiporta para 15 portas pode ser mais rápida que a regra definida equivalente (como na resposta de Hauke Laging ). Portanto, não apenas o número de regras é importante, mas também o tipo delas.
O código-fonte para tcp/udp , multiport e set match extensions oferece algumas regras básicas, mas como é 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 executo o iperf3 com uma lista de apenas 3 portas, e o módulo tcp foi um pouco mais rápido que os módulos multiport e set que ofereceram uma taxa de transferência semelhante.
Se você ainda gosta de microbenchmarks, contei os ciclos de CPU necessários para executar a função do kernel usando este script SystemTap
ipt_do_table
muito, muito rudimentar :Estes são meus resultados para um pacote que percorre todas as regras em uma máquina virtual executando o Linux 4.15:
Não sei como o Linux lida com as regras do Netfilter no nível do opcode. Mas a abordagem multiporta pode fazer várias verificações com uma única operação.
Como 1Gb/s não é muito para uma CPU (mesmo lenta), não é de se estranhar 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 com uso intensivo de CPU no mesmo sistema e medir seu desempenho para ver a diferença real.Mas acho que sua comparação é meio injusta porque multiport verifica uma vez
-p tcp
enquanto multirule faz a mesma verificação 65536 vezes. Assim, você faria algo assim:Acabei de perceber que você não pode deixar de fora a verificação do TCP porque é um requisito para o
--dport
. Mas esse é um dos motivos pelos quais a abordagem de regras múltiplas é mais lenta.Não tenho certeza se o multiport foi planejado para casos como o seu. Para enormes listas de comparação
ipset
foram criadas. Então pode ser isso que você está realmente procurando.