]> git.proxmox.com Git - mirror_ifupdown2.git/commitdiff
addons: bridge: bridge-vlan-vni-map: remove stale entry from running config
authorJulien Fortin <jfortin@nvidia.com>
Wed, 12 May 2021 15:02:26 +0000 (17:02 +0200)
committerJulien Fortin <jfortin@nvidia.com>
Thu, 1 Jul 2021 15:53:27 +0000 (17:53 +0200)
Signed-off-by: Julien Fortin <jfortin@nvidia.com>
ifupdown2/addons/bridge.py
ifupdown2/lib/iproute2.py

index 8110f966b263ccb0afe3a6a30f32e673d8cab4c9..709ae6f56acbfbf362b80763eccc503a2fb70ce1 100644 (file)
@@ -7,7 +7,7 @@
 import re
 import time
 import itertools
-from collections import Counter
+from collections import OrderedDict, Counter
 
 try:
     from ifupdown2.lib.addon import Bridge
@@ -2363,8 +2363,11 @@ class bridge(Bridge, moduleBase):
         vxlan_name = ifaceobj.name
         try:
             self.iproute2.batch_start()
-            for bridge_vlan_vni_map_entry in ifaceobj.get_attr_value("bridge-vlan-vni-map"):
 
+            bridge_vlan_tunnel_info_running_config = self.iproute2.bridge_vlan_tunnel_show(vxlan_name)
+            all_user_config = OrderedDict()
+
+            for bridge_vlan_vni_map_entry in ifaceobj.get_attr_value("bridge-vlan-vni-map"):
                 if not bridge_vlan_vni_map_entry:
                     continue
 
@@ -2374,9 +2377,30 @@ class bridge(Bridge, moduleBase):
                     except:
                         return self.__warn_bridge_vlan_vni_map_syntax_error(vxlan_name, vlan_vni_map_entry)
 
-                    # TODO: query the cache prio to executing those commands
-                    self.iproute2.bridge_vlan_add_vid_list_self(vxlan_name, [vlans_str], False)
-                    self.iproute2.bridge_vlan_add_vlan_tunnel_info(vxlan_name, vlans_str, vni_str)
+                    # we need to convert vlan_str and vni_str back to a map {vlan: vni}
+                    for vlan, vni in zip(utils.ranges_to_ints([vlans_str]), utils.ranges_to_ints([vni_str])):
+                        all_user_config[vlan] = vni
+
+            vlan_vni_to_remove = OrderedDict()
+            for k, v in set(bridge_vlan_tunnel_info_running_config.items()) - set(all_user_config.items()):
+                vlan_vni_to_remove[k] = v
+
+            vlan_vni_to_add = OrderedDict()
+            for k, v in set(all_user_config.items()) - set(bridge_vlan_tunnel_info_running_config.items()):
+                vlan_vni_to_add[k] = v
+
+            # convert back to ranges to reduce the number of bridge commands
+            for (start_vlan, end_vlan), (start_vni, end_vni) in zip(utils.ints_to_ranges(vlan_vni_to_remove.keys()), utils.ints_to_ranges(vlan_vni_to_remove.values())):
+                vlan_str = ("%s-%s" % (start_vlan, end_vlan)) if start_vlan != end_vlan else start_vlan
+                vni_str = ("%s-%s" % (start_vni, end_vni)) if start_vni != end_vni else start_vni
+                self.iproute2.bridge_vlan_del_vid_list_self(vxlan_name, [vlans_str], False)
+                self.iproute2.bridge_vlan_del_vlan_tunnel_info(vxlan_name, vlan_str, vni_str)
+
+            for (start_vlan, end_vlan), (start_vni, end_vni) in zip(utils.ints_to_ranges(vlan_vni_to_add.keys()), utils.ints_to_ranges(vlan_vni_to_add.values())):
+                vlan_str = ("%s-%s" % (start_vlan, end_vlan)) if start_vlan != end_vlan else start_vlan
+                vni_str = ("%s-%s" % (start_vni, end_vni)) if start_vni != end_vni else start_vni
+                self.iproute2.bridge_vlan_add_vid_list_self(vxlan_name, [vlans_str], False)
+                self.iproute2.bridge_vlan_add_vlan_tunnel_info(vxlan_name, vlans_str, vni_str)
 
             self.iproute2.batch_commit()
         except Exception as e:
index b4c9e6c0e81e7335b9bd5521f71e28983c69815f..1ca50a7bc7a46bc1112ef0bffcad87c4b6605467 100644 (file)
@@ -691,6 +691,14 @@ class IPRoute2(Cache, Requirements):
                 "vlan del vid %s dev %s %s" % (v, ifname, target)
             )
 
+    def bridge_vlan_del_vlan_tunnel_info(self, ifname, vids, vnis):
+        self.__execute_or_batch(
+            utils.bridge_cmd,
+            "vlan del dev %s vid %s tunnel_info id %s" % (
+                ifname, vids, vnis
+            )
+        )
+
     def bridge_vlan_add_vlan_tunnel_info(self, ifname, vids, vnis):
         try:
             self.__execute_or_batch(
@@ -703,6 +711,37 @@ class IPRoute2(Cache, Requirements):
             if "exists" not in str(e).lower():
                 self.logger.error(e)
 
+    def bridge_vlan_tunnel_show(self, ifname):
+        tunnel_info = {}
+        try:
+            for entry in utils.exec_command("%s vlan tunnel dev %s" % (utils.bridge_cmd, ifname)).splitlines()[1:]:
+
+                if not entry:
+                    continue
+
+                entry_list = entry.split()
+                length = len(entry_list)
+
+                if length > 2:
+                    # if len == 3, we need to remove the ifname from the list
+                    # $ bridge vlan tunnel show dev vxlan42
+                    # port    vlan ids        tunnel id
+                    # vxlan42   1042    1542
+                    entry_list = entry_list[1:]
+
+                if length < 2:
+                    continue
+
+                vnis = utils.ranges_to_ints([entry_list[0]])
+                tunnel_ids = utils.ranges_to_ints([entry_list[1]])
+
+                for vni, tunnel_id in zip(vnis, tunnel_ids):
+                    tunnel_info[int(vni)] = int(tunnel_id)
+
+        except Exception as e:
+            self.logger.debug("iproute2: bridge vlan tunnel dev %s: %s" % (ifname, str(e)))
+        return tunnel_info
+
     @staticmethod
     def bridge_vlan_add_vid_list(ifname, vids):
         for v in vids:
@@ -718,6 +757,14 @@ class IPRoute2(Cache, Requirements):
                 "vlan add vid %s dev %s %s" % (v, ifname, target)
             )
 
+    def bridge_vlan_del_vid_list_self(self, ifname, vids, is_bridge=True):
+        target = "self" if is_bridge else ""
+        for v in vids:
+            self.__execute_or_batch(
+                utils.bridge_cmd,
+                "vlan del vid %s dev %s %s" % (v, ifname, target)
+            )
+
     def bridge_vlan_del_pvid(self, ifname, pvid):
         self.__execute_or_batch(
             utils.bridge_cmd,