1
0
mirror of https://github.com/CumulusNetworks/ifupdown2.git synced 2024-05-06 15:54:50 +00:00
Files
CumulusNetworks-ifupdown2/ifupdownaddons/iproute2.py
Julien Fortin a193d8d1c0 performance fix: better handling fd to allow subprocess.close_fds=False and code re-organisation
Ticket: None
Reviewed By: CCR-4692
Testing Done: smoke + scale tests

If called with close_fds=True the subprocess module will try to close every fd
from 3 to MAXFD before executing the specified command. This is done in Python
not even with a C-implementation which truly affecting performances.

This patch aims to better handle the file descriptor used by ifupdown2. Either
by closing them after use or by setting the close-on-exec flag for the file
descriptor, which causes the file descriptor to be automatically
(and atomically) closed when any of the exec-family functions succeed.

With the actual patch all tests are passing, I can't think of any future issue
but if any a possible future modification might be to use the parameter
'preexec_fn', which allows us to set function which will be executed in the
child process before executing the command line. We can always manually close
any remaining open file descriptors with something like:

>>> os.listdir('/proc/self/fd/')
['0', '1', '2', ‘3’, etc..]
>>> for fd in os.listdir('/proc/self/fd/')
>>>    if int(fd) > 2:
>>>    	  os.close(fd)

This patch is also totally re-organising the use of subprocesses. By removing
all subprocess code redundancy.
2016-06-16 03:37:33 +01:00

904 lines
33 KiB
Python

