From 87bc6683c60245d8cd9fec4b45c55fc8c84e65ad Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Thu, 25 Jul 2013 10:24:30 +0200 Subject: [PATCH] linux: mangle MAC address for enslaved devices With enslaved devices, we may end up with in a situation where we send a packet with a source MAC address that may confuse switches. For example: 1. eth0, MAC X connected to switch A. 2. eth1, MAC Y connected to switch B. 3. Active/backup bond is created, MAC X. 4. eth1 is active, eth0 is backup. If we use the real MAC, eth0 will send LLDP packets with MAC X to switch A that will learn this MAC and send packets on backup port eth0 and they will be discarded. The solution until then was to use a zero MAC address in those cases. However, it seems that some switches may be confused by such a move. See #26. Instead, we set the "local" bit to 1 if not already set. Otherwise, we just use some arbitrary MAC address that I have on an unused 3Com "Tornado" card. It is unlikely to be reused (100 MBps and it is in a basement). If you happen to have an even older MAC address and are willing to give it for lldpd, feel free to tell me. The later case does not handle all problems but allievate the problem with switches discarding or complaining about zero MAC address as a source. --- NEWS | 3 +++ src/daemon/interfaces-linux.c | 27 ++++++++++++++++++++++----- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index 80a74ea5..3af638f2 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,7 @@ lldpd (0.7.7) + * Features: + + Use a locally administered MAC address or an arbitrary one + instead of null MAC address for bond devices on Linux. * Fixes: + Various bugs related to fixed point number handling (for coordinates in LLDP-MED) diff --git a/src/daemon/interfaces-linux.c b/src/daemon/interfaces-linux.c index 00124bef..ebd374eb 100644 --- a/src/daemon/interfaces-linux.c +++ b/src/daemon/interfaces-linux.c @@ -465,14 +465,31 @@ iface_bond_init(struct lldpd *cfg, struct lldpd_hardware *hardware) return 0; } +/** + * Mangle the MAC address to avoid duplicates. + * + * With bonds, we have duplicate MAC address on different physical + * interfaces. We need to alter the source MAC address when we send on + * an inactive slave. We try to set "local" bit to 1 first. If it is + * already set to 1, use an unused MAC address instead. + */ +static void +iface_mangle_mac(char *buffer) +{ + if (buffer[0] & 2) { + /* Already a locally administered MAC address, use a fixed MAC + * address (an old 3c905 MAC address of a card that I own). */ + char arbitrary[] = { 0x00, 0x60, 0x08, 0x69, 0x97, 0xef}; + memcpy(buffer, arbitrary, sizeof(arbitrary)); + return; + } + buffer[0] |= 2; +} + static int iface_bond_send(struct lldpd *cfg, struct lldpd_hardware *hardware, char *buffer, size_t size) { - /* With bonds, we have duplicate MAC address on different physical - * interfaces. We need to alter the source MAC address when we send on - * an inactive slave. To avoid any future problem, we always set the - * source MAC address to 0. */ log_debug("interfaces", "send PDU to bonded device %s", hardware->h_ifname); if (size < 2 * ETHER_ADDR_LEN) { @@ -481,7 +498,7 @@ iface_bond_send(struct lldpd *cfg, struct lldpd_hardware *hardware, hardware->h_ifname); return 0; } - memset(buffer + ETHER_ADDR_LEN, 0, ETHER_ADDR_LEN); + iface_mangle_mac(buffer + ETHER_ADDR_LEN); return write(hardware->h_sendfd, buffer, size); } -- 2.39.5