mirror of
https://github.com/CumulusNetworks/ifupdown2.git
synced 2024-05-06 15:54:50 +00:00
addons: support for new addon module for vrf
This patch adds initial support for vrf in ifupdown2. Example interfaces file section: auto swp1.100 iface swp1.100 vrf blue auto blue iface blue vrf-table 10 iproute2 vrf map is generated under: /etc/iproute2/rt_tables.d/ifupdown2.vrf_map this patch also adds prelimnary support for 'vrf-table auto'. But this needs more work. Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
This commit is contained in:
373
addons/vrf.py
Normal file
373
addons/vrf.py
Normal file
@@ -0,0 +1,373 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
#
|
||||||
|
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
|
||||||
|
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
|
||||||
|
#
|
||||||
|
|
||||||
|
import os
|
||||||
|
import atexit
|
||||||
|
from ifupdown.iface import *
|
||||||
|
import ifupdownaddons
|
||||||
|
from ifupdownaddons.modulebase import moduleBase
|
||||||
|
from ifupdownaddons.bondutil import bondutil
|
||||||
|
from ifupdownaddons.iproute2 import iproute2
|
||||||
|
|
||||||
|
class vrf(moduleBase):
|
||||||
|
""" ifupdown2 addon module to configure vrfs """
|
||||||
|
_modinfo = { 'mhelp' : 'vrf configuration module',
|
||||||
|
'attrs' : {
|
||||||
|
'vrf-table':
|
||||||
|
{'help' : 'vrf device table id. key to ' +
|
||||||
|
'creating a vrf device',
|
||||||
|
'example': ['vrf-table-id 1']},
|
||||||
|
'vrf':
|
||||||
|
{'help' : 'vrf the interface is part of.',
|
||||||
|
'example': ['vrf blue']}}}
|
||||||
|
|
||||||
|
iproute2_vrf_filename = '/etc/iproute2/rt_tables.d/ifupdown2.vrf_map'
|
||||||
|
iproute2_vrf_filehdr = '# This file is autogenerated by ifupdown2.\n' + \
|
||||||
|
'# It contains the vrf name to table mapping.\n' + \
|
||||||
|
'# Reserved table range 150-200\n'
|
||||||
|
vrf_table_reserved_start = 150
|
||||||
|
vrf_table_reserved_end = 200
|
||||||
|
|
||||||
|
def __init__(self, *args, **kargs):
|
||||||
|
ifupdownaddons.modulebase.moduleBase.__init__(self, *args, **kargs)
|
||||||
|
self.ipcmd = None
|
||||||
|
self.bondcmd = None
|
||||||
|
try:
|
||||||
|
ip_rules = self.exec_command('/sbin/ip rule show').splitlines()
|
||||||
|
self.ip_rule_cache = [' '.join(r.split()) for r in ip_rules]
|
||||||
|
except Exception, e:
|
||||||
|
self.ip_rule_cache = []
|
||||||
|
self.logger.warn('%s' %str(e))
|
||||||
|
|
||||||
|
try:
|
||||||
|
ip_rules = self.exec_command('/sbin/ip -6 rule show').splitlines()
|
||||||
|
self.ip6_rule_cache = [' '.join(r.split()) for r in ip_rules]
|
||||||
|
except Exception, e:
|
||||||
|
self.ip6_rule_cache = []
|
||||||
|
self.logger.warn('%s' %str(e))
|
||||||
|
|
||||||
|
#self.logger.debug("vrf: ip rule cache")
|
||||||
|
#self.logger.info(self.ip_rule_cache)
|
||||||
|
|
||||||
|
#self.logger.info("vrf: ip -6 rule cache")
|
||||||
|
#self.logger.info(self.ip6_rule_cache)
|
||||||
|
|
||||||
|
# XXX: check for vrf reserved overlap in /etc/iproute2/rt_tables
|
||||||
|
self.iproute2_vrf_map = {}
|
||||||
|
# read or create /etc/iproute2/rt_tables.d/ifupdown2.vrf_map
|
||||||
|
if os.path.exists(self.iproute2_vrf_filename):
|
||||||
|
self.vrf_map_fd = open(self.iproute2_vrf_filename, 'a+')
|
||||||
|
lines = self.vrf_map_fd.readlines()
|
||||||
|
for l in lines:
|
||||||
|
l = l.strip()
|
||||||
|
if l[0] == '#':
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
(table, vrf_name) = l.strip().split()
|
||||||
|
self.iproute2_vrf_map[table] = vrf_name
|
||||||
|
except Exception, e:
|
||||||
|
self.logger.info('vrf: iproute2_vrf_map: unable to parse %s'
|
||||||
|
%l)
|
||||||
|
pass
|
||||||
|
#self.logger.info("vrf: dumping iproute2_vrf_map")
|
||||||
|
#self.logger.info(self.iproute2_vrf_map)
|
||||||
|
|
||||||
|
# purge vrf table entries that are not around
|
||||||
|
iproute2_vrf_map_pruned = {}
|
||||||
|
for t, v in self.iproute2_vrf_map.iteritems():
|
||||||
|
if os.path.exists('/sys/class/net/%s' %v):
|
||||||
|
iproute2_vrf_map_pruned[t] = v
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
# cleanup rules
|
||||||
|
self._del_vrf_rules(v, t)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
self.iproute2_vrf_map = iproute2_vrf_map_pruned
|
||||||
|
|
||||||
|
last_used_vrf_table = self.vrf_table_reserved_start
|
||||||
|
for t in range(self.vrf_table_reserved_start,
|
||||||
|
self.vrf_table_reserved_end):
|
||||||
|
last_used_vrf_table = t
|
||||||
|
if not self.iproute2_vrf_map.get(t):
|
||||||
|
break
|
||||||
|
self.last_used_vrf_table = last_used_vrf_table
|
||||||
|
self.iproute2_write_vrf_map = False
|
||||||
|
atexit.register(self.iproute2_vrf_map_write)
|
||||||
|
|
||||||
|
def iproute2_vrf_map_write(self):
|
||||||
|
if not self.iproute2_write_vrf_map:
|
||||||
|
return
|
||||||
|
self.logger.info('vrf: writing table map to %s'
|
||||||
|
%self.iproute2_vrf_filename)
|
||||||
|
with open(self.iproute2_vrf_filename, 'w') as f:
|
||||||
|
f.write(self.iproute2_vrf_filehdr)
|
||||||
|
for t, v in self.iproute2_vrf_map.iteritems():
|
||||||
|
f.write('%s %s\n' %(t, v))
|
||||||
|
|
||||||
|
def _is_vrf(self, ifaceobj):
|
||||||
|
if ifaceobj.get_attr_value_first('vrf-table'):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
|
||||||
|
""" Returns list of interfaces dependent on ifaceobj """
|
||||||
|
|
||||||
|
vrf_iface_name = ifaceobj.get_attr_value_first('vrf')
|
||||||
|
if not vrf_iface_name:
|
||||||
|
return None
|
||||||
|
return [vrf_iface_name]
|
||||||
|
|
||||||
|
def get_dependent_ifacenames_running(self, ifaceobj):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _get_iproute2_vrf_table(self, vrf_dev_name):
|
||||||
|
for t, v in self.iproute2_vrf_map.iteritems():
|
||||||
|
if v == vrf_dev_name:
|
||||||
|
return t
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _get_avail_vrf_table_id(self):
|
||||||
|
for t in range(self.last_used_vrf_table + 1,
|
||||||
|
self.vrf_table_reserved_end):
|
||||||
|
if not self.iproute2_vrf_map.get(t):
|
||||||
|
self.last_used_vrf_table = t
|
||||||
|
return t
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _iproute2_vrf_table_entry_add(self, vrf_dev_name, table_id):
|
||||||
|
self.iproute2_vrf_map[table_id] = vrf_dev_name
|
||||||
|
self.iproute2_write_vrf_map = True
|
||||||
|
|
||||||
|
def _iproute2_vrf_table_entry_del(self, table_id):
|
||||||
|
try:
|
||||||
|
del self.iproute2_vrf_map[table_id]
|
||||||
|
self.iproute2_write_vrf_map = True
|
||||||
|
except Exception, e:
|
||||||
|
self.logger.info('vrf: iproute2 vrf map del failed for %d (%s)'
|
||||||
|
%(table_id, str(e)))
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _up_vrf_slave(self, ifaceobj, vrf):
|
||||||
|
try:
|
||||||
|
self.ipcmd.link_set(ifaceobj.name, 'master', vrf)
|
||||||
|
except Exception, e:
|
||||||
|
self.logger.warn('%s: %s' %(ifaceobj.name, str(e)))
|
||||||
|
|
||||||
|
def _del_vrf_rules(self, vrf_dev_name, vrf_table):
|
||||||
|
pref = 200
|
||||||
|
ip_rule_out_format = '%s: from all %s %s lookup %s'
|
||||||
|
ip_rule_cmd = 'ip %s rule del pref %s %s %s table %s'
|
||||||
|
|
||||||
|
rule = ip_rule_out_format %(pref, 'oif', vrf_dev_name, vrf_table)
|
||||||
|
if rule in self.ip_rule_cache:
|
||||||
|
rule_cmd = ip_rule_cmd %('', pref, 'oif', vrf_dev_name, vrf_table)
|
||||||
|
self.exec_command(rule_cmd)
|
||||||
|
|
||||||
|
rule = ip_rule_out_format %(pref, 'iif', vrf_dev_name, vrf_table)
|
||||||
|
if rule in self.ip_rule_cache:
|
||||||
|
rule_cmd = ip_rule_cmd %('', pref, 'iif', vrf_dev_name, vrf_table)
|
||||||
|
self.exec_command(rule_cmd)
|
||||||
|
|
||||||
|
rule = ip_rule_out_format %(pref, 'oif', vrf_dev_name, vrf_table)
|
||||||
|
if rule in self.ip_rule_cache:
|
||||||
|
rule_cmd = ip_rule_cmd %('-6', pref, 'oif', vrf_dev_name,
|
||||||
|
vrf_table)
|
||||||
|
self.exec_command(rule_cmd)
|
||||||
|
|
||||||
|
rule = ip_rule_out_format %(pref, 'iif', vrf_dev_name, vrf_table)
|
||||||
|
if rule in self.ip_rule_cache:
|
||||||
|
rule_cmd = ip_rule_cmd %('-6', pref, 'iif', vrf_dev_name,
|
||||||
|
vrf_table)
|
||||||
|
self.exec_command(rule_cmd)
|
||||||
|
|
||||||
|
def _add_vrf_rules(self, vrf_dev_name, vrf_table):
|
||||||
|
pref = 200
|
||||||
|
ip_rule_out_format = '%s: from all %s %s lookup %s'
|
||||||
|
ip_rule_cmd = 'ip %s rule add pref %s %s %s table %s'
|
||||||
|
|
||||||
|
rule = ip_rule_out_format %(pref, 'oif', vrf_dev_name, vrf_table)
|
||||||
|
if rule not in self.ip_rule_cache:
|
||||||
|
rule_cmd = ip_rule_cmd %('', pref, 'oif', vrf_dev_name, vrf_table)
|
||||||
|
self.exec_command(rule_cmd)
|
||||||
|
|
||||||
|
rule = ip_rule_out_format %(pref, 'iif', vrf_dev_name, vrf_table)
|
||||||
|
if rule not in self.ip_rule_cache:
|
||||||
|
rule_cmd = ip_rule_cmd %('', pref, 'iif', vrf_dev_name, vrf_table)
|
||||||
|
self.exec_command(rule_cmd)
|
||||||
|
|
||||||
|
rule = ip_rule_out_format %(pref, 'oif', vrf_dev_name, vrf_table)
|
||||||
|
if rule not in self.ip_rule_cache:
|
||||||
|
rule_cmd = ip_rule_cmd %('-6', pref, 'oif', vrf_dev_name,
|
||||||
|
vrf_table)
|
||||||
|
self.exec_command(rule_cmd)
|
||||||
|
|
||||||
|
rule = ip_rule_out_format %(pref, 'iif', vrf_dev_name, vrf_table)
|
||||||
|
if rule not in self.ip_rule_cache:
|
||||||
|
rule_cmd = ip_rule_cmd %('-6', pref, 'iif', vrf_dev_name,
|
||||||
|
vrf_table)
|
||||||
|
self.exec_command(rule_cmd)
|
||||||
|
|
||||||
|
|
||||||
|
def _up_vrf_dev(self, ifaceobj, vrf_table):
|
||||||
|
if vrf_table == 'auto':
|
||||||
|
vrf_table = _get_avail_vrf_table_id(ifaceobj.name)
|
||||||
|
|
||||||
|
try:
|
||||||
|
if not self.ipcmd.link_exists(ifaceobj.name):
|
||||||
|
self.ipcmd.link_create(ifaceobj.name, 'vrf',
|
||||||
|
{'table' : '%s' %vrf_table})
|
||||||
|
self._iproute2_vrf_table_entry_add(ifaceobj.name, vrf_table)
|
||||||
|
self._add_vrf_rules(ifaceobj.name, vrf_table)
|
||||||
|
except Exception, e:
|
||||||
|
self.logger.warn('%s: %s' %(ifaceobj.name, str(e)))
|
||||||
|
|
||||||
|
def _up(self, ifaceobj):
|
||||||
|
try:
|
||||||
|
vrf_table = ifaceobj.get_attr_value_first('vrf-table')
|
||||||
|
if vrf_table:
|
||||||
|
self._up_vrf_dev(ifaceobj, vrf_table)
|
||||||
|
else:
|
||||||
|
vrf = ifaceobj.get_attr_value_first('vrf')
|
||||||
|
if vrf:
|
||||||
|
self._up_vrf_slave(ifaceobj, vrf)
|
||||||
|
except Exception, e:
|
||||||
|
self.log_error(str(e))
|
||||||
|
|
||||||
|
def _down_vrf_dev(self, ifaceobj, vrf_table):
|
||||||
|
if vrf_table == 'auto':
|
||||||
|
vrf_table = self._get_iproute2_vrf_table(ifaceobj.name)
|
||||||
|
try:
|
||||||
|
self.ipcmd.link_delete(ifaceobj.name)
|
||||||
|
self._iproute2_vrf_table_entry_del(vrf_table)
|
||||||
|
self._del_vrf_rules(ifaceobj.name, vrf_table)
|
||||||
|
except Exception, e:
|
||||||
|
self.logger.warn('%s: %s' %(ifaceobj.name, str(e)))
|
||||||
|
|
||||||
|
def _down_vrf_slave(self, ifaceobj, vrf):
|
||||||
|
try:
|
||||||
|
self.ipcmd.link_set(ifaceobj.name, 'nomaster')
|
||||||
|
except Exception, e:
|
||||||
|
self.logger.warn('%s: %s' %(ifaceobj.name, str(e)))
|
||||||
|
|
||||||
|
def _down(self, ifaceobj):
|
||||||
|
try:
|
||||||
|
vrf_table = ifaceobj.get_attr_value_first('vrf-table')
|
||||||
|
if vrf_table:
|
||||||
|
self._down_vrf_dev(ifaceobj, vrf_table)
|
||||||
|
else:
|
||||||
|
vrf = ifaceobj.get_attr_value_first('vrf')
|
||||||
|
if vrf:
|
||||||
|
self._down_vrf_slave(ifaceobj, vrf)
|
||||||
|
except Exception, e:
|
||||||
|
self.log_warn(str(e))
|
||||||
|
|
||||||
|
def _query_check_vrf_slave(self, ifaceobj, ifaceobjcurr, vrf):
|
||||||
|
try:
|
||||||
|
master = self.ipcmd.link_get_master(ifacename)
|
||||||
|
if not master or master != vrf:
|
||||||
|
ifaceobjcurr.update_config_with_status('vrf', master, 1)
|
||||||
|
else:
|
||||||
|
ifaceobjcurr.update_config_with_status('vrf', master, 0)
|
||||||
|
except Exception, e:
|
||||||
|
self.log_warn(str(e))
|
||||||
|
|
||||||
|
def _query_check_vrf_dev(self, ifaceobj, ifaceobjcurr, vrf_table):
|
||||||
|
try:
|
||||||
|
if not self.ipcmd.link_exists(ifaceobj.name):
|
||||||
|
self.logger.info('%s: vrf: does not exist' %(ifaceobj.name))
|
||||||
|
return
|
||||||
|
if vrf_table == 'auto':
|
||||||
|
config_table = self._get_iproute2_vrf_table(ifaceobj.name)
|
||||||
|
else:
|
||||||
|
config_table = vrf_table
|
||||||
|
vrfdev_attrs = self.ipcmd.link_get_linkinfo_attrs(ifaceobj.name)
|
||||||
|
if not vrfdev_attrs:
|
||||||
|
ifaceobjcurr.update_config_with_status('vrf-table', 'None', 1)
|
||||||
|
return
|
||||||
|
running_table = vrfdev_attrs.get('table')
|
||||||
|
if not running_table:
|
||||||
|
ifaceobjcurr.update_config_with_status('vrf-table', 'None', 1)
|
||||||
|
return
|
||||||
|
if config_table != running_table:
|
||||||
|
ifaceobjcurr.update_config_with_status('vrf-table',
|
||||||
|
running_table, 1)
|
||||||
|
else:
|
||||||
|
ifaceobjcurr.update_config_with_status('vrf-table',
|
||||||
|
running_table, 0)
|
||||||
|
except Exception, e:
|
||||||
|
self.log_warn(str(e))
|
||||||
|
|
||||||
|
def _query_check(self, ifaceobj, ifaceobjcurr):
|
||||||
|
try:
|
||||||
|
vrf_table = ifaceobj.get_attr_value_first('vrf-table')
|
||||||
|
if vrf_table:
|
||||||
|
self._query_check_vrf_dev(ifaceobj, ifaceobjcurr, vrf_table)
|
||||||
|
else:
|
||||||
|
vrf = ifaceobj.get_attr_value_first('vrf')
|
||||||
|
if vrf:
|
||||||
|
self._query_check_vrf_slave(ifaceobj, ifaceobjcurr, vrf)
|
||||||
|
except Exception, e:
|
||||||
|
self.log_warn(str(e))
|
||||||
|
|
||||||
|
def _query_running(self, ifaceobjrunning):
|
||||||
|
try:
|
||||||
|
kind = self.ipcmd.link_get_kind(ifaceobjrunning.name)
|
||||||
|
if kind == 'vrf':
|
||||||
|
vrfdev_attrs = self.ipcmd.link_get_linkinfo_attrs(ifaceobj.name)
|
||||||
|
if vrfdev_attrs:
|
||||||
|
running_table = vrfdev_attrs.get('table')
|
||||||
|
if running_table:
|
||||||
|
ifaceobjrunning.update_config('vrf-table',
|
||||||
|
running_table)
|
||||||
|
elif kind == 'vrf_slave':
|
||||||
|
vrf = self.link_get_master(ifaceobjrunning.name)
|
||||||
|
if vrf:
|
||||||
|
ifaceobjrunning.update_config('vrf', vrf)
|
||||||
|
except Exception, e:
|
||||||
|
self.log_warn(str(e))
|
||||||
|
|
||||||
|
_run_ops = {'pre-up' : _up,
|
||||||
|
'post-down' : _down,
|
||||||
|
'query-running' : _query_running,
|
||||||
|
'query-checkcurr' : _query_check}
|
||||||
|
|
||||||
|
def get_ops(self):
|
||||||
|
""" returns list of ops supported by this module """
|
||||||
|
return self._run_ops.keys()
|
||||||
|
|
||||||
|
def _init_command_handlers(self):
|
||||||
|
flags = self.get_flags()
|
||||||
|
if not self.ipcmd:
|
||||||
|
self.ipcmd = iproute2(**flags)
|
||||||
|
if not self.bondcmd:
|
||||||
|
self.bondcmd = bondutil(**flags)
|
||||||
|
|
||||||
|
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
|
||||||
|
""" run bond configuration on the interface object passed as argument
|
||||||
|
|
||||||
|
Args:
|
||||||
|
**ifaceobj** (object): iface object
|
||||||
|
|
||||||
|
**operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
|
||||||
|
'query-running'
|
||||||
|
|
||||||
|
Kwargs:
|
||||||
|
**query_ifaceobj** (object): query check ifaceobject. This is only
|
||||||
|
valid when op is 'query-checkcurr'. It is an object same as
|
||||||
|
ifaceobj, but contains running attribute values and its config
|
||||||
|
status. The modules can use it to return queried running state
|
||||||
|
of interfaces. status is success if the running state is same
|
||||||
|
as user required state in ifaceobj. error otherwise.
|
||||||
|
"""
|
||||||
|
op_handler = self._run_ops.get(operation)
|
||||||
|
if not op_handler:
|
||||||
|
return
|
||||||
|
self._init_command_handlers()
|
||||||
|
if operation == 'query-checkcurr':
|
||||||
|
op_handler(self, ifaceobj, query_ifaceobj)
|
||||||
|
else:
|
||||||
|
op_handler(self, ifaceobj)
|
@@ -7,6 +7,7 @@ pre-up,usercmds
|
|||||||
pre-up,bridge
|
pre-up,bridge
|
||||||
pre-up,bridgevlan
|
pre-up,bridgevlan
|
||||||
pre-up,mstpctl
|
pre-up,mstpctl
|
||||||
|
pre-up,vrf
|
||||||
up,dhcp
|
up,dhcp
|
||||||
up,address
|
up,address
|
||||||
up,addressvirtual
|
up,addressvirtual
|
||||||
@@ -22,6 +23,7 @@ down,dhcp
|
|||||||
down,addressvirtual
|
down,addressvirtual
|
||||||
down,address
|
down,address
|
||||||
down,usercmds
|
down,usercmds
|
||||||
|
post-down,vrf
|
||||||
post-down,clagd
|
post-down,clagd
|
||||||
post-down,mstpctl
|
post-down,mstpctl
|
||||||
post-down,bridgevlan
|
post-down,bridgevlan
|
||||||
|
@@ -585,6 +585,9 @@ class iproute2(utilsBase):
|
|||||||
def get_vxlandev_attrs(self, ifacename):
|
def get_vxlandev_attrs(self, ifacename):
|
||||||
return self._cache_get('link', [ifacename, 'linkinfo'])
|
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):
|
def link_get_mtu(self, ifacename):
|
||||||
return self._cache_get('link', [ifacename, 'mtu'])
|
return self._cache_get('link', [ifacename, 'mtu'])
|
||||||
|
|
||||||
@@ -600,13 +603,17 @@ class iproute2(utilsBase):
|
|||||||
%ifacename)
|
%ifacename)
|
||||||
return address
|
return address
|
||||||
|
|
||||||
def link_create(self, ifacename, type, link=None):
|
def link_create(self, ifacename, type, attrs={}):
|
||||||
|
""" generic link_create function """
|
||||||
if self.link_exists(ifacename):
|
if self.link_exists(ifacename):
|
||||||
return
|
return
|
||||||
cmd = 'link add'
|
cmd = 'link add'
|
||||||
if link:
|
|
||||||
cmd += ' link %s' %link
|
|
||||||
cmd += ' name %s type %s' %(ifacename, type)
|
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:
|
if self.ipbatch and not self.ipbatch_pause:
|
||||||
self.add_to_batch(cmd)
|
self.add_to_batch(cmd)
|
||||||
else:
|
else:
|
||||||
@@ -623,6 +630,17 @@ class iproute2(utilsBase):
|
|||||||
self.exec_command('ip %s' %cmd)
|
self.exec_command('ip %s' %cmd)
|
||||||
self._cache_invalidate()
|
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):
|
def bridge_port_vids_add(self, bridgeportname, vids):
|
||||||
[self.exec_command('bridge vlan add vid %s dev %s'
|
[self.exec_command('bridge vlan add vid %s dev %s'
|
||||||
%(v, bridgeportname)) for v in vids]
|
%(v, bridgeportname)) for v in vids]
|
||||||
|
2
setup.py
2
setup.py
@@ -16,7 +16,7 @@ setup(name='ifupdown2',
|
|||||||
'addons/dhcp.py', 'addons/usercmds.py',
|
'addons/dhcp.py', 'addons/usercmds.py',
|
||||||
'addons/ethtool.py',
|
'addons/ethtool.py',
|
||||||
'addons/addressvirtual.py', 'addons/vxlan.py',
|
'addons/addressvirtual.py', 'addons/vxlan.py',
|
||||||
'addons/link.py',
|
'addons/link.py', 'addons/vrf.py',
|
||||||
'addons/bridgevlan.py']),
|
'addons/bridgevlan.py']),
|
||||||
('/etc/network/ifupdown2/', ['config/addons.conf']),
|
('/etc/network/ifupdown2/', ['config/addons.conf']),
|
||||||
('/var/lib/ifupdown2/policy.d/', []),
|
('/var/lib/ifupdown2/policy.d/', []),
|
||||||
|
Reference in New Issue
Block a user