1
0
mirror of https://github.com/CumulusNetworks/ifupdown2.git synced 2024-05-06 15:54:50 +00:00

misc query and fdb/vlan add fixes

Ticket: CM-3346
Reviewed By:
Testing Done: ifupdown2 sanity
This commit is contained in:
Roopa Prabhu
2014-11-03 17:55:51 -08:00
parent 9e012f9e8a
commit 8e113d6319
9 changed files with 195 additions and 63 deletions

View File

@@ -55,6 +55,7 @@ class address(moduleBase):
def __init__(self, *args, **kargs):
moduleBase.__init__(self, *args, **kargs)
self.ipcmd = None
self._bridge_fdb_query_cache = {}
def _add_address_to_bridge(self, ifaceobj, hwaddress):
if '.' in ifaceobj.name:
@@ -135,14 +136,15 @@ class address(moduleBase):
dhclientcmd.release6(ifaceobj.name)
except:
pass
self.ipcmd.batch_start()
self._inet_address_config(ifaceobj)
mtu = ifaceobj.get_attr_value_first('mtu')
if mtu:
self.ipcmd.link_set(ifaceobj.name, 'mtu', mtu)
self.ipcmd.link_set(ifaceobj.name, 'mtu', mtu)
alias = ifaceobj.get_attr_value_first('alias')
if alias:
self.ipcmd.link_set_alias(ifaceobj.name, alias)
self.ipcmd.link_set_alias(ifaceobj.name, alias)
hwaddress = ifaceobj.get_attr_value_first('hwaddress')
if hwaddress:
self.ipcmd.link_set(ifaceobj.name, 'address', hwaddress)
@@ -193,6 +195,26 @@ class address(moduleBase):
outaddrlist.append(addr)
return outaddrlist
def _get_bridge_fdbs(self, bridgename, vlan):
fdbs = self._bridge_fdb_query_cache.get(bridgename)
if not fdbs:
fdbs = self.ipcmd.bridge_fdb_show_dev(bridgename)
if not fdbs:
return
self._bridge_fdb_query_cache[bridgename] = fdbs
return fdbs.get(vlan)
def _check_addresses_in_bridge(self, ifaceobj, hwaddress):
""" If the device is a bridge, make sure the addresses
are in the bridge """
if '.' in ifaceobj.name:
(bridgename, vlan) = ifaceobj.name.split('.')
if self.ipcmd.bridge_is_vlan_aware(bridgename):
fdb_addrs = self._get_bridge_fdbs(bridgename, vlan)
if not fdb_addrs or hwaddress not in fdb_addrs:
return False
return True
def _query_check(self, ifaceobj, ifaceobjcurr):
runningaddrsdict = None
if not self.ipcmd.link_exists(ifaceobj.name):
@@ -200,8 +222,20 @@ class address(moduleBase):
return
self.query_n_update_ifaceobjcurr_attr(ifaceobj, ifaceobjcurr,
'mtu', self.ipcmd.link_get_mtu)
self.query_n_update_ifaceobjcurr_attr(ifaceobj, ifaceobjcurr,
'hwaddress', self.ipcmd.link_get_hwaddress)
hwaddress = ifaceobj.get_attr_value_first('hwaddress')
if hwaddress:
rhwaddress = self.ipcmd.link_get_hwaddress(ifaceobj.name)
if not rhwaddress or rhwaddress != hwaddress:
ifaceobjcurr.update_config_with_status('hwaddress', rhwaddress,
1)
elif not self._check_addresses_in_bridge(ifaceobj, hwaddress):
# XXX: hw address is not in bridge
ifaceobjcurr.update_config_with_status('hwaddress', rhwaddress,
1)
ifaceobjcurr.status_str = 'bridge fdb error'
else:
ifaceobjcurr.update_config_with_status('hwaddress', rhwaddress,
0)
self.query_n_update_ifaceobjcurr_attr(ifaceobj, ifaceobjcurr,
'alias', self.ipcmd.link_get_alias)
# compare addresses
@@ -305,7 +339,8 @@ class address(moduleBase):
of interfaces. status is success if the running state is same
as user required state in ifaceobj. error otherwise.
"""
if ifaceobj.type == ifaceType.BRIDGE_VLAN:
return
op_handler = self._run_ops.get(operation)
if not op_handler:
return

View File

@@ -24,9 +24,11 @@ class addressvirtual(moduleBase):
'example' : ['address-virtual 00:11:22:33:44:01 11.0.1.254/24 11.0.1.254/24']}
}}
def __init__(self, *args, **kargs):
moduleBase.__init__(self, *args, **kargs)
self.ipcmd = None
self._bridge_fdb_query_cache = {}
def _is_supported(self, ifaceobj):
if ifaceobj.get_attr_value_first('address-virtual'):
@@ -34,18 +36,46 @@ class addressvirtual(moduleBase):
return False
def _add_addresses_to_bridge(self, ifaceobj, hwaddress):
# XXX: batch the addresses
if '.' in ifaceobj.name:
(bridgename, vlan) = ifaceobj.name.split('.')
if self.ipcmd.bridge_is_vlan_aware(bridgename):
[self.ipcmd.bridge_fdb_add(bridgename, addr,
vlan) for addr in hwaddress]
elif self.ipcmd.is_bridge(ifaceobj.name):
[self.ipcmd.bridge_fdb_add(ifaceobj.name, addr)
for addr in hwaddress]
def _remove_addresses_from_bridge(self, ifaceobj, hwaddress):
# XXX: batch the addresses
if '.' in ifaceobj.name:
(bridgename, vlan) = ifaceobj.name.split('.')
if self.ipcmd.bridge_is_vlan_aware(bridgename):
[self.ipcmd.bridge_fdb_del(bridgename, addr,
vlan) for addr in hwaddress]
elif self.ipcmd.is_bridge(ifaceobj.name):
[self.ipcmd.bridge_fdb_del(ifaceobj.name, addr)
for addr in hwaddress]
def _get_bridge_fdbs(self, bridgename, vlan):
fdbs = self._bridge_fdb_query_cache.get(bridgename)
if not fdbs:
fdbs = self.ipcmd.bridge_fdb_show_dev(bridgename)
if not fdbs:
return
self._bridge_fdb_query_cache[bridgename] = fdbs
return fdbs.get(vlan)
def _check_addresses_in_bridge(self, ifaceobj, hwaddress):
""" If the device is a bridge, make sure the addresses
are in the bridge """
if '.' in ifaceobj.name:
(bridgename, vlan) = ifaceobj.name.split('.')
if self.ipcmd.bridge_is_vlan_aware(bridgename):
fdb_addrs = self._get_bridge_fdbs(bridgename, vlan)
if not fdb_addrs or hwaddress not in fdb_addrs:
return False
return True
def _apply_address_config(self, ifaceobj, address_virtual_list):
purge_existing = False if self.PERFMODE else True
@@ -177,11 +207,9 @@ class addressvirtual(moduleBase):
ifaceobjcurr.update_config_with_status('address-virtual', '', 1)
av_idx += 1
continue
raddrs = raddrs.keys()
self.logger.info(rhwaddress)
self.logger.info(raddrs)
if rhwaddress == av_attrs[0] and raddrs == av_attrs[1:]:
if (rhwaddress == av_attrs[0] and raddrs == av_attrs[1:] and
self._check_addresses_in_bridge(ifaceobj, av_attrs[0])):
ifaceobjcurr.update_config_with_status('address-virtual',
address_virtual, 0)
else:
@@ -192,7 +220,18 @@ class addressvirtual(moduleBase):
return
def _query_running(self, ifaceobjrunning):
# Not implemented
macvlan_prefix = '%s-v' %ifaceobjrunning.name.replace('.', '-')
address_virtuals = glob.glob("/sys/class/net/%s*" %macvlan_prefix)
for av in address_virtuals:
macvlan_ifacename = os.path.basename(av)
rhwaddress = self.ipcmd.link_get_hwaddress(macvlan_ifacename)
raddress = self.ipcmd.addr_get(macvlan_ifacename)
if not raddress:
self.logger.warn('%s: no running addresses'
%ifaceobjrunning.name)
raddress = []
ifaceobjrunning.update_config('address-virtual',
'%s %s' %(rhwaddress, ''.join(raddress)))
return
_run_ops = {'up' : _up,

View File

@@ -753,7 +753,7 @@ class bridge(moduleBase):
self._apply_bridge_settings(ifaceobj)
self._apply_bridge_port_settings_all(ifaceobj,
ifaceobj_getfunc=ifaceobj_getfunc)
self._flush_running_vidinfo()
#self._flush_running_vidinfo()
except Exception, e:
self.log_error(str(e))
if porterr:

View File

@@ -87,7 +87,7 @@ class ethtool(moduleBase):
else:
ifaceobjcurr.update_config_with_status('link-duplex',
running_duplex, 0)
except Exception, e:
except Exception:
pass
return

View File

@@ -25,9 +25,11 @@ class vlan(moduleBase):
'vlan-id' :
{'help' : 'vlan id'}}}
def __init__(self, *args, **kargs):
moduleBase.__init__(self, *args, **kargs)
self.ipcmd = None
self._bridge_vids_query_cache = {}
def _is_vlan_device(self, ifaceobj):
vlan_raw_device = ifaceobj.get_attr_value_first('vlan-raw-device')
@@ -92,27 +94,30 @@ class vlan(moduleBase):
return None
return [self._get_vlan_raw_device(ifaceobj)]
def _get_bridge_vids(self, bridgename, ifaceobj_getfunc):
ifaceobjs = ifaceobj_getfunc(bridgename)
for ifaceobj in ifaceobjs:
vids = ifaceobj.get_attr_value_first('bridge-vids')
if vids: return re.split(r'[\s\t]\s*', vids)
return None
def _bridge_vid_add_del(self, ifaceobj, bridgename, vlanid,
ifaceobj_getfunc, add=True):
add=True):
""" If the lower device is a vlan aware bridge, add/del the vlanid
to the bridge """
if self.ipcmd.bridge_is_vlan_aware(bridgename):
# Check if the bridge vids has the vlanid
vids = self._get_bridge_vids(bridgename, ifaceobj_getfunc)
if vids and vlanid in vids:
return
else:
if add:
self.ipcmd.bridge_vids_add(bridgename, [vlanid])
else:
self.ipcmd.bridge_vids_del(bridgename, [vlanid])
if add:
self.ipcmd.bridge_vids_add(bridgename, [vlanid])
else:
self.ipcmd.bridge_vids_del(bridgename, [vlanid])
def _up(self, ifaceobj, ifaceobj_getfunc=None):
def _bridge_vid_check(self, ifaceobj, ifaceobjcurr, bridgename, vlanid):
""" If the lower device is a vlan aware bridge, check if the vlanid
is configured on the bridge """
if not self.ipcmd.bridge_is_vlan_aware(bridgename):
return
vids = self._bridge_vids_query_cache.get(bridgename)
if vids == None:
vids = self.ipcmd.bridge_port_vids_get(bridgename)
self._bridge_vids_query_cache[bridgename] = vids
if not vids or vlanid not in vids:
ifaceobjcurr.status = ifaceStatus.ERROR
ifaceobjcurr.status_str = 'bridge vid error'
def _up(self, ifaceobj):
vlanid = self._get_vlan_id(ifaceobj)
if vlanid == -1:
raise Exception('could not determine vlanid')
@@ -123,15 +128,13 @@ class vlan(moduleBase):
if not self.ipcmd.link_exists(vlanrawdevice):
raise Exception('rawdevice %s not present' %vlanrawdevice)
if self.ipcmd.link_exists(ifaceobj.name):
self._bridge_vid_add_del(ifaceobj, vlanrawdevice, vlanid,
ifaceobj_getfunc)
self._bridge_vid_add_del(ifaceobj, vlanrawdevice, vlanid)
return
rtnetlink_api.rtnl_api.create_vlan(vlanrawdevice,
ifaceobj.name, vlanid)
self._bridge_vid_add_del(ifaceobj, vlanrawdevice, vlanid,
ifaceobj_getfunc)
self._bridge_vid_add_del(ifaceobj, vlanrawdevice, vlanid)
def _down(self, ifaceobj, ifaceobj_getfunc=None):
def _down(self, ifaceobj):
vlanid = self._get_vlan_id(ifaceobj)
if vlanid == -1:
raise Exception('could not determine vlanid')
@@ -142,12 +145,11 @@ class vlan(moduleBase):
return
try:
self.ipcmd.link_delete(ifaceobj.name)
self._bridge_vid_add_del(ifaceobj, vlanrawdevice, vlanid,
ifaceobj_getfunc, add=False)
self._bridge_vid_add_del(ifaceobj, vlanrawdevice, vlanid, add=False)
except Exception, e:
self.log_warn(str(e))
def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None):
def _query_check(self, ifaceobj, ifaceobjcurr):
if not self.ipcmd.link_exists(ifaceobj.name):
ifaceobjcurr.status = ifaceStatus.NOTFOUND
return
@@ -165,8 +167,9 @@ class vlan(moduleBase):
else:
ifaceobjcurr.update_config_with_status('vlan-id',
vlanid, 0)
self._bridge_vid_check(ifaceobj, ifaceobjcurr, vlanrawdev, vlanid)
def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
def _query_running(self, ifaceobjrunning):
if not self.ipcmd.link_exists(ifaceobjrunning.name):
if self._is_vlan_by_name(ifaceobjrunning.name):
ifaceobjcurr.status = ifaceStatus.NOTFOUND
@@ -195,8 +198,7 @@ class vlan(moduleBase):
if not self.ipcmd:
self.ipcmd = iproute2(**self.get_flags())
def run(self, ifaceobj, operation, query_ifaceobj=None,
ifaceobj_getfunc=None, **extra_args):
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
""" run vlan configuration on the interface object passed as argument
Args:
@@ -222,6 +224,6 @@ class vlan(moduleBase):
return
self._init_command_handlers()
if operation == 'query-checkcurr':
op_handler(self, ifaceobj, query_ifaceobj, ifaceobj_getfunc)
op_handler(self, ifaceobj, query_ifaceobj)
else:
op_handler(self, ifaceobj, ifaceobj_getfunc)
op_handler(self, ifaceobj)

