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

First phase checkin for new format for vlan aware bridge

Ticket: CM-3346
Reviewed By:
Testing Done: Sanity test + test new bridge format

There are a bunch of open issues with `vlan` interface handling.
Below is the format.

auto swp1
iface swp1
    bridge-access 300
    mstpctl-pathcost 0
    mstpctl-adminedge yes
    mstpctl-autoedge yes
    mstpctl-p2p yes
    mstpctl-bpduguard yes
    mstpctl-treeprio 64
    mstpctl-network yes
    mstpctl-bpdufilter yes

auto swp2
iface swp2
    bridge-vids 301
    bridge-pvid 302
    bridge-pathcost 10
    bridge-priority 10
    bridge-multicast-router 0
    bridge-multicast-fast-leave 1

auto br0
iface br0
    bridge-vlan-aware yes
    bridge-stp on
    bridge-ports swp1 swp2
    bridge-vids 2001

auto br0.2001
iface br0.2001
    address 10.0.14.2
    hwaddress 00:03:00:00:00:12
    address-virtual 00:00:5e:00:01:01 11.0.4.1/24

auto br0.2001
vlan br0.2001
    bridge-igmp-querier-src 172.16.101.1
This commit is contained in:
Roopa Prabhu
2014-10-24 10:11:07 -07:00
parent 48ca05db88
commit 84ca006f82
23 changed files with 649 additions and 193 deletions

View File

