|

Filtrado VLAN en Linux con systemd-networkd

En pocas palabras: Un bridge de Linux no aísla VLANs por defecto: reenvía todos los frames sin mirar la etiqueta 802.1Q. Para frenar la fuga activá el filtrado VLAN (vlan_filtering=1), disponible desde el kernel 3.8 (2013) y declarable con systemd-networkd, que convierte el bridge en un switch L2 con aislamiento real.

Un bridge de Linux por defecto NO aísla las VLANs: reenvía todos los frames sin mirar la etiqueta 802.1Q, así que si trunkeás dos VLANs en el mismo bridge y encima le colgás un puerto de acceso sin filtrado, no armaste un switch, armaste un mezclador. El filtrado VLAN Linux, disponible en el kernel desde 2013, es la solución.

El filtrado VLAN en Linux (VLAN filtering) es una función del bridge del kernel que hace cumplir el estándar 802.1Q: cada puerto declara a qué VLANs pertenece y el bridge descarta los frames que no correspondan. Está disponible desde el kernel 3.8 (2013) y se activa con vlan_filtering=1 o, de forma declarativa, con systemd-networkd. Convierte un bridge común en un switch L2 con aislamiento de verdad.

En 30 segundos

  • El bridge por defecto no filtra por VLAN: frames etiquetados y sin etiquetar comparten el mismo dominio L2, según el artículo de Dev.to del 12/08/2026.
  • La función existe desde el kernel 3.8 (2013): se activa con vlan_filtering=1 más membresía por puerto.
  • Con systemd-networkd lo declarás entero: VLANFiltering=yes en el .netdev y bloques [BridgeVLAN] por puerto.
  • Puerto trunk = varias VLANs etiquetadas; puerto access = una sola VLAN sin etiqueta (con su PVID).
  • Verificás con bridge vlan show: ahí ves qué VLAN toca cada puerto y quién es untagged.

Hosting es un servicio que aloja sitios web, aplicaciones y datos en servidores conectados a internet. Lo desarrollan y ofrecen múltiples proveedores como infraestructura fundamental para acceder a contenido en línea.

¿Por qué mi bridge de Linux no aísla las VLANs?

Porque un bridge común es un switch de software que reenvía frames sin tratar la etiqueta 802.1Q como un límite de seguridad. Ponele que trunkeás la VLAN 10 y la VLAN 20 hacia br0 y, en el mismo bridge, conectás un puerto de acceso sin activar el filtrado. Lo que construiste no separa nada. El tráfico de un tenant puede ver el del otro.

El detalle que sorprende: por defecto, los frames sin etiqueta y los etiquetados conviven en el mismo dominio L2 con mucha más libertad de la que casi todos asumen. El bridge no fue pensado para hacer de guardia. Fue pensado para conectar máquinas virtuales y contenedores rápido, y eso lo hace bárbaro (que no es poco), pero el aislamiento no viene de fábrica. Tema relacionado: guía de infraestructura cloud-hosting.

¿Y qué pasa cuando descubrís esto en producción? Exacto, cuando ya tenés VMs de clientes distintos compartiendo L2 sin saberlo.

¿Qué es el filtrado VLAN Linux y cómo activa el 802.1Q del kernel?

El filtrado VLAN es la capacidad del bridge del kernel de decidir, por puerto, qué VLANs entran y cuáles se descartan, cumpliendo 802.1Q. Existe desde el kernel 3.8 (2013), según la documentación de Red Hat. Sin filtrado, el bridge ignora las etiquetas como frontera. Con filtrado, cada puerto tiene una membresía explícita y el PVID define qué VLAN se le asigna al tráfico que llega sin etiqueta.

La lógica es la de un switch administrable de verdad. Un puerto de acceso recibe frames sin tag, el bridge les pega el PVID adentro, y al salir se los saca (egress untagged). Un puerto trunk, en cambio, transporta varias VLANs y mantiene las etiquetas puestas. Si un frame llega con una VLAN que ese puerto no tiene declarada, el kernel lo tira. Ese descarte es todo el punto.

