From ca43693778e7c35cc41494a07109e3ea426a09c6 Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Thu, 6 Aug 2020 14:29:28 +0200 Subject: [PATCH] addons: vxlan: new attribute: vxlan-mcastgrp-map "vxlan-mcastgrp-map": { "help": "vxlan multicast group for single-vxlan device", "validvals": [""], "example": ["vxlan-mcastgrp-map 1000=239.1.1.100 1001=239.1.1.200"], } Signed-off-by: Julien Fortin --- debian/changelog | 1 + ifupdown2/addons/vxlan.py | 43 ++++++++++++++++++++++++++++++++++++++- ifupdown2/lib/iproute2.py | 27 ++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index bd9dec4..55e7701 100644 --- a/debian/changelog +++ b/debian/changelog @@ -5,6 +5,7 @@ ifupdown2 (3.0.0-1) unstable; urgency=medium * New: bridge-always-up attribute * New: set bridge mtu with policy default * New: ES bond with "es-sys-mac" attribute + * New: vxlan attribute: vxlan-mcastgrp-map * New: support for "veth-peer-name" attribute * New: dhcp policy: dhclient_retry_on_failure * New: support for marking interfaces as mgmt interfaces diff --git a/ifupdown2/addons/vxlan.py b/ifupdown2/addons/vxlan.py index b6f5b6f..8e96061 100644 --- a/ifupdown2/addons/vxlan.py +++ b/ifupdown2/addons/vxlan.py @@ -109,7 +109,12 @@ class vxlan(Addon, moduleBase): "help": "vxlan multicast group", "validvals": [""], "example": ["vxlan-mcastgrp ff02::15c"], - } + }, + "vxlan-mcastgrp-map": { + "help": "vxlan multicast group for single-vxlan device", + "validvals": [""], + "example": ["vxlan-mcastgrp-map 1000=239.1.1.100 1001=239.1.1.200"], + }, } } @@ -816,6 +821,33 @@ class vxlan(Addon, moduleBase): self.log_error("%s: vxlan creation failed: %s" % (ifname, str(e)), ifaceobj) return + if ifaceobj.link_privflags & ifaceLinkPrivFlags.SINGLE_VXLAN: + # check current fdb entries + vxlan_fdb_data = utils.exec_command("bridge fdb show dev %s" % ifname) + current_fdb = [] + + if vxlan_fdb_data: + # each entry should look like the following: + # 00:00:00:00:00:00 dst 239.1.1.100 src_vni 1000 self permanent + for entry in [line for line in vxlan_fdb_data.strip().split("\n") if "src_vni" in line]: + mac, _, dst, _, src_vni = entry.split()[0:5] + current_fdb.append((mac, src_vni, dst)) + + user_config_fdb = self.get_vxlan_fdb_src_vni(ifaceobj.get_attr_value("vxlan-mcastgrp-map")) + + fdb_to_remove = set(current_fdb) - set(user_config_fdb) + + for mac, vni, _ in fdb_to_remove: + self.iproute2.bridge_fdb_del_src_vni(ifname, mac, vni) + + for mac, src_vni, dst_ip in user_config_fdb: + if (mac, src_vni, dst_ip) not in current_fdb: + try: + self.iproute2.bridge_fdb_add_src_vni(ifname, src_vni, dst_ip) + except Exception as e: + ifaceobj.set_status(ifaceStatus.ERROR) + self.log_error("%s: vxlan-mcastgrp-map: %s=%s: %s" % (ifname, src_vni, dst_ip, str(e)), raise_error=False) + vxlan_purge_remotes = self.__get_vlxan_purge_remotes(ifaceobj) remoteips = ifaceobj.get_attr_value('vxlan-remoteip') @@ -866,6 +898,15 @@ class vxlan(Addon, moduleBase): except Exception: pass + @staticmethod + def get_vxlan_fdb_src_vni(vxlan_mcast_grp_map): + fdbs = [] + for entry in vxlan_mcast_grp_map or []: + for vni_ip in entry.split(): + src_vni, dst_ip = vni_ip.split("=") + fdbs.append(("00:00:00:00:00:00", src_vni, dst_ip)) + return fdbs + def _down(self, ifaceobj): try: self.netlink.link_del(ifaceobj.name) diff --git a/ifupdown2/lib/iproute2.py b/ifupdown2/lib/iproute2.py index 2e810df..e4317b4 100644 --- a/ifupdown2/lib/iproute2.py +++ b/ifupdown2/lib/iproute2.py @@ -575,6 +575,21 @@ class IPRoute2(Cache, Requirements): ) ) + @staticmethod + def bridge_fdb_add_src_vni(dev, src_vni, dst_ip): + """ + bridge fdb add dev $dev 00:00:00:00:00:00 src_vni $src_vni dst $dst_ip + """ + utils.exec_command( + "%s fdb add dev %s 00:00:00:00:00:00 src_vni %s dst %s" + % ( + utils.bridge_cmd, + dev, + src_vni, + dst_ip + ) + ) + @staticmethod def bridge_fdb_append(dev, address, vlan=None, bridge=True, remote=None): target = "self" if bridge else "" @@ -593,6 +608,18 @@ class IPRoute2(Cache, Requirements): ) ) + @staticmethod + def bridge_fdb_del_src_vni(dev, mac, src_vni): + utils.exec_command( + "%s fdb del %s dev %s src_vni %s" + % ( + utils.bridge_cmd, + mac, + dev, + src_vni + ) + ) + @staticmethod def bridge_fdb_del(dev, address, vlan=None, bridge=True, remote=None): target = "self" if bridge else ""