mirror of
https://github.com/CumulusNetworks/ifupdown2.git
synced 2024-05-06 15:54:50 +00:00
Misc fixes + ifreload new option + cleanups + more ifquery support etc
Ticket: CM-3346, CM-3784, CM-3841 Reviewed By: Testing Done: various ifupdown2 tests
This commit is contained in:
@@ -168,7 +168,8 @@ class bridge(moduleBase):
|
||||
'If specified under the bridge the ports ' +
|
||||
'inherit it unless overridden by a ' +
|
||||
'bridge-vids attribuet under the port',
|
||||
'example' : ['bridge-vids 4000']},
|
||||
'example' : ['bridge-vids 4000',
|
||||
'bridge-vids 2000 2200-3000']},
|
||||
'bridge-pvid' :
|
||||
{ 'help' : 'bridge port pvid. Must be specified under' +
|
||||
' the bridge port',
|
||||
@@ -198,6 +199,9 @@ class bridge(moduleBase):
|
||||
self.brctlcmd = None
|
||||
self._running_vidinfo = {}
|
||||
self._running_vidinfo_valid = False
|
||||
self._resv_vlan_range = self._get_reserved_vlan_range()
|
||||
self.logger.debug('%s: using reserved vlan range %s'
|
||||
%(self.__class__.__name__, str(self._resv_vlan_range)))
|
||||
|
||||
def _is_bridge(self, ifaceobj):
|
||||
if ifaceobj.get_attr_value_first('bridge-ports'):
|
||||
@@ -605,7 +609,8 @@ class bridge(moduleBase):
|
||||
%(bportifaceobj.name, pvid, str(e)))
|
||||
|
||||
def _apply_bridge_vlan_aware_port_settings_all(self, bportifaceobj,
|
||||
bridge_vids=None):
|
||||
bridge_vids=None,
|
||||
bridge_pvid=None):
|
||||
running_vidinfo = self._get_running_vidinfo()
|
||||
vids = None
|
||||
pvids = None
|
||||
@@ -613,10 +618,10 @@ class bridge(moduleBase):
|
||||
if bport_access:
|
||||
vids = re.split(r'[\s\t]\s*', bport_access)
|
||||
pvids = vids
|
||||
|
||||
else:
|
||||
bport_vids = bportifaceobj.get_attr_value_first('bridge-vids')
|
||||
if bport_vids:
|
||||
vids = re.split(r'[\s\t]\s*', bport_vids)
|
||||
vids = re.split(r'[\s\t,]\s*', bport_vids)
|
||||
|
||||
bport_pvids = bportifaceobj.get_attr_value_first('bridge-pvid')
|
||||
if bport_pvids:
|
||||
@@ -625,10 +630,15 @@ class bridge(moduleBase):
|
||||
if pvids:
|
||||
self._apply_bridge_port_pvids(bportifaceobj, pvids[0],
|
||||
running_vidinfo.get(bportifaceobj.name, {}).get('pvid'))
|
||||
else:
|
||||
elif bridge_pvid:
|
||||
self._apply_bridge_port_pvids(bportifaceobj,
|
||||
'1', running_vidinfo.get(bportifaceobj.name,
|
||||
bridge_pvid, running_vidinfo.get(bportifaceobj.name,
|
||||
{}).get('pvid'))
|
||||
# XXX: default pvid is already one
|
||||
#else:
|
||||
# self._apply_bridge_port_pvids(bportifaceobj,
|
||||
# '1', running_vidinfo.get(bportifaceobj.name,
|
||||
# {}).get('pvid'))
|
||||
|
||||
if vids:
|
||||
self._apply_bridge_vids(bportifaceobj, vids,
|
||||
@@ -686,10 +696,16 @@ class bridge(moduleBase):
|
||||
|
||||
bridge_vids = ifaceobj.get_attr_value_first('bridge-vids')
|
||||
if bridge_vids:
|
||||
bridge_vids = re.split(r'[\s\t]\s*', bridge_vids)
|
||||
bridge_vids = re.split(r'[\s\t,]\s*', bridge_vids)
|
||||
else:
|
||||
bridge_vids = None
|
||||
|
||||
bridge_pvid = ifaceobj.get_attr_value_first('bridge-pvid')
|
||||
if bridge_pvid:
|
||||
bridge_pvid = re.split(r'[\s\t]\s*', bridge_pvid)
|
||||
else:
|
||||
bridge_pvid = None
|
||||
|
||||
bridgeports = self._get_bridge_port_list(ifaceobj)
|
||||
for bport in bridgeports:
|
||||
# Use the brctlcmd bulk set method: first build a dictionary
|
||||
@@ -711,7 +727,7 @@ class bridge(moduleBase):
|
||||
# Add attributes specific to the vlan aware bridge
|
||||
if bridge_vlan_aware:
|
||||
self._apply_bridge_vlan_aware_port_settings_all(
|
||||
bportifaceobj, bridge_vids)
|
||||
bportifaceobj, bridge_vids, bridge_pvid)
|
||||
self._apply_bridge_port_settings(bportifaceobj,
|
||||
bridgeifaceobj=ifaceobj)
|
||||
|
||||
@@ -722,8 +738,11 @@ class bridge(moduleBase):
|
||||
if self.ipcmd.bridge_is_vlan_aware(bridgename):
|
||||
bridge_vids = self._get_bridge_vids(bridgename,
|
||||
ifaceobj_getfunc)
|
||||
bridge_pvid = self._get_bridge_pvid(bridgename,
|
||||
ifaceobj_getfunc)
|
||||
self._apply_bridge_vlan_aware_port_settings_all(ifaceobj,
|
||||
bridge_vids)
|
||||
bridge_vids,
|
||||
bridge_pvid)
|
||||
self._apply_bridge_port_settings(ifaceobj, bridgename=bridgename)
|
||||
ifaceobj.priv_flags |= self._BRIDGE_PORT_PROCESSED
|
||||
return
|
||||
@@ -1096,9 +1115,16 @@ class bridge(moduleBase):
|
||||
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)
|
||||
if vids: return re.split(r'[\s\t,]\s*', vids)
|
||||
return None
|
||||
|
||||
def _get_bridge_pvid(self, bridgename, ifaceobj_getfunc):
|
||||
ifaceobjs = ifaceobj_getfunc(bridgename)
|
||||
pvid = None
|
||||
for ifaceobj in ifaceobjs:
|
||||
pvid = ifaceobj.get_attr_value_first('bridge-pvid')
|
||||
return pvid
|
||||
|
||||
def _get_bridge_name(self, ifaceobj):
|
||||
return self.ipcmd.bridge_port_get_bridge_name(ifaceobj.name)
|
||||
|
||||
|
@@ -1,863 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
|
||||
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
|
||||
#
|
||||
|
||||
from sets import Set
|
||||
from ifupdown.iface import *
|
||||
from ifupdownaddons.modulebase import moduleBase
|
||||
from ifupdownaddons.bridgeutils import brctl
|
||||
from ifupdownaddons.iproute2 import iproute2
|
||||
import itertools
|
||||
import re
|
||||
import os
|
||||
|
||||
class bridgevlanaware(moduleBase):
|
||||
""" ifupdown2 addon module to configure linux bridges """
|
||||
|
||||
_modinfo = { 'mhelp' : 'bridge configuration module',
|
||||
'attrs' : {
|
||||
'bridge' :
|
||||
{'help': 'bridge this interface is part of',
|
||||
'example' : ['bridge br0']},
|
||||
'bridge-vlan-aware' :
|
||||
{'help': 'Is this a vlan aware bridge ?',
|
||||
'default' : 'no',
|
||||
'required' : False,
|
||||
'example' : ['bridge-vlan-aware yes']},
|
||||
'type' :
|
||||
{'help': 'type of interface this module supports',
|
||||
'example' : ['type bridge']},
|
||||
'bridge-stp' :
|
||||
{'help': 'bridge-stp yes/no',
|
||||
'example' : ['bridge-stp no'],
|
||||
'validvals' : ['yes', 'on', 'off', 'no'],
|
||||
'default' : 'no'},
|
||||
'bridge-bridgeprio' :
|
||||
{'help': 'bridge priority',
|
||||
'example' : ['bridge-bridgeprio 32768'],
|
||||
'default' : '32768'},
|
||||
'bridge-ageing' :
|
||||
{'help': 'bridge ageing',
|
||||
'example' : ['bridge-ageing 300'],
|
||||
'default' : '300'},
|
||||
'bridge-fd' :
|
||||
{ 'help' : 'bridge forward delay',
|
||||
'example' : ['bridge-fd 15'],
|
||||
'default' : '15'},
|
||||
'bridge-gcint' :
|
||||
# XXX: recheck values
|
||||
{ 'help' : 'bridge garbage collection interval in secs',
|
||||
'example' : ['bridge-gcint 4'],
|
||||
'default' : '4'},
|
||||
'bridge-hello' :
|
||||
{ 'help' : 'bridge set hello time',
|
||||
'example' : ['bridge-hello 2'],
|
||||
'default' : '2'},
|
||||
'bridge-maxage' :
|
||||
{ 'help' : 'bridge set maxage',
|
||||
'example' : ['bridge-maxage 20'],
|
||||
'default' : '20'},
|
||||
'bridge-pathcosts' :
|
||||
{ 'help' : 'bridge set port path costs',
|
||||
'example' : ['bridge-pathcosts swp1=100 swp2=100'],
|
||||
'default' : '100'},
|
||||
'bridge-priority' :
|
||||
{ 'help' : 'bridge port priority',
|
||||
'example' : ['bridge-priority 32'],
|
||||
'default' : '32'},
|
||||
'bridge-mclmc' :
|
||||
{ 'help' : 'set multicast last member count',
|
||||
'example' : ['bridge-mclmc 2'],
|
||||
'default' : '2'},
|
||||
'bridge-mcrouter' :
|
||||
{ 'help' : 'set multicast router',
|
||||
'default' : '1',
|
||||
'example' : ['bridge-mcrouter 1']},
|
||||
'bridge-mcsnoop' :
|
||||
{ 'help' : 'set multicast snooping',
|
||||
'default' : '1',
|
||||
'example' : ['bridge-mcsnoop 1']},
|
||||
'bridge-mcsqc' :
|
||||
{ 'help' : 'set multicast startup query count',
|
||||
'default' : '2',
|
||||
'example' : ['bridge-mcsqc 2']},
|
||||
'bridge-mcqifaddr' :
|
||||
{ 'help' : 'set multicast query to use ifaddr',
|
||||
'default' : '0',
|
||||
'example' : ['bridge-mcqifaddr 0']},
|
||||
'bridge-mcquerier' :
|
||||
{ 'help' : 'set multicast querier',
|
||||
'default' : '0',
|
||||
'example' : ['bridge-mcquerier 0']},
|
||||
'bridge-hashel' :
|
||||
{ 'help' : 'set hash elasticity',
|
||||
'default' : '4096',
|
||||
'example' : ['bridge-hashel 4096']},
|
||||
'bridge-hashmax' :
|
||||
{ 'help' : 'set hash max',
|
||||
'default' : '4096',
|
||||
'example' : ['bridge-hashmax 4096']},
|
||||
'bridge-mclmi' :
|
||||
{ 'help' : 'set multicast last member interval (in secs)',
|
||||
'default' : '1',
|
||||
'example' : ['bridge-mclmi 1']},
|
||||
'bridge-mcmi' :
|
||||
{ 'help' : 'set multicast membership interval (in secs)',
|
||||
'default' : '260',
|
||||
'example' : ['bridge-mcmi 260']},
|
||||
'bridge-mcqpi' :
|
||||
{ 'help' : 'set multicast querier interval (in secs)',
|
||||
'default' : '255',
|
||||
'example' : ['bridge-mcqpi 255']},
|
||||
'bridge-mcqi' :
|
||||
{ 'help' : 'set multicast query interval (in secs)',
|
||||
'default' : '125',
|
||||
'example' : ['bridge-mcqi 125']},
|
||||
'bridge-mcqri' :
|
||||
{ 'help' : 'set multicast query response interval (in secs)',
|
||||
'default' : '10',
|
||||
'example' : ['bridge-mcqri 10']},
|
||||
'bridge-mcsqi' :
|
||||
{ 'help' : 'set multicast startup query interval (in secs)',
|
||||
'default' : '31',
|
||||
'example' : ['bridge-mcsqi 31']},
|
||||
'bridge-mcqv4src' :
|
||||
{ 'help' : 'set per VLAN v4 multicast querier source address',
|
||||
'compat' : True,
|
||||
'example' : ['bridge-mcqv4src 172.16.100.1']},
|
||||
'bridge-igmp-querier-src' :
|
||||
{ 'help' : 'set per VLAN v4 multicast querier source address',
|
||||
'example' : ['bridge-igmp-querier-src 172.16.100.1']},
|
||||
'bridge-mcfl' :
|
||||
{ 'help' : 'port multicast fast leave',
|
||||
'default' : '0',
|
||||
'example' : ['bridge-mcfl 0']},
|
||||
'bridge-waitport' :
|
||||
{ 'help' : 'wait for a max of time secs for the' +
|
||||
' specified ports to become available,' +
|
||||
'if no ports are specified then those' +
|
||||
' specified on bridge-ports will be' +
|
||||
' used here. Specifying no ports here ' +
|
||||
'should not be used if we are using ' +
|
||||
'regex or \"all\" on bridge_ports,' +
|
||||
'as it wouldnt work.',
|
||||
'default' : '0',
|
||||
'example' : ['bridge-waitport 4 swp1 swp2']},
|
||||
'bridge-maxwait' :
|
||||
{ 'help' : 'forces to time seconds the maximum time ' +
|
||||
'that the Debian bridge setup scripts will ' +
|
||||
'wait for the bridge ports to get to the ' +
|
||||
'forwarding status, doesn\'t allow factional ' +
|
||||
'part. If it is equal to 0 then no waiting' +
|
||||
' is done',
|
||||
'default' : '0',
|
||||
'example' : ['bridge-maxwait 3']},
|
||||
'bridge-vlan' :
|
||||
{ 'help' : 'bridge vlans',
|
||||
'example' : ['bridge-vlan 4000']},
|
||||
'bridge-vlan-native' :
|
||||
{ 'compat' : True,
|
||||
'help' : 'bridge port vlan',
|
||||
'example' : ['bridge-vlan-native 1']},
|
||||
}}
|
||||
|
||||
def __init__(self, *args, **kargs):
|
||||
moduleBase.__init__(self, *args, **kargs)
|
||||
self.ipcmd = None
|
||||
self.brctlcmd = None
|
||||
|
||||
def _is_bridge_port(self, ifaceobj):
|
||||
if ifaceobj.get_attr_value_first('bridge'):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _is_bridge(self, ifaceobj):
|
||||
if ifaceobj.type == ifaceType.BRIDGE:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _is_bridge_vlan(self, ifaceobj):
|
||||
if ifaceobj.type & ifaceType.BRIDGE_VLAN:
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
|
||||
bridge = ifaceobj.get_attr_value_first('bridge')
|
||||
if bridge:
|
||||
match = re.match("^%s-([\d]+)" %bridge, ifaceobj.name)
|
||||
if match:
|
||||
ifaceobj.priv_data = int(match.groups()[0], 10)
|
||||
# XXX: mark this iface as a bridge_vlan iface
|
||||
ifaceobj.type = ifaceType.BRIDGE_VLAN
|
||||
return [bridge]
|
||||
elif ifaceobj.get_attr_value_first('type') == 'bridge':
|
||||
ifaceobj.type = ifaceType.BRIDGE
|
||||
return None
|
||||
|
||||
def get_dependent_ifacenames_running(self, ifaceobj):
|
||||
self._init_command_handlers()
|
||||
if not self.brctlcmd.bridge_exists(ifaceobj.name):
|
||||
return None
|
||||
return self.brctlcmd.get_bridge_ports(ifaceobj.name)
|
||||
|
||||
def _process_bridge_waitport(self, ifaceobj, portlist):
|
||||
waitport_value = ifaceobj.get_attr_value_first('bridge-waitport')
|
||||
if not waitport_value: return
|
||||
try:
|
||||
waitportvals = re.split(r'[\s\t]\s*', waitport_value, 1)
|
||||
if not waitportvals: return
|
||||
try:
|
||||
waitporttime = int(waitportvals[0])
|
||||
except:
|
||||
self.log_warn('%s: invalid waitport value \'%s\''
|
||||
%(ifaceobj.name, waitporttime))
|
||||
return
|
||||
if waitporttime <= 0: return
|
||||
try:
|
||||
waitportlist = self.parse_port_list(waitportvals[1])
|
||||
except IndexError, e:
|
||||
# ignore error and use all bridge ports
|
||||
waitportlist = portlist
|
||||
pass
|
||||
if not waitportlist: return
|
||||
self.logger.info('%s: waiting for ports %s to exist ...'
|
||||
%(ifaceobj.name, str(waitportlist)))
|
||||
starttime = time.time()
|
||||
while ((time.time() - starttime) < waitporttime):
|
||||
if all([False for p in waitportlist
|
||||
if not self.ipcmd.link_exists(p)]):
|
||||
break;
|
||||
time.sleep(1)
|
||||
except Exception, e:
|
||||
self.log_warn('%s: unable to process waitport: %s'
|
||||
%(ifaceobj.name, str(e)))
|
||||
|
||||
def _add_ports(self, ifaceobj):
|
||||
bridgeports = self._get_bridge_port_list(ifaceobj)
|
||||
runningbridgeports = []
|
||||
|
||||
self._process_bridge_waitport(ifaceobj, bridgeports)
|
||||
# Delete active ports not in the new port list
|
||||
if not self.PERFMODE:
|
||||
runningbridgeports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
|
||||
if runningbridgeports:
|
||||
[self.ipcmd.link_set(bport, 'nomaster')
|
||||
for bport in runningbridgeports
|
||||
if not bridgeports or bport not in bridgeports]
|
||||
else:
|
||||
runningbridgeports = []
|
||||
if not bridgeports:
|
||||
return
|
||||
err = 0
|
||||
for bridgeport in Set(bridgeports).difference(Set(runningbridgeports)):
|
||||
try:
|
||||
if not self.DRYRUN and not self.ipcmd.link_exists(bridgeport):
|
||||
self.log_warn('%s: bridge port %s does not exist'
|
||||
%(ifaceobj.name, bridgeport))
|
||||
err += 1
|
||||
continue
|
||||
self.ipcmd.link_set(bridgeport, 'master', ifaceobj.name)
|
||||
self.write_file('/proc/sys/net/ipv6/conf/%s' %bridgeport +
|
||||
'/disable_ipv6', '1')
|
||||
self.ipcmd.addr_flush(bridgeport)
|
||||
except Exception, e:
|
||||
self.log_error(str(e))
|
||||
if err:
|
||||
self.log_error('bridge configuration failed (missing ports)')
|
||||
|
||||
def _process_bridge_maxwait(self, ifaceobj, portlist):
|
||||
maxwait = ifaceobj.get_attr_value_first('bridge-maxwait')
|
||||
if not maxwait: return
|
||||
try:
|
||||
maxwait = int(maxwait)
|
||||
except:
|
||||
self.log_warn('%s: invalid maxwait value \'%s\'' %(ifaceobj.name,
|
||||
maxwait))
|
||||
return
|
||||
if not maxwait: return
|
||||
self.logger.info('%s: waiting for ports to go to fowarding state ..'
|
||||
%ifaceobj.name)
|
||||
try:
|
||||
starttime = time.time()
|
||||
while ((time.time() - starttime) < maxwait):
|
||||
if all([False for p in portlist
|
||||
if self.read_file_oneline(
|
||||
'/sys/class/net/%s/brif/%s/state'
|
||||
%(ifaceobj.name, p)) != '3']):
|
||||
break;
|
||||
time.sleep(1)
|
||||
except Exception, e:
|
||||
self.log_warn('%s: unable to process maxwait: %s'
|
||||
%(ifaceobj.name, str(e)))
|
||||
|
||||
def _ints_to_ranges(self, ints):
|
||||
for a, b in itertools.groupby(enumerate(ints), lambda (x, y): y - x):
|
||||
b = list(b)
|
||||
yield b[0][1], b[-1][1]
|
||||
|
||||
def _ranges_to_ints(self, rangelist):
|
||||
""" returns expanded list of integers given set of string ranges
|
||||
example: ['1', '2-4', '6'] returns [1, 2, 3, 4, 6]
|
||||
"""
|
||||
result = []
|
||||
for part in rangelist:
|
||||
if '-' in part:
|
||||
a, b = part.split('-')
|
||||
a, b = int(a), int(b)
|
||||
result.extend(range(a, b + 1))
|
||||
else:
|
||||
a = int(part)
|
||||
result.append(a)
|
||||
return result
|
||||
|
||||
def _diff_vids(self, vids1, vids2):
|
||||
vids_to_add = None
|
||||
vids_to_del = None
|
||||
|
||||
vids1_ints = self._ranges_to_ints(vids1)
|
||||
vids2_ints = self._ranges_to_ints(vids2)
|
||||
vids1_diff = Set(vids1_ints).difference(vids2_ints)
|
||||
vids2_diff = Set(vids2_ints).difference(vids1_ints)
|
||||
if vids1_diff:
|
||||
vids_to_add = ['%d' %start if start == end else '%d-%d' %(start, end)
|
||||
for start, end in self._ints_to_ranges(vids1_diff)]
|
||||
if vids2_diff:
|
||||
vids_to_del = ['%d' %start if start == end else '%d-%d' %(start, end)
|
||||
for start, end in self._ints_to_ranges(vids2_diff)]
|
||||
return (vids_to_del, vids_to_add)
|
||||
|
||||
def _compare_vids(self, vids1, vids2):
|
||||
""" Returns true if the vids are same else return false """
|
||||
|
||||
vids1_ints = self._ranges_to_ints(vids1)
|
||||
vids2_ints = self._ranges_to_ints(vids2)
|
||||
if Set(vids1_ints).symmetric_difference(vids2_ints):
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def _set_bridge_mcqv4src(self, ifaceobj):
|
||||
attrval = ifaceobj.get_attr_value_first('bridge-mcqv4src')
|
||||
if attrval:
|
||||
running_mcqv4src = {}
|
||||
if not self.PERFMODE:
|
||||
running_mcqv4src = self.brctlcmd.get_mcqv4src(ifaceobj.name)
|
||||
mcqs = {}
|
||||
srclist = attrval.split()
|
||||
for s in srclist:
|
||||
k, v = s.split('=')
|
||||
mcqs[k] = v
|
||||
|
||||
k_to_del = Set(running_mcqv4src.keys()).difference(mcqs.keys())
|
||||
for v in k_to_del:
|
||||
self.brctlcmd.del_mcqv4src(ifaceobj.name, int(v, 10))
|
||||
for v in mcqs.keys():
|
||||
self.brctlcmd.set_mcqv4src(ifaceobj.name, int(v, 10), mcqs[v])
|
||||
|
||||
def _set_bridge_vidinfo(self, ifaceobj, isbridge=True):
|
||||
# Handle bridge vlan attrs
|
||||
running_vidinfo = {}
|
||||
if not self.PERFMODE:
|
||||
running_vidinfo = self.ipcmd.bridge_port_vids_get_all()
|
||||
attrval = ifaceobj.get_attr_value_first('bridge-vlan')
|
||||
if attrval:
|
||||
vids = re.split(r'[\s\t]\s*', attrval)
|
||||
#vids = attrval.split(',')
|
||||
try:
|
||||
if running_vidinfo.get(ifaceobj.name):
|
||||
(vids_to_del, vids_to_add) = \
|
||||
self._diff_vids(vids,
|
||||
running_vidinfo.get(ifaceobj.name, {}).get('vlan'))
|
||||
if vids_to_del:
|
||||
self.ipcmd.bridge_vids_del(ifaceobj.name,
|
||||
vids_to_del, isbridge)
|
||||
if vids_to_add:
|
||||
self.ipcmd.bridge_vids_add(ifaceobj.name,
|
||||
vids_to_add, isbridge)
|
||||
else:
|
||||
self.ipcmd.bridge_vids_add(ifaceobj.name, vids,
|
||||
isbridge)
|
||||
except Exception, e:
|
||||
self.log_warn('%s: failed to set vid `%s` (%s)'
|
||||
%(ifaceobj.name, str(vids), str(e)))
|
||||
else:
|
||||
running_vids = running_vidinfo.get(ifaceobj.name, {}).get('vlan')
|
||||
if running_vids:
|
||||
self.ipcmd.bridge_vids_del(ifaceobj.name, running_vids)
|
||||
|
||||
# Install pvids
|
||||
pvid = ifaceobj.get_attr_value_first('bridge-vlan-native')
|
||||
if pvid:
|
||||
try:
|
||||
running_pvid = running_vidinfo.get(ifaceobj.name,
|
||||
{}).get('pvid')
|
||||
if running_pvid:
|
||||
if running_pvid != pvid:
|
||||
self.ipcmd.bridge_port_pvid_del(ifaceobj.name,
|
||||
running_pvid)
|
||||
self.ipcmd.bridge_port_pvid_add(ifaceobj.name, pvid)
|
||||
else:
|
||||
self.ipcmd.bridge_port_pvid_add(ifaceobj.name, pvid)
|
||||
except Exception, e:
|
||||
self.log_warn('%s: failed to set pvid `%s` (%s)'
|
||||
%(ifaceobj.name, pvid, str(e)))
|
||||
|
||||
def _apply_bridge_settings(self, ifaceobj):
|
||||
try:
|
||||
stp = ifaceobj.get_attr_value_first('bridge-stp')
|
||||
if stp:
|
||||
self.brctlcmd.set_stp(ifaceobj.name, stp)
|
||||
# Use the brctlcmd bulk set method: first build a dictionary
|
||||
# and then call set
|
||||
bridgeattrs = { k:v for k,v in
|
||||
{'ageing' :
|
||||
ifaceobj.get_attr_value_first('bridge-ageing'),
|
||||
'bridgeprio' :
|
||||
ifaceobj.get_attr_value_first(
|
||||
'bridge-bridgeprio'),
|
||||
'fd' :
|
||||
ifaceobj.get_attr_value_first('bridge-fd'),
|
||||
'gcint' :
|
||||
ifaceobj.get_attr_value_first('bridge-gcint'),
|
||||
'hello' :
|
||||
ifaceobj.get_attr_value_first('bridge-hello'),
|
||||
'maxage' :
|
||||
ifaceobj.get_attr_value_first('bridge-maxage'),
|
||||
'mclmc' :
|
||||
ifaceobj.get_attr_value_first('bridge-mclmc'),
|
||||
'mcrouter' :
|
||||
ifaceobj.get_attr_value_first(
|
||||
'bridge-mcrouter'),
|
||||
'mcsnoop' :
|
||||
ifaceobj.get_attr_value_first('bridge-mcsnoop'),
|
||||
'mcsqc' :
|
||||
ifaceobj.get_attr_value_first('bridge-mcsqc'),
|
||||
'mcqifaddr' :
|
||||
ifaceobj.get_attr_value_first(
|
||||
'bridge-mcqifaddr'),
|
||||
'mcquerier' :
|
||||
ifaceobj.get_attr_value_first(
|
||||
'bridge-mcquerier'),
|
||||
'hashel' :
|
||||
ifaceobj.get_attr_value_first('bridge-hashel'),
|
||||
'hashmax' :
|
||||
ifaceobj.get_attr_value_first('bridge-hashmax'),
|
||||
'mclmi' :
|
||||
ifaceobj.get_attr_value_first('bridge-mclmi'),
|
||||
'mcmi' :
|
||||
ifaceobj.get_attr_value_first('bridge-mcmi'),
|
||||
'mcqpi' :
|
||||
ifaceobj.get_attr_value_first('bridge-mcqpi'),
|
||||
'mcqi' :
|
||||
ifaceobj.get_attr_value_first('bridge-mcqi'),
|
||||
'mcqri' :
|
||||
ifaceobj.get_attr_value_first('bridge-mcqri'),
|
||||
'mcsqi' :
|
||||
ifaceobj.get_attr_value_first('bridge-mcsqi')
|
||||
}.items()
|
||||
if v }
|
||||
if bridgeattrs:
|
||||
self.brctlcmd.set_bridge_attrs(ifaceobj.name, bridgeattrs)
|
||||
self._set_bridge_vidinfo(ifaceobj)
|
||||
|
||||
self._set_bridge_mcqv4src(ifaceobj)
|
||||
|
||||
#self._process_bridge_maxwait(ifaceobj,
|
||||
# self._get_bridge_port_list(ifaceobj))
|
||||
except Exception, e:
|
||||
self.log_warn(str(e))
|
||||
|
||||
def _apply_bridge_port_settings(self, ifaceobj, bridge):
|
||||
try:
|
||||
# Use the brctlcmd bulk set method: first build a dictionary
|
||||
# and then call set
|
||||
portattrs = {}
|
||||
for attrname, dstattrname in {'bridge-pathcost' : 'pathcost',
|
||||
'bridge-prio' : 'portprio',
|
||||
'bridge-mcrouter' : 'portmcrouter',
|
||||
'bridge-mcfl' : 'portmcfl'}.items():
|
||||
attrval = ifaceobj.get_attr_value_first(attrname)
|
||||
if not attrval:
|
||||
continue
|
||||
portattrs[ifaceobj.name] = attrval
|
||||
self.brctlcmd.set_bridgeport_attrs(bridge, ifaceobj.name, portattrs)
|
||||
self._set_bridge_vidinfo(ifaceobj, isbridge=False)
|
||||
except Exception, e:
|
||||
self.log_warn(str(e))
|
||||
|
||||
def _apply_bridge_vlan_settings(self, ifaceobj, bridge):
|
||||
mcq = ifaceobj.get_attrs_value_first(['bridge-mcqv4src',
|
||||
'bridge-igmp-querier-src'])
|
||||
if mcq:
|
||||
running_mcq = None
|
||||
if not self.PERFMODE:
|
||||
running_mcq = self.brctlcmd.get_mcqv4src(bridge,
|
||||
vlan=ifaceobj.priv_data)
|
||||
if running_mcq != mcq:
|
||||
self.brctlcmd.set_mcqv4src(bridge, ifaceobj.priv_data, mcq)
|
||||
|
||||
self.ipcmd.bridge_vids_add(bridge, [ifaceobj.priv_data], True)
|
||||
|
||||
def _delete_bridge_vlan_settings(self, ifaceobj, bridge):
|
||||
# delete vlan from bridge
|
||||
self.ipcmd.bridge_vids_del(bridge, [ifaceobj.priv_data], True)
|
||||
|
||||
mcq = ifaceobj.get_attr_value_first('bridge-mcqv4src')
|
||||
if mcq:
|
||||
self.brctlcmd.del_mcqv4src(bridge, ifaceobj.name)
|
||||
|
||||
def _up_bridge(self, ifaceobj):
|
||||
try:
|
||||
if not self.PERFMODE:
|
||||
if not self.ipcmd.link_exists(ifaceobj.name):
|
||||
self.ipcmd.link_create(ifaceobj.name, 'bridge')
|
||||
else:
|
||||
self.ipcmd.link_create(ifaceobj.name, 'bridge')
|
||||
self._apply_bridge_settings(ifaceobj)
|
||||
except Exception, e:
|
||||
self.log_error(str(e))
|
||||
|
||||
def _up_bridge_port(self, ifaceobj, bridge):
|
||||
try:
|
||||
self.ipcmd.link_set(ifaceobj.name, 'master', bridge)
|
||||
self._apply_bridge_port_settings(ifaceobj, bridge)
|
||||
except Exception, e:
|
||||
self.log_error(str(e))
|
||||
|
||||
def _up_bridge_vlan(self, ifaceobj, bridge):
|
||||
purge_existing = False if self.PERFMODE else True
|
||||
try:
|
||||
address = ifaceobj.get_attr_value('address')
|
||||
if address:
|
||||
# Create a vlan device,
|
||||
ifacename = '%s.%s' %(bridge, ifaceobj.priv_data)
|
||||
if not self.ipcmd.link_exists(ifacename):
|
||||
self.ipcmd.link_create_vlan(ifacename, bridge,
|
||||
ifaceobj.priv_data)
|
||||
purge_existing = False
|
||||
hwaddress = ifaceobj.get_attr_value_first('hwaddress')
|
||||
if hwaddress:
|
||||
self.ipcmd.link_set_hwaddress(ifacename, hwaddress)
|
||||
self.ipcmd.addr_add_multiple(ifacename, address, purge_existing)
|
||||
self._apply_bridge_vlan_settings(ifaceobj, bridge)
|
||||
except Exception, e:
|
||||
self.log_error(str(e))
|
||||
|
||||
def _up(self, ifaceobj):
|
||||
bridge = ifaceobj.get_attr_value_first('bridge')
|
||||
if ifaceobj.type == ifaceType.BRIDGE_VLAN:
|
||||
self._up_bridge_vlan(ifaceobj, bridge)
|
||||
elif bridge:
|
||||
self._up_bridge_port(ifaceobj, bridge)
|
||||
elif self._is_bridge(ifaceobj):
|
||||
self._up_bridge(ifaceobj)
|
||||
else:
|
||||
# Was this interface part of the bridge at some point and now
|
||||
# got removed ?. If we attached it to the bridge last time
|
||||
# we should release it
|
||||
if os.path.exists('/sys/class/net/%s/brport' %ifaceobj.name):
|
||||
bridgelink = os.readlink('/sys/class/net/%s/brport/bridge'
|
||||
%ifaceobj.name)
|
||||
if bridgelink:
|
||||
bridge = os.path.basename(bridgelink)
|
||||
if (not ifaceobj.upperifaces or
|
||||
bridge not in ifaceobj.upperifaces):
|
||||
# set nomaster
|
||||
self.ipcmd.link_set(ifaceobj.name, 'nomaster')
|
||||
|
||||
def _down_bridge(self, ifaceobj):
|
||||
try:
|
||||
self.brctlcmd.delete_bridge(ifaceobj.name)
|
||||
except Exception, e:
|
||||
self.log_error(str(e))
|
||||
|
||||
def _down_bridge_port(self, ifaceobj):
|
||||
self.ipcmd.link_set(ifaceobj.name, 'nomaster')
|
||||
|
||||
def _down_bridge_vlan(self, ifaceobj, bridge):
|
||||
try:
|
||||
address = ifaceobj.get_attr_value('address')
|
||||
if address:
|
||||
# Create a vlan device,
|
||||
ifacename = '%s.%s' %(bridge, ifaceobj.priv_data)
|
||||
self.ipcmd.link_delete(ifacename)
|
||||
self._delete_bridge_vlan_settings(ifaceobj, bridge)
|
||||
except Exception, e:
|
||||
self.log_error(str(e))
|
||||
|
||||
def _down(self, ifaceobj):
|
||||
bridge = ifaceobj.get_attr_value_first('bridge')
|
||||
if ifaceobj.type == ifaceType.BRIDGE_VLAN:
|
||||
self._down_bridge_vlan(ifaceobj, bridge)
|
||||
elif bridge:
|
||||
self._down_bridge_port(ifaceobj)
|
||||
elif self._is_bridge(ifaceobj):
|
||||
self._down_bridge(ifaceobj)
|
||||
|
||||
def _query_running_vidinfo(self, ifaceobjrunning, ports):
|
||||
running_attrs = {}
|
||||
running_vidinfo = self.ipcmd.bridge_port_vids_get_all()
|
||||
|
||||
if ports:
|
||||
running_bridge_port_vids = ''
|
||||
for p in ports:
|
||||
try:
|
||||
running_vids = running_vidinfo.get(p, {}).get('vlan')
|
||||
if running_vids:
|
||||
running_bridge_port_vids += ' %s=%s' %(p,
|
||||
','.join(running_vids))
|
||||
except Exception:
|
||||
pass
|
||||
running_attrs['bridge-port-vids'] = running_bridge_port_vids
|
||||
|
||||
running_bridge_port_pvids = ''
|
||||
for p in ports:
|
||||
try:
|
||||
running_pvids = running_vidinfo.get(p, {}).get('pvid')
|
||||
if running_pvids:
|
||||
running_bridge_port_pvids += ' %s=%s' %(p,
|
||||
running_pvids)
|
||||
except Exception:
|
||||
pass
|
||||
running_attrs['bridge-port-pvids'] = running_bridge_port_pvids
|
||||
|
||||
running_bridge_vids = running_vidinfo.get(ifaceobjrunning.name, {}).get('vlan')
|
||||
if running_bridge_vids:
|
||||
running_attrs['bridge-vids'] = ','.join(running_bridge_vids)
|
||||
return running_attrs
|
||||
|
||||
def _query_running_mcqv4src(self, ifaceobjrunning):
|
||||
running_mcqv4src = self.brctlcmd.get_mcqv4src(ifaceobjrunning.name)
|
||||
mcqs = ['%s=%s' %(v, i) for v, i in running_mcqv4src.items()]
|
||||
mcqs.sort()
|
||||
mcq = ' '.join(mcqs)
|
||||
return mcq
|
||||
|
||||
def _query_running_attrs(self, ifaceobjrunning):
|
||||
bridgeattrdict = {}
|
||||
userspace_stp = 0
|
||||
ports = None
|
||||
skip_kernel_stp_attrs = 0
|
||||
|
||||
if self.sysctl_get('net.bridge.bridge-stp-user-space') == '1':
|
||||
userspace_stp = 1
|
||||
|
||||
tmpbridgeattrdict = self.brctlcmd.get_bridge_attrs(ifaceobjrunning.name)
|
||||
if not tmpbridgeattrdict:
|
||||
self.logger.warn('%s: unable to get bridge attrs'
|
||||
%ifaceobjrunning.name)
|
||||
return bridgeattrdict
|
||||
|
||||
# Fill bridge_ports and bridge stp attributes first
|
||||
ports = tmpbridgeattrdict.get('ports')
|
||||
if ports:
|
||||
bridgeattrdict['bridge-ports'] = [' '.join(ports.keys())]
|
||||
stp = tmpbridgeattrdict.get('stp', 'no')
|
||||
if stp != self.get_mod_subattr('bridge-stp', 'default'):
|
||||
bridgeattrdict['bridge-stp'] = [stp]
|
||||
|
||||
if stp == 'yes' and userspace_stp:
|
||||
skip_kernel_stp_attrs = 1
|
||||
|
||||
# pick all other attributes
|
||||
for k,v in tmpbridgeattrdict.items():
|
||||
if not v:
|
||||
continue
|
||||
if k == 'ports' or k == 'stp':
|
||||
continue
|
||||
|
||||
if skip_kernel_stp_attrs and k[:2] != 'mc':
|
||||
# only include igmp attributes if kernel stp is off
|
||||
continue
|
||||
attrname = 'bridge-' + k
|
||||
if v != self.get_mod_subattr(attrname, 'default'):
|
||||
bridgeattrdict[attrname] = [v]
|
||||
|
||||
bridgevidinfo = self._query_running_vidinfo(ifaceobjrunning, ports)
|
||||
if bridgevidinfo:
|
||||
bridgeattrdict.update({k : [v] for k, v in bridgevidinfo.items()
|
||||
if v})
|
||||
|
||||
mcq = self._query_running_mcqv4src(ifaceobjrunning)
|
||||
if mcq:
|
||||
bridgeattrdict['bridge-mcqv4src'] = [mcq]
|
||||
|
||||
if skip_kernel_stp_attrs:
|
||||
return bridgeattrdict
|
||||
|
||||
if ports:
|
||||
portconfig = {'bridge-pathcosts' : '',
|
||||
'bridge-portprios' : ''}
|
||||
for p, v in ports.items():
|
||||
v = self.brctlcmd.get_pathcost(ifaceobjrunning.name, p)
|
||||
if v and v != self.get_mod_subattr('bridge-pathcosts',
|
||||
'default'):
|
||||
portconfig['bridge-pathcosts'] += ' %s=%s' %(p, v)
|
||||
|
||||
v = self.brctlcmd.get_portprio(ifaceobjrunning.name, p)
|
||||
if v and v != self.get_mod_subattr('bridge-portprios',
|
||||
'default'):
|
||||
portconfig['bridge-portprios'] += ' %s=%s' %(p, v)
|
||||
|
||||
bridgeattrdict.update({k : [v] for k, v in portconfig.items()
|
||||
if v})
|
||||
|
||||
return bridgeattrdict
|
||||
|
||||
def _query_check_mcqv4src(self, ifaceobj, ifaceobjcurr):
|
||||
running_mcqs = self._query_running_mcqv4src(ifaceobj)
|
||||
attrval = ifaceobj.get_attr_value_first('bridge-mcqv4src')
|
||||
if attrval:
|
||||
mcqs = attrval.split()
|
||||
mcqs.sort()
|
||||
mcqsout = ' '.join(mcqs)
|
||||
ifaceobjcurr.update_config_with_status('bridge-mcqv4src',
|
||||
running_mcqs, 1 if running_mcqs != mcqsout else 0)
|
||||
|
||||
def _query_check_vidinfo(self, ifaceobj, ifaceobjcurr):
|
||||
|
||||
err = 0
|
||||
running_vidinfo = self.ipcmd.bridge_port_vids_get_all()
|
||||
attrval = ifaceobj.get_attr_value_first('bridge-port-vids')
|
||||
if attrval:
|
||||
running_bridge_port_vids = ''
|
||||
portlist = self.parse_port_list(attrval)
|
||||
if not portlist:
|
||||
self.log_warn('%s: could not parse \'%s %s\''
|
||||
%(ifaceobj.name, attrname, attrval))
|
||||
return
|
||||
err = 0
|
||||
for p in portlist:
|
||||
try:
|
||||
(port, val) = p.split('=')
|
||||
vids = val.split(',')
|
||||
running_vids = running_vidinfo.get(port, {}).get('vlan')
|
||||
if running_vids:
|
||||
if not self._compare_vids(vids, running_vids):
|
||||
err += 1
|
||||
running_bridge_port_vids += ' %s=%s' %(port,
|
||||
','.join(running_vids))
|
||||
else:
|
||||
running_bridge_port_vids += ' %s' %p
|
||||
else:
|
||||
err += 1
|
||||
except Exception, e:
|
||||
self.log_warn('%s: failure checking vid %s (%s)'
|
||||
%(ifaceobj.name, p, str(e)))
|
||||
if err:
|
||||
ifaceobjcurr.update_config_with_status('bridge-port-vids',
|
||||
running_bridge_port_vids, 1)
|
||||
else:
|
||||
ifaceobjcurr.update_config_with_status('bridge-port-vids',
|
||||
attrval, 0)
|
||||
|
||||
# Install pvids
|
||||
attrval = ifaceobj.get_attr_value_first('bridge-port-pvids')
|
||||
if attrval:
|
||||
portlist = self.parse_port_list(attrval)
|
||||
if not portlist:
|
||||
self.log_warn('%s: could not parse \'%s %s\''
|
||||
%(ifaceobj.name, attrname, attrval))
|
||||
return
|
||||
running_bridge_port_pvids = ''
|
||||
err = 0
|
||||
for p in portlist:
|
||||
try:
|
||||
(port, pvid) = p.split('=')
|
||||
running_pvid = running_vidinfo.get(port, {}).get('pvid')
|
||||
if running_pvid and running_pvid == pvid:
|
||||
running_bridge_port_pvids += ' %s' %p
|
||||
else:
|
||||
err += 1
|
||||
running_bridge_port_pvids += ' %s=%s' %(port,
|
||||
running_pvid)
|
||||
except Exception, e:
|
||||
self.log_warn('%s: failure checking pvid %s (%s)'
|
||||
%(ifaceobj.name, pvid, str(e)))
|
||||
if err:
|
||||
ifaceobjcurr.update_config_with_status('bridge-port-pvids',
|
||||
running_bridge_port_pvids, 1)
|
||||
else:
|
||||
ifaceobjcurr.update_config_with_status('bridge-port-pvids',
|
||||
running_bridge_port_pvids, 0)
|
||||
|
||||
attrval = ifaceobj.get_attr_value_first('bridge-vids')
|
||||
if attrval:
|
||||
vids = re.split(r'[\s\t]\s*', attrval)
|
||||
running_vids = running_vidinfo.get(ifaceobj.name, {}).get('vlan')
|
||||
if running_vids:
|
||||
if self._compare_vids(vids, running_vids):
|
||||
ifaceobjcurr.update_config_with_status('bridge-vids',
|
||||
attrval, 0)
|
||||
else:
|
||||
ifaceobjcurr.update_config_with_status('bridge-vids',
|
||||
','.join(running_vids), 1)
|
||||
else:
|
||||
ifaceobjcurr.update_config_with_status('bridge-vids', attrval,
|
||||
1)
|
||||
|
||||
def _query_check_bridge(self, ifaceobj, ifaceobjcurr):
|
||||
return
|
||||
|
||||
def _query_check_bridge_port(self, ifaceobj, bridge, ifaceobjcurr):
|
||||
return
|
||||
|
||||
def _query_check_bridge_vlan(self, ifaceobj, bridge, ifaceobjcurr):
|
||||
return
|
||||
|
||||
def _query_check(self, ifaceobj, ifaceobjcurr):
|
||||
bridge = ifaceobj.get_attr_value_first('bridge')
|
||||
if ifaceobj.type == ifaceType.BRIDGE_VLAN:
|
||||
self._query_check_bridge_vlan(ifaceobj, bridge, ifaceobjcurr)
|
||||
elif bridge:
|
||||
self._query_check_bridge_port(ifaceobj, bridge, ifaceobjcurr)
|
||||
elif self._is_bridge(ifaceobj):
|
||||
self._query_check_bridge(ifaceobj, ifaceobjcurr)
|
||||
|
||||
def _query_running(self, ifaceobjrunning):
|
||||
return
|
||||
|
||||
_run_ops = {'pre-up' : _up,
|
||||
'post-down' : _down,
|
||||
'query-checkcurr' : _query_check,
|
||||
'query-running' : _query_running}
|
||||
|
||||
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.brctlcmd:
|
||||
self.brctlcmd = brctl(**flags)
|
||||
|
||||
def run(self, ifaceobj, operation, query_ifaceobj=None):
|
||||
""" run bridge configuration on the interface object passed as
|
||||
argument. Can create bridge interfaces if they dont exist already
|
||||
|
||||
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)
|
@@ -321,6 +321,7 @@ class ifenslave(moduleBase):
|
||||
self.ifenslavecmd.get_lacp_fallback_period(bondname),
|
||||
'bond-lacp-fallback-priority' :
|
||||
self.ifenslavecmd.get_lacp_fallback_priority(bondname)}
|
||||
|
||||
slaves = self.ifenslavecmd.get_slaves(bondname)
|
||||
if slaves:
|
||||
bondattrs['bond-slaves'] = slaves
|
||||
|
@@ -30,6 +30,9 @@ class vlan(moduleBase):
|
||||
moduleBase.__init__(self, *args, **kargs)
|
||||
self.ipcmd = None
|
||||
self._bridge_vids_query_cache = {}
|
||||
self._resv_vlan_range = self._get_reserved_vlan_range()
|
||||
self.logger.debug('%s: using reserved vlan range %s'
|
||||
%(self.__class__.__name__, str(self._resv_vlan_range)))
|
||||
|
||||
def _is_vlan_device(self, ifaceobj):
|
||||
vlan_raw_device = ifaceobj.get_attr_value_first('vlan-raw-device')
|
||||
@@ -198,6 +201,7 @@ class vlan(moduleBase):
|
||||
if not self.ipcmd:
|
||||
self.ipcmd = iproute2(**self.get_flags())
|
||||
|
||||
|
||||
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
|
||||
""" run vlan configuration on the interface object passed as argument
|
||||
|
||||
|
@@ -13,12 +13,21 @@ template_lookuppath=/etc/network/ifupdown2/templates
|
||||
# Support /etc/network/if-*/ scripts
|
||||
addon_scripts_support=0
|
||||
|
||||
# By defauly ifupdown2 only supports a single vlan filtering bridge
|
||||
# on the system. Set this flag to 1 to support multiple vlan
|
||||
# filtering bridges
|
||||
multiple_vlan_aware_bridge_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.
|
||||
#
|
||||
# ifquery_check_success_str=
|
||||
# ifquery_check_error_str=(x)
|
||||
#
|
||||
|
||||
# check_success_str=
|
||||
# check_error_str=(x)
|
||||
# This attribute controls iface/vlan range expansions
|
||||
# in ifquery default output.
|
||||
ifquery_ifacename_expand_range=0
|
||||
|
||||
multiple_vlan_aware_bridge_support=0
|
||||
|
@@ -18,10 +18,9 @@ import logging
|
||||
import json
|
||||
|
||||
class ifaceType():
|
||||
UNKNOWN = 0x1
|
||||
GENERIC = 0x2
|
||||
BRIDGE = 0x3
|
||||
BRIDGE_VLAN = 0x4
|
||||
UNKNOWN = 0x0
|
||||
IFACE = 0x1
|
||||
BRIDGE_VLAN = 0x2
|
||||
|
||||
class ifaceStatus():
|
||||
"""Enumerates iface status """
|
||||
@@ -180,6 +179,8 @@ class iface():
|
||||
# flag to indicate that the object was created from pickled state
|
||||
_PICKLED = 0x1
|
||||
HAS_SIBLINGS = 0x2
|
||||
IFACERANGE_ENTRY = 0x3
|
||||
IFACERANGE_START = 0x4
|
||||
|
||||
version = '0.1'
|
||||
|
||||
@@ -214,7 +215,7 @@ class iface():
|
||||
self.type = ifaceType.UNKNOWN
|
||||
"""interface type"""
|
||||
self.priv_data = None
|
||||
self.real_name = None
|
||||
self.realname = None
|
||||
|
||||
def _set_attrs_from_dict(self, attrdict):
|
||||
self.auto = attrdict.get('auto', False)
|
||||
@@ -436,15 +437,20 @@ class iface():
|
||||
logger.info('}')
|
||||
|
||||
def dump_pretty(self, with_status=False,
|
||||
successstr='success', errorstr='error'):
|
||||
successstr='success', errorstr='error',
|
||||
use_realname=False):
|
||||
indent = '\t'
|
||||
outbuf = ''
|
||||
if self.auto:
|
||||
outbuf += 'auto %s\n' %self.name
|
||||
if self.type == ifaceType.BRIDGE_VLAN:
|
||||
outbuf += 'vlan %s' %self.name
|
||||
if use_realname:
|
||||
name = self.realname
|
||||
else:
|
||||
outbuf += 'iface %s' %self.name
|
||||
name = self.name
|
||||
if self.auto:
|
||||
outbuf += 'auto %s\n' %name
|
||||
if self.type == ifaceType.BRIDGE_VLAN:
|
||||
outbuf += 'vlan %s' %name
|
||||
else:
|
||||
outbuf += 'iface %s' %name
|
||||
if self.addr_family:
|
||||
outbuf += ' %s' %self.addr_family
|
||||
if self.addr_method:
|
||||
|
@@ -165,6 +165,8 @@ class ifupdownMain(ifupdownBase):
|
||||
self.config = config
|
||||
self.logger.debug(self.config)
|
||||
|
||||
self.type = ifaceType.UNKNOWN
|
||||
|
||||
# Can be used to provide hints for caching
|
||||
self.CACHE_FLAGS = 0x0
|
||||
self._DELETE_DEPENDENT_IFACES_WITH_NOCONFIG = False
|
||||
@@ -348,7 +350,7 @@ class ifupdownMain(ifupdownBase):
|
||||
for d in del_list:
|
||||
dlist.remove(d)
|
||||
|
||||
def query_dependents(self, ifaceobj, ops, ifacenames):
|
||||
def query_dependents(self, ifaceobj, ops, ifacenames, type=None):
|
||||
""" Gets iface dependents by calling into respective modules """
|
||||
ret_dlist = []
|
||||
|
||||
@@ -742,8 +744,17 @@ class ifupdownMain(ifupdownBase):
|
||||
traceback.print_tb(t)
|
||||
self.logger.warning('error saving state (%s)' %str(e))
|
||||
|
||||
def set_type(self, type):
|
||||
if type == 'iface':
|
||||
self.type = ifaceType.IFACE
|
||||
elif type == 'vlan':
|
||||
self.type = ifaceType.BRIDGE_VLAN
|
||||
else:
|
||||
self.type = ifaceType.UNKNOWN
|
||||
|
||||
def up(self, ops, auto=False, allow_classes=None, ifacenames=None,
|
||||
excludepats=None, printdependency=None, syntaxcheck=False):
|
||||
excludepats=None, printdependency=None, syntaxcheck=False,
|
||||
type=None):
|
||||
"""This brings the interface(s) up
|
||||
|
||||
Args:
|
||||
@@ -758,6 +769,8 @@ class ifupdownMain(ifupdownBase):
|
||||
syntaxcheck (bool): only perform syntax check
|
||||
"""
|
||||
|
||||
self.set_type(type)
|
||||
|
||||
if allow_classes:
|
||||
self.IFACE_CLASS = True
|
||||
if not self.ADDONS_ENABLE: self.STATEMANAGER_UPDATE = False
|
||||
@@ -800,9 +813,12 @@ class ifupdownMain(ifupdownBase):
|
||||
self._save_state()
|
||||
|
||||
def down(self, ops, auto=False, allow_classes=None, ifacenames=None,
|
||||
excludepats=None, printdependency=None, usecurrentconfig=False):
|
||||
excludepats=None, printdependency=None, usecurrentconfig=False,
|
||||
type=None):
|
||||
""" down an interface """
|
||||
|
||||
self.set_type(type)
|
||||
|
||||
if allow_classes:
|
||||
self.IFACE_CLASS = True
|
||||
if not self.ADDONS_ENABLE: self.STATEMANAGER_UPDATE = False
|
||||
@@ -858,9 +874,11 @@ class ifupdownMain(ifupdownBase):
|
||||
|
||||
def query(self, ops, auto=False, allow_classes=None, ifacenames=None,
|
||||
excludepats=None, printdependency=None,
|
||||
format='native'):
|
||||
format='native', type=None):
|
||||
""" query an interface """
|
||||
|
||||
self.set_type(type)
|
||||
|
||||
if allow_classes:
|
||||
self.IFACE_CLASS = True
|
||||
if self.STATEMANAGER_ENABLE and ops[0] == 'query-savedstate':
|
||||
@@ -902,8 +920,6 @@ class ifupdownMain(ifupdownBase):
|
||||
raise Exception('no ifaces found matching ' +
|
||||
'given allow lists')
|
||||
|
||||
# Roopa
|
||||
#self.populate_dependency_info(ops, filtered_ifacenames)
|
||||
self.populate_dependency_info(ops)
|
||||
if ops[0] == 'query-dependency' and printdependency:
|
||||
self.print_dependency(filtered_ifacenames, printdependency)
|
||||
@@ -925,16 +941,87 @@ class ifupdownMain(ifupdownBase):
|
||||
self.print_ifaceobjsrunning_pretty(filtered_ifacenames, format)
|
||||
return
|
||||
|
||||
def reload(self, upops, downops, auto=False, allow=None,
|
||||
ifacenames=None, excludepats=None, usecurrentconfig=False):
|
||||
""" reload interface config """
|
||||
def _reload_currentlyup(self, upops, downops, auto=True, allow=None,
|
||||
ifacenames=None, excludepats=None, usecurrentconfig=False,
|
||||
**extra_args):
|
||||
""" reload currently up interfaces """
|
||||
allow_classes = []
|
||||
new_ifaceobjdict = {}
|
||||
|
||||
self.logger.debug('reloading interface config ..')
|
||||
if auto:
|
||||
self.ALL = True
|
||||
self.WITH_DEPENDS = True
|
||||
# Override auto to true
|
||||
auto = True
|
||||
|
||||
try:
|
||||
self.read_iface_config()
|
||||
except:
|
||||
raise
|
||||
|
||||
if not self.ifaceobjdict:
|
||||
self.logger.warn("nothing to reload ..exiting.")
|
||||
return
|
||||
|
||||
already_up_ifacenames = []
|
||||
# generate dependency graph of interfaces
|
||||
self.populate_dependency_info(upops)
|
||||
if (not usecurrentconfig and self.STATEMANAGER_ENABLE
|
||||
and self.statemanager.ifaceobjdict):
|
||||
already_up_ifacenames = self.statemanager.ifaceobjdict.keys()
|
||||
|
||||
if not ifacenames: ifacenames = self.ifaceobjdict.keys()
|
||||
filtered_ifacenames = [i for i in ifacenames
|
||||
if self._iface_whitelisted(auto, allow_classes,
|
||||
excludepats, i)]
|
||||
|
||||
# Get already up interfaces that still exist in the interfaces file
|
||||
already_up_ifacenames_not_present = Set(
|
||||
already_up_ifacenames).difference(ifacenames)
|
||||
already_up_ifacenames_still_present = Set(
|
||||
already_up_ifacenames).difference(
|
||||
already_up_ifacenames_not_present)
|
||||
interfaces_to_up = Set(already_up_ifacenames_still_present).union(
|
||||
filtered_ifacenames)
|
||||
|
||||
if (already_up_ifacenames_not_present and
|
||||
self.config.get('ifreload_currentlyup_down_notpresent') == '1'):
|
||||
self.logger.info('reload: schedule down on interfaces: %s'
|
||||
%str(already_up_ifacenames_not_present))
|
||||
|
||||
# Save a copy of new iface objects and dependency_graph
|
||||
new_ifaceobjdict = dict(self.ifaceobjdict)
|
||||
new_dependency_graph = dict(self.dependency_graph)
|
||||
|
||||
# old interface config is read into self.ifaceobjdict
|
||||
self.read_old_iface_config()
|
||||
|
||||
# reinitialize dependency graph
|
||||
self.dependency_graph = OrderedDict({})
|
||||
self.populate_dependency_info(downops,
|
||||
already_up_ifacenames_not_present)
|
||||
self._sched_ifaces(already_up_ifacenames_not_present, downops)
|
||||
else:
|
||||
self.logger.debug('no interfaces to down ..')
|
||||
|
||||
# Now, run 'up' with new config dict
|
||||
# reset statemanager update flag to default
|
||||
if new_ifaceobjdict:
|
||||
self.ifaceobjdict = new_ifaceobjdict
|
||||
self.dependency_graph = new_dependency_graph
|
||||
|
||||
if not self.ifaceobjdict:
|
||||
return
|
||||
self.logger.info('reload: scheduling up on interfaces: %s'
|
||||
%str(interfaces_to_up))
|
||||
self._sched_ifaces(interfaces_to_up, upops)
|
||||
if self.DRYRUN:
|
||||
return
|
||||
self._save_state()
|
||||
|
||||
def _reload_default(self, upops, downops, auto=False, allow=None,
|
||||
ifacenames=None, excludepats=None, usecurrentconfig=False,
|
||||
**extra_args):
|
||||
""" reload interface config """
|
||||
allow_classes = []
|
||||
new_ifaceobjdict = {}
|
||||
|
||||
try:
|
||||
self.read_iface_config()
|
||||
@@ -975,7 +1062,8 @@ class ifupdownMain(ifupdownBase):
|
||||
# config
|
||||
#
|
||||
ifacedownlist = []
|
||||
for ifname, lastifaceobjlist in self.ifaceobjdict.items():
|
||||
for ifname in filtered_ifacenames:
|
||||
lastifaceobjlist = self.ifaceobjdict.get(ifname)
|
||||
objidx = 0
|
||||
# If interface is not present in the new file
|
||||
# append it to the down list
|
||||
@@ -997,7 +1085,7 @@ class ifupdownMain(ifupdownBase):
|
||||
continue
|
||||
|
||||
if ifacedownlist:
|
||||
self.logger.info('Executing down on interfaces: %s'
|
||||
self.logger.info('reload: scheduling down on interfaces: %s'
|
||||
%str(ifacedownlist))
|
||||
# reinitialize dependency graph
|
||||
self.dependency_graph = OrderedDict({})
|
||||
@@ -1018,13 +1106,25 @@ class ifupdownMain(ifupdownBase):
|
||||
if self._iface_whitelisted(auto, allow_classes,
|
||||
excludepats, i)]
|
||||
|
||||
self.logger.info('Scheduling up on interfaces: %s'
|
||||
self.logger.info('reload: scheduling up on interfaces: %s'
|
||||
%str(filtered_ifacenames))
|
||||
self._sched_ifaces(filtered_ifacenames, upops)
|
||||
if self.DRYRUN:
|
||||
return
|
||||
self._save_state()
|
||||
|
||||
def reload(self, *args, **kargs):
|
||||
""" reload interface config """
|
||||
if kargs.get('auto', False):
|
||||
self.ALL = True
|
||||
self.WITH_DEPENDS = True
|
||||
|
||||
self.logger.debug('reloading interface config ..')
|
||||
if kargs.get('currentlyup', False):
|
||||
self._reload_currentlyup(*args, **kargs)
|
||||
else:
|
||||
self._reload_default(*args, **kargs)
|
||||
|
||||
def _pretty_print_ordered_dict(self, prefix, argdict):
|
||||
outbuf = prefix + ' {\n'
|
||||
for k, vlist in argdict.items():
|
||||
@@ -1085,7 +1185,14 @@ class ifupdownMain(ifupdownBase):
|
||||
print json.dumps(ifaceobjs, cls=ifaceJsonEncoder,
|
||||
indent=4, separators=(',', ': '))
|
||||
else:
|
||||
map(lambda i: i.dump_pretty(), ifaceobjs)
|
||||
expand = int(self.config.get('ifquery_ifacename_expand_range', '0'))
|
||||
for i in ifaceobjs:
|
||||
if not expand and (i.flags & iface.IFACERANGE_ENTRY):
|
||||
# print only the first one
|
||||
if i.flags & iface.IFACERANGE_START:
|
||||
i.dump_pretty(use_realname=True)
|
||||
else:
|
||||
i.dump_pretty()
|
||||
|
||||
def _get_ifaceobjscurr_pretty(self, ifacenames, ifaceobjs):
|
||||
ret = 0
|
||||
@@ -1122,9 +1229,9 @@ class ifupdownMain(ifupdownBase):
|
||||
separators=(',', ': '))
|
||||
else:
|
||||
map(lambda i: i.dump_pretty(with_status=True,
|
||||
successstr=self.config.get('check_success_str',
|
||||
successstr=self.config.get('ifquery_check_success_str',
|
||||
_success_sym),
|
||||
errorstr=self.config.get('check_error_str', _error_sym)),
|
||||
errorstr=self.config.get('ifquery_check_error_str', _error_sym)),
|
||||
ifaceobjs)
|
||||
return ret
|
||||
|
||||
|
@@ -266,8 +266,11 @@ class networkInterfaces():
|
||||
if range_val:
|
||||
for v in range(range_val[1], range_val[2]):
|
||||
ifaceobj_new = copy.deepcopy(ifaceobj)
|
||||
ifaceobj_new.real_name = ifaceobj.name
|
||||
ifaceobj_new.realname = ifaceobj.name
|
||||
ifaceobj_new.name = "%s%d" %(range_val[0], v)
|
||||
ifaceobj_new.flags |= iface.IFACERANGE_ENTRY
|
||||
if v == range_val[1]:
|
||||
ifaceobj_new.flags |= iface.IFACERANGE_START
|
||||
self.callbacks.get('iface_found')(ifaceobj_new)
|
||||
else:
|
||||
self.callbacks.get('iface_found')(ifaceobj)
|
||||
@@ -282,9 +285,12 @@ class networkInterfaces():
|
||||
if range_val:
|
||||
for v in range(range_val[1], range_val[2]):
|
||||
ifaceobj_new = copy.deepcopy(ifaceobj)
|
||||
ifaceobj_new.real_name = ifaceobj.name
|
||||
ifaceobj_new.realname = ifaceobj.name
|
||||
ifaceobj_new.name = "%s%d" %(range_val[0], v)
|
||||
ifaceobj_new.type = ifaceType.BRIDGE_VLAN
|
||||
ifaceobj_new.flags |= iface.IFACERANGE_ENTRY
|
||||
if v == range_val[1]:
|
||||
ifaceobj_new.flags |= iface.IFACERANGE_START
|
||||
self.callbacks.get('iface_found')(ifaceobj_new)
|
||||
else:
|
||||
ifaceobj.type = ifaceType.BRIDGE_VLAN
|
||||
|
@@ -43,6 +43,9 @@ class ifaceScheduler():
|
||||
""" Runs sub operation on an interface """
|
||||
ifacename = ifaceobj.name
|
||||
|
||||
if ifupdownobj.type and ifupdownobj.type != ifaceobj.Type:
|
||||
return
|
||||
|
||||
if (cls._STATE_CHECK and
|
||||
(ifaceobj.state >= ifaceState.from_str(op))):
|
||||
ifupdownobj.logger.debug('%s: already in state %s' %(ifacename, op))
|
||||
@@ -151,27 +154,6 @@ class ifaceScheduler():
|
||||
not ifupdownobj.ALL)):
|
||||
return True
|
||||
|
||||
if ifaceobj.type == ifaceType.BRIDGE:
|
||||
#
|
||||
# XXX: This function's job is to return True for
|
||||
# logical devices when any of the upperifaces are still around.
|
||||
# In the new model, where bridge is represented as a dependency
|
||||
# for a bridge port, bridge becomes a lowerdevice of a bridge port,
|
||||
# which is not really true. To handle this case, add a special
|
||||
# check for bridge device. Will figure out a better way to handle
|
||||
# this.
|
||||
# Long term this function should be replaced by
|
||||
# walking the sysfs links to upper and lower device available in
|
||||
# latest kernels.
|
||||
try:
|
||||
if os.listdir('/sys/class/net/%s/brif' %ifaceobj.name):
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
except Exception:
|
||||
pass
|
||||
return True
|
||||
|
||||
ulist = ifaceobj.upperifaces
|
||||
if not ulist:
|
||||
return True
|
||||
|
@@ -320,3 +320,13 @@ class moduleBase(object):
|
||||
return dict(force=self.FORCE, dryrun=self.DRYRUN, nowait=self.NOWAIT,
|
||||
perfmode=self.PERFMODE, cache=self.CACHE,
|
||||
cacheflags=self.CACHE_FLAGS)
|
||||
|
||||
def _get_reserved_vlan_range(self):
|
||||
start = end = 0
|
||||
get_resvvlan = '/usr/share/python-ifupdown2/get_reserved_vlan_range.sh'
|
||||
try:
|
||||
(start, end) = self.exec_command(get_resvvlan).split('-')
|
||||
except:
|
||||
# ignore errors
|
||||
pass
|
||||
return (start, end)
|
||||
|
@@ -51,13 +51,13 @@ def run_up(args):
|
||||
ifupdown_handle.up(['up'], args.all, args.CLASS, iflist,
|
||||
excludepats=args.excludepats,
|
||||
printdependency=args.printdependency,
|
||||
syntaxcheck=args.syntaxcheck)
|
||||
syntaxcheck=args.syntaxcheck, type=args.type)
|
||||
else:
|
||||
ifupdown_handle.up(['pre-up', 'up', 'post-up'],
|
||||
args.all, args.CLASS, iflist,
|
||||
excludepats=args.excludepats,
|
||||
printdependency=args.printdependency,
|
||||
syntaxcheck=args.syntaxcheck)
|
||||
syntaxcheck=args.syntaxcheck, type=args.type)
|
||||
except:
|
||||
raise
|
||||
|
||||
@@ -81,7 +81,8 @@ def run_down(args):
|
||||
args.all, args.CLASS, iflist,
|
||||
excludepats=args.excludepats,
|
||||
printdependency=args.printdependency,
|
||||
usecurrentconfig=args.usecurrentconfig)
|
||||
usecurrentconfig=args.usecurrentconfig,
|
||||
type=args.type)
|
||||
except:
|
||||
raise
|
||||
|
||||
@@ -123,7 +124,7 @@ def run_query(args):
|
||||
ifupdown_handle.query([qop], args.all, args.CLASS, iflist,
|
||||
excludepats=args.excludepats,
|
||||
printdependency=args.printdependency,
|
||||
format=args.format)
|
||||
format=args.format, type=args.type)
|
||||
except:
|
||||
raise
|
||||
|
||||
@@ -139,7 +140,8 @@ def run_reload(args):
|
||||
['pre-down', 'down', 'post-down'],
|
||||
args.all, None, None,
|
||||
excludepats=args.excludepats,
|
||||
usecurrentconfig=args.usecurrentconfig)
|
||||
usecurrentconfig=args.usecurrentconfig,
|
||||
currentlyup=args.currentlyup)
|
||||
except:
|
||||
raise
|
||||
|
||||
@@ -226,6 +228,13 @@ def update_argparser(argparser):
|
||||
default='native',
|
||||
choices=['native', 'json'],
|
||||
help='interfaces file format')
|
||||
argparser.add_argument('-T', '--type',
|
||||
dest='type',
|
||||
default=None,
|
||||
choices=['iface', 'vlan'],
|
||||
help='type of interface entry (iface or vlan).' +
|
||||
'This option can be used in case of ambiguity between ' +
|
||||
'a vlan interface and an iface interface of the same name')
|
||||
|
||||
def update_ifupdown_argparser(argparser):
|
||||
""" common arg parser for ifup and ifdown """
|
||||
@@ -294,8 +303,13 @@ def update_ifquery_argparser(argparser):
|
||||
|
||||
def update_ifreload_argparser(argparser):
|
||||
""" parser for ifreload """
|
||||
argparser.add_argument('-a', '--all', action='store_true', required=True,
|
||||
group = argparser.add_mutually_exclusive_group(required=True)
|
||||
group.add_argument('-a', '--all', action='store_true',
|
||||
help='process all interfaces marked \"auto\"')
|
||||
group.add_argument('-c', '--currently-up', dest='currentlyup',
|
||||
action='store_true',
|
||||
help='only reload auto and other interfaces that are ' +
|
||||
'currently up')
|
||||
argparser.add_argument('iflist', metavar='IFACE',
|
||||
nargs='*', help=argparse.SUPPRESS)
|
||||
argparser.add_argument('-n', '--no-act', dest='noact',
|
||||
@@ -367,8 +381,8 @@ def validate_args(op, args):
|
||||
if op == 'query' and args.syntaxhelp:
|
||||
return True
|
||||
if op == 'reload':
|
||||
if not args.all:
|
||||
print '\'-a\' option is required'
|
||||
if not args.all and not args.currentlyup:
|
||||
print '\'-a\' or \'-c\' option is required'
|
||||
return False
|
||||
elif (not args.iflist and
|
||||
not args.all and not args.CLASS):
|
||||
|
Reference in New Issue
Block a user