Puertos trunk vs access: ¿cuál es la diferencia?

Un puerto trunk transporta múltiples VLANs con sus etiquetas 802.1Q intactas; un puerto access pertenece a una sola VLAN y entrega el tráfico sin etiqueta. El trunk se usa para uplinks (la NIC física que sube al switch de la red). El access se usa para lo que no entiende de VLANs: una VM, un contenedor, un servidor que solo quiere su red y listo.

AspectoPuerto trunkPuerto access
VLANs que llevaVarias, etiquetadasUna sola, sin etiqueta
Uso típicoUplink a la NIC físicaVM, contenedor, host final
Config systemd-networkdVLAN=10, VLAN=20PVID=10 + EgressUntagged=10
¿Etiqueta al salir?Sí, la mantieneNo, la quita
Quién entiende 802.1QEl otro switchNadie del otro lado

¿Cómo configurar systemd-networkd para VLAN filtering paso a paso?

Se declara en tres archivos: un .netdev que crea el bridge con VLANFiltering=yes, y un .network por puerto con su bloque [BridgeVLAN]. La ventaja frente a los comandos ip link sueltos es que queda persistente y versionable, sin scripts que se pierden en el primer reboot. Para más detalles técnicos, mirá solucionar problemas de conectividad.

Primero el bridge, en /etc/systemd/network/br0.netdev:

[NetDev]
Name=br0
Kind=bridge

[Bridge]
VLANFiltering=yes
DefaultPVID=0

El DefaultPVID=0 es un seguro: evita que el kernel le asigne la VLAN 1 por defecto a cualquier puerto que agregues sin pensar. Después, el uplink trunk en eth0.network:

[Match]
Name=eth0

[Network]
Bridge=br0

[BridgeVLAN]
VLAN=10

[BridgeVLAN]
VLAN=20

Y un puerto de acceso para una VM en la VLAN 10, en vnet0.network:

[Match]
Name=vnet0

[Network]
Bridge=br0

[BridgeVLAN]
PVID=10
EgressUntagged=10
VLAN=10

Si querés que el propio host tenga IP en una VLAN (una SVI), creás un netdev tipo vlan arriba de br0 y le ponés la dirección ahí. Un networkctl reload aplica todo. Netplan, por si lo usás en otras distros, termina generando esta misma config de systemd-networkd por debajo.

¿Cómo verificar que las VLANs están aisladas correctamente?

Con bridge vlan show. Ese comando lista, puerto por puerto, qué VLANs tiene declaradas y cuál sale untagged (PVID). Si un puerto de acceso muestra su VLAN marcada como PVID Egress Untagged y nada más, está bien. Si aparece la VLAN 1 fantasma o una VLAN que no debería, ahí tenés la fuga.

  • Confirmá el filtrado activo: ip -d link show br0 tiene que mostrar vlan_filtering 1.
  • Revisá la membresía: bridge vlan show por cada puerto, buscando VLANs de más.
  • Probá el aislamiento real: desde una VM en la VLAN 10, un ping a una IP de la VLAN 20 tiene que fallar sin un router L3 de por medio.

El test de conectividad es el que no miente. Podés tener la config perfecta en papel y una regla vieja que la contradiga. Cubrimos ese tema en detalle en arquitectura moderna de cloud-hosting.

Errores comunes que rompen el aislamiento

Estos son los que aparecen una y otra vez cuando algo “filtra” entre VLANs y nadie entiende por qué:

  • Olvidarte de activar el filtrado en el bridge master: configurás todos los puertos con sus [BridgeVLAN] pero VLANFiltering=yes no está. El kernel ignora la membresía y reenvía todo. Es el error número uno.
  • PVID incompatible entre el switch y Linux: si tu switch usa VLAN nativa 1 en el trunk y tu bridge espera otra cosa, el tráfico untagged cae en la VLAN equivocada. Alineá la VLAN nativa de los dos lados.
  • No declarar la membresía en algún puerto: un puerto sin bloque [BridgeVLAN] queda con el DefaultPVID. Si ese default es 1, acabás de conectar una puerta trasera.
  • Confundir VRF con aislamiento L2: el VRF separa tablas de ruteo en L3, no reemplaza el filtrado VLAN. Son capas distintas y hacen falta las dos.