@@ -265,7 +265,7 @@ class address(moduleBase):
if not self.ipcmd:
self.ipcmd = iproute2(**self.get_flags())
def run(self, ifaceobj, operation, query_ifaceobj=None):
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
""" run address configuration on the interface object passed as argument
Args:

View File

@@ -147,7 +147,7 @@ class addressvirtual(moduleBase):
if not self.ipcmd:
self.ipcmd = iproute2(**self.get_flags())
def run(self, ifaceobj, operation, query_ifaceobj=None):
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
""" run vlan configuration on the interface object passed as argument
Args:
@@ -163,6 +163,8 @@ class addressvirtual(moduleBase):
of interfaces. status is success if the running state is same
as user required state in ifaceobj. error otherwise.
"""
if ifaceobj.type == ifaceType.BRIDGE_VLAN:
return
op_handler = self._run_ops.get(operation)
if not op_handler:
return

View File

@@ -18,6 +18,9 @@ class bridge(moduleBase):
_modinfo = { 'mhelp' : 'bridge configuration module',
'attrs' : {
'bridge-vlan-aware' :
{'help' : 'bridge vlan aware',
'example' : ['bridge-vlan-aware yes/no']},
'bridge-ports' :
{'help' : 'bridge ports',
'required' : True,
@@ -152,24 +155,52 @@ class bridge(moduleBase):
'bridge-vids' :
{ 'help' : 'bridge vlans',
'example' : ['bridge-vids 4000']},
'bridge-pvid' :
{ 'help' : 'bridge vlans',
'example' : ['bridge-pvid 1']},
'bridge-access' :
{ 'help' : 'bridge access vlans',
'example' : ['bridge-access 300']},
'bridge-port-vids' :
{ 'help' : 'bridge vlans',
'example' : ['bridge-port-vids bond0=1-1000,1010-1020']},
'bridge-port-pvids' :
{ 'help' : 'bridge port vlans',
'example' : ['bridge-port-pvids bond0=100 bond1=200']},
'bridge-pathcost' :
{ 'help' : 'bridge port path cost',
'example' : ['bridge-pathcost 10']},
'bridge-priority' :
{ 'help' : 'bridge port priority',
'example' : ['bridge-priority 10']},
'bridge-multicast-router' :
{ 'help' : 'bridge multicast router',
'example' : ['bridge-multicast-router 1']},
'bridge-multicast-fast-leave' :
{ 'help' : 'bridge multicast fast leave',
'example' : ['bridge-multicast-fast-leave 1']},
'bridge-igmp-querier-src' :
{ 'help' : 'bridge igmp querier src',
'example' : ['bridge-igmp-querier-src 172.16.101.1']},
}}
def __init__(self, *args, **kargs):
moduleBase.__init__(self, *args, **kargs)
self.ipcmd = None
self.brctlcmd = None
self._running_vidinfo = {}
self._running_vidinfo_valid = False
def _is_bridge(self, ifaceobj):
if ifaceobj.get_attr_value_first('bridge-ports'):
return True
return False
def _is_bridge_port(self, ifaceobj):
if self.brctlcmd.is_bridge_port(ifaceobj.name):
return True
return False
def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
if not self._is_bridge(ifaceobj):
return None
@@ -332,7 +363,10 @@ class bridge(moduleBase):
else:
return True
def _set_bridge_mcqv4src(self, ifaceobj):
def _set_bridge_mcqv4src_compat(self, ifaceobj):
#
# Sets old style igmp querier
#
attrval = ifaceobj.get_attr_value_first('bridge-mcqv4src')
if attrval:
running_mcqv4src = {}
@@ -349,12 +383,52 @@ class bridge(moduleBase):
self.brctlcmd.del_mcqv4src(ifaceobj.name, v)
for v in mcqs.keys():
self.brctlcmd.set_mcqv4src(ifaceobj.name, v, mcqs[v])
def _set_bridge_vidinfo(self, ifaceobj):
# Handle bridge vlan attrs
running_vidinfo = {}
def _get_running_vidinfo(self):
if self._running_vidinfo_valid:
return self._running_vidinfo
self._running_vidinfo = {}
if not self.PERFMODE:
running_vidinfo = self.ipcmd.bridge_port_vids_get_all()
self._running_vidinfo = self.ipcmd.bridge_port_vids_get_all()
self._running_vidinfo_valid = True
return self._running_vidinfo
def _flush_running_vidinfo(self):
self._running_vidinfo = {}
self._running_vidinfo_valid = False
def _set_bridge_vidinfo_compat(self, ifaceobj):
#
# Supports old style vlan vid info format
# for compatibility
#
# Handle bridge vlan attrs
running_vidinfo = self._get_running_vidinfo()
# 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
for p in portlist:
try:
(port, pvid) = p.split('=')
running_pvid = running_vidinfo.get(port, {}).get('pvid')
if running_pvid:
if running_pvid == pvid:
continue
else:
self.ipcmd.bridge_port_pvid_del(port, running_pvid)
self.ipcmd.bridge_port_pvid_add(port, pvid)
except Exception, e:
self.log_warn('%s: failed to set pvid `%s` (%s)'
%(ifaceobj.name, p, str(e)))
# install port vids
attrval = ifaceobj.get_attr_value_first('bridge-port-vids')
if attrval:
portlist = self.parse_port_list(attrval)
@@ -380,28 +454,7 @@ class bridge(moduleBase):
self.log_warn('%s: failed to set vid `%s` (%s)'
%(ifaceobj.name, p, str(e)))
# 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
for p in portlist:
try:
(port, pvid) = p.split('=')
running_pvid = running_vidinfo.get(port, {}).get('pvid')
if running_pvid:
if running_pvid == pvid:
continue
else:
self.ipcmd.bridge_port_pvid_del(port, running_pvid)
self.ipcmd.bridge_port_pvid_add(port, pvid)
except Exception, e:
self.log_warn('%s: failed to set pvid `%s` (%s)'
%(ifaceobj.name, p, str(e)))
# install vids
attrval = ifaceobj.get_attr_value_first('bridge-vids')
if attrval:
vids = re.split(r'[\s\t]\s*', attrval)
@@ -501,16 +554,162 @@ class bridge(moduleBase):
for port, attrdict in portattrs.iteritems():
self.brctlcmd.set_bridgeport_attrs(ifaceobj.name, port,
attrdict)
self._set_bridge_vidinfo(ifaceobj)
self._set_bridge_vidinfo_compat(ifaceobj)
self._set_bridge_mcqv4src(ifaceobj)
self._set_bridge_mcqv4src_compat(ifaceobj)
self._process_bridge_maxwait(ifaceobj,
self._get_bridge_port_list(ifaceobj))
except Exception, e:
self.log_warn(str(e))
def _up(self, ifaceobj):
def _apply_bridge_vids(self, bportifaceobj, vids, running_vids, isbridge):
try:
if running_vids:
(vids_to_del, vids_to_add) = \
self._diff_vids(vids, running_vids)
if vids_to_del:
self.ipcmd.bridge_vids_del(bportifaceobj.name,
vids_to_del, isbridge)
if vids_to_add:
self.ipcmd.bridge_vids_add(bportifaceobj.name,
vids_to_add, isbridge)
else:
self.ipcmd.bridge_vids_add(bportifaceobj.name, vids, isbridge)
except Exception, e:
self.log_warn('%s: failed to set vid `%s` (%s)'
%(bportifaceobj.name, str(vids), str(e)))
def _apply_bridge_port_pvids(self, bportifaceobj, pvid, running_pvid):
# Install pvids
try:
if running_pvid:
if running_pvid != pvid:
self.ipcmd.bridge_port_pvid_del(bportifaceobj.name,
running_pvid)
self.ipcmd.bridge_port_pvid_add(bportifaceobj.name, pvid)
except Exception, e:
self.log_warn('%s: failed to set pvid `%s` (%s)'
%(bportifaceobj.name, pvid, str(e)))
def _apply_bridge_vlan_aware_port_settings_all(self, bportifaceobj,
bridge_vids):
running_vidinfo = self._get_running_vidinfo()
vids = None
pvids = None
bport_access = bportifaceobj.get_attr_value_first('bridge-access')
if bport_access:
vids = re.split(r'[\s\t]\s*', bport_access)
pvids = vids
bport_vids = bportifaceobj.get_attr_value_first('bridge-vids')
if bport_vids:
vids = re.split(r'[\s\t]\s*', bport_vids)
bport_pvids = bportifaceobj.get_attr_value_first('bridge-pvid')
if bport_pvids:
pvids = re.split(r'[\s\t]\s*', bport_pvids)
if pvids:
self._apply_bridge_port_pvids(bportifaceobj, pvids[0],
running_vidinfo.get(bportifaceobj.name, {}).get('pvid'))
else:
self._apply_bridge_port_pvids(bportifaceobj,
'1', running_vidinfo.get(bportifaceobj.name,
{}).get('pvid'))
if vids:
self._apply_bridge_vids(bportifaceobj, vids,
running_vidinfo.get(bportifaceobj.name,
{}).get('vlan'), False)
elif bridge_vids:
self._apply_bridge_vids(bportifaceobj,
bridge_vids, running_vidinfo.get(
bportifaceobj.name, {}).get('vlan'), False)
def _apply_bridge_port_settings(self, bportifaceobj, bridgename=None,
bridgeifaceobj=None):
if not bridgename and bridgeifaceobj:
bridgename = bridgeifaceobj.name
# Set other stp and igmp attributes
portattrs = {}
for attrname, dstattrname in {
'bridge-pathcost' : 'pathcost',
'bridge-prio' : 'portprio',
'bridge-priority' : 'portprio',
'bridge-mcrouter' : 'portmcrouter',
'bridge-multicast-router' : 'portmcrouter',
'bridge-multicast-fast-leave' : 'portmcfl'}.items():
attrval = bportifaceobj.get_attr_value_first(attrname)
if not attrval:
# Check if bridge has that attribute
if bridgeifaceobj:
attrval = bridgeifaceobj.get_attr_value_first(attrname)
if not attrval:
continue
else:
continue
portattrs[dstattrname] = attrval
try:
self.brctlcmd.set_bridgeport_attrs(bridgename,
bportifaceobj.name, portattrs)
except Exception, e:
self.log_warn(str(e))
def _apply_bridge_port_settings_all(self, ifaceobj,
ifaceobj_getfunc=None):
bridge_vlan_aware = ifaceobj.get_attr_value_first(
'bridge-vlan-aware')
if bridge_vlan_aware and bridge_vlan_aware == 'yes':
bridge_vlan_aware = True
else:
bridge_vlan_aware = False
if (ifaceobj.get_attr_value_first('bridge-port-vids') and
ifaceobj.get_attr_value_first('bridge-port-pvids')):
# Old style bridge port vid info
# skip new style setting on ports
return
self.logger.info('%s: applying bridge configuration '
%ifaceobj.name + 'specific to ports')
bridge_vids = ifaceobj.get_attr_value_first('bridge-vids')
if bridge_vids:
bridge_vids = re.split(r'[\s\t]\s*', bridge_vids)
else:
bridge_vids = None
bridgeports = self._get_bridge_port_list(ifaceobj)
for bport in bridgeports:
# Use the brctlcmd bulk set method: first build a dictionary
# and then call set
self.logger.info('%s: processing bridge config for port %s'
%(ifaceobj.name, bport))
bportifaceobjlist = ifaceobj_getfunc(bport)
if not bportifaceobjlist:
continue
for bportifaceobj in bportifaceobjlist:
# Add attributes specific to the vlan aware bridge
if bridge_vlan_aware:
self._apply_bridge_vlan_aware_port_settings_all(
bportifaceobj, bridge_vids)
self._apply_bridge_port_settings(
bportifaceobj, bridgeifaceobj=ifaceobj)
def _up(self, ifaceobj, ifaceobj_getfunc=None):
# Check if bridge port
if self._is_bridge_port(ifaceobj):
bridgename = ifaceobj.upperifaces[0]
if not bridgename:
self.logger.warn('%s: unable to determine bridge name'
%ifaceobj.name)
return
self._apply_bridge_port_settings(ifaceobj, bridgename=bridgename)
return
if not self._is_bridge(ifaceobj):
return
try:
porterr = False
porterrstr = ''
@@ -529,12 +728,15 @@ class bridge(moduleBase):
finally:
self.ipcmd.batch_commit()
self._apply_bridge_settings(ifaceobj)
self._apply_bridge_port_settings_all(ifaceobj,
ifaceobj_getfunc=ifaceobj_getfunc)
self._flush_running_vidinfo()
except Exception, e:
self.log_error(str(e))
if porterr:
raise Exception(porterrstr)
def _down(self, ifaceobj):
def _down(self, ifaceobj, ifaceobj_getfunc=None):
try:
if ifaceobj.get_attr_value_first('bridge-ports'):
ports = self.brctlcmd.get_bridge_ports(ifaceobj.name)
@@ -549,8 +751,7 @@ class bridge(moduleBase):
def _query_running_vidinfo(self, ifaceobjrunning, ports):
running_attrs = {}
running_vidinfo = self.ipcmd.bridge_port_vids_get_all()
running_vidinfo = self._get_running_vidinfo()
if ports:
running_bridge_port_vids = ''
for p in ports:
@@ -574,7 +775,8 @@ class bridge(moduleBase):
pass
running_attrs['bridge-port-pvids'] = running_bridge_port_pvids
running_bridge_vids = running_vidinfo.get(ifaceobjrunning.name, {}).get('vlan')
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
@@ -749,101 +951,103 @@ class bridge(moduleBase):
ifaceobjcurr.update_config_with_status('bridge-vids', attrval,
1)
def _query_check(self, ifaceobj, ifaceobjcurr):
if not self.brctlcmd.bridge_exists(ifaceobj.name):
self.logger.info('%s: bridge: does not exist' %(ifaceobj.name))
ifaceobjcurr.status = ifaceStatus.NOTFOUND
return
ifaceattrs = self.dict_key_subset(ifaceobj.config,
self.get_mod_attrs())
if not ifaceattrs:
return
try:
runningattrs = self.brctlcmd.get_bridge_attrs(ifaceobj.name)
if not runningattrs:
self.logger.debug('%s: bridge: unable to get bridge attrs'
%ifaceobj.name)
runningattrs = {}
except Exception, e:
self.logger.warn(str(e))
runningattrs = {}
filterattrs = ['bridge-vids', 'bridge-port-vids',
'bridge-port-pvids']
for k in Set(ifaceattrs).difference(filterattrs):
# get the corresponding ifaceobj attr
v = ifaceobj.get_attr_value_first(k)
if not v:
continue
rv = runningattrs.get(k[7:])
if k == 'bridge-mcqv4src':
continue
if k == 'bridge-stp':
# special case stp compare because it may
# contain more than one valid values
stp_on_vals = ['on', 'yes']
stp_off_vals = ['off']
if ((v in stp_on_vals and rv in stp_on_vals) or
(v in stp_off_vals and rv in stp_off_vals)):
ifaceobjcurr.update_config_with_status('bridge-stp',
v, 0)
else:
ifaceobjcurr.update_config_with_status('bridge-stp',
def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None):
if not self._is_bridge(ifaceobj):
return
if not self.brctlcmd.bridge_exists(ifaceobj.name):
self.logger.info('%s: bridge: does not exist' %(ifaceobj.name))
ifaceobjcurr.status = ifaceStatus.NOTFOUND
return
ifaceattrs = self.dict_key_subset(ifaceobj.config,
self.get_mod_attrs())
if not ifaceattrs:
return
try:
runningattrs = self.brctlcmd.get_bridge_attrs(ifaceobj.name)
if not runningattrs:
self.logger.debug('%s: bridge: unable to get bridge attrs'
%ifaceobj.name)
runningattrs = {}
except Exception, e:
self.logger.warn(str(e))
runningattrs = {}
filterattrs = ['bridge-vids', 'bridge-port-vids',
'bridge-port-pvids']
for k in Set(ifaceattrs).difference(filterattrs):
# get the corresponding ifaceobj attr
v = ifaceobj.get_attr_value_first(k)
if not v:
continue
rv = runningattrs.get(k[7:])
if k == 'bridge-mcqv4src':
continue
if k == 'bridge-stp':
# special case stp compare because it may
# contain more than one valid values
stp_on_vals = ['on', 'yes']
stp_off_vals = ['off']
if ((v in stp_on_vals and rv in stp_on_vals) or
(v in stp_off_vals and rv in stp_off_vals)):
ifaceobjcurr.update_config_with_status('bridge-stp',
v, 0)
else:
ifaceobjcurr.update_config_with_status('bridge-stp',
v, 1)
elif k == 'bridge-ports':
# special case ports because it can contain regex or glob
running_port_list = rv.keys() if rv else []
bridge_port_list = self._get_bridge_port_list(ifaceobj)
if not running_port_list and not bridge_port_list:
continue
portliststatus = 1
if running_port_list and bridge_port_list:
difference = set(running_port_list
).symmetric_difference(bridge_port_list)
if not difference:
portliststatus = 0
ifaceobjcurr.update_config_with_status('bridge-ports',
' '.join(running_port_list)
if running_port_list else '', portliststatus)
elif (k == 'bridge-pathcosts' or
k == 'bridge-portprios' or k == 'bridge-portmcrouter'
or k == 'bridge-portmcfl'):
brctlcmdattrname = k[11:].rstrip('s')
# for port attributes, the attributes are in a list
# <portname>=<portattrvalue>
status = 0
currstr = ''
vlist = self.parse_port_list(v)
if not vlist:
continue
for vlistitem in vlist:
try:
(p, v) = vlistitem.split('=')
currv = self.brctlcmd.get_bridgeport_attr(
ifaceobj.name, p,
brctlcmdattrname)
if currv:
currstr += ' %s=%s' %(p, currv)
else:
currstr += ' %s=%s' %(p, 'None')
if currv != v:
status = 1
except Exception, e:
self.log_warn(str(e))
pass
ifaceobjcurr.update_config_with_status(k, currstr, status)
elif not rv:
ifaceobjcurr.update_config_with_status(k, 'notfound', 1)
elif k == 'bridge-ports':
# special case ports because it can contain regex or glob
running_port_list = rv.keys() if rv else []
bridge_port_list = self._get_bridge_port_list(ifaceobj)
if not running_port_list and not bridge_port_list:
continue
elif v != rv:
ifaceobjcurr.update_config_with_status(k, rv, 1)
else:
ifaceobjcurr.update_config_with_status(k, rv, 0)
portliststatus = 1
if running_port_list and bridge_port_list:
difference = set(running_port_list
).symmetric_difference(bridge_port_list)
if not difference:
portliststatus = 0
ifaceobjcurr.update_config_with_status('bridge-ports',
' '.join(running_port_list)
if running_port_list else '', portliststatus)
elif (k == 'bridge-pathcosts' or
k == 'bridge-portprios' or k == 'bridge-portmcrouter'
or k == 'bridge-portmcfl'):
brctlcmdattrname = k[11:].rstrip('s')
# for port attributes, the attributes are in a list
# <portname>=<portattrvalue>
status = 0
currstr = ''
vlist = self.parse_port_list(v)
if not vlist:
continue
for vlistitem in vlist:
try:
(p, v) = vlistitem.split('=')
currv = self.brctlcmd.get_bridgeport_attr(
ifaceobj.name, p,
brctlcmdattrname)
if currv:
currstr += ' %s=%s' %(p, currv)
else:
currstr += ' %s=%s' %(p, 'None')
if currv != v:
status = 1
except Exception, e:
self.log_warn(str(e))
pass
ifaceobjcurr.update_config_with_status(k, currstr, status)
elif not rv:
ifaceobjcurr.update_config_with_status(k, 'notfound', 1)
continue
elif v != rv:
ifaceobjcurr.update_config_with_status(k, rv, 1)
else:
ifaceobjcurr.update_config_with_status(k, rv, 0)
self._query_check_vidinfo(ifaceobj, ifaceobjcurr)
self._query_check_mcqv4src(ifaceobj, ifaceobjcurr)
def _query_running(self, ifaceobjrunning):
def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
if not self.brctlcmd.bridge_exists(ifaceobjrunning.name):
return
ifaceobjrunning.update_config_dict(self._query_running_attrs(
@@ -865,7 +1069,8 @@ class bridge(moduleBase):
if not self.brctlcmd:
self.brctlcmd = brctl(**flags)
def run(self, ifaceobj, operation, query_ifaceobj=None):
def run(self, ifaceobj, operation, query_ifaceobj=None,
ifaceobj_getfunc=None):
""" run bridge configuration on the interface object passed as
argument. Can create bridge interfaces if they dont exist already
@@ -886,11 +1091,10 @@ class bridge(moduleBase):
op_handler = self._run_ops.get(operation)
if not op_handler:
return
if (operation != 'query-running' and
not self._is_bridge(ifaceobj)):
return
self._init_command_handlers()
self._flush_running_vidinfo()
if operation == 'query-checkcurr':
op_handler(self, ifaceobj, query_ifaceobj)
op_handler(self, ifaceobj, query_ifaceobj,
ifaceobj_getfunc=ifaceobj_getfunc)
else:
op_handler(self, ifaceobj)
op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc)

