Soluciones MPLS con GNU/Linux

Buenas!

Volvemos a nuestro querido mundo del networking, sobre la potencia absoluta que nos dan los entornos GNU/Linux y que tanta pasión nos despierta 😉

Esta vez queremos comentar una de las principales novedades del kernel 4.3 que nos interesan mucho: el soporte de lo que se conoce como «light weight tunnels»  (lwtunnel), en concreto, en el área MPLS, que es la que nos interesa describir en este post.

Antes de esta release del Kernel, hubo un intento importante por parte de Igor Maravić, publicado en Github junto con las herramientas de user space necesarias (principalmente: iproute2 parcheado para soportar MPLS), se trató en la lista NETDEV del Kernel, y, posteriormente está muy comentado, casi de forma recurrente en lista de Quagga DEV.

MPLS en sí

El protocolo MPLS, en muchos casos considerado como de capa «2.5», se podría decir que es  como un MUST BE en toda red grande, sobre todo ahora que fabricantes como Mikrotik con soporte nativo  MPLS e interoperable en su routerOS venden devices a un precio muy asequible.

Existe múltiples presentaciones comentándolo en detalle, nosotros nos quedamos especialmente con esta presentación de Alex Vishnyakov dónde explican desde el punto de vista del ISP las ventajas de tener una red con soporte MPLS; y con esta otra presentación resumen, que como intro es más que suficiente.

Lo que nos aplica en este caso

¿Dónde estamos en este post y para qué?

En este post no queremos entrar en el detalle de asuntos reservados ISP’s y/o carriers de tránsito o similares con complejas técnicas de Traffic Engineering. Nos centraremos exclusivamente en su soporte reciente nativo en Linux así como en alguna posibilidad moderna, de estas que nos gustan ;).

Principalmente hablamos desde la perspectiva de alguien que no es «Network Owner» y que se construye su infraestructura con ingenierías de routing sobre túneles, mezclando «clouds» de operadores e infraestructura propia, algo así como un Net Power User 🙂 (o un net cowboy obligado 😉 ).

Proof of concept!

Preparando el kernel

La versión mínima que tenemos que disponer es 4.3, Debian Jessie por defecto viene con 3.16. Así que tenemos dos opciones:

Si optamos por la compilación manual, debemos asegurarnos que al menos estas opciones están activadas (al hacer el clásico y casi olvidado ya make menuconfig): lwtunnel, mpls-iptunnel, mpls-gso y finalmente mpls-router.

Una vez descomprimido el fuente, ejecutado el make menuconfig, podemos crear paquetes DEB para instalarlos cómodamente:

fakeroot make-kpkg --initrd --revision=XXX.MPLS kernel_image

(podemos añadir opciones -j para compilación paralela).

Tras bootear con el new kernel podemos cargar mpls_router por ejemplo y ver:

root@zgor-mpls-02:~# lsmod | grep mpls
mpls_iptunnel          16384  0 
mpls_gso               16384  0 
mpls_router            24576  1 mpls_iptunnel

Este nuevo kernel nos expone un interface en /proc, siendo /proc/sys/net/mpls/conf/ dónde se define la activación o no global por interface.

 

Herramients de user space

Principalmente, necesitamos iproute2 con soporte MPLS para poder realizar configuraciones, descargable por ejemplo aquí.

La compilación no tiene misterior (./configure;make && make install).

Una vez instalado, vemos que ejecutando directamente «ip» obtenemos ya un output indicando soporte mpls:

Usage: ip [ OPTIONS ] OBJECT { COMMAND | help }
       ip [ -force ] -batch filename
where  OBJECT := { link | address | addrlabel | route | rule | neigh | ntable |
                   tunnel | tuntap | maddress | mroute | mrule | monitor | xfrm |
                   netns | l2tp | fou | tcp_metrics | token | netconf }
       OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |
                    -h[uman-readable] | -iec |
                    -f[amily] { inet | inet6 | ipx | dnet | mpls | bridge | link } |
                    -4 | -6 | -I | -D | -B | -0 |
                    -l[oops] { maximum-addr-flush-attempts } | -br[ief] |
                    -o[neline] | -t[imestamp] | -ts[hort] | -b[atch] [filename] |
                    -rc[vbuf] [size] | -n[etns] name | -a[ll] | -c[olor]}

y podemos, igualmente ejecutar por ejemplo:

ip -f mpls route show

dónde «-f mpls» es de address family MPLS, ni IPV4 ni IPV6, MPLS! Bienvenidos al mundo de los labels!

Ni routing por origen ni destino, decisión/»switching» por etiquetas 😉

Hello World MPLS

De cara a tener un esquema mínimo de prueba, necesitamos al menos:

  • Ingress node (LER label edge router): Equipo que recibe tráfico y lo re-encamina hacia la red MPLS, encapsulado en MPLS.
  • Egress node (LER también): Equipo recibe tráfico encapsulado en MPLS y finalmente elimina la parte MPLS y hace el delivery.

