3 # Copyright 2014 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
8 from ifupdown
.iface
import *
9 from ifupdownaddons
.modulebase
import moduleBase
10 from ifupdownaddons
.bridgeutils
import brctl
11 from ifupdownaddons
.iproute2
import iproute2
16 class bridge(moduleBase
):
17 """ ifupdown2 addon module to configure linux bridges """
19 _modinfo
= { 'mhelp' : 'Bridge configuration module. Supports both ' +
20 'vlan aware and non vlan aware bridges. For the vlan ' +
21 'aware bridge, the port specific attributes must be ' +
22 'specified under the port. And for vlan unaware bridge ' +
23 'port specific attributes must be specified under the ' +
27 {'help' : 'vlan aware bridge. Setting this ' +
28 'attribute to yes enables vlan filtering' +
30 'example' : ['bridge-vlan-aware yes/no']},
32 {'help' : 'bridge ports',
34 'example' : ['bridge-ports swp1.100 swp2.100 swp3.100',
35 'bridge-ports glob swp1-3.100',
36 'bridge-ports regex (swp[1|2|3].100)']},
38 {'help': 'bridge-stp yes/no',
39 'example' : ['bridge-stp no'],
40 'validvals' : ['yes', 'on', 'off', 'no'],
43 {'help': 'bridge priority',
44 'example' : ['bridge-bridgeprio 32768'],
47 {'help': 'bridge ageing',
48 'example' : ['bridge-ageing 300'],
51 { 'help' : 'bridge forward delay',
52 'example' : ['bridge-fd 15'],
56 { 'help' : 'bridge garbage collection interval in secs',
57 'example' : ['bridge-gcint 4'],
60 { 'help' : 'bridge set hello time',
61 'example' : ['bridge-hello 2'],
64 { 'help' : 'bridge set maxage',
65 'example' : ['bridge-maxage 20'],
68 { 'help' : 'bridge set port path costs',
69 'example' : ['bridge-pathcosts swp1=100 swp2=100'],
72 { 'help' : 'bridge port prios',
73 'example' : ['bridge-portprios swp1=32 swp2=32'],
76 { 'help' : 'set multicast last member count',
77 'example' : ['bridge-mclmc 2'],
80 { 'help' : 'set multicast router',
82 'example' : ['bridge-mcrouter 1']},
84 { 'help' : 'set multicast snooping',
86 'example' : ['bridge-mcsnoop 1']},
88 { 'help' : 'set multicast startup query count',
90 'example' : ['bridge-mcsqc 2']},
92 { 'help' : 'set multicast query to use ifaddr',
94 'example' : ['bridge-mcqifaddr 0']},
96 { 'help' : 'set multicast querier',
98 'example' : ['bridge-mcquerier 0']},
100 { 'help' : 'set hash elasticity',
102 'example' : ['bridge-hashel 4096']},
104 { 'help' : 'set hash max',
106 'example' : ['bridge-hashmax 4096']},
108 { 'help' : 'set multicast last member interval (in secs)',
110 'example' : ['bridge-mclmi 1']},
112 { 'help' : 'set multicast membership interval (in secs)',
114 'example' : ['bridge-mcmi 260']},
116 { 'help' : 'set multicast querier interval (in secs)',
118 'example' : ['bridge-mcqpi 255']},
120 { 'help' : 'set multicast query interval (in secs)',
122 'example' : ['bridge-mcqi 125']},
124 { 'help' : 'set multicast query response interval (in secs)',
126 'example' : ['bridge-mcqri 10']},
128 { 'help' : 'set multicast startup query interval (in secs)',
130 'example' : ['bridge-mcsqi 31']},
132 { 'help' : 'set per VLAN v4 multicast querier source address',
134 'example' : ['bridge-mcqv4src 100=172.16.100.1 101=172.16.101.1']},
135 'bridge-portmcrouter' :
136 { 'help' : 'set port multicast routers',
138 'example' : ['under the bridge: bridge-portmcrouter swp1=1 swp2=1',
139 'under the port: bridge-portmcrouter 1']},
141 { 'help' : 'port multicast fast leave.',
143 'example' : ['under the bridge: bridge-portmcfl swp1=0 swp2=0',
144 'under the port: bridge-portmcfl 0']},
146 { 'help' : 'wait for a max of time secs for the' +
147 ' specified ports to become available,' +
148 'if no ports are specified then those' +
149 ' specified on bridge-ports will be' +
150 ' used here. Specifying no ports here ' +
151 'should not be used if we are using ' +
152 'regex or \"all\" on bridge_ports,' +
153 'as it wouldnt work.',
155 'example' : ['bridge-waitport 4 swp1 swp2']},
157 { 'help' : 'forces to time seconds the maximum time ' +
158 'that the Debian bridge setup scripts will ' +
159 'wait for the bridge ports to get to the ' +
160 'forwarding status, doesn\'t allow factional ' +
161 'part. If it is equal to 0 then no waiting' +
164 'example' : ['bridge-maxwait 3']},
166 { 'help' : 'bridge port vids. Can be specified ' +
167 'under the bridge or under the port. ' +
168 'If specified under the bridge the ports ' +
169 'inherit it unless overridden by a ' +
170 'bridge-vids attribuet under the port',
171 'example' : ['bridge-vids 4000']},
173 { 'help' : 'bridge port pvid. Must be specified under' +
175 'example' : ['bridge-pvid 1']},
177 { 'help' : 'bridge port access vlan. Must be ' +
178 'specified under the bridge port',
179 'example' : ['bridge-access 300']},
181 { 'help' : 'bridge vlans',
183 'example' : ['bridge-port-vids bond0=1-1000,1010-1020']},
184 'bridge-port-pvids' :
185 { 'help' : 'bridge port vlans',
187 'example' : ['bridge-port-pvids bond0=100 bond1=200']},
188 'bridge-igmp-querier-src' :
189 { 'help' : 'bridge igmp querier src. Must be ' +
190 'specified under the vlan interface',
191 'example' : ['bridge-igmp-querier-src 172.16.101.1']},
194 # declare some ifaceobj priv_flags.
195 # XXX: This assumes that the priv_flags is owned by this module
197 _BRIDGE_PORT_PROCESSED
= 0x1
199 def __init__(self
, *args
, **kargs
):
200 moduleBase
.__init
__(self
, *args
, **kargs
)
203 self
._running
_vidinfo
= {}
204 self
._running
_vidinfo
_valid
= False
206 def _is_bridge(self
, ifaceobj
):
207 if ifaceobj
.get_attr_value_first('bridge-ports'):
211 def _is_bridge_port(self
, ifaceobj
):
212 if self
.brctlcmd
.is_bridge_port(ifaceobj
.name
):
216 def get_dependent_ifacenames(self
, ifaceobj
, ifacenames_all
=None):
217 if not self
._is
_bridge
(ifaceobj
):
219 return self
.parse_port_list(ifaceobj
.get_attr_value_first(
220 'bridge-ports'), ifacenames_all
)
222 def get_dependent_ifacenames_running(self
, ifaceobj
):
223 self
._init
_command
_handlers
()
224 if not self
.brctlcmd
.bridge_exists(ifaceobj
.name
):
226 return self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
228 def _get_bridge_port_list(self
, ifaceobj
):
230 # port list is also available in the previously
231 # parsed dependent list. Use that if available, instead
232 # of parsing port expr again
233 port_list
= ifaceobj
.lowerifaces
236 ports
= ifaceobj
.get_attr_value_first('bridge-ports')
238 return self
.parse_port_list(ports
)
242 def _process_bridge_waitport(self
, ifaceobj
, portlist
):
243 waitport_value
= ifaceobj
.get_attr_value_first('bridge-waitport')
244 if not waitport_value
: return
246 waitportvals
= re
.split(r
'[\s\t]\s*', waitport_value
, 1)
247 if not waitportvals
: return
249 waitporttime
= int(waitportvals
[0])
251 self
.log_warn('%s: invalid waitport value \'%s\''
252 %(ifaceobj
.name
, waitporttime
))
254 if waitporttime
<= 0: return
256 waitportlist
= self
.parse_port_list(waitportvals
[1])
257 except IndexError, e
:
258 # ignore error and use all bridge ports
259 waitportlist
= portlist
261 if not waitportlist
: return
262 self
.logger
.info('%s: waiting for ports %s to exist ...'
263 %(ifaceobj
.name
, str(waitportlist
)))
264 starttime
= time
.time()
265 while ((time
.time() - starttime
) < waitporttime
):
266 if all([False for p
in waitportlist
267 if not self
.ipcmd
.link_exists(p
)]):
271 self
.log_warn('%s: unable to process waitport: %s'
272 %(ifaceobj
.name
, str(e
)))
274 def _add_ports(self
, ifaceobj
):
275 bridgeports
= self
._get
_bridge
_port
_list
(ifaceobj
)
276 runningbridgeports
= []
278 self
._process
_bridge
_waitport
(ifaceobj
, bridgeports
)
279 # Delete active ports not in the new port list
280 if not self
.PERFMODE
:
281 runningbridgeports
= self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
282 if runningbridgeports
:
283 [self
.ipcmd
.link_set(bport
, 'nomaster')
284 for bport
in runningbridgeports
285 if not bridgeports
or bport
not in bridgeports
]
287 runningbridgeports
= []
291 for bridgeport
in Set(bridgeports
).difference(Set(runningbridgeports
)):
293 if not self
.DRYRUN
and not self
.ipcmd
.link_exists(bridgeport
):
294 self
.log_warn('%s: bridge port %s does not exist'
295 %(ifaceobj
.name
, bridgeport
))
298 self
.ipcmd
.link_set(bridgeport
, 'master', ifaceobj
.name
)
299 self
.write_file('/proc/sys/net/ipv6/conf/%s' %bridgeport
+
300 '/disable_ipv6', '1')
301 self
.ipcmd
.addr_flush(bridgeport
)
303 self
.log_error(str(e
))
305 self
.log_error('bridge configuration failed (missing ports)')
307 def _process_bridge_maxwait(self
, ifaceobj
, portlist
):
308 maxwait
= ifaceobj
.get_attr_value_first('bridge-maxwait')
309 if not maxwait
: return
311 maxwait
= int(maxwait
)
313 self
.log_warn('%s: invalid maxwait value \'%s\'' %(ifaceobj
.name
,
316 if not maxwait
: return
317 self
.logger
.info('%s: waiting for ports to go to fowarding state ..'
320 starttime
= time
.time()
321 while ((time
.time() - starttime
) < maxwait
):
322 if all([False for p
in portlist
323 if self
.read_file_oneline(
324 '/sys/class/net/%s/brif/%s/state'
325 %(ifaceobj
.name
, p
)) != '3']):
329 self
.log_warn('%s: unable to process maxwait: %s'
330 %(ifaceobj
.name
, str(e
)))
332 def _ints_to_ranges(self
, ints
):
333 for a
, b
in itertools
.groupby(enumerate(ints
), lambda (x
, y
): y
- x
):
335 yield b
[0][1], b
[-1][1]
337 def _ranges_to_ints(self
, rangelist
):
338 """ returns expanded list of integers given set of string ranges
339 example: ['1', '2-4', '6'] returns [1, 2, 3, 4, 6]
342 for part
in rangelist
:
344 a
, b
= part
.split('-')
345 a
, b
= int(a
), int(b
)
346 result
.extend(range(a
, b
+ 1))
352 def _diff_vids(self
, vids1
, vids2
):
356 vids1_ints
= self
._ranges
_to
_ints
(vids1
)
357 vids2_ints
= self
._ranges
_to
_ints
(vids2
)
358 vids1_diff
= Set(vids1_ints
).difference(vids2_ints
)
359 vids2_diff
= Set(vids2_ints
).difference(vids1_ints
)
361 vids_to_add
= ['%d' %start
if start
== end
else '%d-%d' %(start
, end
)
362 for start
, end
in self
._ints
_to
_ranges
(vids1_diff
)]
364 vids_to_del
= ['%d' %start
if start
== end
else '%d-%d' %(start
, end
)
365 for start
, end
in self
._ints
_to
_ranges
(vids2_diff
)]
366 return (vids_to_del
, vids_to_add
)
368 def _compare_vids(self
, vids1
, vids2
):
369 """ Returns true if the vids are same else return false """
371 vids1_ints
= self
._ranges
_to
_ints
(vids1
)
372 vids2_ints
= self
._ranges
_to
_ints
(vids2
)
373 if Set(vids1_ints
).symmetric_difference(vids2_ints
):
378 def _set_bridge_mcqv4src_compat(self
, ifaceobj
):
380 # Sets old style igmp querier
382 attrval
= ifaceobj
.get_attr_value_first('bridge-mcqv4src')
384 running_mcqv4src
= {}
385 if not self
.PERFMODE
:
386 running_mcqv4src
= self
.brctlcmd
.get_mcqv4src(ifaceobj
.name
)
388 srclist
= attrval
.split()
393 k_to_del
= Set(running_mcqv4src
.keys()).difference(mcqs
.keys())
395 self
.brctlcmd
.del_mcqv4src(ifaceobj
.name
, v
)
396 for v
in mcqs
.keys():
397 self
.brctlcmd
.set_mcqv4src(ifaceobj
.name
, v
, mcqs
[v
])
399 def _get_running_vidinfo(self
):
400 if self
._running
_vidinfo
_valid
:
401 return self
._running
_vidinfo
402 self
._running
_vidinfo
= {}
403 if not self
.PERFMODE
:
404 self
._running
_vidinfo
= self
.ipcmd
.bridge_port_vids_get_all()
405 self
._running
_vidinfo
_valid
= True
406 return self
._running
_vidinfo
408 def _flush_running_vidinfo(self
):
409 self
._running
_vidinfo
= {}
410 self
._running
_vidinfo
_valid
= False
412 def _set_bridge_vidinfo_compat(self
, ifaceobj
):
414 # Supports old style vlan vid info format
418 # Handle bridge vlan attrs
419 running_vidinfo
= self
._get
_running
_vidinfo
()
422 attrval
= ifaceobj
.get_attr_value_first('bridge-port-pvids')
424 portlist
= self
.parse_port_list(attrval
)
426 self
.log_warn('%s: could not parse \'%s %s\''
427 %(ifaceobj
.name
, attrname
, attrval
))
431 (port
, pvid
) = p
.split('=')
432 running_pvid
= running_vidinfo
.get(port
, {}).get('pvid')
434 if running_pvid
== pvid
:
437 self
.ipcmd
.bridge_port_pvid_del(port
, running_pvid
)
438 self
.ipcmd
.bridge_port_pvid_add(port
, pvid
)
440 self
.log_warn('%s: failed to set pvid `%s` (%s)'
441 %(ifaceobj
.name
, p
, str(e
)))
444 attrval
= ifaceobj
.get_attr_value_first('bridge-port-vids')
446 portlist
= self
.parse_port_list(attrval
)
448 self
.log_warn('%s: could not parse \'%s %s\''
449 %(ifaceobj
.name
, attrname
, attrval
))
453 (port
, val
) = p
.split('=')
454 vids
= val
.split(',')
455 if running_vidinfo
.get(port
):
456 (vids_to_del
, vids_to_add
) = \
457 self
._diff
_vids
(vids
,
458 running_vidinfo
.get(port
).get('vlan'))
460 self
.ipcmd
.bridge_port_vids_del(port
, vids_to_del
)
462 self
.ipcmd
.bridge_port_vids_add(port
, vids_to_add
)
464 self
.ipcmd
.bridge_port_vids_add(port
, vids
)
466 self
.log_warn('%s: failed to set vid `%s` (%s)'
467 %(ifaceobj
.name
, p
, str(e
)))
470 # XXX: Commenting out this code for now because it was decided
471 # that this is not needed
472 #attrval = ifaceobj.get_attr_value_first('bridge-vids')
474 # vids = re.split(r'[\s\t]\s*', attrval)
475 # if running_vidinfo.get(ifaceobj.name):
476 # (vids_to_del, vids_to_add) = \
477 # self._diff_vids(vids,
478 # running_vidinfo.get(ifaceobj.name).get('vlan'))
480 # self.ipcmd.bridge_vids_del(ifaceobj.name, vids_to_del)
482 # self.ipcmd.bridge_vids_add(ifaceobj.name, vids_to_add)
484 # self.ipcmd.bridge_vids_add(ifaceobj.name, vids)
486 # running_vids = running_vidinfo.get(ifaceobj.name)
488 # self.ipcmd.bridge_vids_del(ifaceobj.name, running_vids)
490 def _apply_bridge_settings(self
, ifaceobj
):
492 stp
= ifaceobj
.get_attr_value_first('bridge-stp')
494 self
.brctlcmd
.set_stp(ifaceobj
.name
, stp
)
495 # Use the brctlcmd bulk set method: first build a dictionary
497 bridgeattrs
= { k
:v
for k
,v
in
499 ifaceobj
.get_attr_value_first('bridge-ageing'),
501 ifaceobj
.get_attr_value_first(
502 'bridge-bridgeprio'),
504 ifaceobj
.get_attr_value_first('bridge-fd'),
506 ifaceobj
.get_attr_value_first('bridge-gcint'),
508 ifaceobj
.get_attr_value_first('bridge-hello'),
510 ifaceobj
.get_attr_value_first('bridge-maxage'),
512 ifaceobj
.get_attr_value_first('bridge-mclmc'),
514 ifaceobj
.get_attr_value_first(
517 ifaceobj
.get_attr_value_first('bridge-mcsnoop'),
519 ifaceobj
.get_attr_value_first('bridge-mcsqc'),
521 ifaceobj
.get_attr_value_first(
524 ifaceobj
.get_attr_value_first(
527 ifaceobj
.get_attr_value_first('bridge-hashel'),
529 ifaceobj
.get_attr_value_first('bridge-hashmax'),
531 ifaceobj
.get_attr_value_first('bridge-mclmi'),
533 ifaceobj
.get_attr_value_first('bridge-mcmi'),
535 ifaceobj
.get_attr_value_first('bridge-mcqpi'),
537 ifaceobj
.get_attr_value_first('bridge-mcqi'),
539 ifaceobj
.get_attr_value_first('bridge-mcqri'),
541 ifaceobj
.get_attr_value_first('bridge-mcsqi')
545 self
.brctlcmd
.set_bridge_attrs(ifaceobj
.name
, bridgeattrs
)
547 for attrname
, dstattrname
in {'bridge-pathcosts' : 'pathcost',
548 'bridge-portprios' : 'portprio',
549 'bridge-portmcrouter' : 'portmcrouter',
550 'bridge-portmcfl' : 'portmcfl'}.items():
551 attrval
= ifaceobj
.get_attr_value_first(attrname
)
554 portlist
= self
.parse_port_list(attrval
)
556 self
.log_warn('%s: could not parse \'%s %s\''
557 %(ifaceobj
.name
, attrname
, attrval
))
561 (port
, val
) = p
.split('=')
562 if not portattrs
.get(port
):
564 portattrs
[port
].update({dstattrname
: val
})
566 self
.log_warn('%s: could not parse %s (%s)'
567 %(ifaceobj
.name
, attrname
, str(e
)))
568 for port
, attrdict
in portattrs
.iteritems():
569 self
.brctlcmd
.set_bridgeport_attrs(ifaceobj
.name
, port
,
571 self
._set
_bridge
_vidinfo
_compat
(ifaceobj
)
573 self
._set
_bridge
_mcqv
4src
_compat
(ifaceobj
)
575 self
._process
_bridge
_maxwait
(ifaceobj
,
576 self
._get
_bridge
_port
_list
(ifaceobj
))
578 self
.log_warn(str(e
))
580 def _apply_bridge_vids(self
, bportifaceobj
, vids
, running_vids
, isbridge
):
583 (vids_to_del
, vids_to_add
) = \
584 self
._diff
_vids
(vids
, running_vids
)
586 self
.ipcmd
.bridge_vids_del(bportifaceobj
.name
,
587 vids_to_del
, isbridge
)
589 self
.ipcmd
.bridge_vids_add(bportifaceobj
.name
,
590 vids_to_add
, isbridge
)
592 self
.ipcmd
.bridge_vids_add(bportifaceobj
.name
, vids
, isbridge
)
594 self
.log_warn('%s: failed to set vid `%s` (%s)'
595 %(bportifaceobj
.name
, str(vids
), str(e
)))
597 def _apply_bridge_port_pvids(self
, bportifaceobj
, pvid
, running_pvid
):
601 if running_pvid
!= pvid
:
602 self
.ipcmd
.bridge_port_pvid_del(bportifaceobj
.name
,
604 self
.ipcmd
.bridge_port_pvid_add(bportifaceobj
.name
, pvid
)
606 self
.ipcmd
.bridge_port_pvid_add(bportifaceobj
.name
, pvid
)
608 self
.log_warn('%s: failed to set pvid `%s` (%s)'
609 %(bportifaceobj
.name
, pvid
, str(e
)))
611 def _apply_bridge_vlan_aware_port_settings_all(self
, bportifaceobj
,
613 running_vidinfo
= self
._get
_running
_vidinfo
()
616 bport_access
= bportifaceobj
.get_attr_value_first('bridge-access')
618 vids
= re
.split(r
'[\s\t]\s*', bport_access
)
621 bport_vids
= bportifaceobj
.get_attr_value_first('bridge-vids')
623 vids
= re
.split(r
'[\s\t]\s*', bport_vids
)
625 bport_pvids
= bportifaceobj
.get_attr_value_first('bridge-pvid')
627 pvids
= re
.split(r
'[\s\t]\s*', bport_pvids
)
630 self
._apply
_bridge
_port
_pvids
(bportifaceobj
, pvids
[0],
631 running_vidinfo
.get(bportifaceobj
.name
, {}).get('pvid'))
633 self
._apply
_bridge
_port
_pvids
(bportifaceobj
,
634 '1', running_vidinfo
.get(bportifaceobj
.name
,
638 self
._apply
_bridge
_vids
(bportifaceobj
, vids
,
639 running_vidinfo
.get(bportifaceobj
.name
,
640 {}).get('vlan'), False)
642 self
._apply
_bridge
_vids
(bportifaceobj
,
643 bridge_vids
, running_vidinfo
.get(
644 bportifaceobj
.name
, {}).get('vlan'), False)
647 def _apply_bridge_port_settings(self
, bportifaceobj
, bridgename
=None,
648 bridgeifaceobj
=None):
649 if not bridgename
and bridgeifaceobj
:
650 bridgename
= bridgeifaceobj
.name
651 # Set other stp and igmp attributes
653 for attrname
, dstattrname
in {
654 'bridge-pathcosts' : 'pathcost',
655 'bridge-portprios' : 'portprio',
656 'bridge-portmcrouter' : 'portmcrouter',
657 'bridge-portmcfl' : 'portmcfl'}.items():
658 attrval
= bportifaceobj
.get_attr_value_first(attrname
)
660 # Check if bridge has that attribute
662 # attrval = bridgeifaceobj.get_attr_value_first(attrname)
667 portattrs
[dstattrname
] = attrval
669 self
.brctlcmd
.set_bridgeport_attrs(bridgename
,
670 bportifaceobj
.name
, portattrs
)
672 self
.log_warn(str(e
))
674 def _apply_bridge_port_settings_all(self
, ifaceobj
,
675 ifaceobj_getfunc
=None):
676 bridge_vlan_aware
= ifaceobj
.get_attr_value_first(
678 if bridge_vlan_aware
and bridge_vlan_aware
== 'yes':
679 bridge_vlan_aware
= True
681 bridge_vlan_aware
= False
683 if (ifaceobj
.get_attr_value_first('bridge-port-vids') and
684 ifaceobj
.get_attr_value_first('bridge-port-pvids')):
685 # Old style bridge port vid info
686 # skip new style setting on ports
688 self
.logger
.info('%s: applying bridge configuration '
689 %ifaceobj
.name
+ 'specific to ports')
691 bridge_vids
= ifaceobj
.get_attr_value_first('bridge-vids')
693 bridge_vids
= re
.split(r
'[\s\t]\s*', bridge_vids
)
697 bridgeports
= self
._get
_bridge
_port
_list
(ifaceobj
)
698 for bport
in bridgeports
:
699 # Use the brctlcmd bulk set method: first build a dictionary
701 if not self
.ipcmd
.bridge_port_exists(ifaceobj
.name
, bport
):
702 self
.logger
.info('%s: skipping bridge config' %ifaceobj
.name
+
703 ' for port %s (missing port)' %bport
)
705 self
.logger
.info('%s: processing bridge config for port %s'
706 %(ifaceobj
.name
, bport
))
707 bportifaceobjlist
= ifaceobj_getfunc(bport
)
708 if not bportifaceobjlist
:
710 for bportifaceobj
in bportifaceobjlist
:
711 # Dont process bridge port if it already has been processed
712 if bportifaceobj
.priv_flags
& self
._BRIDGE
_PORT
_PROCESSED
:
715 # Add attributes specific to the vlan aware bridge
716 if bridge_vlan_aware
:
717 self
._apply
_bridge
_vlan
_aware
_port
_settings
_all
(
718 bportifaceobj
, bridge_vids
)
719 self
._apply
_bridge
_port
_settings
(bportifaceobj
,
720 bridgeifaceobj
=ifaceobj
)
722 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
723 # Check if bridge port
724 bridgename
= self
.ipcmd
.bridge_port_get_bridge_name(ifaceobj
.name
)
726 if self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
727 bridge_vids
= self
._get
_bridge
_vids
(bridgename
,
729 self
._apply
_bridge
_vlan
_aware
_port
_settings
_all
(ifaceobj
,
731 self
._apply
_bridge
_port
_settings
(ifaceobj
, bridgename
=bridgename
)
732 ifaceobj
.priv_flags |
= self
._BRIDGE
_PORT
_PROCESSED
734 if not self
._is
_bridge
(ifaceobj
):
739 self
.ipcmd
.batch_start()
740 if not self
.PERFMODE
:
741 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
742 self
.ipcmd
.link_create(ifaceobj
.name
, 'bridge')
744 self
.ipcmd
.link_create(ifaceobj
.name
, 'bridge')
746 self
._add
_ports
(ifaceobj
)
752 self
.ipcmd
.batch_commit()
753 self
._apply
_bridge
_settings
(ifaceobj
)
754 self
._apply
_bridge
_port
_settings
_all
(ifaceobj
,
755 ifaceobj_getfunc
=ifaceobj_getfunc
)
756 self
._flush
_running
_vidinfo
()
758 self
.log_error(str(e
))
760 raise Exception(porterrstr
)
762 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
764 if ifaceobj
.get_attr_value_first('bridge-ports'):
765 ports
= self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
768 proc_file
= ('/proc/sys/net/ipv6/conf/%s' %p
+
770 self
.write_file(proc_file
, '0')
771 self
.brctlcmd
.delete_bridge(ifaceobj
.name
)
773 self
.log_error(str(e
))
775 def _query_running_vidinfo_compat(self
, ifaceobjrunning
, ports
):
777 running_vidinfo
= self
._get
_running
_vidinfo
()
779 running_bridge_port_vids
= ''
782 running_vids
= running_vidinfo
.get(p
, {}).get('vlan')
784 running_bridge_port_vids
+= ' %s=%s' %(p
,
785 ','.join(running_vids
))
788 running_attrs
['bridge-port-vids'] = running_bridge_port_vids
790 running_bridge_port_pvids
= ''
793 running_pvids
= running_vidinfo
.get(p
, {}).get('pvid')
795 running_bridge_port_pvids
+= ' %s=%s' %(p
,
799 running_attrs
['bridge-port-pvids'] = running_bridge_port_pvids
801 running_bridge_vids
= running_vidinfo
.get(ifaceobjrunning
.name
,
803 if running_bridge_vids
:
804 running_attrs
['bridge-vids'] = ','.join(running_bridge_vids
)
807 def _query_running_vidinfo(self
, ifaceobjrunning
):
809 running_vidinfo
= self
._get
_running
_vidinfo
()
810 running_bridge_vids
= running_vidinfo
.get(ifaceobjrunning
.name
,
812 if running_bridge_vids
:
813 running_attrs
['bridge-vids'] = ','.join(running_bridge_vids
)
816 def _query_running_mcqv4src(self
, ifaceobjrunning
):
817 running_mcqv4src
= self
.brctlcmd
.get_mcqv4src(ifaceobjrunning
.name
)
818 mcqs
= ['%s=%s' %(v
, i
) for v
, i
in running_mcqv4src
.items()]
823 def _query_running_attrs(self
, ifaceobjrunning
, bridge_vlan_aware
=False):
827 skip_kernel_stp_attrs
= 0
829 if self
.sysctl_get('net.bridge.bridge-stp-user-space') == '1':
832 tmpbridgeattrdict
= self
.brctlcmd
.get_bridge_attrs(ifaceobjrunning
.name
)
833 if not tmpbridgeattrdict
:
834 self
.logger
.warn('%s: unable to get bridge attrs'
835 %ifaceobjrunning
.name
)
836 return bridgeattrdict
838 # Fill bridge_ports and bridge stp attributes first
839 ports
= tmpbridgeattrdict
.get('ports')
841 bridgeattrdict
['bridge-ports'] = [' '.join(ports
.keys())]
842 stp
= tmpbridgeattrdict
.get('stp', 'no')
843 if stp
!= self
.get_mod_subattr('bridge-stp', 'default'):
844 bridgeattrdict
['bridge-stp'] = [stp
]
846 if stp
== 'yes' and userspace_stp
:
847 skip_kernel_stp_attrs
= 1
849 # pick all other attributes
850 for k
,v
in tmpbridgeattrdict
.items():
853 if k
== 'ports' or k
== 'stp':
856 if skip_kernel_stp_attrs
and k
[:2] != 'mc':
857 # only include igmp attributes if kernel stp is off
859 attrname
= 'bridge-' + k
860 if v
!= self
.get_mod_subattr(attrname
, 'default'):
861 bridgeattrdict
[attrname
] = [v
]
863 if bridge_vlan_aware
:
864 bridgevidinfo
= self
._query
_running
_vidinfo
(ifaceobjrunning
)
866 bridgevidinfo
= self
._query
_running
_vidinfo
_compat
(ifaceobjrunning
,
869 bridgeattrdict
.update({k
: [v
] for k
, v
in bridgevidinfo
.items()
872 mcq
= self
._query
_running
_mcqv
4src
(ifaceobjrunning
)
874 bridgeattrdict
['bridge-mcqv4src'] = [mcq
]
876 if skip_kernel_stp_attrs
:
877 return bridgeattrdict
880 portconfig
= {'bridge-pathcosts' : '',
881 'bridge-portprios' : ''}
882 for p
, v
in ports
.items():
883 v
= self
.brctlcmd
.get_pathcost(ifaceobjrunning
.name
, p
)
884 if v
and v
!= self
.get_mod_subattr('bridge-pathcosts',
886 portconfig
['bridge-pathcosts'] += ' %s=%s' %(p
, v
)
888 v
= self
.brctlcmd
.get_portprio(ifaceobjrunning
.name
, p
)
889 if v
and v
!= self
.get_mod_subattr('bridge-portprios',
891 portconfig
['bridge-portprios'] += ' %s=%s' %(p
, v
)
893 bridgeattrdict
.update({k
: [v
] for k
, v
in portconfig
.items()
896 return bridgeattrdict
898 def _query_check_mcqv4src(self
, ifaceobj
, ifaceobjcurr
):
899 running_mcqs
= self
._query
_running
_mcqv
4src
(ifaceobj
)
900 attrval
= ifaceobj
.get_attr_value_first('bridge-mcqv4src')
902 mcqs
= attrval
.split()
904 mcqsout
= ' '.join(mcqs
)
905 ifaceobjcurr
.update_config_with_status('bridge-mcqv4src',
906 running_mcqs
, 1 if running_mcqs
!= mcqsout
else 0)
908 def _query_check_bridge_vidinfo(self
, ifaceobj
, ifaceobjcurr
):
910 running_vidinfo
= self
._get
_running
_vidinfo
()
911 attrval
= ifaceobj
.get_attr_value_first('bridge-port-vids')
913 running_bridge_port_vids
= ''
914 portlist
= self
.parse_port_list(attrval
)
916 self
.log_warn('%s: could not parse \'%s %s\''
917 %(ifaceobj
.name
, attrname
, attrval
))
922 (port
, val
) = p
.split('=')
923 vids
= val
.split(',')
924 running_vids
= running_vidinfo
.get(port
, {}).get('vlan')
926 if not self
._compare
_vids
(vids
, running_vids
):
928 running_bridge_port_vids
+= ' %s=%s' %(port
,
929 ','.join(running_vids
))
931 running_bridge_port_vids
+= ' %s' %p
935 self
.log_warn('%s: failure checking vid %s (%s)'
936 %(ifaceobj
.name
, p
, str(e
)))
938 ifaceobjcurr
.update_config_with_status('bridge-port-vids',
939 running_bridge_port_vids
, 1)
941 ifaceobjcurr
.update_config_with_status('bridge-port-vids',
944 attrval
= ifaceobj
.get_attr_value_first('bridge-port-pvids')
946 portlist
= self
.parse_port_list(attrval
)
948 self
.log_warn('%s: could not parse \'%s %s\''
949 %(ifaceobj
.name
, attrname
, attrval
))
951 running_bridge_port_pvids
= ''
955 (port
, pvid
) = p
.split('=')
956 running_pvid
= running_vidinfo
.get(port
, {}).get('pvid')
957 if running_pvid
and running_pvid
== pvid
:
958 running_bridge_port_pvids
+= ' %s' %p
961 running_bridge_port_pvids
+= ' %s=%s' %(port
,
964 self
.log_warn('%s: failure checking pvid %s (%s)'
965 %(ifaceobj
.name
, pvid
, str(e
)))
967 ifaceobjcurr
.update_config_with_status('bridge-port-pvids',
968 running_bridge_port_pvids
, 1)
970 ifaceobjcurr
.update_config_with_status('bridge-port-pvids',
971 running_bridge_port_pvids
, 0)
973 # XXX: No need to check for bridge-vids on the bridge
974 # This is used by the ports. The vids on the bridge
975 # come from the vlan interfaces on the bridge.
977 attrval
= ifaceobj
.get_attr_value_first('bridge-vids')
979 # vids = re.split(r'[\s\t]\s*', attrval)
980 # running_vids = running_vidinfo.get(ifaceobj.name, {}).get('vlan')
982 # if self._compare_vids(vids, running_vids):
983 # ifaceobjcurr.update_config_with_status('bridge-vids',
986 # ifaceobjcurr.update_config_with_status('bridge-vids',
987 # ','.join(running_vids), 1)
989 # ifaceobjcurr.update_config_with_status('bridge-vids', attrval,
992 ifaceobjcurr
.update_config_with_status('bridge-vids', attrval
, -1)
994 def _query_check_bridge(self
, ifaceobj
, ifaceobjcurr
,
995 ifaceobj_getfunc
=None):
996 if not self
._is
_bridge
(ifaceobj
):
998 if not self
.brctlcmd
.bridge_exists(ifaceobj
.name
):
999 self
.logger
.info('%s: bridge: does not exist' %(ifaceobj
.name
))
1000 ifaceobjcurr
.status
= ifaceStatus
.NOTFOUND
1003 ifaceattrs
= self
.dict_key_subset(ifaceobj
.config
,
1004 self
.get_mod_attrs())
1008 runningattrs
= self
.brctlcmd
.get_bridge_attrs(ifaceobj
.name
)
1009 if not runningattrs
:
1010 self
.logger
.debug('%s: bridge: unable to get bridge attrs'
1013 except Exception, e
:
1014 self
.logger
.warn(str(e
))
1016 filterattrs
= ['bridge-vids', 'bridge-port-vids',
1017 'bridge-port-pvids']
1018 for k
in Set(ifaceattrs
).difference(filterattrs
):
1019 # get the corresponding ifaceobj attr
1020 v
= ifaceobj
.get_attr_value_first(k
)
1023 rv
= runningattrs
.get(k
[7:])
1024 if k
== 'bridge-mcqv4src':
1026 if k
== 'bridge-vlan-aware' and v
== 'yes':
1027 if self
.ipcmd
.bridge_is_vlan_aware(ifaceobj
.name
):
1028 ifaceobjcurr
.update_config_with_status('bridge-vlan-aware',
1031 ifaceobjcurr
.update_config_with_status('bridge-vlan-aware',
1033 elif k
== 'bridge-stp':
1034 # special case stp compare because it may
1035 # contain more than one valid values
1036 stp_on_vals
= ['on', 'yes']
1037 stp_off_vals
= ['off']
1038 if ((v
in stp_on_vals
and rv
in stp_on_vals
) or
1039 (v
in stp_off_vals
and rv
in stp_off_vals
)):
1040 ifaceobjcurr
.update_config_with_status('bridge-stp',
1043 ifaceobjcurr
.update_config_with_status('bridge-stp',
1045 elif k
== 'bridge-ports':
1046 # special case ports because it can contain regex or glob
1047 running_port_list
= rv
.keys() if rv
else []
1048 bridge_port_list
= self
._get
_bridge
_port
_list
(ifaceobj
)
1049 if not running_port_list
and not bridge_port_list
:
1052 if running_port_list
and bridge_port_list
:
1053 difference
= set(running_port_list
1054 ).symmetric_difference(bridge_port_list
)
1057 ifaceobjcurr
.update_config_with_status('bridge-ports',
1058 ' '.join(running_port_list
)
1059 if running_port_list
else '', portliststatus
)
1060 elif (k
== 'bridge-pathcosts' or
1061 k
== 'bridge-portprios' or k
== 'bridge-portmcrouter'
1062 or k
== 'bridge-portmcfl'):
1063 brctlcmdattrname
= k
[11:].rstrip('s')
1064 # for port attributes, the attributes are in a list
1065 # <portname>=<portattrvalue>
1068 vlist
= self
.parse_port_list(v
)
1071 for vlistitem
in vlist
:
1073 (p
, v
) = vlistitem
.split('=')
1074 currv
= self
.brctlcmd
.get_bridgeport_attr(
1078 currstr
+= ' %s=%s' %(p
, currv
)
1080 currstr
+= ' %s=%s' %(p
, 'None')
1083 except Exception, e
:
1084 self
.log_warn(str(e
))
1086 ifaceobjcurr
.update_config_with_status(k
, currstr
, status
)
1088 ifaceobjcurr
.update_config_with_status(k
, 'notfound', 1)
1091 ifaceobjcurr
.update_config_with_status(k
, rv
, 1)
1093 ifaceobjcurr
.update_config_with_status(k
, rv
, 0)
1095 self
._query
_check
_bridge
_vidinfo
(ifaceobj
, ifaceobjcurr
)
1097 self
._query
_check
_mcqv
4src
(ifaceobj
, ifaceobjcurr
)
1099 def _get_bridge_vids(self
, bridgename
, ifaceobj_getfunc
):
1100 ifaceobjs
= ifaceobj_getfunc(bridgename
)
1101 for ifaceobj
in ifaceobjs
:
1102 vids
= ifaceobj
.get_attr_value_first('bridge-vids')
1103 if vids
: return re
.split(r
'[\s\t]\s*', vids
)
1106 def _get_bridge_name(self
, ifaceobj
):
1107 return self
.ipcmd
.bridge_port_get_bridge_name(ifaceobj
.name
)
1109 def _query_check_bridge_port_vidinfo(self
, ifaceobj
, ifaceobjcurr
,
1110 ifaceobj_getfunc
, bridgename
):
1111 running_vidinfo
= self
._get
_running
_vidinfo
()
1113 attr_name
= 'bridge-access'
1114 vids
= ifaceobj
.get_attr_value_first(attr_name
)
1116 running_pvids
= running_vidinfo
.get(ifaceobj
.name
,
1118 running_vids
= running_vidinfo
.get(ifaceobj
.name
,
1120 if (not running_pvids
or running_pvids
!= vids
or
1122 ifaceobjcurr
.update_config_with_status(attr_name
,
1125 ifaceobjcurr
.update_config_with_status(attr_name
, vids
, 0)
1128 attr_name
= 'bridge-vids'
1129 vids
= ifaceobj
.get_attr_value_first(attr_name
)
1131 vids
= re
.split(r
'[\s\t]\s*', vids
)
1132 running_vids
= running_vidinfo
.get(ifaceobj
.name
,
1134 if not running_vids
or not self
._compare
_vids
(vids
, running_vids
):
1135 ifaceobjcurr
.update_config_with_status(attr_name
,
1136 ' '.join(running_vids
), 1)
1138 ifaceobjcurr
.update_config_with_status(attr_name
,
1139 ' '.join(running_vids
), 0)
1141 # check if it matches the bridge vids
1142 bridge_vids
= self
._get
_bridge
_vids
(bridgename
, ifaceobj_getfunc
)
1143 running_vids
= running_vidinfo
.get(ifaceobj
.name
,
1145 if (bridge_vids
and (not running_vids
or
1146 not self
._compare
_vids
(bridge_vids
, running_vids
))):
1147 ifaceobjcurr
.status
= ifaceStatus
.ERROR
1148 ifaceobjcurr
.status_str
= 'bridge vid error'
1150 running_pvid
= running_vidinfo
.get(ifaceobj
.name
,
1152 attr_name
= 'bridge-pvid'
1153 pvid
= ifaceobj
.get_attr_value_first(attr_name
)
1155 if running_pvid
and running_pvid
== pvid
:
1156 ifaceobjcurr
.update_config_with_status(attr_name
,
1159 ifaceobjcurr
.update_config_with_status(attr_name
,
1161 elif not running_pvid
or running_pvid
!= '1':
1162 ifaceobjcurr
.status
= ifaceStatus
.ERROR
1163 ifaceobjcurr
.status_str
= 'bridge pvid error'
1165 def _query_check_bridge_port(self
, ifaceobj
, ifaceobjcurr
,
1167 if not self
._is
_bridge
_port
(ifaceobj
):
1168 # Mark all bridge attributes as failed
1169 ifaceobj
.check_n_update_config_with_status_many(
1170 ['bridge-vids', 'bridge-pvid', 'bridge-access',
1171 'bridge-pathcosts', 'bridge-portprios',
1172 'bridge-portmcrouter',
1174 'bridge-igmp-querier-src'], 0)
1176 bridgename
= self
._get
_bridge
_name
(ifaceobj
)
1178 self
.logger
.warn('%s: unable to determine bridge name'
1182 if self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
1183 self
._query
_check
_bridge
_port
_vidinfo
(ifaceobj
, ifaceobjcurr
,
1186 for attr
, dstattr
in {'bridge-pathcosts' : 'pathcost',
1187 'bridge-portprios' : 'priority',
1188 'bridge-portmcrouter' : 'mcrouter',
1189 'bridge-portmcfl' : 'mcfl' }.items():
1190 attrval
= ifaceobj
.get_attr_value_first(attr
)
1195 running_attrval
= self
.brctlcmd
.get_bridgeport_attr(
1196 bridgename
, ifaceobj
.name
, dstattr
)
1197 if running_attrval
!= attrval
:
1198 ifaceobjcurr
.update_config_with_status(attr
,
1201 ifaceobjcurr
.update_config_with_status(attr
,
1203 except Exception, e
:
1204 self
.log_warn('%s: %s' %(ifaceobj
.name
, str(e
)))
1206 def _query_check(self
, ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
=None):
1207 if self
._is
_bridge
(ifaceobj
):
1208 self
._query
_check
_bridge
(ifaceobj
, ifaceobjcurr
)
1210 self
._query
_check
_bridge
_port
(ifaceobj
, ifaceobjcurr
,
1213 def _query_running_bridge(self
, ifaceobjrunning
):
1214 if self
.ipcmd
.bridge_is_vlan_aware(ifaceobjrunning
.name
):
1215 ifaceobjrunning
.update_config('bridge-vlan-aware', 'yes')
1216 ifaceobjrunning
.update_config_dict(self
._query
_running
_attrs
(
1218 bridge_vlan_aware
=True))
1220 ifaceobjrunning
.update_config_dict(self
._query
_running
_attrs
(
1223 def _query_running_bridge_port_attrs(self
, ifaceobjrunning
, bridgename
):
1224 if self
.sysctl_get('net.bridge.bridge-stp-user-space') == '1':
1227 v
= self
.brctlcmd
.get_pathcost(bridgename
, ifaceobjrunning
.name
)
1228 if v
and v
!= self
.get_mod_subattr('bridge-pathcosts', 'default'):
1229 ifaceobjrunning
.update_config('bridge-pathcosts', v
)
1231 v
= self
.brctlcmd
.get_pathcost(bridgename
, ifaceobjrunning
.name
)
1232 if v
and v
!= self
.get_mod_subattr('bridge-portprios', 'default'):
1233 ifaceobjrunning
.update_config('bridge-portprios', v
)
1235 def _query_running_bridge_port(self
, ifaceobjrunning
,
1236 ifaceobj_getfunc
=None):
1237 bridgename
= self
.ipcmd
.bridge_port_get_bridge_name(
1238 ifaceobjrunning
.name
)
1240 self
.logger
.warn('%s: unable to find bridgename'
1241 %ifaceobjrunning
.name
)
1243 if not self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
1246 running_vidinfo
= self
._get
_running
_vidinfo
()
1248 bridge_vids
= running_vidinfo
.get(bridgename
, {}).get('vlan')
1250 bridge_port_vids
= running_vidinfo
.get(ifaceobjrunning
.name
,
1252 bridge_port_pvid
= running_vidinfo
.get(ifaceobjrunning
.name
,
1255 if not bridge_port_vids
and bridge_port_pvid
:
1256 # must be an access port
1257 ifaceobjrunning
.update_config('bridge-access',
1260 if bridge_port_vids
:
1261 if bridge_vids
and bridge_port_vids
!= bridge_vids
:
1262 ifaceobjrunning
.update_config('bridge-vids',
1263 ' '.join(bridge_port_vids
))
1265 if bridge_port_pvid
and bridge_port_pvid
!= '1':
1266 ifaceobjrunning
.update_config('bridge-pvid',
1269 self
._query
_running
_bridge
_port
_attrs
(ifaceobjrunning
, bridgename
)
1272 def _query_running(self
, ifaceobjrunning
, **extra_args
):
1273 if self
.brctlcmd
.bridge_exists(ifaceobjrunning
.name
):
1274 self
._query
_running
_bridge
(ifaceobjrunning
)
1275 elif self
.brctlcmd
.is_bridge_port(ifaceobjrunning
.name
):
1276 self
._query
_running
_bridge
_port
(ifaceobjrunning
)
1278 _run_ops
= {'pre-up' : _up
,
1279 'post-down' : _down
,
1280 'query-checkcurr' : _query_check
,
1281 'query-running' : _query_running
}
1284 """ returns list of ops supported by this module """
1285 return self
._run
_ops
.keys()
1287 def _init_command_handlers(self
):
1288 flags
= self
.get_flags()
1290 self
.ipcmd
= iproute2(**flags
)
1291 if not self
.brctlcmd
:
1292 self
.brctlcmd
= brctl(**flags
)
1294 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None,
1295 ifaceobj_getfunc
=None):
1296 """ run bridge configuration on the interface object passed as
1297 argument. Can create bridge interfaces if they dont exist already
1300 **ifaceobj** (object): iface object
1302 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
1306 **query_ifaceobj** (object): query check ifaceobject. This is only
1307 valid when op is 'query-checkcurr'. It is an object same as
1308 ifaceobj, but contains running attribute values and its config
1309 status. The modules can use it to return queried running state
1310 of interfaces. status is success if the running state is same
1311 as user required state in ifaceobj. error otherwise.
1313 op_handler
= self
._run
_ops
.get(operation
)
1316 self
._init
_command
_handlers
()
1317 self
._flush
_running
_vidinfo
()
1318 if operation
== 'query-checkcurr':
1319 op_handler(self
, ifaceobj
, query_ifaceobj
,
1320 ifaceobj_getfunc
=ifaceobj_getfunc
)
1322 op_handler(self
, ifaceobj
, ifaceobj_getfunc
=ifaceobj_getfunc
)