Probando SIP anycast con OpenSIPS 2.4

Muy buenas a tod@s!

Hacía ya cierto tiempo que no escribíamos por estos lares, en lo que a materia VoIP/Networking relacionado se refiere, pero no hemos querido desaprovechar la oportunidad, dado que la ocasión se lo merece!

Antes de entrar en harina, destacar que en el blog del proyecto OpenSIPS lo tienen muy muy detallado desde el plano técnico y recomendamos su lectura, de hecho, este post parte de dicha lectura:

Full Anycast support in OpenSIPS 2.4

Y, por otra parte, sin duda las diapositivas de RĂZVAN CRAINEA disponibles en google docs en este enlace.

Lo que es en este post, intentaremos ponerlo en práctica, contextualizado y detallando los aspectos básicos para poder tener un entorno de pruebas fácilmente.

Antes de nada: ¿Anycast?

Si buscamos referencias en los sites habituales de Internet, se dispone de muchas casuísticas diferentes expuestas, siendo principalmente el factor diferenciador vs unicast: La dirección IP, pongamos B, con la que se comunica la IP origen A no tiene que porque estar siempre atada al mismo nodo.

Es decir, en unicast el tráfico va siempre entre dos IP’s, de forma dirigida, con routing directo si están en el mismo dominio l2 o con routing indirecto (enrutado tradicional) si no lo están. En el caso de broadcast, se trata de tráfico hacia todo el dominio L2, como podría ser un ARP Request For o el que seguramente nos viene a tod@s a la mente: el clásico paquete broadcast de NetBIOS. Seguramente al hablar de anycast nos vengan a la mente protocolos “sencillos” como DNS de tipo pregunta/respuesta. Es decir, todo lo contrario a lo que es SIP, dónde hay diálogos-transacciones-record routing-contact headers- … dónde todo lo que tenga que ver con transacciones y diálogos es siempre importante.

De hecho, relacionado con anycast, es muy interesesante esta presentación de  Shawn Zandi de Linkedin.

De hecho, nos permitimos coger una de sus diapositivas para ilustrar mejor el concepto y continuar con nuestro rumbo en este post:

Pues eso, lo dicho: La misma IP está en diferentes nodos / máquinas / entornos.

Montando el entorno anycast: QUAGGA FTW! (100 trying …)

El diseño que nos marcamos como objetivo, sin dibujar todavía los componentes SIP sería este:

Es decir, la idea es que 10.204.204.10 se comunique con 10.205.205.1, y que dicha IP destino no esté “atada” a ningún componente(server,router,container,orquestador,X).

Para ello, el camino que cogemos es OSPF, existen otras vías, pero esta nos convence, dado podemos ir levantando nodos sin tener que preocuparnos de sesiones BGP, para lo que queremos encaja muy bien.

  • La IP 10.206.206.1 es una IP de Loopback o Dummy en los 3 servidores.

De base, para tener la IP everywhere algo tal que:

En lo que respecta el protocolo de routing dinámico que nos permitirá hacer todo esto, hablamos de OSPF y de equal cost multipath, es decir, “mismo coste” por varios caminos diferentes.

En lo que respecta las configuraciones de routing, las siguientes se presentan ejecutadas en Quagga, pero cabe destacar que lo mismo funcionaría en otros vendors (Cisco, Juniper, Ubiquiti EdgeOS(Vyatta))

router

En router poco más que añadir, acordarse de activar el ip_forwarding!

server1

server2

server3

Es decir, y resumiendo de nuevo:

  • Los 3 servidores tienen la IP 10.206.206.1/32
  • Los 3 servidores la anuncian por OSPF.

¿Y esto funciona?

Para comprobarlo, basta con ejecutar el comando ip route show en el equipo router y ver los diferentes next-hop’s:

PCAP or it didn’t happen!

Pues sí, buena petición sí 😉

Capturando tráfico vemos que, efectivamente, tenemos multipath-routing pero:

  • Per-flow multipath

Es decir, entre un SIP UAC 5060UDP contra 10.206.206.1 5060 UDP, el path será siempre siempre el mismo. Con el tema del multipath routing, principalmente lo que se busca es lo contrario a lo que estamos buscando nosotros.