#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
import os
import glob
import shlex
import signal
import subprocess
from ifupdown.utils import utils
from collections import OrderedDict
from utilsbase import *
from systemutils import *
from cache import *
import ifupdown.ifupdownflags as ifupdownflags
VXLAN_UDP_PORT = 4789
class iproute2(utilsBase):
""" This class contains helper methods to cache and interact with the
commands in the iproute2 package """
_cache_fill_done = False
ipbatchbuf = ''
ipbatch = False
ipbatch_pause = False
def __init__(self, *args, **kargs):
utilsBase.__init__(self, *args, **kargs)
if ifupdownflags.flags.CACHE:
self._fill_cache()
def _fill_cache(self):
if not iproute2._cache_fill_done:
self._link_fill()
self._addr_fill()
iproute2._cache_fill_done = True
return True
return False
def _get_vland_id(self, citems, i, warn):
try:
sub = citems[i:]
index = sub.index('id')
int(sub[index + 1])
return sub[index + 1]
except:
if warn:
raise Exception('invalid use of \'vlan\' keyword')
return None
def _link_fill(self, ifacename=None, refresh=False):
""" fills cache with link information
if ifacename argument given, fill cache for ifacename, else
fill cache for all interfaces in the system
"""
warn = True
linkout = {}
if iproute2._cache_fill_done and not refresh: return
try:
# if ifacename already present, return
if (ifacename and not refresh and
linkCache.get_attr([ifacename, 'ifflag'])):
return
except:
pass
cmdout = self.link_show(ifacename=ifacename)
if not cmdout:
return
for c in cmdout.splitlines():
citems = c.split()
ifnamenlink = citems[1].split('@')
if len(ifnamenlink) > 1:
ifname = ifnamenlink[0]
iflink = ifnamenlink[1].strip(':')
else:
ifname = ifnamenlink[0].strip(':')
iflink = None
linkattrs = {}
linkattrs['link'] = iflink
linkattrs['ifindex'] = citems[0].strip(':')
flags = citems[2].strip('<>').split(',')
linkattrs['flags'] = flags
linkattrs['ifflag'] = 'UP' if 'UP' in flags else 'DOWN'
for i in range(0, len(citems)):
try:
if citems[i] == 'mtu':
linkattrs['mtu'] = citems[i + 1]
elif citems[i] == 'state':
linkattrs['state'] = citems[i + 1]
elif citems[i] == 'link/ether':
linkattrs['hwaddress'] = citems[i + 1]
elif citems[i] == 'vlan':
vlanid = self._get_vland_id(citems, i, warn)
if vlanid:
linkattrs['linkinfo'] = {'vlanid': vlanid}
linkattrs['kind'] = 'vlan'
elif citems[i] == 'dummy':
linkattrs['kind'] = 'dummy'
elif citems[i] == 'vxlan' and citems[i + 1] == 'id':
linkattrs['kind'] = 'vxlan'
vattrs = {'vxlanid': citems[i + 2],
'svcnode': None,
'remote': [],
'ageing': citems[i + 2],
'learning': 'on'}
for j in range(i + 2, len(citems)):
if citems[j] == 'local':
vattrs['local'] = citems[j + 1]
elif citems[j] == 'remote':
vattrs['svcnode'] = citems[j + 1]
elif citems[j] == 'ageing':
vattrs['ageing'] = citems[j + 1]
elif citems[j] == 'nolearning':
vattrs['learning'] = 'off'
# get vxlan peer nodes
peers = self.get_vxlan_peers(ifname, vattrs['svcnode'])
if peers:
vattrs['remote'] = peers
linkattrs['linkinfo'] = vattrs
break
elif citems[i] == 'vrf' and citems[i + 1] == 'table':
vattrs = {'table': citems[i + 2]}
linkattrs['linkinfo'] = vattrs
linkattrs['kind'] = 'vrf'
linkCache.vrfs[ifname] = vattrs
break
elif citems[i] == 'vrf_slave':
linkattrs['kind'] = 'vrf_slave'
break
except Exception as e:
if warn:
self.logger.debug('%s: parsing error: id, mtu, state, link/ether, vlan, dummy, vxlan, local, remote, ageing, nolearning, vrf, table, vrf_slave are reserved keywords: %s' % (ifname, str(e)))
warn = False
#linkattrs['alias'] = self.read_file_oneline(
# '/sys/class/net/%s/ifalias' %ifname)
linkout[ifname] = linkattrs
[linkCache.update_attrdict([ifname], linkattrs)
for ifname, linkattrs in linkout.items()]
def _addr_filter(self, ifname, addr, scope=None):
default_addrs = ['127.0.0.1/8', '::1/128' , '0.0.0.0']
if ifname == 'lo' and addr in default_addrs:
return True
if scope and scope == 'link':
return True
return False
def _addr_fill(self, ifacename=None, refresh=False):
""" fills cache with address information
if ifacename argument given, fill cache for ifacename, else
fill cache for all interfaces in the system
"""
linkout = {}
if iproute2._cache_fill_done and not refresh: return
try:
# Check if ifacename is already full, in which case, return
if ifacename and not refresh:
linkCache.get_attr([ifacename, 'addrs'])
return
except:
pass
cmdout = self.addr_show(ifacename=ifacename)
if not cmdout:
return
for c in cmdout.splitlines():
citems = c.split()
ifnamenlink = citems[1].split('@')
if len(ifnamenlink) > 1:
ifname = ifnamenlink[0]
else:
ifname = ifnamenlink[0].strip(':')
if not linkout.get(ifname):
linkattrs = {}
linkattrs['addrs'] = OrderedDict({})
try:
linkout[ifname].update(linkattrs)
except KeyError:
linkout[ifname] = linkattrs
if citems[2] == 'inet':
if self._addr_filter(ifname, citems[3], scope=citems[5]):
continue
addrattrs = {}
addrattrs['scope'] = citems[5]
addrattrs['type'] = 'inet'
linkout[ifname]['addrs'][citems[3]] = addrattrs
elif citems[2] == 'inet6':
if self._addr_filter(ifname, citems[3], scope=citems[5]):
continue
if citems[5] == 'link': continue #skip 'link' addresses
addrattrs = {}
addrattrs['scope'] = citems[5]
addrattrs['type'] = 'inet6'
linkout[ifname]['addrs'][citems[3]] = addrattrs
[linkCache.update_attrdict([ifname], linkattrs)
for ifname, linkattrs in linkout.items()]
def _cache_get(self, type, attrlist, refresh=False):
try:
if ifupdownflags.flags.DRYRUN:
return False
if ifupdownflags.flags.CACHE:
if self._fill_cache():
# if we filled the cache, return new data
return linkCache.get_attr(attrlist)
if not refresh:
return linkCache.get_attr(attrlist)
if type == 'link':
self._link_fill(attrlist[0], refresh)
elif type == 'addr':
self._addr_fill(attrlist[0], refresh)
else:
self._link_fill(attrlist[0], refresh)
self._addr_fill(attrlist[0], refresh)
return linkCache.get_attr(attrlist)
except Exception, e:
self.logger.debug('_cache_get(%s) : [%s]'
%(str(attrlist), str(e)))
pass
return None
def _cache_check(self, type, attrlist, value, refresh=False):
try:
attrvalue = self._cache_get(type, attrlist, refresh)
if attrvalue and attrvalue == value:
return True
except Exception, e:
self.logger.debug('_cache_check(%s) : [%s]'
%(str(attrlist), str(e)))
pass
return False
def _cache_update(self, attrlist, value):
if ifupdownflags.flags.DRYRUN: return
try:
linkCache.add_attr(attrlist, value)
except:
pass
def _cache_delete(self, attrlist):
if ifupdownflags.flags.DRYRUN: return
try:
linkCache.del_attr(attrlist)
except:
pass
def _cache_invalidate(self):
linkCache.invalidate()
iproute2._cache_fill_done = False
def batch_start(self):
self.ipbatcbuf = ''
self.ipbatch = True
self.ipbatch_pause = False
def add_to_batch(self, cmd):
self.ipbatchbuf += cmd + '\n'
def batch_pause(self):
self.ipbatch_pause = True
def batch_resume(self):
self.ipbatch_pause = False
def batch_commit(self):
if not self.ipbatchbuf:
self.ipbatchbuf = ''
self.ipbatch = False
self.ipbatch_pause = False
return
try:
utils.exec_command('ip -force -batch -', stdin=self.ipbatchbuf)
except:
raise
finally:
self.ipbatchbuf = ''
self.ipbatch = False
self.ipbatch_pause = False
def addr_show(self, ifacename=None):
if ifacename:
if not self.link_exists(ifacename):
return
return utils.exec_commandl(['ip', '-o', 'addr', 'show', 'dev',
ifacename])
else:
return utils.exec_commandl(['ip', '-o', 'addr', 'show'])
def link_show(self, ifacename=None):
if ifacename:
return utils.exec_commandl(['ip', '-o', '-d', 'link', 'show', 'dev',
ifacename])
else:
return utils.exec_commandl(['ip', '-o', '-d', 'link', 'show'])
def addr_add(self, ifacename, address, broadcast=None,
peer=None, scope=None, preferred_lifetime=None):
if not address:
return
cmd = 'addr add %s' %address
if broadcast:
cmd += ' broadcast %s' %broadcast
if peer:
cmd += ' peer %s' %peer
if scope:
cmd += ' scope %s' %scope
if preferred_lifetime:
cmd += ' preferred_lft %s' %preferred_lifetime
cmd += ' dev %s' %ifacename
if self.ipbatch and not self.ipbatch_pause:
self.add_to_batch(cmd)
else:
utils.exec_command('ip %s' % cmd)
self._cache_update([ifacename, 'addrs', address], {})
def addr_del(self, ifacename, address, broadcast=None,
peer=None, scope=None):
""" Delete ipv4 address """
if not address:
return
if not self._cache_get('addr', [ifacename, 'addrs', address]):
return
cmd = 'addr del %s' %address
if broadcast:
cmd += 'broadcast %s' %broadcast
if peer:
cmd += 'peer %s' %peer
if scope:
cmd += 'scope %s' %scope
cmd += ' dev %s' %ifacename
utils.exec_command('ip %s' % cmd)
self._cache_delete([ifacename, 'addrs', address])
def addr_flush(self, ifacename):
cmd = 'addr flush dev %s' %ifacename
if self.ipbatch and not self.ipbatch_pause:
self.add_to_batch(cmd)
else:
utils.exec_command('ip %s' % cmd)
self._cache_delete([ifacename, 'addrs'])
def del_addr_all(self, ifacename, skip_addrs=[]):
if not skip_addrs: skip_addrs = []
runningaddrsdict = self.addr_get(ifacename)
try:
# XXX: ignore errors. Fix this to delete secondary addresses
# first
[self.addr_del(ifacename, a) for a in
set(runningaddrsdict.keys()).difference(skip_addrs)]
except:
# ignore errors
pass
def addr_get(self, ifacename, details=True, refresh=False):
addrs = self._cache_get('addr', [ifacename, 'addrs'],
refresh=refresh)
if not addrs:
return None
if details:
return addrs
return addrs.keys()
def addr_add_multiple(self, ifacename, addrs, purge_existing=False):
# purges address
if purge_existing:
# if perfmode is not set and also if iface has no sibling
# objects, purge addresses that are not present in the new
# config
runningaddrs = self.addr_get(ifacename, details=False)
if addrs == runningaddrs:
return
try:
# if primary address is not same, there is no need to keep any.
# reset all addresses
if (addrs and runningaddrs and
(addrs[0] != runningaddrs[0])):
self.del_addr_all(ifacename)
else:
self.del_addr_all(ifacename, addrs)
except Exception, e:
self.log_warn(str(e))
for a in addrs:
try:
self.addr_add(ifacename, a)
except Exception, e:
self.logger.error(str(e))
def _link_set_ifflag(self, ifacename, value):
# Dont look at the cache, the cache may have stale value
# because link status can be changed by external
# entity (One such entity is ifupdown main program)
cmd = 'link set dev %s %s' %(ifacename, value.lower())
if self.ipbatch:
self.add_to_batch(cmd)
else:
utils.exec_command('ip %s' % cmd)
def link_up(self, ifacename):
self._link_set_ifflag(ifacename, 'UP')
def link_down(self, ifacename):
self._link_set_ifflag(ifacename, 'DOWN')
def link_set(self, ifacename, key, value=None, force=False, type=None):
if not force:
if (key not in ['master', 'nomaster'] and
self._cache_check('link', [ifacename, key], value)):
return
cmd = 'link set dev %s' %ifacename
if type:
cmd += ' type %s' %type
cmd += ' %s' %key
if value:
cmd += ' %s' %value
if self.ipbatch:
self.add_to_batch(cmd)
else:
utils.exec_command('ip %s' % cmd)
if key not in ['master', 'nomaster']:
self._cache_update([ifacename, key], value)
def link_set_hwaddress(self, ifacename, hwaddress, force=False):
if not force:
if self._cache_check('link', [ifacename, 'hwaddress'], hwaddress):
return
self.link_down(ifacename)
cmd = 'link set dev %s address %s' %(ifacename, hwaddress)
if self.ipbatch:
self.add_to_batch(cmd)
else:
utils.exec_command('ip %s' % cmd)
self.link_up(ifacename)
self._cache_update([ifacename, 'hwaddress'], hwaddress)
def link_set_mtu(self, ifacename, mtu):
if ifupdownflags.flags.DRYRUN:
return True
if not mtu or not ifacename: return
with open('/sys/class/net/%s/mtu' % ifacename, 'w') as f:
f.write(mtu)
self._cache_update([ifacename, 'mtu'], mtu)
def link_set_alias(self, ifacename, alias):
utils.exec_commandl(['ip', 'link', 'set', 'dev', ifacename,
'alias', alias])
def link_get_alias(self, ifacename):
return self.read_file_oneline('/sys/class/net/%s/ifalias'
%ifacename)
def link_isloopback(self, ifacename):
flags = self._cache_get('link', [ifacename, 'flags'])
if not flags:
return
if 'LOOPBACK' in flags:
return True
return False
def link_get_status(self, ifacename):
return self._cache_get('link', [ifacename, 'ifflag'], refresh=True)
def route_add_gateway(self, ifacename, gateway, vrf=None, metric=None):
if not gateway:
return
if not vrf:
cmd = 'ip route add default via %s' %gateway
else:
cmd = 'ip route add table %s default via %s' %(vrf, gateway)
# Add metric
if metric:
cmd += 'metric %s' %metric
cmd += ' dev %s' %ifacename
utils.exec_command(cmd)
def route_del_gateway(self, ifacename, gateway, vrf=None, metric=None):
# delete default gw
if not gateway:
return
if not vrf:
cmd = 'ip route del default via %s' %gateway
else:
cmd = 'ip route del table %s default via %s' %(vrf, gateway)
if metric:
cmd += ' metric %s' %metric
cmd += ' dev %s' %ifacename
utils.exec_command(cmd)
def route6_add_gateway(self, ifacename, gateway):
if not gateway:
return
return utils.exec_command('ip -6 route add default via %s dev %s' %
(gateway, ifacename))
def route6_del_gateway(self, ifacename, gateway):
if not gateway:
return
return utils.exec_command('ip -6 route del default via %s dev %s' %
(gateway, ifacename))
def link_create_vlan(self, vlan_device_name, vlan_raw_device, vlanid):
if self.link_exists(vlan_device_name):
return
utils.exec_command('ip link add link %s name %s type vlan id %d' %
(vlan_raw_device, vlan_device_name, vlanid))
self._cache_update([vlan_device_name], {})
def link_create_vlan_from_name(self, vlan_device_name):
v = vlan_device_name.split('.')
if len(v) != 2:
self.logger.warn('invalid vlan device name %s' %vlan_device_name)
return
self.link_create_vlan(vlan_device_name, v[0], v[1])
def link_create_macvlan(self, name, linkdev, mode='private'):
if self.link_exists(name):
return
cmd = ('link add link %s' %linkdev +
' name %s' %name +
' type macvlan mode %s' %mode)
if self.ipbatch and not self.ipbatch_pause:
self.add_to_batch(cmd)
else:
utils.exec_command('ip %s' % cmd)
self._cache_update([name], {})
def get_vxlan_peers(self, dev, svcnodeip):
cmd = 'bridge fdb show brport %s' % dev
cur_peers = []
try:
ps = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, close_fds=False)
utils.enable_subprocess_signal_forwarding(ps, signal.SIGINT)
output = subprocess.check_output(('grep', '00:00:00:00:00:00'), stdin=ps.stdout)
ps.wait()
utils.disable_subprocess_signal_forwarding(signal.SIGINT)
try:
ppat = re.compile('\s+dst\s+(\d+.\d+.\d+.\d+)\s+')
for l in output.split('\n'):
m = ppat.search(l)
if m and m.group(1) != svcnodeip:
cur_peers.append(m.group(1))
except:
self.logger.warn('error parsing ip link output')
pass
except subprocess.CalledProcessError as e:
if e.returncode != 1:
self.logger.error(str(e))
finally:
utils.disable_subprocess_signal_forwarding(signal.SIGINT)
return cur_peers
def link_create_vxlan(self, name, vxlanid,
localtunnelip=None,
svcnodeip=None,
remoteips=None,
learning='on',
ageing=None,
anycastip=None):
if svcnodeip and remoteips:
raise Exception("svcnodeip and remoteip is mutually exclusive")
args = ''
if svcnodeip:
args += ' remote %s' %svcnodeip
if ageing:
args += ' ageing %s' %ageing
if learning == 'off':
args += ' nolearning'
if self.link_exists(name):
cmd = 'link set dev %s type vxlan dstport %d' %(name, VXLAN_UDP_PORT)
vxlanattrs = self.get_vxlandev_attrs(name)
# on ifreload do not overwrite anycast_ip to individual ip if clagd
# has modified
if vxlanattrs:
running_localtunnelip = vxlanattrs.get('local')
if anycastip and running_localtunnelip and anycastip == running_localtunnelip:
localtunnelip = running_localtunnelip
running_svcnode = vxlanattrs.get('svcnode')
if running_svcnode and not svcnodeip:
args += ' noremote'
else:
cmd = 'link add dev %s type vxlan id %s dstport %d' %(name, vxlanid, VXLAN_UDP_PORT)
if localtunnelip:
args += ' local %s' %localtunnelip
cmd += args
if self.ipbatch and not self.ipbatch_pause:
self.add_to_batch(cmd)
else:
utils.exec_command('ip %s' % cmd)
if not systemUtils.is_service_running(None, '/var/run/vxrd.pid'):
#figure out the diff for remotes and do the bridge fdb updates
#only if provisioned by user and not by vxrd
cur_peers = set(self.get_vxlan_peers(name, svcnodeip))
if remoteips:
new_peers = set(remoteips)
del_list = cur_peers.difference(new_peers)
add_list = new_peers.difference(cur_peers)
else:
del_list = cur_peers
add_list = []
try:
for addr in del_list:
self.bridge_fdb_del(name, '00:00:00:00:00:00', None, True, addr)
except:
pass
try:
for addr in add_list:
self.bridge_fdb_append(name, '00:00:00:00:00:00', None, True, addr)
except:
pass
# XXX: update linkinfo correctly
self._cache_update([name], {})
def link_exists(self, ifacename):
if ifupdownflags.flags.DRYRUN:
return True
return os.path.exists('/sys/class/net/%s' %ifacename)
def is_vlan_device_by_name(self, ifacename):
if re.search(r'\.', ifacename):
return True
return False
def route_add(self, route):
utils.exec_command('ip route add %s' % route)
def route6_add(self, route):
utils.exec_command('ip -6 route add %s' % route)
def get_vlandev_attrs(self, ifacename):
return (self._cache_get('link', [ifacename, 'link']),
self._cache_get('link', [ifacename, 'linkinfo', 'vlanid']))
def get_vxlandev_attrs(self, ifacename):
return self._cache_get('link', [ifacename, 'linkinfo'])
def link_get_linkinfo_attrs(self, ifacename):
return self._cache_get('link', [ifacename, 'linkinfo'])
def link_get_mtu(self, ifacename, refresh=False):
return self._cache_get('link', [ifacename, 'mtu'], refresh=refresh)
def link_get_kind(self, ifacename):
return self._cache_get('link', [ifacename, 'kind'])
def link_get_hwaddress(self, ifacename):
address = self._cache_get('link', [ifacename, 'hwaddress'])
# newly created logical interface addresses dont end up in the cache
# read hwaddress from sysfs file for these interfaces
if not address:
address = self.read_file_oneline('/sys/class/net/%s/address'
%ifacename)
return address
def link_create(self, ifacename, type, attrs={}):
""" generic link_create function """
if self.link_exists(ifacename):
return
cmd = 'link add'
cmd += ' name %s type %s' %(ifacename, type)
if attrs:
for k, v in attrs.iteritems():
cmd += ' %s' %k
if v:
cmd += ' %s' %v
if self.ipbatch and not self.ipbatch_pause:
self.add_to_batch(cmd)
else:
utils.exec_command('ip %s' % cmd)
self._cache_update([ifacename], {})
def link_delete(self, ifacename):
if not self.link_exists(ifacename):
return
cmd = 'link del %s' %ifacename
if self.ipbatch and not self.ipbatch_pause:
self.add_to_batch(cmd)
else:
utils.exec_command('ip %s' % cmd)
self._cache_invalidate()
def link_get_master(self, ifacename):
sysfs_master_path = '/sys/class/net/%s/master' %ifacename
if os.path.exists(sysfs_master_path):
link_path = os.readlink(sysfs_master_path)
if link_path:
return os.path.basename(link_path)
else:
return None
else:
return self._cache_get('link', [ifacename, 'master'])
def bridge_port_vids_add(self, bridgeportname, vids):
[utils.exec_command('bridge vlan add vid %s dev %s' %
(v, bridgeportname)) for v in vids]
def bridge_port_vids_del(self, bridgeportname, vids):
if not vids:
return
[utils.exec_command('bridge vlan del vid %s dev %s' %
(v, bridgeportname)) for v in vids]
def bridge_port_vids_flush(self, bridgeportname, vid):
utils.exec_command('bridge vlan del vid %s dev %s' %
(vid, bridgeportname))
def bridge_port_vids_get(self, bridgeportname):
utils.exec_command('/sbin/bridge vlan show %s' % bridgeportname)
bridgeout = utils.exec_command('/sbin/bridge vlan show dev %s' %
bridgeportname)
if not bridgeout: return []
brvlanlines = bridgeout.readlines()[2:]
vids = [l.strip() for l in brvlanlines]
return [v for v in vids if v]
def bridge_port_vids_get_all(self):
brvlaninfo = {}
bridgeout = utils.exec_command('/sbin/bridge -c vlan show')
if not bridgeout: return brvlaninfo
brvlanlines = bridgeout.splitlines()
brportname=None
for l in brvlanlines[1:]:
if l and l[0] not in [' ', '\t']:
brportname = None
l=l.strip()
if not l:
brportname=None
continue
if 'PVID' in l:
attrs = l.split()
brportname = attrs[0]
brvlaninfo[brportname] = {'pvid' : attrs[1],
'vlan' : []}
elif brportname:
if 'Egress Untagged' not in l:
brvlaninfo[brportname]['vlan'].append(l)
elif not brportname:
attrs = l.split()
if attrs[1] == 'None' or 'Egress Untagged' in attrs[1]:
continue
brportname = attrs[0]
brvlaninfo[brportname] = {'vlan' : [attrs[1]]}
return brvlaninfo
def bridge_port_pvid_add(self, bridgeportname, pvid):
utils.exec_command('bridge vlan add vid %s untagged pvid dev %s' %
(pvid, bridgeportname))
def bridge_port_pvid_del(self, bridgeportname, pvid):
utils.exec_command('bridge vlan del vid %s untagged pvid dev %s' %
(pvid, bridgeportname))
def bridge_port_pvids_get(self, bridgeportname):
return self.read_file_oneline('/sys/class/net/%s/brport/pvid'
%bridgeportname)
def bridge_vids_add(self, bridgeportname, vids, bridge=True):
target = 'self' if bridge else ''
[utils.exec_command('bridge vlan add vid %s dev %s %s' %
(v, bridgeportname, target)) for v in vids]
def bridge_vids_del(self, bridgeportname, vids, bridge=True):
target = 'self' if bridge else ''
[utils.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=None, bridge=True, remote=None):
target = 'self' if bridge else ''
vlan_str = ''
if vlan:
vlan_str = 'vlan %s ' % vlan
dst_str = ''
if remote:
dst_str = 'dst %s ' % remote
utils.exec_command('bridge fdb replace %s dev %s %s %s %s' %
(address, dev, vlan_str, target, dst_str))
def bridge_fdb_append(self, dev, address, vlan=None, bridge=True, remote=None):
target = 'self' if bridge else ''
vlan_str = ''
if vlan:
vlan_str = 'vlan %s ' % vlan
dst_str = ''
if remote:
dst_str = 'dst %s ' % remote
utils.exec_command('bridge fdb append %s dev %s %s %s %s' %
(address, dev, vlan_str, target, dst_str))
def bridge_fdb_del(self, dev, address, vlan=None, bridge=True, remote=None):
target = 'self' if bridge else ''
vlan_str = ''
if vlan:
vlan_str = 'vlan %s ' % vlan
dst_str = ''
if remote:
dst_str = 'dst %s ' % remote
utils.exec_command('bridge fdb del %s dev %s %s %s %s' %
(address, dev, vlan_str, target, dst_str))
def bridge_is_vlan_aware(self, bridgename):
filename = '/sys/class/net/%s/bridge/vlan_filtering' %bridgename
if os.path.exists(filename) and self.read_file_oneline(filename) == '1':
return True
return False
def bridge_port_get_bridge_name(self, bridgeport):
filename = '/sys/class/net/%s/brport/bridge' %bridgeport
try:
return os.path.basename(os.readlink(filename))
except:
return None
def bridge_port_exists(self, bridge, bridgeportname):
try:
return os.path.exists('/sys/class/net/%s/brif/%s'
%(bridge, bridgeportname))
except Exception:
return False
def bridge_fdb_show_dev(self, dev):
try:
fdbs = {}
output = utils.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)
def is_link_up(self, ifacename):
ret = False
try:
flags = self.read_file_oneline('/sys/class/net/%s/flags' %ifacename)
iflags = int(flags, 16)
if (iflags & 0x0001):
ret = True
except:
ret = False
pass
return ret
def ip_route_get_dev(self, prefix):
try:
output = utils.exec_command('ip route get %s' % prefix)
if output:
rline = output.splitlines()[0]
if rline:
rattrs = rline.split()
return rattrs[rattrs.index('dev') + 1]
except Exception, e:
self.logger.debug('ip_route_get_dev: failed .. %s' %str(e))
pass
return None
def link_get_lowers(self, ifacename):
try:
lowers = glob.glob("/sys/class/net/%s/lower_*" %ifacename)
if not lowers:
return []
return [os.path.basename(l)[6:] for l in lowers]
except:
return []
def link_get_upper(self, ifacename):
try:
upper = glob.glob("/sys/class/net/%s/upper_*" %ifacename)
if not upper:
return None
return os.path.basename(upper[0])[6:]
except:
return None
def link_get_vrfs(self):
self._fill_cache()
return linkCache.vrfs