From 42e85fc834d83a55dc9904e1fc0488c15fdcca86 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Wed, 19 Oct 2016 10:43:45 -0700 Subject: [PATCH] [PATCH ifupdown2] addons: addressvirtual: fixup macvlan device enslavements for vrfs Ticket: CM-12988 Reviewed By: julien, nikhil, dsa Testing Done: tested ifup and ifdown of vrf devices with address virtual slaves This patch fixes up macvlan device enslavements when vrf device or vrf slave is brought down and up. address virtual macvlan devices on vrf slaves need to enslaved to the vrf. This patch checks and fixes up those vrf enslavements for the following cases: ifdown && ifup ifdown && ifup starting state: ------------ $ip -br link show myvrf UP 46:c6:44:db:37:60 bridge.901@bridge UP 44:38:39:00:77:88 bridge-901-v0@bridge.901 UP 00:00:5e:00:01:81 $ifdown myvrf $ip -br link show bridge.901@bridge DOWN 44:38:39:00:77:88 bridge-901-v0@bridge.901 DOWN 00:00:5e:00:01:81 before patch (macvlan device bridge-901-v0 did not come up: ---------------------------------------- $ifup myvrf $ip -br link show bridge.901@bridge UP 44:38:39:00:77:88 bridge-901-v0@bridge.901 DOWN 00:00:5e:00:01:81 myvrf UP ce:a6:e1:85:75:73 after patch: ------------ $ifup myvrf $ip -br link show bridge.901@bridge UP 44:38:39:00:77:88 bridge-901-v0@bridge.901 UP 00:00:5e:00:01:81 myvrf UP ce:a6:e1:85:75:73 Signed-off-by: Roopa Prabhu --- addons/addressvirtual.py | 83 +++++++++++++++++++++++++++++++++----- addons/vrf.py | 7 ++-- ifupdown/iface.py | 1 + ifupdownaddons/iproute2.py | 13 +++--- 4 files changed, 85 insertions(+), 19 deletions(-) diff --git a/addons/addressvirtual.py b/addons/addressvirtual.py index 007f2a0..a09b688 100644 --- a/addons/addressvirtual.py +++ b/addons/addressvirtual.py @@ -36,10 +36,9 @@ class addressvirtual(moduleBase): self.ipcmd = None self._bridge_fdb_query_cache = {} - def _is_supported(self, ifaceobj): - if ifaceobj.get_attr_value_first('address-virtual'): - return True - return False + def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None): + if ifaceobj.get_attr_value('address-virtual'): + ifaceobj.link_privflags |= ifaceLinkPrivFlags.ADDRESS_VIRTUAL_SLAVE def _get_macvlan_prefix(self, ifaceobj): return '%s-v' %ifaceobj.name[0:13].replace('.', '-') @@ -292,10 +291,73 @@ class addressvirtual(moduleBase): self.logger.error("%s: Multicast bit is set in the virtual mac address '%s'" %(ifaceobj.name, mac)) return False return True - except Exception, e: + except Exception: return False - def _up(self, ifaceobj): + def _fixup_vrf_enslavements(self, ifaceobj, ifaceobj_getfunc=None): + """ This function fixes up address virtual interfaces + (macvlans) on vrf slaves. Since this fixup is an overhead, + this must be called only in cases when ifupdown2 is + called on the vrf device or its slave and not when + ifupdown2 is called for all devices. When all + interfaces are brought up, the expectation is that + the normal path will fix up a vrf device or its slaves""" + + if not ifaceobj_getfunc: + return + if ((ifaceobj.link_kind & ifaceLinkKind.VRF) and + self.ipcmd.link_exists(ifaceobj.name)): + # if I am a vrf device and I have slaves + # that have address virtual config, + # enslave the slaves 'address virtual + # interfaces (macvlans)' to myself: + running_slaves = self.ipcmd.link_get_lowers(ifaceobj.name) + if running_slaves: + # pick up any existing slaves of a vrf device and + # look for their upperdevices and enslave them to the + # vrf device: + for s in running_slaves: + sobjs = ifaceobj_getfunc(s) + if (sobjs and + (sobjs[0].link_privflags & ifaceLinkPrivFlags.ADDRESS_VIRTUAL_SLAVE)): + # enslave all its upper devices to + # the vrf device + upperdevs = self.ipcmd.link_get_uppers(sobjs[0].name) + if not upperdevs: + continue + for u in upperdevs: + # skip vrf device which + # will also show up in the + # upper device list + if u == ifaceobj.name: + continue + self.ipcmd.link_set(u, 'master', ifaceobj.name, + state='up') + elif ((ifaceobj.link_privflags & ifaceLinkPrivFlags.ADDRESS_VIRTUAL_SLAVE) and + (ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE) and + self.ipcmd.link_exists(ifaceobj.name)): + # If I am a vrf slave and I have 'address virtual' + # config, make sure my addrress virtual interfaces + # (macvlans) are also enslaved to the vrf device + vrfname = ifaceobj.get_attr_value_first('vrf') + if not vrfname or not self.ipcmd.link_exists(vrfname): + return + running_uppers = self.ipcmd.link_get_uppers(ifaceobj.name) + if not running_uppers: + return + macvlan_prefix = self._get_macvlan_prefix(ifaceobj) + if not macvlan_prefix: + return + for u in running_uppers: + if u == vrfname: + continue + if u.startswith(macvlan_prefix): + self.ipcmd.link_set(u, 'master', vrfname, + state='up') + + def _up(self, ifaceobj, ifaceobj_getfunc=None): + if not ifupdownflags.flags.ALL: + self._fixup_vrf_enslavements(ifaceobj, ifaceobj_getfunc) address_virtual_list = ifaceobj.get_attr_value('address-virtual') if not address_virtual_list: # XXX: address virtual is not present. In which case, @@ -313,7 +375,7 @@ class addressvirtual(moduleBase): return self._apply_address_config(ifaceobj, address_virtual_list) - def _down(self, ifaceobj): + def _down(self, ifaceobj, ifaceobj_getfunc=None): try: self._remove_address_config(ifaceobj, ifaceobj.get_attr_value('address-virtual')) @@ -383,7 +445,7 @@ class addressvirtual(moduleBase): av_idx += 1 return - def _query_running(self, ifaceobjrunning): + def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None): macvlan_prefix = self._get_macvlan_prefix(ifaceobjrunning) address_virtuals = glob.glob("/sys/class/net/%s*" %macvlan_prefix) for av in address_virtuals: @@ -411,7 +473,8 @@ class addressvirtual(moduleBase): if not self.ipcmd: self.ipcmd = iproute2() - def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args): + def run(self, ifaceobj, operation, query_ifaceobj=None, + ifaceobj_getfunc=None, **extra_args): """ run vlan configuration on the interface object passed as argument Args: @@ -436,4 +499,4 @@ class addressvirtual(moduleBase): if operation == 'query-checkcurr': op_handler(self, ifaceobj, query_ifaceobj) else: - op_handler(self, ifaceobj) + op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc) diff --git a/addons/vrf.py b/addons/vrf.py index c0e1565..0e02a54 100644 --- a/addons/vrf.py +++ b/addons/vrf.py @@ -151,8 +151,7 @@ class vrf(moduleBase): continue self.iproute2_vrf_map[int(table)] = vrf_name except Exception, e: - self.logger.info('vrf: iproute2_vrf_map: unable to parse %s' - %l) + self.logger.info('vrf: iproute2_vrf_map: unable to parse %s (%s)' %(l, str(e))) pass vrfs = self.ipcmd.link_get_vrfs() @@ -392,8 +391,8 @@ class vrf(moduleBase): try: master_exists = True if vrf_exists or self.ipcmd.link_exists(vrfname): - upper = self.ipcmd.link_get_upper(ifacename) - if not upper or upper != vrfname: + uppers = self.ipcmd.link_get_uppers(ifacename) + if not uppers or vrfname not in uppers: self._handle_existing_connections(ifaceobj, vrfname) self.ipcmd.link_set(ifacename, 'master', vrfname) elif ifaceobj: diff --git a/ifupdown/iface.py b/ifupdown/iface.py index 9dd5e14..d668a75 100644 --- a/ifupdown/iface.py +++ b/ifupdown/iface.py @@ -62,6 +62,7 @@ class ifaceLinkPrivFlags(): VRF_SLAVE = 0x00100 BRIDGE_VLAN_AWARE = 0x01000 BRIDGE_VXLAN = 0x10000 + ADDRESS_VIRTUAL_SLAVE = 0x100000 @classmethod def get_str(cls, flag): diff --git a/ifupdownaddons/iproute2.py b/ifupdownaddons/iproute2.py index 099fdfc..dddbb41 100644 --- a/ifupdownaddons/iproute2.py +++ b/ifupdownaddons/iproute2.py @@ -434,7 +434,8 @@ class iproute2(utilsBase): def link_down(self, ifacename): self._link_set_ifflag(ifacename, 'DOWN') - def link_set(self, ifacename, key, value=None, force=False, type=None): + def link_set(self, ifacename, key, value=None, + force=False, type=None, state=None): if not force: if (key not in ['master', 'nomaster'] and self._cache_check('link', [ifacename, key], value)): @@ -445,6 +446,8 @@ class iproute2(utilsBase): cmd += ' %s' %key if value: cmd += ' %s' %value + if state: + cmd += ' %s' %state if self.ipbatch: self.add_to_batch(cmd) else: @@ -922,12 +925,12 @@ class iproute2(utilsBase): except: return [] - def link_get_upper(self, ifacename): + def link_get_uppers(self, ifacename): try: - upper = glob.glob("/sys/class/net/%s/upper_*" %ifacename) - if not upper: + uppers = glob.glob("/sys/class/net/%s/upper_*" %ifacename) + if not uppers: return None - return os.path.basename(upper[0])[6:] + return [ os.path.basename(u)[6:] for u in uppers ] except: return None -- 2.39.5