mirror of
				https://github.com/CumulusNetworks/ifupdown2.git
				synced 2024-05-06 15:54:50 +00:00 
			
		
		
		
	add support for single vxlan device (bridge-vlan-vni-map)
new attribute:
"bridge-vlan-vni-map": {
    "help": "Single vxlan support",
    "example": "bridge-vlan-vni-map 1000-1001=1000-1001",
}
example of config:
auto bridge
iface bridge
      bridge-vlan-aware yes
      bridge-ports vxlan0 swp1
      bridge-stp on
      bridge-vids 1000-1001
      bridge-pvid 1
auto vxlan0
iface vxlan0
      vxlan-local-tunnelip 27.0.0.9
      bridge-learning off
      # vlan 1000-1001 maps to vni 1000-1001
      bridge-vlan-vni-map 1000-1001=1000-1001
Signed-off-by: Julien Fortin <julien@cumulusnetworks.com>
			
			
This commit is contained in:
		
							
								
								
									
										1
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							@@ -3,6 +3,7 @@ ifupdown2 (3.0.1-1) unstable; urgency=medium
 | 
			
		||||
   * New. Enabled: bridge-always-up attribute
 | 
			
		||||
   * New. Enabled: ES bond with "es-sys-mac" attribute
 | 
			
		||||
   * New. Enabled: dhcp policy: dhclient_retry_on_failure
 | 
			
		||||
   * New. Enabled: bridge-vlan-vni-map attribute (single vxlan device)
 | 
			
		||||
   * Fix: start-networking script is back to handle mgmt & hotplug cases
 | 
			
		||||
 | 
			
		||||
 -- Julien Fortin <julien@cumulusnetworks.com>  Tue, 14 Apr 2020 23:42:42 +0200
 | 
			
		||||
 
 | 
			
		||||
@@ -441,6 +441,10 @@ class bridge(Addon, moduleBase):
 | 
			
		||||
                    "required": False,
 | 
			
		||||
                    "example": ["bridge-ports-condone-regex ^[a-zA-Z0-9]+_v[0-9]{1,4}$"]
 | 
			
		||||
            },
 | 
			
		||||
            "bridge-vlan-vni-map": {
 | 
			
		||||
                "help": "Single vxlan support",
 | 
			
		||||
                "example": "bridge-vlan-vni-map 1000-1001=1000-1001",
 | 
			
		||||
            },
 | 
			
		||||
            "bridge-always-up": {
 | 
			
		||||
                "help": "Enabling this attribute on a bridge will enslave a dummy interface to the bridge",
 | 
			
		||||
                "required": False,
 | 
			
		||||
@@ -917,8 +921,7 @@ class bridge(Addon, moduleBase):
 | 
			
		||||
    def syntax_check_vxlan_in_vlan_aware_br(self, ifaceobj, ifaceobj_getfunc):
 | 
			
		||||
        if not ifaceobj_getfunc:
 | 
			
		||||
            return True
 | 
			
		||||
        if (ifaceobj.link_kind & ifaceLinkKind.VXLAN
 | 
			
		||||
                and ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT):
 | 
			
		||||
        if (ifaceobj.link_kind & ifaceLinkKind.VXLAN and ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT):
 | 
			
		||||
            if ifaceobj.get_attr_value('bridge-access'):
 | 
			
		||||
                return True
 | 
			
		||||
            for iface in ifaceobj.upperifaces if ifaceobj.upperifaces else []:
 | 
			
		||||
@@ -1555,7 +1558,7 @@ class bridge(Addon, moduleBase):
 | 
			
		||||
            because kernel does honor vid info flags during deletes.
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        if not isbridge and bportifaceobj.link_kind & ifaceLinkKind.VXLAN:
 | 
			
		||||
        if not isbridge and (bportifaceobj.link_kind & ifaceLinkKind.VXLAN and not bportifaceobj.link_privflags & ifaceLinkPrivFlags.SINGLE_VXLAN):
 | 
			
		||||
            if not vids or not pvid or len(vids) > 1 or vids[0] != pvid:
 | 
			
		||||
                self._error_vxlan_in_vlan_aware_br(bportifaceobj,
 | 
			
		||||
                                                   bportifaceobj.upperifaces[0])
 | 
			
		||||
@@ -1628,6 +1631,9 @@ class bridge(Addon, moduleBase):
 | 
			
		||||
            if vids_to_del:
 | 
			
		||||
               if pvid_to_add in vids_to_del:
 | 
			
		||||
                   vids_to_del.remove(pvid_to_add)
 | 
			
		||||
 | 
			
		||||
               vids_to_del = self.remove_bridge_vlans_mapped_to_vnis_from_vids_list(None, bportifaceobj, vids_to_del)
 | 
			
		||||
 | 
			
		||||
               self.iproute2.bridge_vlan_del_vid_list_self(bportifaceobj.name,
 | 
			
		||||
                                          self._compress_into_ranges(
 | 
			
		||||
                                          vids_to_del), isbridge)
 | 
			
		||||
@@ -1662,6 +1668,47 @@ class bridge(Addon, moduleBase):
 | 
			
		||||
                               %(bportifaceobj.name, pvid_to_add, str(e)),
 | 
			
		||||
                               bportifaceobj)
 | 
			
		||||
 | 
			
		||||
    def get_bridge_vlans_mapped_to_vnis_as_integer_list(self, ifaceobj):
 | 
			
		||||
        """
 | 
			
		||||
            Get all vlans that the user wants to configured in vlan-vni maps
 | 
			
		||||
        """
 | 
			
		||||
        try:
 | 
			
		||||
            vids = []
 | 
			
		||||
 | 
			
		||||
            for vlans_vnis_map in ifaceobj.get_attr_value("bridge-vlan-vni-map"):
 | 
			
		||||
                vids.extend(self._ranges_to_ints([vlans_vnis_map.split("=")[0]]))
 | 
			
		||||
 | 
			
		||||
            return vids
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            self.logger.debug("get_bridge_vlans_mapped_to_vnis_as_integer_list: %s" % str(e))
 | 
			
		||||
            return []
 | 
			
		||||
 | 
			
		||||
    def remove_bridge_vlans_mapped_to_vnis_from_vids_list(self, bridge_ifaceobj, vxlan_ifaceobj, vids_list):
 | 
			
		||||
        """
 | 
			
		||||
            For single vxlan we need to remove the vlans mapped to vnis
 | 
			
		||||
            from the vids list otherwise they will get removed from the brport
 | 
			
		||||
        """
 | 
			
		||||
        if not (vxlan_ifaceobj.link_privflags & ifaceLinkPrivFlags.SINGLE_VXLAN):
 | 
			
		||||
            return vids_list
 | 
			
		||||
 | 
			
		||||
        user_config_vids = []
 | 
			
		||||
 | 
			
		||||
        if bridge_ifaceobj:
 | 
			
		||||
            for vid in self.get_bridge_vlans_mapped_to_vnis_as_integer_list(bridge_ifaceobj):
 | 
			
		||||
                user_config_vids.append(vid)
 | 
			
		||||
 | 
			
		||||
        if vxlan_ifaceobj:
 | 
			
		||||
            for vid in self.get_bridge_vlans_mapped_to_vnis_as_integer_list(vxlan_ifaceobj):
 | 
			
		||||
                user_config_vids.append(vid)
 | 
			
		||||
 | 
			
		||||
        for vlan in user_config_vids:
 | 
			
		||||
            try:
 | 
			
		||||
                vids_list.remove(vlan)
 | 
			
		||||
            except:
 | 
			
		||||
                pass
 | 
			
		||||
 | 
			
		||||
        return vids_list
 | 
			
		||||
 | 
			
		||||
    def _apply_bridge_vlan_aware_port_settings_all(self, bportifaceobj,
 | 
			
		||||
                                                   bridge_vids=None,
 | 
			
		||||
                                                   bridge_pvid=None):
 | 
			
		||||