View File

@@ -12,3 +12,13 @@ template_lookuppath=/etc/network/ifupdown2/templates
# Support /etc/network/if-*/ scripts
addon_scripts_support=0
# ifquery check status strings.
# By default `ifquery --check` prints the check and
# cross marks against interface attributes.
# Use the below strings to modify the default behaviour.
# check_success_str=
# check_error_str=(x)
multiple_vlan_aware_bridge_support=0

View File

@@ -189,6 +189,8 @@ class ifupdownMain(ifupdownBase):
self.load_scripts(self.scripts_dir)
self.dependency_graph = OrderedDict({})
self._cache_no_repeats = {}
if self.STATEMANAGER_ENABLE:
try:
self.statemanager = stateManager()
@@ -422,19 +424,26 @@ class ifupdownMain(ifupdownBase):
if not self.dependency_graph.get(i):
self.dependency_graph[i] = dlist
def _add_ifaceobj(self, ifaceobj):
currentifaceobjlist = self.ifaceobjdict.get(ifaceobj.name)
if not currentifaceobjlist:
self.ifaceobjdict[ifaceobj.name]= [ifaceobj]
return
if ifaceobj.compare(currentifaceobjlist[0]):
self.logger.warn('duplicate interface %s found' %ifaceobj.name)
return
currentifaceobjlist[0].flags |= iface.HAS_SIBLINGS
ifaceobj.flags |= iface.HAS_SIBLINGS
self.ifaceobjdict[ifaceobj.name].append(ifaceobj)
def _check_config_no_repeats(self, ifaceobj):
""" check if object has an attribute that is
restricted to a single object in the system.
if yes, warn and return """
for k,v in self._cache_no_repeats.items():
iv = ifaceobj.config.get(k)
if iv and iv[0] == v:
self.logger.error('ignoring interface %s. ' %ifaceobj.name +
'Only one object with attribute ' +
'\'%s %s\' allowed.' %(k, v))
return True
for k, v in self.config.get('no_repeats', {}).items():
iv = ifaceobj.config.get(k)
if iv and iv[0] == v:
self._cache_no_repeats[k] = v
return False
def _save_iface(self, ifaceobj):
if self._check_config_no_repeats(ifaceobj):
return
currentifaceobjlist = self.ifaceobjdict.get(ifaceobj.name)
if not currentifaceobjlist:
self.ifaceobjdict[ifaceobj.name]= [ifaceobj]
@@ -442,8 +451,9 @@ class ifupdownMain(ifupdownBase):
if ifaceobj.compare(currentifaceobjlist[0]):
self.logger.warn('duplicate interface %s found' %ifaceobj.name)
return
currentifaceobjlist[0].flags |= iface.HAS_SIBLINGS
ifaceobj.flags |= iface.HAS_SIBLINGS
if currentifaceobjlist[0].type == ifaceobj.type:
currentifaceobjlist[0].flags |= iface.HAS_SIBLINGS
ifaceobj.flags |= iface.HAS_SIBLINGS
self.ifaceobjdict[ifaceobj.name].append(ifaceobj)
def _iface_configattr_syntax_checker(self, attrname, attrval):
@@ -460,7 +470,7 @@ class ifupdownMain(ifupdownBase):
def _ifaceobj_syntax_checker(self, ifaceobj):
err = False
for attrname in ifaceobj.config:
for attrname, attrvalue in ifaceobj.config.items():
found = False
for k, v in self.module_attrs.items():
if v and v.get('attrs', {}).get(attrname):

