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',
22 {'help' : 'bridge vlan aware',
23 'example' : ['bridge-vlan-aware yes/no']},
25 {'help' : 'bridge ports',
27 'example' : ['bridge-ports swp1.100 swp2.100 swp3.100',
28 'bridge-ports glob swp1-3.100',
29 'bridge-ports regex (swp[1|2|3].100)']},
31 {'help': 'bridge-stp yes/no',
32 'example' : ['bridge-stp no'],
33 'validvals' : ['yes', 'on', 'off', 'no'],
36 {'help': 'bridge priority',
37 'example' : ['bridge-bridgeprio 32768'],
40 {'help': 'bridge ageing',
41 'example' : ['bridge-ageing 300'],
44 { 'help' : 'bridge forward delay',
45 'example' : ['bridge-fd 15'],
49 { 'help' : 'bridge garbage collection interval in secs',
50 'example' : ['bridge-gcint 4'],
53 { 'help' : 'bridge set hello time',
54 'example' : ['bridge-hello 2'],
57 { 'help' : 'bridge set maxage',
58 'example' : ['bridge-maxage 20'],
61 { 'help' : 'bridge set port path costs',
62 'example' : ['bridge-pathcosts swp1=100 swp2=100'],
65 { 'help' : 'bridge port prios',
66 'example' : ['bridge-portprios swp1=32 swp2=32'],
69 { 'help' : 'set multicast last member count',
70 'example' : ['bridge-mclmc 2'],
73 { 'help' : 'set multicast router',
75 'example' : ['bridge-mcrouter 1']},
77 { 'help' : 'set multicast snooping',
79 'example' : ['bridge-mcsnoop 1']},
81 { 'help' : 'set multicast startup query count',
83 'example' : ['bridge-mcsqc 2']},
85 { 'help' : 'set multicast query to use ifaddr',
87 'example' : ['bridge-mcqifaddr 0']},
89 { 'help' : 'set multicast querier',
91 'example' : ['bridge-mcquerier 0']},
93 { 'help' : 'set hash elasticity',
95 'example' : ['bridge-hashel 4096']},
97 { 'help' : 'set hash max',
99 'example' : ['bridge-hashmax 4096']},
101 { 'help' : 'set multicast last member interval (in secs)',
103 'example' : ['bridge-mclmi 1']},
105 { 'help' : 'set multicast membership interval (in secs)',
107 'example' : ['bridge-mcmi 260']},
109 { 'help' : 'set multicast querier interval (in secs)',
111 'example' : ['bridge-mcqpi 255']},
113 { 'help' : 'set multicast query interval (in secs)',
115 'example' : ['bridge-mcqi 125']},
117 { 'help' : 'set multicast query response interval (in secs)',
119 'example' : ['bridge-mcqri 10']},
121 { 'help' : 'set multicast startup query interval (in secs)',
123 'example' : ['bridge-mcsqi 31']},
125 { 'help' : 'set per VLAN v4 multicast querier source address',
126 'example' : ['bridge-mcqv4src 100=172.16.100.1 101=172.16.101.1']},
127 'bridge-portmcrouter' :
128 { 'help' : 'set port multicast routers',
130 'example' : ['bridge-portmcrouter swp1=1 swp2=1']},
132 { 'help' : 'port multicast fast leave',
134 'example' : ['bridge-portmcfl swp1=0 swp2=0']},
136 { 'help' : 'wait for a max of time secs for the' +
137 ' specified ports to become available,' +
138 'if no ports are specified then those' +
139 ' specified on bridge-ports will be' +
140 ' used here. Specifying no ports here ' +
141 'should not be used if we are using ' +
142 'regex or \"all\" on bridge_ports,' +
143 'as it wouldnt work.',
145 'example' : ['bridge-waitport 4 swp1 swp2']},
147 { 'help' : 'forces to time seconds the maximum time ' +
148 'that the Debian bridge setup scripts will ' +
149 'wait for the bridge ports to get to the ' +
150 'forwarding status, doesn\'t allow factional ' +
151 'part. If it is equal to 0 then no waiting' +
154 'example' : ['bridge-maxwait 3']},
156 { 'help' : 'bridge vlans',
157 'example' : ['bridge-vids 4000']},
159 { 'help' : 'bridge vlans',
160 'example' : ['bridge-pvid 1']},
162 { 'help' : 'bridge access vlans',
163 'example' : ['bridge-access 300']},
165 { 'help' : 'bridge vlans',
166 'example' : ['bridge-port-vids bond0=1-1000,1010-1020']},
167 'bridge-port-pvids' :
168 { 'help' : 'bridge port vlans',
169 'example' : ['bridge-port-pvids bond0=100 bond1=200']},
171 { 'help' : 'bridge port path cost',
172 'example' : ['bridge-pathcost 10']},
174 { 'help' : 'bridge port priority',
175 'example' : ['bridge-priority 10']},
176 'bridge-multicast-router' :
177 { 'help' : 'bridge multicast router',
178 'example' : ['bridge-multicast-router 1']},
179 'bridge-multicast-fast-leave' :
180 { 'help' : 'bridge multicast fast leave',
181 'example' : ['bridge-multicast-fast-leave 1']},
182 'bridge-igmp-querier-src' :
183 { 'help' : 'bridge igmp querier src',
184 'example' : ['bridge-igmp-querier-src 172.16.101.1']},
187 def __init__(self
, *args
, **kargs
):
188 moduleBase
.__init
__(self
, *args
, **kargs
)
191 self
._running
_vidinfo
= {}
192 self
._running
_vidinfo
_valid
= False
194 def _is_bridge(self
, ifaceobj
):
195 if ifaceobj
.get_attr_value_first('bridge-ports'):
199 def _is_bridge_port(self
, ifaceobj
):
200 if self
.brctlcmd
.is_bridge_port(ifaceobj
.name
):
204 def get_dependent_ifacenames(self
, ifaceobj
, ifacenames_all
=None):
205 if not self
._is
_bridge
(ifaceobj
):
207 return self
.parse_port_list(ifaceobj
.get_attr_value_first(
208 'bridge-ports'), ifacenames_all
)
210 def get_dependent_ifacenames_running(self
, ifaceobj
):
211 self
._init
_command
_handlers
()
212 if not self
.brctlcmd
.bridge_exists(ifaceobj
.name
):
214 return self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
216 def _get_bridge_port_list(self
, ifaceobj
):
218 # port list is also available in the previously
219 # parsed dependent list. Use that if available, instead
220 # of parsing port expr again
221 port_list
= ifaceobj
.lowerifaces
224 ports
= ifaceobj
.get_attr_value_first('bridge-ports')
226 return self
.parse_port_list(ports
)
230 def _process_bridge_waitport(self
, ifaceobj
, portlist
):
231 waitport_value
= ifaceobj
.get_attr_value_first('bridge-waitport')
232 if not waitport_value
: return
234 waitportvals
= re
.split(r
'[\s\t]\s*', waitport_value
, 1)
235 if not waitportvals
: return
237 waitporttime
= int(waitportvals
[0])
239 self
.log_warn('%s: invalid waitport value \'%s\''
240 %(ifaceobj
.name
, waitporttime
))
242 if waitporttime
<= 0: return
244 waitportlist
= self
.parse_port_list(waitportvals
[1])
245 except IndexError, e
:
246 # ignore error and use all bridge ports
247 waitportlist
= portlist
249 if not waitportlist
: return
250 self
.logger
.info('%s: waiting for ports %s to exist ...'
251 %(ifaceobj
.name
, str(waitportlist
)))
252 starttime
= time
.time()
253 while ((time
.time() - starttime
) < waitporttime
):
254 if all([False for p
in waitportlist
255 if not self
.ipcmd
.link_exists(p
)]):
259 self
.log_warn('%s: unable to process waitport: %s'
260 %(ifaceobj
.name
, str(e
)))
262 def _add_ports(self
, ifaceobj
):
263 bridgeports
= self
._get
_bridge
_port
_list
(ifaceobj
)
264 runningbridgeports
= []
266 self
._process
_bridge
_waitport
(ifaceobj
, bridgeports
)
267 # Delete active ports not in the new port list
268 if not self
.PERFMODE
:
269 runningbridgeports
= self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
270 if runningbridgeports
:
271 [self
.ipcmd
.link_set(bport
, 'nomaster')
272 for bport
in runningbridgeports
273 if not bridgeports
or bport
not in bridgeports
]
275 runningbridgeports
= []
279 for bridgeport
in Set(bridgeports
).difference(Set(runningbridgeports
)):
281 if not self
.DRYRUN
and not self
.ipcmd
.link_exists(bridgeport
):
282 self
.log_warn('%s: bridge port %s does not exist'
283 %(ifaceobj
.name
, bridgeport
))
286 self
.ipcmd
.link_set(bridgeport
, 'master', ifaceobj
.name
)
287 self
.write_file('/proc/sys/net/ipv6/conf/%s' %bridgeport
+
288 '/disable_ipv6', '1')
289 self
.ipcmd
.addr_flush(bridgeport
)
291 self
.log_error(str(e
))
293 self
.log_error('bridge configuration failed (missing ports)')
295 def _process_bridge_maxwait(self
, ifaceobj
, portlist
):
296 maxwait
= ifaceobj
.get_attr_value_first('bridge-maxwait')
297 if not maxwait
: return
299 maxwait
= int(maxwait
)
301 self
.log_warn('%s: invalid maxwait value \'%s\'' %(ifaceobj
.name
,
304 if not maxwait
: return
305 self
.logger
.info('%s: waiting for ports to go to fowarding state ..'
308 starttime
= time
.time()
309 while ((time
.time() - starttime
) < maxwait
):
310 if all([False for p
in portlist
311 if self
.read_file_oneline(
312 '/sys/class/net/%s/brif/%s/state'
313 %(ifaceobj
.name
, p
)) != '3']):
317 self
.log_warn('%s: unable to process maxwait: %s'
318 %(ifaceobj
.name
, str(e
)))
320 def _ints_to_ranges(self
, ints
):
321 for a
, b
in itertools
.groupby(enumerate(ints
), lambda (x
, y
): y
- x
):
323 yield b
[0][1], b
[-1][1]
325 def _ranges_to_ints(self
, rangelist
):
326 """ returns expanded list of integers given set of string ranges
327 example: ['1', '2-4', '6'] returns [1, 2, 3, 4, 6]
330 for part
in rangelist
:
332 a
, b
= part
.split('-')
333 a
, b
= int(a
), int(b
)
334 result
.extend(range(a
, b
+ 1))
340 def _diff_vids(self
, vids1
, vids2
):
344 vids1_ints
= self
._ranges
_to
_ints
(vids1
)
345 vids2_ints
= self
._ranges
_to
_ints
(vids2
)
346 vids1_diff
= Set(vids1_ints
).difference(vids2_ints
)
347 vids2_diff
= Set(vids2_ints
).difference(vids1_ints
)
349 vids_to_add
= ['%d' %start
if start
== end
else '%d-%d' %(start
, end
)
350 for start
, end
in self
._ints
_to
_ranges
(vids1_diff
)]
352 vids_to_del
= ['%d' %start
if start
== end
else '%d-%d' %(start
, end
)
353 for start
, end
in self
._ints
_to
_ranges
(vids2_diff
)]
354 return (vids_to_del
, vids_to_add
)
356 def _compare_vids(self
, vids1
, vids2
):
357 """ Returns true if the vids are same else return false """
359 vids1_ints
= self
._ranges
_to
_ints
(vids1
)
360 vids2_ints
= self
._ranges
_to
_ints
(vids2
)
361 if Set(vids1_ints
).symmetric_difference(vids2_ints
):
366 def _set_bridge_mcqv4src_compat(self
, ifaceobj
):
368 # Sets old style igmp querier
370 attrval
= ifaceobj
.get_attr_value_first('bridge-mcqv4src')
372 running_mcqv4src
= {}
373 if not self
.PERFMODE
:
374 running_mcqv4src
= self
.brctlcmd
.get_mcqv4src(ifaceobj
.name
)
376 srclist
= attrval
.split()
381 k_to_del
= Set(running_mcqv4src
.keys()).difference(mcqs
.keys())
383 self
.brctlcmd
.del_mcqv4src(ifaceobj
.name
, v
)
384 for v
in mcqs
.keys():
385 self
.brctlcmd
.set_mcqv4src(ifaceobj
.name
, v
, mcqs
[v
])
387 def _get_running_vidinfo(self
):
388 if self
._running
_vidinfo
_valid
:
389 return self
._running
_vidinfo
390 self
._running
_vidinfo
= {}
391 if not self
.PERFMODE
:
392 self
._running
_vidinfo
= self
.ipcmd
.bridge_port_vids_get_all()
393 self
._running
_vidinfo
_valid
= True
394 return self
._running
_vidinfo
396 def _flush_running_vidinfo(self
):
397 self
._running
_vidinfo
= {}
398 self
._running
_vidinfo
_valid
= False
400 def _set_bridge_vidinfo_compat(self
, ifaceobj
):
402 # Supports old style vlan vid info format
406 # Handle bridge vlan attrs
407 running_vidinfo
= self
._get
_running
_vidinfo
()
410 attrval
= ifaceobj
.get_attr_value_first('bridge-port-pvids')
412 portlist
= self
.parse_port_list(attrval
)
414 self
.log_warn('%s: could not parse \'%s %s\''
415 %(ifaceobj
.name
, attrname
, attrval
))
419 (port
, pvid
) = p
.split('=')
420 running_pvid
= running_vidinfo
.get(port
, {}).get('pvid')
422 if running_pvid
== pvid
:
425 self
.ipcmd
.bridge_port_pvid_del(port
, running_pvid
)
426 self
.ipcmd
.bridge_port_pvid_add(port
, pvid
)
428 self
.log_warn('%s: failed to set pvid `%s` (%s)'
429 %(ifaceobj
.name
, p
, str(e
)))
432 attrval
= ifaceobj
.get_attr_value_first('bridge-port-vids')
434 portlist
= self
.parse_port_list(attrval
)
436 self
.log_warn('%s: could not parse \'%s %s\''
437 %(ifaceobj
.name
, attrname
, attrval
))
441 (port
, val
) = p
.split('=')
442 vids
= val
.split(',')
443 if running_vidinfo
.get(port
):
444 (vids_to_del
, vids_to_add
) = \
445 self
._diff
_vids
(vids
,
446 running_vidinfo
.get(port
).get('vlan'))
448 self
.ipcmd
.bridge_port_vids_del(port
, vids_to_del
)
450 self
.ipcmd
.bridge_port_vids_add(port
, vids_to_add
)
452 self
.ipcmd
.bridge_port_vids_add(port
, vids
)
454 self
.log_warn('%s: failed to set vid `%s` (%s)'
455 %(ifaceobj
.name
, p
, str(e
)))
458 attrval
= ifaceobj
.get_attr_value_first('bridge-vids')
460 vids
= re
.split(r
'[\s\t]\s*', attrval
)
461 if running_vidinfo
.get(ifaceobj
.name
):
462 (vids_to_del
, vids_to_add
) = \
463 self
._diff
_vids
(vids
,
464 running_vidinfo
.get(ifaceobj
.name
).get('vlan'))
466 self
.ipcmd
.bridge_vids_del(ifaceobj
.name
, vids_to_del
)
468 self
.ipcmd
.bridge_vids_add(ifaceobj
.name
, vids_to_add
)
470 self
.ipcmd
.bridge_vids_add(ifaceobj
.name
, vids
)
472 running_vids
= running_vidinfo
.get(ifaceobj
.name
)
474 self
.ipcmd
.bridge_vids_del(ifaceobj
.name
, running_vids
)
476 def _apply_bridge_settings(self
, ifaceobj
):
478 stp
= ifaceobj
.get_attr_value_first('bridge-stp')
480 self
.brctlcmd
.set_stp(ifaceobj
.name
, stp
)
481 # Use the brctlcmd bulk set method: first build a dictionary
483 bridgeattrs
= { k
:v
for k
,v
in
485 ifaceobj
.get_attr_value_first('bridge-ageing'),
487 ifaceobj
.get_attr_value_first(
488 'bridge-bridgeprio'),
490 ifaceobj
.get_attr_value_first('bridge-fd'),
492 ifaceobj
.get_attr_value_first('bridge-gcint'),
494 ifaceobj
.get_attr_value_first('bridge-hello'),
496 ifaceobj
.get_attr_value_first('bridge-maxage'),
498 ifaceobj
.get_attr_value_first('bridge-mclmc'),
500 ifaceobj
.get_attr_value_first(
503 ifaceobj
.get_attr_value_first('bridge-mcsnoop'),
505 ifaceobj
.get_attr_value_first('bridge-mcsqc'),
507 ifaceobj
.get_attr_value_first(
510 ifaceobj
.get_attr_value_first(
513 ifaceobj
.get_attr_value_first('bridge-hashel'),
515 ifaceobj
.get_attr_value_first('bridge-hashmax'),
517 ifaceobj
.get_attr_value_first('bridge-mclmi'),
519 ifaceobj
.get_attr_value_first('bridge-mcmi'),
521 ifaceobj
.get_attr_value_first('bridge-mcqpi'),
523 ifaceobj
.get_attr_value_first('bridge-mcqi'),
525 ifaceobj
.get_attr_value_first('bridge-mcqri'),
527 ifaceobj
.get_attr_value_first('bridge-mcsqi')
531 self
.brctlcmd
.set_bridge_attrs(ifaceobj
.name
, bridgeattrs
)
533 for attrname
, dstattrname
in {'bridge-pathcosts' : 'pathcost',
534 'bridge-portprios' : 'portprio',
535 'bridge-portmcrouter' : 'portmcrouter',
536 'bridge-portmcfl' : 'portmcfl'}.items():
537 attrval
= ifaceobj
.get_attr_value_first(attrname
)
540 portlist
= self
.parse_port_list(attrval
)
542 self
.log_warn('%s: could not parse \'%s %s\''
543 %(ifaceobj
.name
, attrname
, attrval
))
547 (port
, val
) = p
.split('=')
548 if not portattrs
.get(port
):
550 portattrs
[port
].update({dstattrname
: val
})
552 self
.log_warn('%s: could not parse %s (%s)'
553 %(ifaceobj
.name
, attrname
, str(e
)))
554 for port
, attrdict
in portattrs
.iteritems():
555 self
.brctlcmd
.set_bridgeport_attrs(ifaceobj
.name
, port
,
557 self
._set
_bridge
_vidinfo
_compat
(ifaceobj
)
559 self
._set
_bridge
_mcqv
4src
_compat
(ifaceobj
)
561 self
._process
_bridge
_maxwait
(ifaceobj
,
562 self
._get
_bridge
_port
_list
(ifaceobj
))
564 self
.log_warn(str(e
))
566 def _apply_bridge_vids(self
, bportifaceobj
, vids
, running_vids
, isbridge
):
569 (vids_to_del
, vids_to_add
) = \
570 self
._diff
_vids
(vids
, running_vids
)
572 self
.ipcmd
.bridge_vids_del(bportifaceobj
.name
,
573 vids_to_del
, isbridge
)
575 self
.ipcmd
.bridge_vids_add(bportifaceobj
.name
,
576 vids_to_add
, isbridge
)
578 self
.ipcmd
.bridge_vids_add(bportifaceobj
.name
, vids
, isbridge
)
580 self
.log_warn('%s: failed to set vid `%s` (%s)'
581 %(bportifaceobj
.name
, str(vids
), str(e
)))
583 def _apply_bridge_port_pvids(self
, bportifaceobj
, pvid
, running_pvid
):
587 if running_pvid
!= pvid
:
588 self
.ipcmd
.bridge_port_pvid_del(bportifaceobj
.name
,
590 self
.ipcmd
.bridge_port_pvid_add(bportifaceobj
.name
, pvid
)
592 self
.log_warn('%s: failed to set pvid `%s` (%s)'
593 %(bportifaceobj
.name
, pvid
, str(e
)))
595 def _apply_bridge_vlan_aware_port_settings_all(self
, bportifaceobj
,
597 running_vidinfo
= self
._get
_running
_vidinfo
()
600 bport_access
= bportifaceobj
.get_attr_value_first('bridge-access')
602 vids
= re
.split(r
'[\s\t]\s*', bport_access
)
605 bport_vids
= bportifaceobj
.get_attr_value_first('bridge-vids')
607 vids
= re
.split(r
'[\s\t]\s*', bport_vids
)
609 bport_pvids
= bportifaceobj
.get_attr_value_first('bridge-pvid')
611 pvids
= re
.split(r
'[\s\t]\s*', bport_pvids
)
614 self
._apply
_bridge
_port
_pvids
(bportifaceobj
, pvids
[0],
615 running_vidinfo
.get(bportifaceobj
.name
, {}).get('pvid'))
617 self
._apply
_bridge
_port
_pvids
(bportifaceobj
,
618 '1', running_vidinfo
.get(bportifaceobj
.name
,
622 self
._apply
_bridge
_vids
(bportifaceobj
, vids
,
623 running_vidinfo
.get(bportifaceobj
.name
,
624 {}).get('vlan'), False)
626 self
._apply
_bridge
_vids
(bportifaceobj
,
627 bridge_vids
, running_vidinfo
.get(
628 bportifaceobj
.name
, {}).get('vlan'), False)
631 def _apply_bridge_port_settings(self
, bportifaceobj
, bridgename
=None,
632 bridgeifaceobj
=None):
633 if not bridgename
and bridgeifaceobj
:
634 bridgename
= bridgeifaceobj
.name
635 # Set other stp and igmp attributes
637 for attrname
, dstattrname
in {
638 'bridge-pathcost' : 'pathcost',
639 'bridge-prio' : 'portprio',
640 'bridge-priority' : 'portprio',
641 'bridge-mcrouter' : 'portmcrouter',
642 'bridge-multicast-router' : 'portmcrouter',
643 'bridge-mcfl' : 'portmcfl',
644 'bridge-multicast-fast-leave' : 'portmcfl'}.items():
645 attrval
= bportifaceobj
.get_attr_value_first(attrname
)
647 # Check if bridge has that attribute
649 # attrval = bridgeifaceobj.get_attr_value_first(attrname)
654 portattrs
[dstattrname
] = attrval
656 self
.brctlcmd
.set_bridgeport_attrs(bridgename
,
657 bportifaceobj
.name
, portattrs
)
659 self
.log_warn(str(e
))
661 def _apply_bridge_port_settings_all(self
, ifaceobj
,
662 ifaceobj_getfunc
=None):
663 bridge_vlan_aware
= ifaceobj
.get_attr_value_first(
665 if bridge_vlan_aware
and bridge_vlan_aware
== 'yes':
666 bridge_vlan_aware
= True
668 bridge_vlan_aware
= False
670 if (ifaceobj
.get_attr_value_first('bridge-port-vids') and
671 ifaceobj
.get_attr_value_first('bridge-port-pvids')):
672 # Old style bridge port vid info
673 # skip new style setting on ports
675 self
.logger
.info('%s: applying bridge configuration '
676 %ifaceobj
.name
+ 'specific to ports')
678 bridge_vids
= ifaceobj
.get_attr_value_first('bridge-vids')
680 bridge_vids
= re
.split(r
'[\s\t]\s*', bridge_vids
)
684 bridgeports
= self
._get
_bridge
_port
_list
(ifaceobj
)
685 for bport
in bridgeports
:
686 # Use the brctlcmd bulk set method: first build a dictionary
688 self
.logger
.info('%s: processing bridge config for port %s'
689 %(ifaceobj
.name
, bport
))
690 bportifaceobjlist
= ifaceobj_getfunc(bport
)
691 if not bportifaceobjlist
:
693 for bportifaceobj
in bportifaceobjlist
:
694 # Add attributes specific to the vlan aware bridge
695 if bridge_vlan_aware
:
696 self
._apply
_bridge
_vlan
_aware
_port
_settings
_all
(
697 bportifaceobj
, bridge_vids
)
698 self
._apply
_bridge
_port
_settings
(
699 bportifaceobj
, bridgeifaceobj
=ifaceobj
)
701 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
702 # Check if bridge port
703 if self
._is
_bridge
_port
(ifaceobj
):
704 bridgename
= ifaceobj
.upperifaces
[0]
706 self
.logger
.warn('%s: unable to determine bridge name'
709 if self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
710 self
._apply
_bridge
_vlan
_aware
_port
_settings
_all
(
712 self
._apply
_bridge
_port
_settings
(ifaceobj
, bridgename
=bridgename
)
715 if not self
._is
_bridge
(ifaceobj
):
720 self
.ipcmd
.batch_start()
721 if not self
.PERFMODE
:
722 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
723 self
.ipcmd
.link_create(ifaceobj
.name
, 'bridge')
725 self
.ipcmd
.link_create(ifaceobj
.name
, 'bridge')
727 self
._add
_ports
(ifaceobj
)
733 self
.ipcmd
.batch_commit()
734 self
._apply
_bridge
_settings
(ifaceobj
)
735 self
._apply
_bridge
_port
_settings
_all
(ifaceobj
,
736 ifaceobj_getfunc
=ifaceobj_getfunc
)
737 self
._flush
_running
_vidinfo
()
739 self
.log_error(str(e
))
741 raise Exception(porterrstr
)
743 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
745 if ifaceobj
.get_attr_value_first('bridge-ports'):
746 ports
= self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
749 proc_file
= ('/proc/sys/net/ipv6/conf/%s' %p
+
751 self
.write_file(proc_file
, '0')
752 self
.brctlcmd
.delete_bridge(ifaceobj
.name
)
754 self
.log_error(str(e
))
756 def _query_running_vidinfo(self
, ifaceobjrunning
, ports
):
758 running_vidinfo
= self
._get
_running
_vidinfo
()
760 running_bridge_port_vids
= ''
763 running_vids
= running_vidinfo
.get(p
, {}).get('vlan')
765 running_bridge_port_vids
+= ' %s=%s' %(p
,
766 ','.join(running_vids
))
769 running_attrs
['bridge-port-vids'] = running_bridge_port_vids
771 running_bridge_port_pvids
= ''
774 running_pvids
= running_vidinfo
.get(p
, {}).get('pvid')
776 running_bridge_port_pvids
+= ' %s=%s' %(p
,
780 running_attrs
['bridge-port-pvids'] = running_bridge_port_pvids
782 running_bridge_vids
= running_vidinfo
.get(ifaceobjrunning
.name
,
784 if running_bridge_vids
:
785 running_attrs
['bridge-vids'] = ','.join(running_bridge_vids
)
788 def _query_running_mcqv4src(self
, ifaceobjrunning
):
789 running_mcqv4src
= self
.brctlcmd
.get_mcqv4src(ifaceobjrunning
.name
)
790 mcqs
= ['%s=%s' %(v
, i
) for v
, i
in running_mcqv4src
.items()]
795 def _query_running_attrs(self
, ifaceobjrunning
):
799 skip_kernel_stp_attrs
= 0
801 if self
.sysctl_get('net.bridge.bridge-stp-user-space') == '1':
804 tmpbridgeattrdict
= self
.brctlcmd
.get_bridge_attrs(ifaceobjrunning
.name
)
805 if not tmpbridgeattrdict
:
806 self
.logger
.warn('%s: unable to get bridge attrs'
807 %ifaceobjrunning
.name
)
808 return bridgeattrdict
810 # Fill bridge_ports and bridge stp attributes first
811 ports
= tmpbridgeattrdict
.get('ports')
813 bridgeattrdict
['bridge-ports'] = [' '.join(ports
.keys())]
814 stp
= tmpbridgeattrdict
.get('stp', 'no')
815 if stp
!= self
.get_mod_subattr('bridge-stp', 'default'):
816 bridgeattrdict
['bridge-stp'] = [stp
]
818 if stp
== 'yes' and userspace_stp
:
819 skip_kernel_stp_attrs
= 1
821 # pick all other attributes
822 for k
,v
in tmpbridgeattrdict
.items():
825 if k
== 'ports' or k
== 'stp':
828 if skip_kernel_stp_attrs
and k
[:2] != 'mc':
829 # only include igmp attributes if kernel stp is off
831 attrname
= 'bridge-' + k
832 if v
!= self
.get_mod_subattr(attrname
, 'default'):
833 bridgeattrdict
[attrname
] = [v
]
835 bridgevidinfo
= self
._query
_running
_vidinfo
(ifaceobjrunning
, ports
)
837 bridgeattrdict
.update({k
: [v
] for k
, v
in bridgevidinfo
.items()
840 mcq
= self
._query
_running
_mcqv
4src
(ifaceobjrunning
)
842 bridgeattrdict
['bridge-mcqv4src'] = [mcq
]
844 if skip_kernel_stp_attrs
:
845 return bridgeattrdict
848 portconfig
= {'bridge-pathcosts' : '',
849 'bridge-portprios' : ''}
850 for p
, v
in ports
.items():
851 v
= self
.brctlcmd
.get_pathcost(ifaceobjrunning
.name
, p
)
852 if v
and v
!= self
.get_mod_subattr('bridge-pathcosts',
854 portconfig
['bridge-pathcosts'] += ' %s=%s' %(p
, v
)
856 v
= self
.brctlcmd
.get_portprio(ifaceobjrunning
.name
, p
)
857 if v
and v
!= self
.get_mod_subattr('bridge-portprios',
859 portconfig
['bridge-portprios'] += ' %s=%s' %(p
, v
)
861 bridgeattrdict
.update({k
: [v
] for k
, v
in portconfig
.items()
864 return bridgeattrdict
866 def _query_check_mcqv4src(self
, ifaceobj
, ifaceobjcurr
):
867 running_mcqs
= self
._query
_running
_mcqv
4src
(ifaceobj
)
868 attrval
= ifaceobj
.get_attr_value_first('bridge-mcqv4src')
870 mcqs
= attrval
.split()
872 mcqsout
= ' '.join(mcqs
)
873 ifaceobjcurr
.update_config_with_status('bridge-mcqv4src',
874 running_mcqs
, 1 if running_mcqs
!= mcqsout
else 0)
876 def _query_check_vidinfo(self
, ifaceobj
, ifaceobjcurr
):
879 running_vidinfo
= self
.ipcmd
.bridge_port_vids_get_all()
880 attrval
= ifaceobj
.get_attr_value_first('bridge-port-vids')
882 running_bridge_port_vids
= ''
883 portlist
= self
.parse_port_list(attrval
)
885 self
.log_warn('%s: could not parse \'%s %s\''
886 %(ifaceobj
.name
, attrname
, attrval
))
891 (port
, val
) = p
.split('=')
892 vids
= val
.split(',')
893 running_vids
= running_vidinfo
.get(port
, {}).get('vlan')
895 if not self
._compare
_vids
(vids
, running_vids
):
897 running_bridge_port_vids
+= ' %s=%s' %(port
,
898 ','.join(running_vids
))
900 running_bridge_port_vids
+= ' %s' %p
904 self
.log_warn('%s: failure checking vid %s (%s)'
905 %(ifaceobj
.name
, p
, str(e
)))
907 ifaceobjcurr
.update_config_with_status('bridge-port-vids',
908 running_bridge_port_vids
, 1)
910 ifaceobjcurr
.update_config_with_status('bridge-port-vids',
914 attrval
= ifaceobj
.get_attr_value_first('bridge-port-pvids')
916 portlist
= self
.parse_port_list(attrval
)
918 self
.log_warn('%s: could not parse \'%s %s\''
919 %(ifaceobj
.name
, attrname
, attrval
))
921 running_bridge_port_pvids
= ''
925 (port
, pvid
) = p
.split('=')
926 running_pvid
= running_vidinfo
.get(port
, {}).get('pvid')
927 if running_pvid
and running_pvid
== pvid
:
928 running_bridge_port_pvids
+= ' %s' %p
931 running_bridge_port_pvids
+= ' %s=%s' %(port
,
934 self
.log_warn('%s: failure checking pvid %s (%s)'
935 %(ifaceobj
.name
, pvid
, str(e
)))
937 ifaceobjcurr
.update_config_with_status('bridge-port-pvids',
938 running_bridge_port_pvids
, 1)
940 ifaceobjcurr
.update_config_with_status('bridge-port-pvids',
941 running_bridge_port_pvids
, 0)
943 attrval
= ifaceobj
.get_attr_value_first('bridge-vids')
945 vids
= re
.split(r
'[\s\t]\s*', attrval
)
946 running_vids
= running_vidinfo
.get(ifaceobj
.name
, {}).get('vlan')
948 if self
._compare
_vids
(vids
, running_vids
):
949 ifaceobjcurr
.update_config_with_status('bridge-vids',
952 ifaceobjcurr
.update_config_with_status('bridge-vids',
953 ','.join(running_vids
), 1)
955 ifaceobjcurr
.update_config_with_status('bridge-vids', attrval
,
958 def _query_check(self
, ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
=None):
959 if not self
._is
_bridge
(ifaceobj
):
961 if not self
.brctlcmd
.bridge_exists(ifaceobj
.name
):
962 self
.logger
.info('%s: bridge: does not exist' %(ifaceobj
.name
))
963 ifaceobjcurr
.status
= ifaceStatus
.NOTFOUND
965 ifaceattrs
= self
.dict_key_subset(ifaceobj
.config
,
966 self
.get_mod_attrs())
970 runningattrs
= self
.brctlcmd
.get_bridge_attrs(ifaceobj
.name
)
972 self
.logger
.debug('%s: bridge: unable to get bridge attrs'
976 self
.logger
.warn(str(e
))
978 filterattrs
= ['bridge-vids', 'bridge-port-vids',
980 for k
in Set(ifaceattrs
).difference(filterattrs
):
981 # get the corresponding ifaceobj attr
982 v
= ifaceobj
.get_attr_value_first(k
)
985 rv
= runningattrs
.get(k
[7:])
986 if k
== 'bridge-mcqv4src':
988 if k
== 'bridge-stp':
989 # special case stp compare because it may
990 # contain more than one valid values
991 stp_on_vals
= ['on', 'yes']
992 stp_off_vals
= ['off']
993 if ((v
in stp_on_vals
and rv
in stp_on_vals
) or
994 (v
in stp_off_vals
and rv
in stp_off_vals
)):
995 ifaceobjcurr
.update_config_with_status('bridge-stp',
998 ifaceobjcurr
.update_config_with_status('bridge-stp',
1000 elif k
== 'bridge-ports':
1001 # special case ports because it can contain regex or glob
1002 running_port_list
= rv
.keys() if rv
else []
1003 bridge_port_list
= self
._get
_bridge
_port
_list
(ifaceobj
)
1004 if not running_port_list
and not bridge_port_list
:
1007 if running_port_list
and bridge_port_list
:
1008 difference
= set(running_port_list
1009 ).symmetric_difference(bridge_port_list
)
1012 ifaceobjcurr
.update_config_with_status('bridge-ports',
1013 ' '.join(running_port_list
)
1014 if running_port_list
else '', portliststatus
)
1015 elif (k
== 'bridge-pathcosts' or
1016 k
== 'bridge-portprios' or k
== 'bridge-portmcrouter'
1017 or k
== 'bridge-portmcfl'):
1018 brctlcmdattrname
= k
[11:].rstrip('s')
1019 # for port attributes, the attributes are in a list
1020 # <portname>=<portattrvalue>
1023 vlist
= self
.parse_port_list(v
)
1026 for vlistitem
in vlist
:
1028 (p
, v
) = vlistitem
.split('=')
1029 currv
= self
.brctlcmd
.get_bridgeport_attr(
1033 currstr
+= ' %s=%s' %(p
, currv
)
1035 currstr
+= ' %s=%s' %(p
, 'None')
1038 except Exception, e
:
1039 self
.log_warn(str(e
))
1041 ifaceobjcurr
.update_config_with_status(k
, currstr
, status
)
1043 ifaceobjcurr
.update_config_with_status(k
, 'notfound', 1)
1046 ifaceobjcurr
.update_config_with_status(k
, rv
, 1)
1048 ifaceobjcurr
.update_config_with_status(k
, rv
, 0)
1050 self
._query
_check
_vidinfo
(ifaceobj
, ifaceobjcurr
)
1052 self
._query
_check
_mcqv
4src
(ifaceobj
, ifaceobjcurr
)
1054 def _query_running(self
, ifaceobjrunning
, ifaceobj_getfunc
=None):
1055 if not self
.brctlcmd
.bridge_exists(ifaceobjrunning
.name
):
1057 ifaceobjrunning
.update_config_dict(self
._query
_running
_attrs
(
1060 _run_ops
= {'pre-up' : _up
,
1061 'post-down' : _down
,
1062 'query-checkcurr' : _query_check
,
1063 'query-running' : _query_running
}
1066 """ returns list of ops supported by this module """
1067 return self
._run
_ops
.keys()
1069 def _init_command_handlers(self
):
1070 flags
= self
.get_flags()
1072 self
.ipcmd
= iproute2(**flags
)
1073 if not self
.brctlcmd
:
1074 self
.brctlcmd
= brctl(**flags
)
1076 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None,
1077 ifaceobj_getfunc
=None):
1078 """ run bridge configuration on the interface object passed as
1079 argument. Can create bridge interfaces if they dont exist already
1082 **ifaceobj** (object): iface object
1084 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
1088 **query_ifaceobj** (object): query check ifaceobject. This is only
1089 valid when op is 'query-checkcurr'. It is an object same as
1090 ifaceobj, but contains running attribute values and its config
1091 status. The modules can use it to return queried running state
1092 of interfaces. status is success if the running state is same
1093 as user required state in ifaceobj. error otherwise.
1095 op_handler
= self
._run
_ops
.get(operation
)
1098 self
._init
_command
_handlers
()
1099 self
._flush
_running
_vidinfo
()
1100 if operation
== 'query-checkcurr':
1101 op_handler(self
, ifaceobj
, query_ifaceobj
,
1102 ifaceobj_getfunc
=ifaceobj_getfunc
)
1104 op_handler(self
, ifaceobj
, ifaceobj_getfunc
=ifaceobj_getfunc
)