@@ -1916,6 +1963,7 @@ class bridge(Addon, moduleBase):
 | 
			
		||||
 | 
			
		||||
    def up_apply_brports_attributes(self, ifaceobj, ifaceobj_getfunc, bridge_vlan_aware, target_ports=[], newly_enslaved_ports=[]):
 | 
			
		||||
        ifname = ifaceobj.name
 | 
			
		||||
        single_vxlan_device_ifaceobj = None
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            brports_ifla_info_slave_data    = dict()
 | 
			
		||||
@@ -2221,8 +2269,19 @@ class bridge(Addon, moduleBase):
 | 
			
		||||
                            pass
 | 
			
		||||
 | 
			
		||||
                    #
 | 
			
		||||
                    # SINGLE VXLAN - enable IFLA_BRPORT_VLAN_TUNNEL
 | 
			
		||||
                    #
 | 
			
		||||
                    #
 | 
			
		||||
 | 
			
		||||
                    if brport_ifaceobj.link_privflags & ifaceLinkPrivFlags.SINGLE_VXLAN:
 | 
			
		||||
                        single_vxlan_device_ifaceobj = brport_ifaceobj
 | 
			
		||||
                        brport_vlan_tunnel_cached_value = self.cache.get_link_info_slave_data_attribute(
 | 
			
		||||
                            brport_name,
 | 
			
		||||
                            Link.IFLA_BRPORT_VLAN_TUNNEL
 | 
			
		||||
                        )
 | 
			
		||||
 | 
			
		||||
                        if not brport_vlan_tunnel_cached_value:
 | 
			
		||||
                            self.logger.info("%s: %s: enabling vlan_tunnel on single vxlan device" % (ifname, brport_name))
 | 
			
		||||
                            brport_ifla_info_slave_data[Link.IFLA_BRPORT_VLAN_TUNNEL] = 1
 | 
			
		||||
 | 
			
		||||
                else:
 | 
			
		||||
                    kind = None
 | 
			
		||||