View File

@@ -616,15 +616,23 @@ class iproute2(utilsBase):
[self.exec_command('bridge vlan del vid %s dev %s %s'
%(v, bridgeportname, target)) for v in vids]
def bridge_fdb_add(self, dev, address, vlan, bridge=True):
def bridge_fdb_add(self, dev, address, vlan=None, bridge=True):
target = 'self' if bridge else ''
self.exec_command('bridge fdb add %s dev %s vlan %s %s'
%(address, dev, vlan, target))
if vlan:
self.exec_command('bridge fdb add %s dev %s vlan %s %s'
%(address, dev, vlan, target))
else:
self.exec_command('bridge fdb add %s dev %s %s'
%(address, dev, target))
def bridge_fdb_del(self, dev, address, vlan, bridge=True):
def bridge_fdb_del(self, dev, address, vlan=None, bridge=True):
target = 'self' if bridge else ''
self.exec_command('bridge fdb del %s dev %s vlan %s %s'
%(address, dev, vlan, target))
if vlan:
self.exec_command('bridge fdb del %s dev %s vlan %s %s'
%(address, dev, vlan, target))
else:
self.exec_command('bridge fdb del %s dev %s %s'
%(address, dev, target))
def bridge_is_vlan_aware(self, bridgename):
filename = '/sys/class/net/%s/bridge/vlan_filtering' %bridgename
@@ -645,3 +653,23 @@ class iproute2(utilsBase):
%(bridge, bridgeportname))
except Exception:
return False
def bridge_fdb_show_dev(self, dev):
try:
fdbs = {}
output = self.exec_command('bridge fdb show dev %s' %dev)
if output:
for fdb_entry in output.splitlines():
try:
entries = fdb_entry.split()
fdbs.setdefault(entries[2], []).append(entries[0])
except:
self.logger.debug('%s: invalid fdb line \'%s\''
%(dev, fdb_entry))
pass
return fdbs
except Exception:
return None
def is_bridge(self, bridge):
return os.path.exists('/sys/class/net/%s/bridge' %bridge)

View File

@@ -372,6 +372,14 @@ def read_config():
parser.readfp(configFP)
configmap_g = dict(parser.items('ifupdown2'))
# Preprocess config map
configval = configmap_g.get('multiple_vlan_aware_bridge_support', '0')
if configval == '0':
# if multiple bridges not allowed, set the bridge-vlan-aware
# attribute in the 'no_repeats' config, so that the ifupdownmain
# module can catch it appropriately
configmap_g['no_repeats'] = {'bridge-vlan-aware' : 'yes'}
def main(argv):
""" main function """
args = None