Lo que hemos visto como más significativo para ilustrar los cambios en multipath routing es esta frase:

Es de  Peter Nørlund, enviada en la la lista de NET DEV del Kernel:

When the routing cache was removed in 3.6, the IPv4 multipath algorithm changed
from more or less being destination-based into being quasi-random per-packet
scheduling. This increases the risk of out-of-order packets and makes it
impossible to use multipath together with anycast services.

Sobre este punto, si estáis interesad@s en todo esto, estos links nos han parecido clave en nuestro research:

 

Montando el entorno anycast: QUAGGA FTW! (302 Redirect Contact: QUAGGA + GNS3)

Finalmente, para no liarnos demasiado, que al final estamos hablando más de linux networking que de SIP / OpenSIPS, optamos por montar un entorno hibrido, ilustrado con el esquema a continuación, que se resume en:

Y cómo GNS3 nos permite conectarlo contra instancias o bridges locales, podemos unirlo contra los OpenSIPS, y con la ventaja de usar protocolos standard como OSPF, automáticamente tenemos

 

Si finalmente optáis por ir probando este camino, la configuración del Cisco Router en GNS3 tendría que tener la configuración para el per-packet load balancing:

PCAP Reality 😉

Capturamos directamente en la salida del router (dado que el cliente sipp01) ya está en otro ámbito L2, y si nos fijamos en la MAC origen del paquete, vemos que, efectivamente estamos logrando per-packet load balancing, es decir: WIN! Con las stats de wireshark se ve francamente bien:

 

La gráfica superior muestra el total de respuestas echo reply (estamos pingando desde sipp01), las otras 3 gráficas son las diferentes posibles respuestas, siempre filtrando con la misma ip origen (10.206.206.1)

Recapitulando

Tenemos un entorno IP que ya nos permite hacer anycast real, sin balanceo por flujo ni nada, es decir, cada paquete IP (que realmente será luego un paquete SIP INVITE, 200 OK, etc …) está acabando en un nodo diferente.

 

Configurando OpenSIPS

Sobre este punto, destacar que seguiremos lo que nos proponen los desarrolladores de OpenSIPS en su último blog post, que realmente es el origen que nos ha animado a escribir este post, de nuevo la referencia para que la tengáis a mano:

Base del entorno

Lo que tendremos son:

  • 3 nodos OpenSIPS con anycast, clusterer module
  • 1 nodo de bbdd para la persistencia
  • 2 clientes SIP simulados con SIPP

Primer paso: Configurar los listen’s de tipo anycast

Seguimos al pie de la letra el artículo y en todos los OpenSIPS:

Configurando proto_bin / Clusterer module

Para este punto, lo que hacemos es escuchar en proto_bin (escuchamos en 0.0.0.0 para que sea más fácil copiar la configuración):

Como veis, os dejamos la contraseña porque la idea es luego subir a nuestro cloud las imágenes de las máquinas virtuales, por si alguien quiere probar todo esto sin tener que montarlo 😉

En cuanto a la tabla de clusterer:

En el startup de OpenSIPS vemos claramente, por ejemplo en OpensSIPS01:

Si apagamos el servicio en el nodo opensips03:

Vemos directamente en los logs, tras los diferentes reintentos:

Siguiendo con el post de opensips: TM, Dialog

En todos los nodos:

Con eso hacemos que se repliquen las transacciones y diálogos

Gestionando cuando una transacción no la tiene el nodo que la recibe

Principalmente, los desarrolladores de OpenSIPS han permitido con el módulo clusterer, que si una request no te pertenece, la puedas enviar por el proto_bin hacia el resto para que sea contestada por quien le pertenezca (en base a un tag que ponen en las via headers):

El camino es hacer uso de la función t_anycast_replicate del módulo TM en 2.4:

 

 

Facilitando el debugging

Para facilitar el debugging, lo que haremos es que cada servidor tenga una server header diferente:

Y, por otra parte, dado que el módulo dialog exporta stats, lo usaremos a modo de debugging, en todos los OpenSIPS:

 

Probando (estilo The Incredible Machine 😉 )

Si lanzamos una llamada desde el emisor al receptor, en la imagen de la arquitectura los de la izquierda, capturamos en este punto:

