miércoles, diciembre 05, 2012

Conntrack: "ip_conntrack: table full, dropping packet", o cuando el sistema no puede manejar todas las conexiones entrantes.


Conntrack, o más correctamente, ip_conntrack, es un módulo del kernel (y que viene con iptables) que se encarga de gestionar y seguir las conexiones entrantes a nuestros sistema. El número de conexiones que ip_conntrack puede seguir en nuestro sistema es configurable, y puede verse con el comando (en Red Hat)

cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max

Para ver todos los valores relacionados con los parámetros posibles de ip_conntrack se puede usar

sysctl -a | grep conntrack


El valor máximo típico por defecto para  ip_conntrack_max es 65536. El comando para ver cuántas conexiones hay en uso en un momento dado es

cat /proc/sys/net/ipv4/netfilter/ip_conntrack_count


Cuando el número de conexiones entrantes supera el máximo configurado, comienza a producirse pérdida de paquetes y lentitud generalizada en las conexiones a nuestro servidor. El síntoma definitivo de que el sistema ya no puede manejar la cantidad de conexiones entrantes es la aparición repetida de esta línea en el log del sistema:


ip_conntrack: table full, dropping packet


(echando un vistazo con, por ejemplo, grep conntrack /var/log/messages).


Si tenemos los recursos suficientes (principalmente, memoria RAM), podemos modificar la cantidad máxima de conexiones admisibles por el sistema. Antes de nada, hay que tener en cuenta que el seguimiento de las conexiones se hace listándolas en una tabla hash de determinado tamaño. El tamaño por defecto es de 8192 entradas, lo que implica que cada entrada de la tabla almacena 8 conexiones de media (65536/8192). El tamaño de la tabla configurado en nuestro sistema puede verse con

cat /proc/sys/net/ipv4/netfilter/ip_conntrack_buckets


Si nos vemos en la necesidad de aumentar la cantidad de conexiones a manejar por el sistema hay que tener en cuenta un par de cosas:


- es recomendable mantener la relación ip_conntrack_max / ip_conntrack_buckets en un valor de al menos 8 por cuestiones de rendimiento, pero si podemos reducirla, mejor: cuanto menor sea la relación, menos tiempo tardará el módulo en encontrar y gestionar una conexión dada. Es decir, si la cantidad de entradas en la tabla fuese igual al número de conexiones máximas, cada entrada se correspondería con una conexión, y el módulo ahorrará algo de tiempo en encontrarla (ya que no tiene que buscar en cada una de las entradas entre varias conexiones posibles).

- asegurarnos de que tenemos RAM suficiente. Hoy en día, con las cantidades de RAM típicas que utiliza una máquina cualquiera, no debería suponer mayor problema multiplicar varias veces el número máximo de conexiones gestionables. Para valorar cuánto podemos aumentar ip_conntrack_max debemos saber qué cantidad de memoria ocupa la gestión de una conexión. Tipicamente los valores van de 200 a 350 bytes, pero podemos averiguar cuánto está ocupando cada conexión en nuestro sistema con

cat /proc/slabinfo | grep conntrack


Para un valor de 300 bytes por conexión, 65536 conexiones ocupan unos 19 Mbytes de memoria. No es mucho.


Cambiar los valores de ip_conntrack_max e ip_conntrack_bucket puede hacerse de manera directa con 

echo <nuevo_valor_maximo_de_conexiones> > /proc/sys/net/ipv4/netfilter/ip_conntrack_max


echo <nuevo_tamaño_de_tabla> > /sys/module/ip_conntrack/parameters/hashsize


Por ejemplo, si queremos duplicar el número máximo de conexiones posibles, y proporcionalmente el tamaño de la tabla hash, los comandos serían


echo 131072 > /proc/sys/net/ipv4/netfilter/ip_conntrack_max


echo 16384 > /sys/module/ip_conntrack/parameters/hashsize

Lo que supone usar unos 38 Mbytes de memoria dedicados a la gestión de conexiones. Si además queremos optimizar la tabla para igualarla a la cantidad de ip_conntrack_max:

echo 131072 > /sys/module/ip_conntrack/parameters/hashsize


El cambio es instantáneo, como podemos comprobar, pero no permanente:  al reiniciar la máquina los cambios no se guardan, y se vuelve a los valores por defecto. Para hacerlos permanentes hay que editar el fichero sysctl.conf y añadir las líneas correspondientes a ip_conntrack_max e ip_conntrack_buckets:

net.ipv4.netfilter.ip_conntrack_max = 131072

net.ipv4.netfilter.ip_conntrack_buckets = 131072


Con esto los mensajes " ip_conntrack: table full, dropping packet" deberían desaparecer y el sistema debería ir más ligero a la hora de gesionar conexiones.