From 5f658dacf0d82f7f17ae5d54689fc2901fb95e33 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Sat, 12 Aug 2017 20:09:22 +0200 Subject: [PATCH] interfaces: enable team interfaces like a bond interface Unfortunately, we are not able to retrieve the real MAC address as the kernel doesn't know it. Only the teamd daemon knows it. We could ask for it through ethtool but it would be the permenant MAC address which may be incorrect. Fix #234 --- NEWS | 3 +++ src/daemon/interfaces-linux.c | 3 +++ src/daemon/netlink.c | 4 ++++ tests/integration/fixtures/network.py | 16 +++++++++++++--- tests/integration/test_interfaces.py | 23 +++++++++++++++++++++++ 5 files changed, 46 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index 46423519..61f917a6 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,9 @@ lldpd (0.9.8) * Changes: + "Station" capability is only set if no other bit is set. + * Fixes: + + Handle team interfaces like a bond. Real MAC address cannot be + retrieved yet. lldpd (0.9.7) * Changes: diff --git a/src/daemon/interfaces-linux.c b/src/daemon/interfaces-linux.c index 92aad6a5..3150e6b8 100644 --- a/src/daemon/interfaces-linux.c +++ b/src/daemon/interfaces-linux.c @@ -293,6 +293,9 @@ iflinux_get_permanent_mac(struct lldpd *cfg, if ((master = iface->upper) == NULL || master->type != IFACE_BOND_T) return; + if (master->driver == NULL || strcmp(master->driver, "bonding")) + /* Not a bond interface, maybe a team */ + return; /* We have a bond, we need to query it to get real MAC addresses */ if (snprintf(path, SYSFS_PATH_MAX, "/proc/net/bonding/%s", diff --git a/src/daemon/netlink.c b/src/daemon/netlink.c index 1a64a231..6e80d254 100644 --- a/src/daemon/netlink.c +++ b/src/daemon/netlink.c @@ -211,6 +211,10 @@ netlink_parse_linkinfo(struct interfaces_device *iff, struct rtattr *rta, int le log_debug("netlink", "interface %s is a bond", iff->name); iff->type |= IFACE_BOND_T; + } else if (!strcmp(kind, "team")) { + log_debug("netlink", "interface %s is a team", + iff->name); + iff->type |= IFACE_BOND_T; } } } diff --git a/tests/integration/fixtures/network.py b/tests/integration/fixtures/network.py index 42ff48e1..8aa8cf92 100644 --- a/tests/integration/fixtures/network.py +++ b/tests/integration/fixtures/network.py @@ -77,12 +77,12 @@ class LinksFactory(object): ipr.link('set', index=idx, state='up') return idx - def bond(self, name, *ifaces): - """Create a bond.""" + def _bond_or_team(self, kind, name, *ifaces): + """Create a bond or a team.""" ipr = pyroute2.IPRoute() # Create the bond ipr.link_create(ifname=name, - kind='bond') + kind=kind) idx = ipr.link_lookup(ifname=name)[0] # Attach interfaces for iface in ifaces: @@ -93,6 +93,16 @@ class LinksFactory(object): ipr.link('set', index=idx, state='up') return idx + def team(self, name, *ifaces): + """Create a team.""" + # Unfortunately, pyroute2 will try to run teamd too. This + # doesn't work. + return self._bond_or_team("team", name, *ifaces) + + def bond(self, name, *ifaces): + """Create a bond.""" + return self._bond_or_team("bond", name, *ifaces) + def vlan(self, name, id, iface): """Create a VLAN.""" ipr = pyroute2.IPRoute() diff --git a/tests/integration/test_interfaces.py b/tests/integration/test_interfaces.py index c09fc8db..292bf7fb 100644 --- a/tests/integration/test_interfaces.py +++ b/tests/integration/test_interfaces.py @@ -64,6 +64,29 @@ def test_bond(lldpd1, lldpd, lldpcli, namespaces, links, when): assert out['lldp.eth0.port.mac'] == '00:00:00:00:00:02' +@pytest.mark.skipif('Dot3' not in pytest.config.lldpd.features, + reason="Dot3 not supported") +@pytest.mark.skip(reason="Cannot create a simple team interface without teamd") +@pytest.mark.parametrize('when', ['before', 'after']) +def test_team(lldpd1, lldpd, lldpcli, namespaces, links, when): + links(namespaces(3), namespaces(2)) # Another link to setup a bond + with namespaces(2): + if when == 'after': + lldpd() + idx = links.team('team42', 'eth3', 'eth1') + if when == 'before': + lldpd() + else: + time.sleep(6) + with namespaces(1): + out = lldpcli("-f", "keyvalue", "show", "neighbors", "details") + assert out['lldp.eth0.port.descr'] == 'eth1' + assert out['lldp.eth0.port.aggregation'] == str(idx) + # Unfortunately, we cannot get the right MAC currently... So, + # this bit will fail. + assert out['lldp.eth0.port.mac'] == '00:00:00:00:00:02' + + @pytest.mark.skipif('Dot3' not in pytest.config.lldpd.features, reason="Dot3 not supported") @pytest.mark.skipif('Dot1' not in pytest.config.lldpd.features, -- 2.39.5