La idea es capturar en el interface de R1, para poder ver mac’s origen y destino, porque recordemos que la IP es la misma ! Estamos en anycast 😉

Callflow base

Iniciamos primero lanzando una llamada desde el emisor (que todavía no será SIPP, es sólo una prueba) hacia el receptor, que es el único registrado, lo que vemos por delante con SNGREP capturando en dicho interface:

 

Es decir, lo que parece un flujo totalmente normal de A llama a B.

¿Y para esto tanto lío? Pues si, jijiji, tanto lío para verlo así de bonito, un flujo limpio. Si bajamos a más bajo nivel en la captura, al layer2:

Lo que se le ha mandado:

Lo que que es interesante es que en esa captura se ven 3 MAC’s de destino:

  • 52:54:00:41:92:e3
  • 52:54:00:32:e8:df
  • 52:54:00:87:b3:81

Esas 3 MAC’s corresponden a:

Es decir, tenemos un diálogo iniciado con una transacción invite, que ha ha sido contestada con una respuesta temporal 1XX para finalmente una 200OK con su correspondiente ACK; cerrado finalmente con una transacción BYE, con su correspondiente respuesta 200 OK, todo ello enviado a nodos OpenSIPS diferentes!

Ilustrando el callflow con el Layer2

A continuación mostramos el mismo flujo pero detallando las requests y responses por mac address:

 

Principalmente, lo que queremos ilustrar es que es independiente el nodo destino a nivel físico, la transacción se gestiona correctamente. Si el nodo que la recibe no es el responsable de ella, al enviarla por el proto_bin la recibe quien sí lo es (en base a un tag en las cabeceras VIA se sabe tb) y éste sí que la gestiona.

Recapitulando:

  • Podemos enviar tanto nuevas requests que inician diálogo como in-dialog request contra nodos diferentes, sin que esto afecte al tráfico SIP.
  • Se puede por tanto entrar/salir del cluster por tareas de mantenimiento sin downtime de ningún tipo 😉

Viéndolo más gráficamente

Esta quizás sea la comparativa de imágenes que más evidencia esta situación, ambas cogidas con etherape (que ya usamos de alguna forma divertida hace tiempo):

Concluyendo

Llegamos al final de este post, que recapitulando de forma express, si queréis montarlos un laboratorio de pruebas:

  • Si queréis probar anycast, warning con montarlo con GNU/Linux, no es tan trivial per-packet load balancing, o al menos no lo hemos encontrando nosotros. Si que es cierto que con TEQL se puede, pero manualmente, no lo hemos visto desplegable fácilmente con Quagga/OSPF.
  • OpenSIPS tiene que ser la nightly build si queremos desplegar por paquetes (2.4), sources.list: deb http://apt.opensips.org stretch 2.4-nightly

Y nada más que felicitar de nuevo a todo el equipo de OpenSIPS, gracias a su esfuerzo, los profesionales que opten por este tipo de soluciones como Proxy para exponerlo a los usuarios, a los operadores o como pieza interna necesaria en nuestra arquitectura podrán gracias a estas nuevas funcionalidades de la 2.4 actuar como activo/activo, con lo que las actualizaciones, scheduled downtimes, fast not dry run, son mucho más manejables 🙂

En lo respecta a implementaciones de la vida real, queremos destacar a nuestro partner Sarenet con su servicio Sarevoz, dónde llevan ya tiempo usando el concepto de anycast, trabajando conjuntamente con nuestro querido ExaBGP, Congratulations tb!

Por lo que comentan, en el OpenSIPS Submit se hablará de éste y de otras muchas cuestiones de interés!

 

 

 

 

 

 



¿Te gusta este post? Es solo un ejemplo de cómo podemos ayudar a tu empresa...
Sobre Gorka Gorrotxategi

CTO en Irontec, en el frente técnico desde un par de lustros ya, para todo lo que tenga que ver con Networking, VoIP y Sistemas, en ese orden :D) Desde @zetagor escribo algo, pero poco verbose la verdad

1 Comentario

¿Por qué no comentas tú también?


  • Wow, excelente!.

    Alberto Llamas Hace 6 meses Responde


Queremos tu opinión :)