Es decir, partimos de un primer ejemplo sin tránsito ni nada MPLS, casi que punto a punto y fin.

Para comenzar con este despliegue, la base, tan sencilla como:

esquema_helloworld

Es decir, un par de hosts conectados en una red cualquiera, con una dirección de loop añadida (que hacemos se parezca a su NIC eth0 para que sea más fácil verlo):

MPLS01:

root@zgor-mpls-01:~# ip address add dev lo 192.168.10.187/32

MPLS02:

root@zgor-mpls-02:~# ip address add dev lo 192.168.10.152/32

Con esto tenemos las loopbacks ready.

Para realizar el envío de tráfico MPLS Encapsulated:

MPLS01

root@zgor-mpls-01:~# ip route add 192.168.10.152/32 encap mpls 101 via 10.10.0.152

MPLS02:

root@zgor-mpls-02:~# ip route add 192.168.10.187/32 encap mpls 101 via 10.10.0.187

 

Llegados a este punto, podríamos intentar pingar, peroooo:

root@zgor-mpls-01:~# ping -I 192.168.10.187 192.168.10.152
PING 192.168.10.152 (192.168.10.152) from 192.168.10.187 : 56(84) bytes of data.
^C
--- 192.168.10.152 ping statistics ---
9 packets transmitted, 0 received, 100% packet loss, time 8022ms

Peroooooooooooooooooooo ¿Porqué no llegan?!!!

Si capturamos tráfico, vemos el ICMP:

icmp

 

Entrando en detalle vemos:
layer25

Efectivamente! Se trata de un paquete ICMP, pero tiene un layer adicional entre l2(frame ethernet) y l3(ip), de ahí que mucha gente lo llame protocolo 2.5

¿Entonces porque no llegan? No llegan porque hace falta realizar la salida ! El LER final tiene que desencapsular !

Por tanto, como queremos que funcione tanto en ida como en vuelta:

MPLS01:

root@zgor-mpls-01:~# ip -f mpls route add 101 dev lo

MPLS02:

root@zgor-mpls-02:~# ip -f mpls route add 101 dev lo

Y finalmente:

root@zgor-mpls-01:~# ping -I 192.168.10.187 192.168.10.152
PING 192.168.10.152 (192.168.10.152) from 192.168.10.187 : 56(84) bytes of data.
64 bytes from 192.168.10.152: icmp_seq=1 ttl=63 time=0.577 ms
64 bytes from 192.168.10.152: icmp_seq=2 ttl=63 time=0.654 ms
64 bytes from 192.168.10.152: icmp_seq=3 ttl=63 time=0.636 ms
^C
--- 192.168.10.152 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1998ms
rtt min/avg/max/mdev = 0.577/0.622/0.654/0.038 ms

 

Encaminando tráfico

En el lado de GNU/Linux, actuar como un LSR (Label Switch Router) es prácticamente igual de sencillo que un LER:

ip -f mpls route add XXXX as YYY via inet 192.168.2.2

Dónde:

 

  • X es la etiqueta recibida
  • Y es la etiqueta sobre-escrita
  • 192.168.2.2 (ejemplo) es el nexthop al que mandar los paquetes MPLS recibidos con la etiqueta X y que serán re-enviados con la etiqueta Y.

Y ya está! Con esto ya hemos transformado nuestra linux box en un LSR 🙂

Transportando MPLS over OpenVPN !

¿Por qué alguien puede querer hacer esto ? 😉

Generalmente, como comentábamos al principio, MPLS está presente en las redes grandes y/o de ISPS’s, en las que finalmente se ha acabando transportando ATM over IP y caminos semejantes. Bajo la perspectiva de empresas usuarias de redes, salvo acuerdos de integración en MPLS de ISP’s que actúen tb como Hoster’s y tengamos máquinas ahí que querer integrar de una forma muy específica, no parecen presentarse muchos casos de uso claros. Uno que si vemos muy probable es el de interconnecting entre los diversos clouds, transportando MPLS over OpenVPN y siendo por tanto agnósticos a lo que haya por de bajo, direccionamiento incluido 🙂 Así podemos hacer uso interno de las bondades de cada tipo de cloud, o, si se da el caso y por tipos de proyecto/legislación/X tenemos que estar si o si principalmente en una 😉

esquema_multinube

Fight!

De cara a realizar el escenario mínimo de proof of concept, nos planteamos:

esquema_mplsopenvpn (1)

Lo que es la configuración:

MPLS01

# Activamos MPLS en eth0:
echo 1 > /proc/sys/net/mpls/conf/eth0/input

# Informamos al kernel de que 10.200.200.2 es via 10.10.0.152 con encapsulación MPLS (LABEL100)
ip route add 10.200.200.2/32 encap mpls 100 via 10.10.0.152 dev eth0