@@ -2244,6 +2303,41 @@ class bridge(Addon, moduleBase):
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            self.log_error(str(e), ifaceobj)
 | 
			
		||||
 | 
			
		||||
        if single_vxlan_device_ifaceobj:
 | 
			
		||||
            self.apply_bridge_port_vlan_vni_map(single_vxlan_device_ifaceobj)
 | 
			
		||||
 | 
			
		||||
    def apply_bridge_port_vlan_vni_map(self, ifaceobj):
 | 
			
		||||
        """
 | 
			
		||||
        bridge vlan add vid <vlan-id> dev vxlan0
 | 
			
		||||
        bridge vlan add dev vxlan0 vid <vlan-id> tunnel_info id <vni>
 | 
			
		||||
        """
 | 
			
		||||
        vxlan_name = ifaceobj.name
 | 
			
		||||
        try:
 | 
			
		||||
            self.iproute2.batch_start()
 | 
			
		||||
            for vlan_vni_map in ifaceobj.get_attr_value("bridge-vlan-vni-map"):
 | 
			
		||||
 | 
			
		||||
                try:
 | 
			
		||||
                    vlans_str, vni_str = vlan_vni_map.split("=")
 | 
			
		||||
                except:
 | 
			
		||||
                    return self.__warn_bridge_vlan_vni_map_syntax_error(vlan_vni_map)
 | 
			
		||||
 | 
			
		||||
                vlans = self._ranges_to_ints([vlans_str])
 | 
			
		||||
                vnis = self._ranges_to_ints([vni_str])
 | 
			
		||||
 | 
			
		||||
                if len(vlans) != len(vnis):
 | 
			
		||||
                    return self.__warn_bridge_vlan_vni_map_syntax_error(vlan_vni_map)
 | 
			
		||||
 | 
			
		||||
                # TODO: query the cache prio to executing those commands
 | 
			
		||||
                self.iproute2.bridge_vlan_add_vid_list_self(vxlan_name, vlans, False)
 | 
			
		||||
                self.iproute2.bridge_vlan_add_vlan_tunnel_info(vxlan_name, vlans, vnis)
 | 
			
		||||
 | 
			
		||||
            self.iproute2.batch_commit()
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            self.log_error("%s: error while processing bridge-vlan-vni-map attribute: %s" % (vxlan_name, str(e)))
 | 
			
		||||
 | 
			
		||||
    def __warn_bridge_vlan_vni_map_syntax_error(self, user_config_vlan_vni_map):
 | 
			
		||||
        self.logger.warning("%s: syntax error: bridge-vlan-vni-map %s" % user_config_vlan_vni_map)
 | 
			
		||||
 | 
			
		||||
    def is_qinq_bridge(self, ifaceobj, brport_name, running_brports, brport_ifaceobj_dict, ifaceobj_getfunc):
 | 
			
		||||
        """ Detect QinQ bridge
 | 
			
		||||
        Potential improvement: We could add a ifaceobj.link_privflags called
 | 
			
		||||
@@ -3259,6 +3353,21 @@ class bridge(Addon, moduleBase):
 | 
			
		||||
        attr_name, vids = self.get_ifaceobj_bridge_vids(ifaceobj)
 | 
			
		||||
        if vids:
 | 
			
		||||
           vids = re.split(r'[\s\t]\s*', vids)
 | 
			
		||||
 | 
			
		||||
           # Special treatment to make sure that the vlans mapped with vnis
 | 
			
		||||
           # (in single-vxlan context) are not mistaken for regular vlans.
 | 
			
		||||
           # We need to proactively remove them from the "running_vids"
 | 
			
		||||
           vlans_mapped_with_vnis = self.get_bridge_vlans_mapped_to_vnis_as_integer_list(ifaceobj)
 | 
			
		||||
           new_running_vids = []
 | 
			
		||||
           user_config_vids = self._ranges_to_ints(vids)
 | 
			
		||||
           for v in running_vids:
 | 
			
		||||
               if v in user_config_vids:
 | 
			
		||||
                   new_running_vids.append(v)
 | 
			
		||||
               elif v not in vlans_mapped_with_vnis:
 | 
			
		||||
                   new_running_vids.append(v)
 | 
			
		||||
           running_vids = new_running_vids
 | 
			
		||||
           #####################################################################
 | 
			
		||||
 | 
			
		||||
           if not running_vids or not self._compare_vids(vids, running_vids, running_pvid, expand_range=False):
 | 
			
		||||
               running_vids = [str(o) for o in running_vids]
 | 
			
		||||
               ifaceobjcurr.update_config_with_status(attr_name,
 | 
			
		||||
@@ -3401,6 +3510,85 @@ class bridge(Addon, moduleBase):
 | 
			
		||||
 | 
			
		||||
        self._query_check_l2protocol_tunnel_on_port(ifaceobj, ifaceobjcurr)
 | 
			
		||||
 | 
			
		||||
        #
 | 
			
		||||
        # bridge-vlan-vni-map
 | 
			
		||||
        #
 | 
			
		||||
        fail = False
 | 
			
		||||
        cached_vlans, cached_vnis = self.get_vlan_vni_ranges(self.cache.get_vlan_vni(ifaceobj.name))
 | 
			
		||||
 | 
			
		||||
        for bridge_vlan_vni_map in ifaceobj.get_attr_value("bridge-vlan-vni-map"):
 | 
			
		||||
 | 
			
		||||
            if fail:
 | 
			
		||||
                ifaceobjcurr.update_config_with_status("bridge-vlan-vni-map", bridge_vlan_vni_map, 1)
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
            try:
 | 
			
		||||
                vlans_str, vni_str = bridge_vlan_vni_map.split("=")
 | 
			
		||||
            except:
 | 
			
		||||
                ifaceobjcurr.update_config_with_status("bridge-vlan-vni-map", bridge_vlan_vni_map, 1)
 | 
			
		||||
                return self.__warn_bridge_vlan_vni_map_syntax_error(bridge_vlan_vni_map)
 | 
			
		||||
 | 
			
		||||
            vlans_list = self._ranges_to_ints([vlans_str])   # self.bridge_vlan_vni_map_convert_user_config_to_set(vlans_str)
 | 
			
		||||
            vnis_list = self._ranges_to_ints([vni_str]) #self.bridge_vlan_vni_map_convert_user_config_to_set(vni_str)
 | 
			
		||||
 | 
			
		||||
            # since there can be multiple entry of bridge-vlan-vni-map
 | 
			
		||||
            # we could simply check that all vlans and vnis are correctly
 | 
			
		||||
            # set on the vxlan but we would probably miss the case where extra
 | 
			
		||||
            # vlans and vnis were added. So we ned to keep a copy of the cache
 | 
			
		||||
            # entry and pop vlans and svis from the cache copy as we iterate
 | 
			
		||||
            # through the user config. After processing only extra vlans and
 | 
			
		||||
            # vnis should be left.
 | 
			
		||||
            try:
 | 
			
		||||
                for vlan in vlans_list:
 | 
			
		||||
                    cached_vlans.remove(vlan)
 | 
			
		||||
            except:
 | 
			
		||||
                ifaceobjcurr.update_config_with_status("bridge-vlan-vni-map", bridge_vlan_vni_map, 1)
 | 
			
		||||
                fail = True
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
            try:
 | 
			
		||||
                for vni in vnis_list:
 | 
			
		||||
                    cached_vnis.remove(vni)
 | 
			
		||||
            except:
 | 
			
		||||
                ifaceobjcurr.update_config_with_status("bridge-vlan-vni-map", bridge_vlan_vni_map, 1)
 | 
			
		||||
                fail = True
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
            ifaceobjcurr.update_config_with_status("bridge-vlan-vni-map", bridge_vlan_vni_map, 0)
 | 
			
		||||
 | 
			
		||||
        if not fail and (cached_vlans or cached_vnis):
 | 
			
		||||
            # cached_vlans and cached_vnis are not empty, it means more
 | 
			
		||||
            # vlans-vni maps were configured on the bridge port
 | 
			
		||||
            ifaceobjcurr.update_config_with_status(
 | 
			
		||||
                "bridge-vlan-vni-map",
 | 
			
		||||
                "%s=%s" % (cached_vlans, cached_vnis),
 | 
			
		||||
                1
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def get_vlan_vni_ranges(bridge_vlan_tunnel):
 | 
			
		||||
        vlans = []
 | 
			
		||||
        vnis = []
 | 
			
		||||
 | 
			
		||||
        tunnel_vlan_range = None
 | 
			
		||||
        tunnel_vni_range = None
 | 
			
		||||
 | 
			
		||||
        for tunnel_vlan, tunnel_vni, tunnel_flags in bridge_vlan_tunnel:
 | 
			
		||||
 | 
			
		||||
            if tunnel_flags & Link.BRIDGE_VLAN_INFO_RANGE_BEGIN:
 | 
			
		||||
                tunnel_vlan_range = tunnel_vlan
 | 
			
		||||
                tunnel_vni_range = tunnel_vni
 | 
			
		||||
 | 
			
		||||
            elif tunnel_flags & Link.BRIDGE_VLAN_INFO_RANGE_END:
 | 
			
		||||
                vlans.extend(range(tunnel_vlan_range, tunnel_vlan + 1))
 | 
			
		||||
                vnis.extend(range(tunnel_vni_range, tunnel_vni + 1))
 | 
			
		||||
 | 
			
		||||
            else:
 | 
			
		||||
                vlans.append(tunnel_vlan)
 | 
			
		||||
                vnis.append(tunnel_vni)
 | 
			
		||||
 | 
			
		||||
        return vlans, vnis
 | 
			
		||||
 | 
			
		||||
    def _query_check_l2protocol_tunnel_on_port(self, ifaceobj, ifaceobjcurr):
 | 
			
		||||
        user_config_l2protocol_tunnel = ifaceobj.get_attr_value_first('bridge-l2protocol-tunnel')
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -156,6 +156,9 @@ class vxlan(Addon, moduleBase):
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    def get_dependent_ifacenames(self, ifaceobj, ifaceobjs_all=None):
 | 
			
		||||
        if ifaceobj.get_attr_value_first("bridge-vlan-vni-map"):
 | 
			
		||||
            ifaceobj.link_privflags |= ifaceLinkPrivFlags.SINGLE_VXLAN
 | 
			
		||||
 | 
			
		||||
        if self._is_vxlan_device(ifaceobj):
 | 
			
		||||
            ifaceobj.link_kind |= ifaceLinkKind.VXLAN
 | 
			
		||||
            self._set_global_local_ip(ifaceobj)
 | 
			
		||||
@@ -191,7 +194,10 @@ class vxlan(Addon, moduleBase):
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def _is_vxlan_device(ifaceobj):
 | 
			
		||||
        return ifaceobj.link_kind & ifaceLinkKind.VXLAN or ifaceobj.get_attr_value_first('vxlan-id')
 | 
			
		||||
        return ifaceobj.link_kind & ifaceLinkKind.VXLAN \
 | 
			
		||||
               or ifaceobj.link_privflags & ifaceLinkPrivFlags.SINGLE_VXLAN \
 | 
			
		||||
               or ifaceobj.get_attr_value_first("vxlan-id") \
 | 
			
		||||
               or ifaceobj.get_attr_value_first("bridge-vlan-vni-map")
 | 
			
		||||
 | 
			
		||||
    def __get_vlxan_purge_remotes(self, ifaceobj):
 | 
			
		||||
        if not ifaceobj:
 | 
			
		||||
@@ -609,7 +615,8 @@ class vxlan(Addon, moduleBase):
 | 
			
		||||
    def _up(self, ifaceobj):
 | 
			
		||||
        vxlan_id_str = ifaceobj.get_attr_value_first("vxlan-id")
 | 
			
		||||
 | 
			
		||||
        if not vxlan_id_str:
 | 
			
		||||
        if not ifaceobj.link_privflags & ifaceLinkPrivFlags.SINGLE_VXLAN and not vxlan_id_str:
 | 
			
		||||
            self.logger.warning("%s: missing vxlan-id attribute on vxlan device" % ifaceobj.name)
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        ifname = ifaceobj.name
 | 
			
		||||
@@ -634,7 +641,10 @@ class vxlan(Addon, moduleBase):
 | 
			
		||||
 | 
			
		||||
        user_request_vxlan_info_data = {}
 | 
			
		||||
 | 
			
		||||
        self.__config_vxlan_id(ifname, ifaceobj, vxlan_id_str, user_request_vxlan_info_data, cached_vxlan_ifla_info_data)
 | 
			
		||||
        if vxlan_id_str:
 | 
			
		||||
            # for single vxlan device we don't have a vxlan-id
 | 
			
		||||
            self.__config_vxlan_id(ifname, ifaceobj, vxlan_id_str, user_request_vxlan_info_data, cached_vxlan_ifla_info_data)
 | 
			
		||||
 | 
			
		||||
        self.__config_vxlan_learning(ifaceobj, link_exists, user_request_vxlan_info_data, cached_vxlan_ifla_info_data)
 | 
			
		||||
        self.__config_vxlan_ageing(ifname, ifaceobj, link_exists, user_request_vxlan_info_data, cached_vxlan_ifla_info_data)
 | 
			
		||||
        self.__config_vxlan_port(ifname, ifaceobj, link_exists, user_request_vxlan_info_data, cached_vxlan_ifla_info_data)
 | 
			
		||||
@@ -674,20 +684,30 @@ class vxlan(Addon, moduleBase):
 | 
			
		||||
                # element: vxlan-id
 | 
			
		||||
                self.logger.info('%s: vxlan already exists - no change detected' % ifname)
 | 
			
		||||
            else:
 | 
			
		||||
                try:
 | 
			
		||||
                    if flap_vxlan_device:
 | 
			
		||||
                        self.netlink.link_down_force(ifname)
 | 
			
		||||
 | 
			
		||||
                    self.netlink.link_add_vxlan_with_info_data(ifname, user_request_vxlan_info_data)
 | 
			
		||||
 | 
			
		||||
                    if flap_vxlan_device:
 | 
			
		||||
                        self.netlink.link_up_force(ifname)
 | 
			
		||||
                except Exception as e:
 | 
			
		||||
                if ifaceobj.link_privflags & ifaceLinkPrivFlags.SINGLE_VXLAN:
 | 
			
		||||
                    if link_exists:
 | 
			
		||||
                        self.log_error("%s: applying vxlan change failed: %s" % (ifname, str(e)), ifaceobj)
 | 
			
		||||
                        self.logger.warning("%s: updating existing single vxlan device is not support yet" % ifname)
 | 
			
		||||
                    else:
 | 
			
		||||
                        self.log_error("%s: vxlan creation failed: %s" % (ifname, str(e)), ifaceobj)
 | 
			
		||||
                    return
 | 
			
		||||
                        self.iproute2.link_add_single_vxlan(
 | 
			
		||||
                            ifname,
 | 
			
		||||
                            local,
 | 
			
		||||
                            user_request_vxlan_info_data.get(Link.IFLA_VXLAN_PORT)
 | 
			
		||||
                        )
 | 
			
		||||
                else:
 | 
			
		||||
                    try:
 | 
			
		||||
                        if flap_vxlan_device:
 | 
			
		||||
                            self.netlink.link_down_force(ifname)
 | 
			
		||||
 | 
			
		||||
                        self.netlink.link_add_vxlan_with_info_data(ifname, user_request_vxlan_info_data)
 | 
			
		||||
 | 
			
		||||
                        if flap_vxlan_device:
 | 
			
		||||
                            self.netlink.link_up_force(ifname)
 | 
			
		||||
                    except Exception as e:
 | 
			
		||||
                        if link_exists:
 | 
			
		||||
                            self.log_error("%s: applying vxlan change failed: %s" % (ifname, str(e)), ifaceobj)
 | 
			
		||||
                        else:
 | 
			
		||||
                            self.log_error("%s: vxlan creation failed: %s" % (ifname, str(e)), ifaceobj)
 | 
			
		||||
                        return
 | 
			
		||||
 | 
			
		||||
        vxlan_purge_remotes = self.__get_vlxan_purge_remotes(ifaceobj)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -79,6 +79,7 @@ class ifaceLinkKind():
 | 
			
		||||
class ifaceLinkPrivFlags():
 | 
			
		||||
    """ This corresponds to kernel netdev->priv_flags
 | 
			
		||||
        and can be BRIDGE_PORT, BOND_SLAVE etc """
 | 
			
		||||
 | 
			
		||||
    UNKNOWN =           0x00000
 | 
			
		||||
    BRIDGE_PORT =       0x00001
 | 
			
		||||
    BOND_SLAVE =        0x00010
 | 
			
		||||
@@ -89,7 +90,8 @@ class ifaceLinkPrivFlags():
 | 
			
		||||
    LOOPBACK = 0x1000000
 | 
			
		||||
    KEEP_LINK_DOWN = 0x10000000
 | 
			
		||||
    MGMT_INTF = 0x100000000
 | 
			
		||||
    ES_BOND = 0x1000000000
 | 
			
		||||
    SINGLE_VXLAN = 0x1000000000
 | 
			
		||||
    ES_BOND = 0x10000000000
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def get_str(cls, flag):
 | 
			
		||||
 
 | 
			
		||||
@@ -269,6 +269,20 @@ class IPRoute2(Cache, Requirements):
 | 
			
		||||
 | 
			
		||||
    ###
 | 
			
		||||
 | 
			
		||||
    def link_add_single_vxlan(self, ifname, ip, port):
 | 
			
		||||
        self.logger.info("creating single vxlan device: %s" % ifname)
 | 
			
		||||
 | 
			
		||||
        cmd = ["link add dev %s type vxlan external" % ifname]
 | 
			
		||||
 | 
			
		||||
        if ip:
 | 
			
		||||
            cmd.append("local %s" % ip)
 | 
			
		||||
 | 
			
		||||
        if port:
 | 
			
		||||
            cmd.append("dstport %s" % port)
 | 
			
		||||
 | 
			
		||||
        self.__execute_or_batch(utils.ip_cmd, " ".join(cmd))
 | 
			
		||||
        self.__update_cache_after_link_creation(ifname, "vxlan")
 | 
			
		||||
 | 
			
		||||
    def link_create_vxlan(self, name, vxlanid, localtunnelip=None, svcnodeip=None,
 | 
			
		||||
                          remoteips=None, learning='on', ageing=None, ttl=None, physdev=None):
 | 
			
		||||
        if svcnodeip and remoteips:
 | 
			
		||||
@@ -583,12 +597,18 @@ class IPRoute2(Cache, Requirements):
 | 
			
		||||
                "vlan del vid %s dev %s %s" % (v, ifname, target)
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def bridge_vlan_add_vid_list(ifname, vids):
 | 
			
		||||
        for v in vids:
 | 
			
		||||
            utils.exec_command(
 | 
			
		||||
                "%s vlan add vid %s dev %s" % (utils.bridge_cmd, v, ifname)
 | 
			
		||||
            )
 | 
			
		||||
    def bridge_vlan_add_vlan_tunnel_info(self, ifname, vids, vnis):
 | 
			
		||||
        for i in range(0, len(vids)):
 | 
			
		||||
            try:
 | 
			
		||||
                self.__execute_or_batch(
 | 
			
		||||
                    utils.bridge_cmd,
 | 
			
		||||
                    "vlan add dev %s vid %s tunnel_info id %s" % (
 | 
			
		||||
                        ifname, vids[i], vnis[i]
 | 
			
		||||
                    )
 | 
			
		||||
                )
 | 
			
		||||
            except Exception as e:
 | 
			
		||||
                if "exists" not in str(e).lower():
 | 
			
		||||
                    self.logger.error(e)
 | 
			
		||||
 | 
			
		||||
    def bridge_vlan_add_vid_list_self(self, ifname, vids, is_bridge=True):
 | 
			
		||||
        target = "self" if is_bridge else ""
 | 
			
		||||
 
 | 
			
		||||
@@ -161,6 +161,7 @@ class _NetlinkCache:
 | 
			
		||||
        self._link_cache = {}
 | 
			
		||||
        self._addr_cache = {}
 | 
			
		||||
        self._bridge_vlan_cache = {}
 | 
			
		||||
        self._bridge_vlan_vni_cache = {}
 | 
			
		||||
 | 
			
		||||
        # helper dictionaries
 | 
			
		||||
        # ifindex: ifname
 | 
			
		||||
@@ -306,6 +307,11 @@ class _NetlinkCache:
 | 
			
		||||
        except KeyError:
 | 
			
		||||
            pass
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            del self._bridge_vlan_vni_cache[slave]
 | 
			
		||||
        except KeyError:
 | 
			
		||||
            pass
 | 
			
		||||
 | 
			
		||||
    def append_to_ignore_rtm_newlinkq(self, ifname):
 | 
			
		||||
        """
 | 
			
		||||
        Register device 'ifname' to the ignore_rtm_newlinkq list pending
 | 
			
		||||