¿Cómo se implementa en producción con VMs, contenedores y hosts?

El caso clásico es un hipervisor KVM con VMs de clientes distintos, cada una en su VLAN de acceso, todas colgando del mismo br0 con filtrado. El uplink va como trunk al switch físico y el host se gestiona por una VLAN separada (nunca la misma que las VMs, esa es la regla de oro). Con contenedores aplica igual si vos sos dueño del bridge; los bridges default de Docker o Podman tienen otro ciclo de vida, pero las ideas del kernel son las mismas.

Si armás esto sobre un VPS o un servidor dedicado para alojar infraestructura de varios clientes, el filtrado VLAN es lo que te deja separar redes en el mismo fierro sin que se vean entre sí; para ese tipo de despliegues, un proveedor local como donweb.com te da el control de red que necesitás. En Proxmox la config vive en la GUI y en /etc/network/interfaces, pero el concepto no cambia: bridge VLAN-aware, membresía por puerto, y un firewall L3 arriba para el ruteo entre VLANs cuando de verdad lo quieras.

Preguntas Frecuentes

¿Qué es el filtrado VLAN en el kernel de Linux?

Es la función del bridge del kernel que aplica el estándar 802.1Q por puerto, descartando los frames de VLANs que un puerto no tiene declaradas. Está en el kernel desde la versión 3.8 (2013) y se activa con vlan_filtering=1. Sin esa función, el bridge reenvía todo sin mirar etiquetas.

¿Cuál es la diferencia entre un puerto trunk y uno access?

Un puerto trunk transporta varias VLANs con sus etiquetas intactas y se usa para uplinks. Un puerto access pertenece a una sola VLAN, entrega el tráfico sin etiqueta y se usa para VMs, contenedores o servidores finales. En systemd-networkd el trunk se declara con varias líneas VLAN= y el access con PVID= más EgressUntagged=. Relacionado: configurar correctamente servidores DNS.

¿Cómo verifico que las VLANs quedaron aisladas?

Corré bridge vlan show para ver la membresía por puerto y ip -d link show br0 para confirmar que aparece vlan_filtering 1. La prueba definitiva es un ping entre dos VLANs distintas: si están aisladas y no hay router L3, tiene que fallar.

¿El VRF reemplaza al filtrado VLAN?

No. El VRF separa tablas de ruteo en capa 3 y el filtrado VLAN aísla dominios de broadcast en capa 2. Son cosas distintas que trabajan en niveles distintos. Para una separación completa entre tenants necesitás las dos: filtrado VLAN abajo y VRF (o un firewall) arriba.

¿Sirve el mismo enfoque para Docker y Podman?

Las ideas del kernel aplican igual siempre que vos seas dueño del bridge. Los bridges por defecto de Docker y Podman tienen su propio ciclo de vida y no los vas a controlar con systemd-networkd, pero si creás un bridge VLAN-aware propio y conectás los contenedores ahí, el filtrado funciona idéntico.

Conclusión

Un bridge de Linux no aísla VLANs por diseño, y asumir lo contrario es cómo terminás con tráfico de un cliente cayendo en la red de otro. La buena noticia es que la solución ya está en el kernel desde 2013 y no requiere Open vSwitch ni nada exótico: activás VLANFiltering=yes, declarás la membresía por puerto en systemd-networkd y verificás con bridge vlan show. Si administrás VMs o contenedores de más de un tenant en el mismo fierro, revisá hoy mismo si tu bridge tiene el filtrado prendido. Ese chequeo de dos minutos separa un switch de un mezclador.

Fuentes

Te puede interesar...