153
addons/bridgevlan.py Normal file
View File

@@ -0,0 +1,153 @@
#!/usr/bin/python
#
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
#
from ifupdown.iface import *
from ifupdownaddons.modulebase import moduleBase
from ifupdownaddons.iproute2 import iproute2
from ifupdownaddons.bridgeutils import brctl
import logging
class bridgevlan(moduleBase):
""" ifupdown2 addon module to configure vlan attributes on a vlan
aware bridge """
_modinfo = {'mhelp' : 'bridgevlan module configures vlan attributes ' +
'on a vlan aware bridge. This module only ' +
'understands vlan interface name ' +
'with dot notations. eg br0.100. where br0 is the ' +
'vlan aware bridge this config is for',
'attrs' : {
'bridge-igmp-querier-src' :
{'help' : 'igmp querier src'}}}
def __init__(self, *args, **kargs):
moduleBase.__init__(self, *args, **kargs)
self.brctlcmd = None
self.ipcmd = None
def _is_bridge_vlan_device(self, ifaceobj):
if ifaceobj.type == ifaceType.BRIDGE_VLAN:
return True
return False
def _get_bridge_n_vlan(self, ifaceobj):
vlist = ifaceobj.name.split('.', 1)
if len(vlist) == 2:
return (vlist[0], vlist[1])
return None
def _get_bridgename(self, ifaceobj):
vlist = ifaceobj.name.split('.', 1)
if len(vlist) == 2:
return vlist[0]
return None
def get_dependent_ifacenames(self, ifaceobj, ifaceobjs_all=None):
if not self._is_bridge_vlan_device(ifaceobj):
return None
return [self._get_bridgename(ifaceobj)]
def _up(self, ifaceobj):
try:
(bridgename, vlan) = self._get_bridge_n_vlan(ifaceobj)
vlanid = int(vlan, 10)
except:
self.logger.warn('%s: bridge vlan interface name ' %ifaceobj.name +
'does not correspond to format (eg. br0.100)')
raise
if not self.ipcmd.link_exists(bridgename):
self.logger.warn('%s: bridge %s does not exist' %(ifaceobj.name,
bridgename))
return
running_mcqv4src = {}
if not self.PERFMODE:
running_mcqv4src = self.brctlcmd.get_mcqv4src(bridgename)
if running_mcqv4src:
r_mcqv4src = running_mcqv4src.get(vlan)
else:
r_mcqv4src = None
mcqv4src = ifaceobj.get_attr_value_first('bridge-igmp-querier-src')
if not mcqv4src:
if r_mcqv4src:
self.brctlcmd.del_mcqv4src(bridgename, vlanid)
return
if r_mcqv4src and r_mcqv4src != mcqv4src:
self.brctlcmd.del_mcqv4src(bridgename, vlanid)
self.brctlcmd.set_mcqv4src(bridgename, vlanid, mcqv4src)
else:
self.brctlcmd.set_mcqv4src(bridgename, vlanid, mcqv4src)
def _down(self, ifaceobj):
try:
(bridgename, vlan) = self._get_bridge_n_vlan(ifaceobj)
vlanid = int(vlan, 10)
except:
self.logger.warn('%s: bridge vlan interface name ' %ifaceobj.name +
'does not correspond to format (eg. br0.100)')
raise
if not self.ipcmd.link_exists(bridgename):
self.logger.warn('%s: bridge %s does not exist' %(ifaceobj.name,
bridgename))
return
mcqv4src = ifaceobj.get_attr_value_first('bridge-igmp-querier-src')
if mcqv4src:
self.brctlcmd.del_mcqv4src(bridgename, vlanid)
def _query_check(self, ifaceobj, ifaceobjcurr):
# XXX not supported
return
def _query_running(self, ifaceobjrunning):
# XXX not supported
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):
if not self.ipcmd:
self.ipcmd = iproute2(**self.get_flags())
if not self.brctlcmd:
self.brctlcmd = brctl(**self.get_flags())
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
""" run vlan 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
if (operation != 'query-running' and
not self._is_bridge_vlan_device(ifaceobj)):
return
self._init_command_handlers()
if operation == 'query-checkcurr':
op_handler(self, ifaceobj, query_ifaceobj)
else:
op_handler(self, ifaceobj)

View File

@@ -95,7 +95,7 @@ class dhcp(moduleBase):
if not self.ipcmd:
self.ipcmd = iproute2(**self.get_flags())
def run(self, ifaceobj, operation, query_ifaceobj=None):
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
""" run dhcp configuration on the interface object passed as argument
Args:

