"looking to apply VLAN %s to physical interface behind %s",
vlan->name, upper->name);
+ /* Some bridges managed VLAN internally, skip them. */
+ if (upper->type & IFACE_BRIDGE_VLAN_T) {
+ log_debug("interfaces", "VLAN %s ignored for VLAN-aware bridge interface %s",
+ vlan->name, upper->name);
+ return;
+ }
+
/* Easy: check if we have a lower interface. */
if (upper->lower) {
log_debug("interfaces", "VLAN %s on lower interface %s",
/* interfaces.c */
/* An interface cannot be both physical and (bridge or bond or vlan) */
-#define IFACE_PHYSICAL_T (1 << 0) /* Physical interface */
-#define IFACE_BRIDGE_T (1 << 1) /* Bridge interface */
-#define IFACE_BOND_T (1 << 2) /* Bond interface */
-#define IFACE_VLAN_T (1 << 3) /* VLAN interface */
-#define IFACE_WIRELESS_T (1 << 4) /* Wireless interface */
+#define IFACE_PHYSICAL_T (1 << 0) /* Physical interface */
+#define IFACE_BRIDGE_T (1 << 1) /* Bridge interface */
+#define IFACE_BOND_T (1 << 2) /* Bond interface */
+#define IFACE_VLAN_T (1 << 3) /* VLAN interface */
+#define IFACE_WIRELESS_T (1 << 4) /* Wireless interface */
+#define IFACE_BRIDGE_VLAN_T (1 << 5) /* Bridge-aware VLAN interface */
#define MAX_VLAN 4096
#define VLAN_BITMAP_LEN (MAX_VLAN / 32)
}
}
+ if (kind && !strcmp(kind, "bridge") && link_info_attrs[IFLA_INFO_DATA]) {
+ struct rtattr *bridge_link_info_data_attrs[IFLA_BR_MAX+1] = {};
+ netlink_parse_rtattr(bridge_link_info_data_attrs, IFLA_BR_MAX,
+ RTA_DATA(link_info_attrs[IFLA_INFO_DATA]),
+ RTA_PAYLOAD(link_info_attrs[IFLA_INFO_DATA]));
+
+ if (bridge_link_info_data_attrs[IFLA_BR_VLAN_FILTERING] &&
+ *(uint8_t *)RTA_DATA(bridge_link_info_data_attrs[IFLA_BR_VLAN_FILTERING]) > 0) {
+ iff->type |= IFACE_BRIDGE_VLAN_T;
+ }
+ }
+
free(kind);
}
with namespaces(2):
if when == 'after':
lldpd()
- links.bridge('br42', 'eth1', 'eth3')
+ links.bridge('br42', 'eth1', 'eth3', filtering=True)
links.bridge_vlan('eth1', 100, pvid=True)
links.bridge_vlan('eth1', 200)
links.bridge_vlan('eth1', 300)
'no'
+@pytest.mark.skipif("'Dot1' not in config.lldpd.features",
+ reason="Dot1 not supported")
+@pytest.mark.parametrize('filtering', [False, True])
+def test_vlan_aware_bridge_filtering(lldpd1, lldpd, lldpcli,
+ namespaces, links, filtering):
+ links(namespaces(3), namespaces(2)) # Another link to setup a bridge
+ with namespaces(2):
+ links.bridge('br42', 'eth1', 'eth3', filtering=filtering)
+ links.bridge_vlan('eth1', 100, pvid=True)
+ links.bridge_vlan('eth1', 200)
+ links.bridge_vlan('eth1', 300)
+ links.bridge_vlan('eth3', 400)
+ links.vlan('vlan400', 400, 'br42')
+ lldpd()
+ with namespaces(1):
+ out = lldpcli("-f", "keyvalue", "show", "neighbors", "details")
+ assert out['lldp.eth0.port.descr'] == 'eth1'
+ if filtering:
+ assert out['lldp.eth0.vlan'] == \
+ ['vlan100', 'vlan200', 'vlan300']
+ assert out['lldp.eth0.vlan.vlan-id'] == \
+ ['100', '200', '300']
+ assert out['lldp.eth0.vlan.pvid'] == \
+ ['yes', 'no', 'no']
+ else:
+ assert out['lldp.eth0.vlan'] == \
+ ['vlan100', 'vlan200', 'vlan300', 'vlan400']
+ assert out['lldp.eth0.vlan.vlan-id'] == \
+ ['100', '200', '300', '400']
+ assert out['lldp.eth0.vlan.pvid'] == \
+ ['yes', 'no', 'no', 'no']
+
+
@pytest.mark.skipif("'Dot3' not in config.lldpd.features",
reason="Dot3 not supported")
@pytest.mark.parametrize('when', ['before', 'after'])