@@ -1022,6 +1028,10 @@ class _NetlinkCache:
 | 
			
		||||
        except (KeyError, AttributeError):
 | 
			
		||||
            return 0
 | 
			
		||||
 | 
			
		||||
    def get_vlan_vni(self, ifname):
 | 
			
		||||
        with self._cache_lock:
 | 
			
		||||
            return self._bridge_vlan_vni_cache.get(ifname)
 | 
			
		||||
 | 
			
		||||
    def get_pvid_and_vids(self, ifname):
 | 
			
		||||
        """
 | 
			
		||||
        vlan-identifiers are stored in:
 | 
			
		||||
@@ -1352,6 +1362,7 @@ class _NetlinkCache:
 | 
			
		||||
        """
 | 
			
		||||
        vlans_list = []
 | 
			
		||||
 | 
			
		||||
        # Todo: acquire the lock only when really needed
 | 
			
		||||
        with self._cache_lock:
 | 
			
		||||
            ifla_af_spec = msg.get_attribute_value(Link.IFLA_AF_SPEC)
 | 
			
		||||
            ifname = msg.get_attribute_value(Link.IFLA_IFNAME)
 | 
			
		||||
@@ -1385,6 +1396,9 @@ class _NetlinkCache:
 | 
			
		||||
                        # (flag, vlan) so that we can sort the list of tuples
 | 
			
		||||
                        vlans_list.append((vlan_id, vlan_flag))
 | 
			
		||||
 | 
			
		||||
                elif x_type == Link.IFLA_BRIDGE_VLAN_TUNNEL_INFO:
 | 
			
		||||
                    self._bridge_vlan_vni_cache.update({ifname: x_value})
 | 
			
		||||
 | 
			
		||||
            self._bridge_vlan_cache.update({ifname: vlans_list})
 | 
			
		||||
 | 
			
		||||
    def force_add_slave(self, master, slave):
 | 
			
		||||