View File

@@ -106,7 +106,7 @@ class ethtool(moduleBase):
if not self.ipcmd:
self.ipcmd = iproute2(**self.get_flags())
def run(self, ifaceobj, operation, query_ifaceobj=None):
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
""" run ethtool configuration on the interface object passed as
argument

View File

@@ -351,7 +351,7 @@ class ifenslave(moduleBase):
if not self.ifenslavecmd:
self.ifenslavecmd = ifenslaveutil(**flags)
def run(self, ifaceobj, operation, query_ifaceobj=None):
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
""" run bond configuration on the interface object passed as argument
Args:

View File

@@ -50,7 +50,7 @@ class loopback(moduleBase):
if not self.ipcmd:
self.ipcmd = iproute2(**self.get_flags())
def run(self, ifaceobj, operation, query_ifaceobj=None):
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
op_handler = self._run_ops.get(operation)
if not op_handler:
return

View File

@@ -211,8 +211,12 @@ class mstpctl(moduleBase):
def _is_bridge(self, ifaceobj):
if (ifaceobj.get_attr_value_first('mstpctl-ports') or
ifaceobj.get_attr_value_first('bridge-ports') or
ifaceobj.type == ifaceType.BRIDGE):
ifaceobj.get_attr_value_first('bridge-ports')):
return True
return False
def _is_bridge_port(self, ifaceobj):
if self.brctlcmd.is_bridge_port(ifaceobj.name):
return True
return False
@@ -344,35 +348,63 @@ class mstpctl(moduleBase):
self.log_warn(str(e))
pass
def _apply_bridge_port_settings(self, ifaceobj, bridge):
def _apply_bridge_port_settings(self, ifaceobj, bridgename=None,
bridgeifaceobj=None):
check = False if self.PERFMODE else True
try:
# set bridge port attributes
for attrname, dstattrname in self._port_attrs_map.items():
attrval = ifaceobj.get_attr_value_first(attrname)
if not attrval:
continue
if not bridgename and bridgeifaceobj:
bridgename = bridgeifaceobj.name
# set bridge port attributes
for attrname, dstattrname in self._port_attrs_map.items():
attrval = ifaceobj.get_attr_value_first(attrname)
if not attrval:
if bridgeifaceobj:
# If bridge object available, check if the bridge
# has the attribute set, in which case,
# inherit it from the bridge
attrval = bridgeifaceobj.get_attr_value_first(attrname)
if not attrval:
continue
else:
continue
try:
self.mstpctlcmd.set_bridgeport_attr(bridgename,
ifaceobj.name, dstattrname, attrval, check)
except Exception, e:
self.log_warn('%s: error setting %s (%s)'
%(ifaceobj.name, attrname, str(e)))
def _apply_bridge_port_settings_all(self, ifaceobj,
ifaceobj_getfunc=None):
self.logger.info('%s: applying bridge configuration '
%ifaceobj.name + 'specific to ports')
bridgeports = self._get_bridge_port_list(ifaceobj)
for bport in bridgeports:
self.logger.info('%s: processing bridge config for port %s'
%(ifaceobj.name, bport))
bportifaceobjlist = ifaceobj_getfunc(bport)
if not bportifaceobjlist:
continue
for bportifaceobj in bportifaceobjlist:
try:
self.mstpctlcmd.set_bridgeport_attr(bridge,
ifaceobj.name, dstattrname, attrval, check)
self._apply_bridge_port_settings(bportifaceobj,
ifaceobj.name, ifaceobj)
except Exception, e:
self.log_warn('%s: error setting %s (%s)'
%(ifaceobj.name, attrname, str(e)))
except Exception, e:
self.log_warn(str(e))
pass
self.log_warn(str(e))
def _up(self, ifaceobj):
def _up(self, ifaceobj, ifaceobj_getfunc=None):
# Check if bridge port
bridge = ifaceobj.get_attr_value_first('bridge')
if bridge:
if self._is_bridge_port(ifaceobj):
if self.mstpctlcmd.is_mstpd_running():
self._apply_bridge_port_settings(ifaceobj, bridge)
bridgename = ifaceobj.upperifaces[0]
if not bridgename:
self.logger.warn('%s: unable to determine bridge name'
%ifaceobj.name)
return
self._apply_bridge_port_settings(ifaceobj, bridgename)
return
if not self._is_bridge(ifaceobj):
return
stp = None
try:
porterr = False
@@ -403,12 +435,16 @@ class mstpctl(moduleBase):
if (self.mstpctlcmd.is_mstpd_running() and
(stp == 'yes' or stp == 'on')):
self._apply_bridge_settings(ifaceobj)
self._apply_bridge_port_settings_all(ifaceobj,
ifaceobj_getfunc=ifaceobj_getfunc)
except Exception, e:
self.log_error(str(e))
if porterr:
raise Exception(porterrstr)
def _down(self, ifaceobj):
def _down(self, ifaceobj, ifaceobj_getfunc=None):
if not self._is_bridge(ifaceobj):
return
try:
if ifaceobj.get_attr_value_first('mstpctl-ports'):
# If bridge ports specified with mstpctl attr, delete the
@@ -599,7 +635,8 @@ class mstpctl(moduleBase):
else:
ifaceobjcurr.update_config_with_status(k, rv, 0)
def _query_check_bridge_port(self, ifaceobj, ifaceobjcurr, bridge):
def _query_check_bridge_port(self, ifaceobj, ifaceobjcurr):
bridge = ifaceobj.upperifaces[0]
# list of attributes that are not supported currently
blacklistedattrs = ['mstpctl-pathcost',
'mstpctl-treeprio', 'mstpctl-treecost']
@@ -633,15 +670,14 @@ class mstpctl(moduleBase):
else:
ifaceobjcurr.update_config_with_status(k, None, 1)
def _query_check(self, ifaceobj, ifaceobjcurr):
def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None):
# Check if bridge port
bridge = ifaceobj.get_attr_value_first('bridge')
if bridge:
self._query_check_bridge_port(ifaceobj, ifaceobjcurr, bridge)
return
self._query_check_bridge(ifaceobj, ifaceobjcurr)
if self._is_bridge_port(ifaceobj):
self._query_check_bridge_port(ifaceobj, ifaceobjcurr)
elif self._is_bridge(ifaceobj):
self._query_check_bridge(ifaceobj, ifaceobjcurr)
def _query_running(self, ifaceobjrunning):
def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
if not self.brctlcmd.bridge_exists(ifaceobjrunning.name):
return
if self.brctlcmd.get_stp(ifaceobjrunning.name) == 'no':
@@ -674,7 +710,8 @@ class mstpctl(moduleBase):
if not self.mstpctlcmd:
self.mstpctlcmd = mstpctlutil(**flags)
def run(self, ifaceobj, operation, query_ifaceobj=None):
def run(self, ifaceobj, operation, query_ifaceobj=None,
ifaceobj_getfunc=None, **extra_args):
""" run mstp configuration on the interface object passed as argument
Args:
@@ -695,6 +732,7 @@ class mstpctl(moduleBase):
return
self._init_command_handlers()
if operation == 'query-checkcurr':
op_handler(self, ifaceobj, query_ifaceobj)
op_handler(self, ifaceobj, query_ifaceobj,
ifaceobj_getfunc=ifaceobj_getfunc)
else:
op_handler(self, ifaceobj)
op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc)

View File

@@ -75,7 +75,7 @@ class usercmds(ifupdownaddons.modulebase.moduleBase):
""" returns list of ops supported by this module """
return self._run_ops.keys()
def run(self, ifaceobj, operation, query_ifaceobj=None):
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
""" run user commands
Args:

View File

@@ -98,8 +98,12 @@ class vlan(moduleBase):
vlanrawdevice = self._get_vlan_raw_device(ifaceobj)
if not vlanrawdevice:
raise Exception('could not determine vlan raw device')
if not self.ipcmd.link_exists(ifaceobj.name):
rtnetlink_api.rtnl_api.create_vlan(vlanrawdevice,
if not self.PERFMODE:
if not self.ipcmd.link_exists(vlanrawdevice):
raise Exception('rawdevice %s not present' %vlanrawdevice)
if self.ipcmd.link_exists(ifaceobj.name):
return
rtnetlink_api.rtnl_api.create_vlan(vlanrawdevice,
ifaceobj.name, vlanid)
def _down(self, ifaceobj):
@@ -164,7 +168,7 @@ class vlan(moduleBase):
if not self.ipcmd:
self.ipcmd = iproute2(**self.get_flags())
def run(self, ifaceobj, operation, query_ifaceobj=None):
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
""" run vlan configuration on the interface object passed as argument
Args:
@@ -180,6 +184,8 @@ class vlan(moduleBase):
of interfaces. status is success if the running state is same
as user required state in ifaceobj. error otherwise.
"""
if ifaceobj.type == ifaceType.BRIDGE_VLAN:
return
op_handler = self._run_ops.get(operation)
if not op_handler:
return

View File

@@ -73,7 +73,7 @@ class vxlan(moduleBase):
if not self.ipcmd:
self.ipcmd = iproute2(**self.get_flags())
def run(self, ifaceobj, operation, query_ifaceobj=None):
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
op_handler = self._run_ops.get(operation)
if not op_handler:
return

View File

@@ -3,8 +3,8 @@ pre-up,vlan
pre-up,vxlan
pre-up,usercmds
pre-up,loopback
pre-up,bridgevlanaware
pre-up,bridge
pre-up,bridgevlan
pre-up,mstpctl
up,dhcp
up,address
@@ -19,7 +19,7 @@ down,addressvirtual
down,address
down,usercmds
post-down,mstpctl
post-down,bridgevlanaware
post-down,bridgevlan
post-down,bridge
post-down,vxlan
post-down,vlan

View File

@@ -351,6 +351,7 @@ class iface():
Returns True if object self is same as dstiface and False otherwise """
if self.name != dstiface.name: return False
if self.type != dstiface.type: return False
if self.addr_family != dstiface.addr_family: return False
if self.addr_method != dstiface.addr_method: return False
if self.auto != dstiface.auto: return False

0
ifupdown/iff.py Executable file → Normal file
View File

View File

@@ -37,6 +37,16 @@ _crossmark = u'\u2717'
_success_sym = '(%s)' %_tickmark
_error_sym = '(%s)' %_crossmark
class ifupdownFlags():
FORCE = False
DRYRUN = False
NOWAIT = False
PERFMODE = False
CACHE = False
# Flags
CACHE_FLAGS = 0x0
class ifupdownMain(ifupdownBase):
""" ifupdown2 main class """
@@ -160,6 +170,14 @@ class ifupdownMain(ifupdownBase):
self._DELETE_DEPENDENT_IFACES_WITH_NOCONFIG = False
self.ADDONS_ENABLE = addons_enable
# Copy flags into ifupdownFlags
# XXX: before we transition fully to ifupdownFlags
ifupdownFlags.FORCE = force
ifupdownFlags.DRYRUN = dryrun
ifupdownFlags.NOWAIT = nowait
ifupdownFlags.PERFMODE = perfmode
ifupdownFlags.CACHE = cache
self.ifaces = OrderedDict()
self.njobs = njobs
self.pp = pprint.PrettyPrinter(indent=4)
@@ -351,7 +369,7 @@ class ifupdownMain(ifupdownBase):
dlist = None
pass
if dlist: ret_dlist.extend(dlist)
return ret_dlist
return list(set(ret_dlist))
def populate_dependency_info(self, ops, ifacenames=None):
""" recursive function to generate iface dependency info """

View File

@@ -266,17 +266,36 @@ class networkInterfaces():
for v in range(range_val[1], range_val[2]):
ifaceobj_new = copy.deepcopy(ifaceobj)
ifaceobj_new.real_name = ifaceobj.name
ifaceobj_new.name = "%s-%d" %(range_val[0], v)
ifaceobj_new.name = "%s%d" %(range_val[0], v)
self.callbacks.get('iface_found')(ifaceobj_new)
else:
self.callbacks.get('iface_found')(ifaceobj)
return lines_consumed # Return next index
def process_vlan(self, lines, cur_idx, lineno):
ifaceobj = iface()
lines_consumed = self.parse_iface(lines, cur_idx, lineno, ifaceobj)
range_val = utils.parse_iface_range(ifaceobj.name)
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.name = "%s%d" %(range_val[0], v)
ifaceobj_new.type = ifaceType.BRIDGE_VLAN
self.callbacks.get('iface_found')(ifaceobj_new)
else:
ifaceobj.type = ifaceType.BRIDGE_VLAN
self.callbacks.get('iface_found')(ifaceobj)
return lines_consumed # Return next index
network_elems = { 'source' : process_source,
'allow' : process_allow,
'auto' : process_auto,
'iface' : process_iface}
'iface' : process_iface,
'vlan' : process_vlan}
def _is_keyword(self, str):
# The additional split here is for allow- keyword

View File

@@ -11,6 +11,7 @@ from socket import AF_UNSPEC
from iff import IFF_UP
from rtnetlink import *
import os
import ifupdownmain
class rtnetlinkApi(RtNetlink):
@@ -39,13 +40,15 @@ class rtnetlinkApi(RtNetlink):
return ifindex
def create_vlan(self, link, ifname, vlanid):
self.logger.info('rtnetlink: creating vlan %s' %ifname)
if ifupdownmain.ifupdownFlags.DRYRUN:
return
try:
ifindex = self.get_ifindex(link)
except Exception, e:
raise Exception('cannot determine ifindex for link %s (%s)' %(link, str(e)))
raise Exception('cannot determine ifindex for link %s (%s)'
%(link, str(e)))
self.logger.info('rtnetlink: creating vlan %s' %ifname)
ifm = Ifinfomsg(AF_UNSPEC)
rtas = {IFLA_IFNAME: ifname,
IFLA_LINK : ifindex,
@@ -56,17 +59,19 @@ class rtnetlinkApi(RtNetlink):
}
}
}
token = self.request(RTM_NEWLINK, NLM_F_CREATE | NLM_F_REQUEST | NLM_F_ACK, ifm, rtas)
token = self.request(RTM_NEWLINK,
NLM_F_CREATE | NLM_F_REQUEST | NLM_F_ACK, ifm, rtas)
self.process_wait([token])
def create_macvlan(self, ifname, link, mode='private'):
self.logger.info('rtnetlink: creating macvlan %s' %ifname)
if ifupdownmain.ifupdownFlags.DRYRUN:
return
try:
ifindex = self.get_ifindex(link)
except Exception, e:
raise Exception('cannot determine ifindex for link %s (%s)' %(link, str(e)))
self.logger.info('rtnetlink: creating macvlan %s' %ifname)
raise Exception('cannot determine ifindex for link %s (%s)'
%(link, str(e)))
ifm = Ifinfomsg(AF_UNSPEC)
rtas = {IFLA_IFNAME: ifname,
@@ -78,14 +83,15 @@ class rtnetlinkApi(RtNetlink):
}
}
}
token = self.request(RTM_NEWLINK, NLM_F_CREATE | NLM_F_REQUEST | NLM_F_ACK,
ifm, rtas)
token = self.request(RTM_NEWLINK, NLM_F_CREATE | NLM_F_REQUEST |
NLM_F_ACK, ifm, rtas)
self.process_wait([token])
def link_set(self, ifname, state):
flags = 0
self.logger.info('rtnetlink: setting link %s %s' %(ifname, state))
if ifupdownmain.ifupdownFlags.DRYRUN:
return
if state == "up":
flags |= IFF_UP

View File

@@ -65,7 +65,7 @@ class ifaceScheduler():
m.run(ifaceobj, op, query_ifaceobj)
else:
ifupdownobj.logger.debug(msg)
m.run(ifaceobj, op)
m.run(ifaceobj, op, ifaceobj_getfunc=ifupdownobj.get_ifaceobjs)
except Exception, e:
err = 1
ifupdownobj.log_error(str(e))

View File

@@ -32,7 +32,7 @@ class utils():
@classmethod
def parse_iface_range(cls, name):
range_match = re.match("^([\w]+)-\[([\d]+)-([\d]+)\]", name)
range_match = re.match("^([\w\.]+)\[([\d]+)-([\d]+)\]", name)
if range_match:
range_groups = range_match.groups()
if range_groups[1] and range_groups[2]:

View File

@@ -484,6 +484,9 @@ class brctl(utilsBase):
def bridge_exists(self, bridge):
return os.path.exists('/sys/class/net/%s/bridge' %bridge)
def is_bridge_port(self, ifacename):
return os.path.exists('/sys/class/net/%s/brport' %ifacename)
def bridge_port_exists(self, bridge, bridgeportname):
try:
return bridgeportname in os.listdir('/sys/class/net/%s/brif'

View File

@@ -486,6 +486,8 @@ class iproute2(utilsBase):
self._cache_update([name], {})
def link_exists(self, ifacename):
if self.DRYRUN:
return True
return os.path.exists('/sys/class/net/%s' %ifacename)
def is_vlan_device_by_name(self, ifacename):

View File

@@ -180,7 +180,11 @@ class moduleBase(object):
if not port_expr:
return None
for expr in re.split(r'[\s\t]\s*', port_expr):
if expr == 'regex':
if expr == 'noregex':
regex = 0
elif expr == 'noglob':
glob = 0
elif expr == 'regex':
regex = 1
elif expr == 'glob':
glob = 1