VRF en Linux con BIRD para OSPF/BGP.
Desde hace mucho tiempo estoy jugando con BGP, inicialmente tenía BGP en pfSense, algo sencillo y con solo algunas rutas, eso fue en los tiempos de dn42.
En el 2016 encontré una comunidad de varios entusiastas de redes al nivel de Internet y pude conseguir un ASN registrado en RIPE.
Muchas cosas han cambiado desde esos días, he aprendido y experimentado, aprender es la razón de ser de aaNetworks. Lo complicado de mi red con direcciones IP Publicas y ASN es que localmente en mi casa no hay forma posible de tener una sesión BGP y publicar los prefijos desde ahí (imagínate que CLARO te permita hacer un túnel L2TP a un router con BGP!), dependo de VPS con Linux y BIRD.
Estado actual.
Usando wireguard se interconectan 4 VPS y 1 servidor físico en mi casa, todos ejecutan BIRD, de esta manera pueden establecer sesiones BGP tanto internas (iBGP) como externas (eBGP) para anunciar los prefijos.
Con OSPF se distribuyen direcciones de enlaces (/30) y direcciones en lo (loopback con /32), es más fácil montar una sesión BGP apuntando a las direcciones en la loopback, se elimina tener que crear una inmensidad de sesiones ya que la dirección en loopback puede ser alcanzada por cualquiera de los routers en el área de OSPF.
El problema que últimamente tengo es cuando la mejor ruta para alcázar uno de los VPS es aprendida por iBGP, esto significa el doble de perdida de paquetes y latencia. Investigando y probando mucho, decidí que la mejor manera de “solucionar el problema” era usando tablas de rutas dedicadas (Policy Based Routing), una para los enlaces wireguard y otra para las rutas aprendidas en BGP. Esto resolvía el problema, pero introdujo unos nuevos que no son de mi agrado.
Nuevos problemas.
- De manera manual tenía que introducir los origines o destinos de mi red interna en ambas tablas.
- Se debe agregar otra IP /32 en la loopback para poder monitorear los VPS.
- La tabla para las rutas aprendidas por OSPF debían ser copiadas a la tabla donde se guardaban las rutas aprendidas por BGP.
- En el traceroute salen asteriscos… GRAVE!!
Solución.
VRF en Linux ya lleva un tiempo algo estable y gracias al trabajo mayormente realizado por Cumulus Network esto ha mejorado bastante. Esta funcionalidad esta lista para ser usada en las distribuciones recientes de Linux, en mi caso he usado Ubuntu y Debian.
Procedemos a inicializar un VRF con el comando:
ip link add name vrf_mesh type vrf table 10
Activamos el VRF:
ip link set dev vrf_mesh up
Ya contamos con un VRF e incluso tenemos una interface disponible para asignar un IP, esta interface es utilizada cuando queremos hacer route leaking de un VRF a otro.
Si hacemos: ip vrf show
Para tener consistencia con relación al VRF y las tablas de enrutamiento de Linux, debemos definir una entrada en /etc/iproute2/rt_tables
Hasta este punto se podría decir que todo es igual a PBR, la diferencia está en los próximos pasos donde movemos interfaces hacia el VRF, este proceso automáticamente asigna todas las rutas existentes al VRF, incluso la dirección IP deja de estar disponible en la tabla main, si existen servicios que usan estas IP directamente, fallaran ya que la IP no está disponible.
ip link set dev enp2s0 vrf vrf_mesh up
Lo revisamos con
ip -br link show type vrf
ip link show
Nos mostrara todas las interfaces en el servidor, además nos deja ver cuales están en un VRF
master vrf_mesh
Es lo que queremos ver!
Un cambio realizado por esta configuración está en las reglas que controlan donde se buscara el próximo salto para alcanzar un host.
L3mdev-table fue agregado cuando creamos nuestro VRF, la idea es primero buscar dentro de esta tabla dependiendo del estado de la interface, si esta es parte de un VRF o no. Otro cambio que se debe hacer y este es de forma manual, es mover el lookup local hacia abajo, esto evitara que se haga la búsqueda en la tabla main y posiblemente enviar el tráfico a la tabla equivocada, es muy útil cuando se tienen varios VRF y prefijos duplicados.
Listo, ahora le toca a BIRD llevar sus rutas al VRF.
Esta configuración fue la más complicada ya que el soporte de VRF en BIRD no está muy bien documentado y todo fue basado en prueba y error.
Gran parte de la configuración de BIRD ya tenía definida tablas de enrutamiento para funcionar con PBR, lo que hice fue cambiarlo todo a una misma tabla, en este caso la tabla 10.
Algo que confunde un poco es que en BIRD se deben definir tabla para IPv4 e IPv6 pero no pueden tener el mismo nombre, es algo interno de BIRD y no refleja que en el Kernel podemos tener rutas de IPv4 e IPv6 en la misma tabla.
El cambio es simple. Luego que se entiende que se debe hacer, debemos agregar vrf “nombre_vrf” en todas las entradas de protocol que queremos que participen del VRF, dentro de cada versión de IP se debe agregar la tabla donde se colocaran las rutas aprendidas, esa es la razón por la que se definen dos tablas en la configuración. Otro proceso adicional es usar el protocol kernel para copiar las rutas que se agregaron a las tablas internas de BIRD a la tabla 10 del kernel, esa es la tabla que en mi caso usa el VRF.
Una de las limitantes de BIRD y VRF es que BIRD desconoce que existe un VRF en Linux y no tienen integración. Se dice que en nuevas versiones esto mejorara.
Ya tengo rutas en mi VRF, cual es la diferencia?
Anteriormente no podía hacer tareas tales como ping o traceroute desde las direcciones IP que usando rules estaban dentro de una de las tablas de enrutamiento. Con VRF es mucho más sencillo.
ip vrf exec vrf_mesh traceroute 1.1.1.1
En la tabla main del equipo solo se puede observar la ruta por defecto que es usada para subir los túneles wireguard.
Si consulto la tabla 10 donde está funcionando el VRF.
Demasiadas rutas para mostrar en un screenshot, vamos a contarlas.
Al final todo esto es para que mis VM/contenedores con direcciones ip publicas puedan llegar a Internet y ser alcanzados desde Internet.
referencias:
Stefan’s Blog – Using VRF (Virtual Routing and Forwarding) on Linux
Virtual Routing and Forwarding (VRF) · Mellanox/mlxsw Wiki · GitHub