@@ -1516,6 +1530,11 @@ class _NetlinkCache:
 | 
			
		||||
            except:
 | 
			
		||||
                pass
 | 
			
		||||
 | 
			
		||||
            try:
 | 
			
		||||
                del self._bridge_vlan_vni_cache[ifname]
 | 
			
		||||
            except:
 | 
			
		||||
                pass
 | 
			
		||||
 | 
			
		||||
            try:
 | 
			
		||||
                del self._ifname_by_ifindex[ifindex]
 | 
			
		||||
            except KeyError:
 | 
			
		||||
 
 | 
			
		||||
@@ -1661,6 +1661,11 @@ class AttributeIFLA_AF_SPEC(Attribute):
 | 
			
		||||
        {
 | 
			
		||||
            Link.IFLA_BRIDGE_FLAGS: flags,
 | 
			
		||||
            Link.IFLA_BRIDGE_VLAN_INFO: (vflags, vlanid)
 | 
			
		||||
            Link.IFLA_BRIDGE_VLAN_TUNNEL_INFO: [
 | 
			
		||||
                    __u32 tunnel_id;
 | 
			
		||||
                    __u16 tunnel_vid;
 | 
			
		||||
                    __u16 tunnel_flags;
 | 
			
		||||
            ]
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        FROM: David Ahern
 | 
			
		||||
@@ -1722,6 +1727,13 @@ class AttributeIFLA_AF_SPEC(Attribute):
 | 
			
		||||
            sub_attr_data = data[4:sub_attr_end]
 | 
			
		||||
 | 
			
		||||
            if self.family == AF_BRIDGE:
 | 
			
		||||
                # /* Bridge management nested attributes
 | 
			
		||||
                #  * [IFLA_AF_SPEC] = {
 | 
			
		||||
                #  *     [IFLA_BRIDGE_FLAGS]
 | 
			
		||||
                #  *     [IFLA_BRIDGE_MODE]
 | 
			
		||||
                #  *     [IFLA_BRIDGE_VLAN_INFO]
 | 
			
		||||
                #  * }
 | 
			
		||||
                #  */
 | 
			
		||||
                if sub_attr_type == Link.IFLA_BRIDGE_FLAGS:
 | 
			
		||||
                    self.value[Link.IFLA_BRIDGE_FLAGS] = unpack("=H", sub_attr_data[0:2])[0]
 | 
			
		||||
 | 
			
		||||
@@ -1730,6 +1742,38 @@ class AttributeIFLA_AF_SPEC(Attribute):
 | 
			
		||||
                        self.value[Link.IFLA_BRIDGE_VLAN_INFO] = []
 | 
			
		||||
                    self.value[Link.IFLA_BRIDGE_VLAN_INFO].append(tuple(unpack("=HH", sub_attr_data[0:4])))
 | 
			
		||||
 | 
			
		||||
                elif sub_attr_type == Link.IFLA_BRIDGE_VLAN_TUNNEL_INFO:
 | 
			
		||||
                    # Link.IFLA_BRIDGE_VLAN_TUNNEL_INFO: {
 | 
			
		||||
                    #     __u32 tunnel_id;
 | 
			
		||||
                    #     __u16 tunnel_vid;
 | 
			
		||||
                    #     __u16 tunnel_flags;
 | 
			
		||||
                    # }
 | 
			
		||||
                    # all the nested attributes are padded on 8 bytes
 | 
			
		||||
 | 
			
		||||
                    tunnel_id = 0
 | 
			
		||||
                    tunnel_vid = 0
 | 
			
		||||
                    tunnel_flags = 0
 | 
			
		||||
 | 
			
		||||
                    while sub_attr_data:
 | 
			
		||||
                        (s_sub_attr_length, s_sub_attr_type) = unpack("=HH", sub_attr_data[:4])
 | 
			
		||||
                        s_sub_attr_end = padded_length(s_sub_attr_length)
 | 
			
		||||
                        d = sub_attr_data[4:s_sub_attr_end]
 | 
			
		||||
 | 
			
		||||
                        if s_sub_attr_type == Link.IFLA_BRIDGE_VLAN_TUNNEL_ID:
 | 
			
		||||
                            tunnel_id = unpack("=L", d)[0]
 | 
			
		||||
 | 
			
		||||
                        elif s_sub_attr_type == Link.IFLA_BRIDGE_VLAN_TUNNEL_VID:
 | 
			
		||||
                            tunnel_vid = unpack("=L", d)[0]
 | 
			
		||||
 | 
			
		||||
                        elif s_sub_attr_type == Link.IFLA_BRIDGE_VLAN_TUNNEL_FLAGS:
 | 
			
		||||
                            tunnel_flags = unpack("=L", d)[0]
 | 
			
		||||
 | 
			
		||||
                        sub_attr_data = sub_attr_data[s_sub_attr_end:]
 | 
			
		||||
 | 
			
		||||
                    if Link.IFLA_BRIDGE_VLAN_TUNNEL_INFO not in self.value:
 | 
			
		||||
                        self.value[Link.IFLA_BRIDGE_VLAN_TUNNEL_INFO] = []
 | 
			
		||||
 | 
			
		||||
                    self.value[Link.IFLA_BRIDGE_VLAN_TUNNEL_INFO].append((tunnel_id, tunnel_vid, tunnel_flags))
 | 
			
		||||
                else:
 | 
			
		||||
                    self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for decoding IFLA_AF_SPEC sub-attribute '
 | 
			
		||||
                                                     'type %s (%d), length %d, padded to %d' %
 | 
			
		||||
@@ -4291,15 +4335,38 @@ class Link(NetlinkPacket, NetlinkPacket_IFLA_LINKINFO_Attributes):
 | 
			
		||||
        IFLA_INET_CONF      : 'IFLA_INET_CONF',
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    # /* Bridge Flags */
 | 
			
		||||
    BRIDGE_FLAGS_MASTER = 1  # /* Bridge command to/from master */
 | 
			
		||||
    BRIDGE_FLAGS_SELF = 2  # /* Bridge command to/from lowerdev */
 | 
			
		||||
 | 
			
		||||
    bridge_flags_to_string = {
 | 
			
		||||
        BRIDGE_FLAGS_MASTER : "BRIDGE_FLAGS_MASTER",
 | 
			
		||||
        BRIDGE_FLAGS_SELF   : "BRIDGE_FLAGS_SELF"
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    BRIDGE_MODE_VEB = 0  # /* Default loopback mode */
 | 
			
		||||
    BRIDGE_MODE_VEPA = 1  # /* 802.1Qbg defined VEPA mode */
 | 
			
		||||
    BRIDGE_MODE_UNDEF = 0xFFFF  # /* mode undefined */
 | 
			
		||||
 | 
			
		||||
    # /* Bridge management nested attributes
 | 
			
		||||
    #  * [IFLA_AF_SPEC] = {
 | 
			
		||||
    #  *     [IFLA_BRIDGE_FLAGS]
 | 
			
		||||
    #  *     [IFLA_BRIDGE_MODE]
 | 
			
		||||
    #  *     [IFLA_BRIDGE_VLAN_INFO]
 | 
			
		||||
    #  * }
 | 
			
		||||
    #  */
 | 
			
		||||
 | 
			
		||||
    # BRIDGE IFLA_AF_SPEC attributes
 | 
			
		||||
    IFLA_BRIDGE_FLAGS     = 0
 | 
			
		||||
    IFLA_BRIDGE_MODE      = 1
 | 
			
		||||
    IFLA_BRIDGE_VLAN_INFO = 2
 | 
			
		||||
    IFLA_BRIDGE_VLAN_TUNNEL_INFO = 3
 | 
			
		||||
 | 
			
		||||
    ifla_bridge_af_spec_to_string = {
 | 
			
		||||
        IFLA_BRIDGE_FLAGS     : 'IFLA_BRIDGE_FLAGS',
 | 
			
		||||
        IFLA_BRIDGE_MODE      : 'IFLA_BRIDGE_MODE',
 | 
			
		||||
        IFLA_BRIDGE_VLAN_INFO : 'IFLA_BRIDGE_VLAN_INFO'
 | 
			
		||||
        IFLA_BRIDGE_VLAN_INFO : 'IFLA_BRIDGE_VLAN_INFO',
 | 
			
		||||
        IFLA_BRIDGE_VLAN_TUNNEL_INFO : "IFLA_BRIDGE_VLAN_TUNNEL_INFO"
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    # BRIDGE_VLAN_INFO flags
 | 
			
		||||
@@ -4319,15 +4386,33 @@ class Link(NetlinkPacket, NetlinkPacket_IFLA_LINKINFO_Attributes):
 | 
			
		||||
        BRIDGE_VLAN_INFO_BRENTRY     : 'BRIDGE_VLAN_INFO_BRENTRY'
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    # Bridge flags
 | 
			
		||||
    BRIDGE_FLAGS_MASTER = 1
 | 
			
		||||
    BRIDGE_FLAGS_SELF   = 2
 | 
			
		||||
    # struct bridge_vlan_info {
 | 
			
		||||
    # 	__u16 flags;
 | 
			
		||||
    # 	__u16 vid;
 | 
			
		||||
    # };
 | 
			
		||||
 | 
			
		||||
    bridge_flags_to_string = {
 | 
			
		||||
        BRIDGE_FLAGS_MASTER : 'BRIDGE_FLAGS_MASTER',
 | 
			
		||||
        BRIDGE_FLAGS_SELF   : 'BRIDGE_FLAGS_SELF'
 | 
			
		||||
    IFLA_BRIDGE_VLAN_TUNNEL_UNSPEC = 0
 | 
			
		||||
    IFLA_BRIDGE_VLAN_TUNNEL_ID = 1
 | 
			
		||||
    IFLA_BRIDGE_VLAN_TUNNEL_VID = 2
 | 
			
		||||
    IFLA_BRIDGE_VLAN_TUNNEL_FLAGS = 3
 | 
			
		||||
 | 
			
		||||
    bridge_vlan_tunnel_to_string = {
 | 
			
		||||
        IFLA_BRIDGE_VLAN_TUNNEL_UNSPEC: "IFLA_BRIDGE_VLAN_TUNNEL_UNSPEC",
 | 
			
		||||
        IFLA_BRIDGE_VLAN_TUNNEL_ID: "IFLA_BRIDGE_VLAN_TUNNEL_ID",
 | 
			
		||||
        IFLA_BRIDGE_VLAN_TUNNEL_VID: "IFLA_BRIDGE_VLAN_TUNNEL_VID",
 | 
			
		||||
        IFLA_BRIDGE_VLAN_TUNNEL_FLAGS: "IFLA_BRIDGE_VLAN_TUNNEL_FLAGS",
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    # struct bridge_vlan_xstats {
 | 
			
		||||
    # 	__u64 rx_bytes;
 | 
			
		||||
    # 	__u64 rx_packets;
 | 
			
		||||
    # 	__u64 tx_bytes;
 | 
			
		||||
    # 	__u64 tx_packets;
 | 
			
		||||
    # 	__u16 vid;
 | 
			
		||||
    # 	__u16 flags;
 | 
			
		||||
    # 	__u32 pad2;
 | 
			
		||||
    # };
 | 
			
		||||
 | 
			
		||||
    # filters for IFLA_EXT_MASK
 | 
			
		||||
    RTEXT_FILTER_VF                = 1 << 0
 | 
			
		||||
    RTEXT_FILTER_BRVLAN            = 1 << 1
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user