# Informamos al kernel que label 200 lo tiene que desencapsular y entregarlo en el device LO:
ip -f mpls route add 200 dev lo

MPLS02

Siendo «VPN» el iface OpenVPN (importante, tiene que ser ‘tap’, no ‘tun’).

# Activamos MPLS en eth0 y VPN:
echo 1 > /proc/sys/net/mpls/conf/eth0/input
echo 1 > /proc/sys/net/mpls/conf/vpn/input

# Los paquetes MPLS con label 100 los encaminamos via 10.96.96.1 (extremo VPN (MPLS03))
ip -f mpls route add 100 as 100 via inet 10.10.0.122

# Los paquetes MPLS con label 200 los mandamos hacia MPLS01
ip -f mpls route add 200 as 200 via inet 10.10.0.187

MPLS03

# Activamos MPLS en eth0 y VPN:
echo 1 > /proc/sys/net/mpls/conf/eth0/input
echo 1 > /proc/sys/net/mpls/conf/vpn/input

# Los paquetes MPLS con label 100 los encaminamos via 10.96.96.1 (extremo VPN (MPLS04))
ip -f mpls route add 100 as 100 via inet 10.10.0.172

# Los paquetes MPLS con label 200 los mandamos hacia MPLS02
ip -f mpls route add 200 as 200 via inet 10.96.96.2

MPLS04

# Activamos MPLS en eth0:
echo 1 > /proc/sys/net/mpls/conf/eth0/input

# Informamos al kernel de que 192.168.10.152 es via 10.10.0.152 con encapsulación MPLS (LABEL100)
ip route add 10.200.200.1/32 encap mpls 200 via 10.10.0.122 dev eth0

# Informamos al kernel que label 200 lo tiene que desencapsular y entregarlo en el device LO:
ip -f mpls route add 100 dev lo

Una vez llegados a este punto, si pingamos desde MPLS04 con su origen loopback (el que usamos para MPLS):

root@zgor-mpls-04:~# ping -I 10.200.200.2 10.200.200.1
PING 10.200.200.1 (10.200.200.1) from 10.200.200.2 : 56(84) bytes of data.
64 bytes from 10.200.200.1: icmp_seq=1 ttl=61 time=1.69 ms

¿Pero, está realmente viajando por el interface VPN? Basta con capturar en MPLS02 por ejemplo:

root@zgor-mpls-02:~# tcpdump -n -v -i vpn
tcpdump: listening on vpn, link-type EN10MB (Ethernet), capture size 262144 bytes
16:41:22.911437 MPLS (label 200, exp 0, [S], ttl 63)
	IP (tos 0x0, ttl 64, id 6258, offset 0, flags [DF], proto ICMP (1), length 84)
    10.200.200.2 > 10.200.200.1: ICMP echo request, id 25860, seq 14, length 64
16:41:22.912246 MPLS (label 100, exp 0, [S], ttl 63)
	IP (tos 0x0, ttl 64, id 46459, offset 0, flags [none], proto ICMP (1), length 84)
    10.200.200.1 > 10.200.200.2: ICMP echo reply, id 25860, seq 14, length 64

 

Despedida y cierre!

Realmente, nos ha quedado un micro-post esta vez 🙂 La verdad es que de MPLS se puede hablar un rato largo y hay muchos mas ingredientes a meter en la cazuela: ¿Routing dinámico? Existe este  Quagga de Renato Westphal   disponible con soporte LDPD.  ¿Interoperabilidad? Con la facilidad que da RouterOS de ser instalado en una MV, montar un escenario piloto es realmente trivial.

Nada más por el momento! Que tengáis un buen inicio de verano!



¿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?


  • Muy interesante lo de los MPLS, donde se pueden conseguir más información al respecto, principalmente sobre aplicaciones concretas de esta.
    Gracias

    Tuanity Hace 8 años Responde


  • Excelente informacion , habras probado la parte interoperatividad ?

    Norman Hace 8 años Responde


  • Buenas Norman,

    Pues sinceramente, lo empezamos a montar, se monta fácil un entorno de test con Mikrotik-RouterOS, permiten descargar un IMG que en KVM(Proxmox, …) arranca fácilmente y puedes por tanto conectarle ifaces contra bridges virtuales con VM’s con MPLS Linux y tal. Lo dejamos montado, pero no acabamos de aterrizarlo, saltamos a otros frentes variopintos 😉

    Gorka Gorrotxategi Hace 8 años Responde


  • Me podrían ayudar, cada vez que intento hacer el encaminamiento recibo este error:
    RTNETLINK answers: Invalid argument

    Jose Luciano Hace 6 años Responde


  • Hola, muy bueno el post. He seguido todos los pasos pero me pasa que el ping no se me responde. Puedo notar que el ping llega al destino, pero este no responde el ping

    Rafael Hace 6 años Responde


Queremos tu opinión :)