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
12 import ifupdown
.rtnetlink_api
as rtnetlink_api
17 class bridge(moduleBase
):
18 """ ifupdown2 addon module to configure linux bridges """
20 _modinfo
= { 'mhelp' : 'Bridge configuration module. Supports both ' +
21 'vlan aware and non vlan aware bridges. For the vlan ' +
22 'aware bridge, the port specific attributes must be ' +
23 'specified under the port. And for vlan unaware bridge ' +
24 'port specific attributes must be specified under the ' +
28 {'help' : 'vlan aware bridge. Setting this ' +
29 'attribute to yes enables vlan filtering' +
31 'example' : ['bridge-vlan-aware yes/no']},
33 {'help' : 'bridge ports',
35 'example' : ['bridge-ports swp1.100 swp2.100 swp3.100',
36 'bridge-ports glob swp1-3.100',
37 'bridge-ports regex (swp[1|2|3].100)']},
39 {'help': 'bridge-stp yes/no',
40 'example' : ['bridge-stp no'],
41 'validvals' : ['yes', 'on', 'off', 'no'],
44 {'help': 'bridge priority',
45 'example' : ['bridge-bridgeprio 32768'],
48 {'help': 'bridge ageing',
49 'example' : ['bridge-ageing 300'],
52 { 'help' : 'bridge forward delay',
53 'example' : ['bridge-fd 15'],
57 { 'help' : 'bridge garbage collection interval in secs',
58 'example' : ['bridge-gcint 4'],
61 { 'help' : 'bridge set hello time',
62 'example' : ['bridge-hello 2'],
65 { 'help' : 'bridge set maxage',
66 'example' : ['bridge-maxage 20'],
69 { 'help' : 'bridge set port path costs',
70 'example' : ['bridge-pathcosts swp1=100 swp2=100'],
73 { 'help' : 'bridge port prios',
74 'example' : ['bridge-portprios swp1=32 swp2=32'],
77 { 'help' : 'set multicast last member count',
78 'example' : ['bridge-mclmc 2'],
81 { 'help' : 'set multicast router',
83 'example' : ['bridge-mcrouter 1']},
85 { 'help' : 'set multicast snooping',
87 'example' : ['bridge-mcsnoop 1']},
89 { 'help' : 'set multicast startup query count',
91 'example' : ['bridge-mcsqc 2']},
93 { 'help' : 'set multicast query to use ifaddr',
95 'example' : ['bridge-mcqifaddr 0']},
97 { 'help' : 'set multicast querier',
99 'example' : ['bridge-mcquerier 0']},
101 { 'help' : 'set hash elasticity',
103 'example' : ['bridge-hashel 4096']},
105 { 'help' : 'set hash max',
107 'example' : ['bridge-hashmax 4096']},
109 { 'help' : 'set multicast last member interval (in secs)',
111 'example' : ['bridge-mclmi 1']},
113 { 'help' : 'set multicast membership interval (in secs)',
115 'example' : ['bridge-mcmi 260']},
117 { 'help' : 'set multicast querier interval (in secs)',
119 'example' : ['bridge-mcqpi 255']},
121 { 'help' : 'set multicast query interval (in secs)',
123 'example' : ['bridge-mcqi 125']},
125 { 'help' : 'set multicast query response interval (in secs)',
127 'example' : ['bridge-mcqri 10']},
129 { 'help' : 'set multicast startup query interval (in secs)',
131 'example' : ['bridge-mcsqi 31']},
133 { 'help' : 'set per VLAN v4 multicast querier source address',
135 'example' : ['bridge-mcqv4src 100=172.16.100.1 101=172.16.101.1']},
136 'bridge-portmcrouter' :
137 { 'help' : 'set port multicast routers',
139 'example' : ['under the bridge: bridge-portmcrouter swp1=1 swp2=1',
140 'under the port: bridge-portmcrouter 1']},
142 { 'help' : 'port multicast fast leave.',
144 'example' : ['under the bridge: bridge-portmcfl swp1=0 swp2=0',
145 'under the port: bridge-portmcfl 0']},
147 { 'help' : 'wait for a max of time secs for the' +
148 ' specified ports to become available,' +
149 'if no ports are specified then those' +
150 ' specified on bridge-ports will be' +
151 ' used here. Specifying no ports here ' +
152 'should not be used if we are using ' +
153 'regex or \"all\" on bridge_ports,' +
154 'as it wouldnt work.',
156 'example' : ['bridge-waitport 4 swp1 swp2']},
158 { 'help' : 'forces to time seconds the maximum time ' +
159 'that the Debian bridge setup scripts will ' +
160 'wait for the bridge ports to get to the ' +
161 'forwarding status, doesn\'t allow factional ' +
162 'part. If it is equal to 0 then no waiting' +
165 'example' : ['bridge-maxwait 3']},
167 { 'help' : 'bridge port vids. Can be specified ' +
168 'under the bridge or under the port. ' +
169 'If specified under the bridge the ports ' +
170 'inherit it unless overridden by a ' +
171 'bridge-vids attribuet under the port',
172 'example' : ['bridge-vids 4000',
173 'bridge-vids 2000 2200-3000']},
175 { 'help' : 'bridge port pvid. Must be specified under' +
177 'example' : ['bridge-pvid 1']},
179 { 'help' : 'bridge port access vlan. Must be ' +
180 'specified under the bridge port',
181 'example' : ['bridge-access 300']},
183 { 'help' : 'bridge vlans',
185 'example' : ['bridge-port-vids bond0=1-1000,1010-1020']},
186 'bridge-port-pvids' :
187 { 'help' : 'bridge port vlans',
189 'example' : ['bridge-port-pvids bond0=100 bond1=200']},
192 # declare some ifaceobj priv_flags.
193 # XXX: This assumes that the priv_flags is owned by this module
195 _BRIDGE_PORT_PROCESSED
= 0x1
197 def __init__(self
, *args
, **kargs
):
198 moduleBase
.__init
__(self
, *args
, **kargs
)
201 self
._running
_vidinfo
= {}
202 self
._running
_vidinfo
_valid
= False
203 self
._resv
_vlan
_range
= self
._get
_reserved
_vlan
_range
()
204 self
.logger
.debug('%s: using reserved vlan range %s'
205 %(self
.__class
__.__name
__, str(self
._resv
_vlan
_range
)))
207 def _is_bridge(self
, ifaceobj
):
208 if ifaceobj
.get_attr_value_first('bridge-ports'):
212 def _is_bridge_port(self
, ifaceobj
):
213 if self
.brctlcmd
.is_bridge_port(ifaceobj
.name
):
217 def get_dependent_ifacenames(self
, ifaceobj
, ifacenames_all
=None):
218 if not self
._is
_bridge
(ifaceobj
):
220 return self
.parse_port_list(ifaceobj
.get_attr_value_first(
221 'bridge-ports'), ifacenames_all
)
223 def get_dependent_ifacenames_running(self
, ifaceobj
):
224 self
._init
_command
_handlers
()
225 if not self
.brctlcmd
.bridge_exists(ifaceobj
.name
):
227 return self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
229 def _get_bridge_port_list(self
, ifaceobj
):
231 # port list is also available in the previously
232 # parsed dependent list. Use that if available, instead
233 # of parsing port expr again
234 port_list
= ifaceobj
.lowerifaces
237 ports
= ifaceobj
.get_attr_value_first('bridge-ports')
239 return self
.parse_port_list(ports
)
243 def _process_bridge_waitport(self
, ifaceobj
, portlist
):
244 waitport_value
= ifaceobj
.get_attr_value_first('bridge-waitport')
245 if not waitport_value
: return
247 waitportvals
= re
.split(r
'[\s\t]\s*', waitport_value
, 1)
248 if not waitportvals
: return
250 waitporttime
= int(waitportvals
[0])
252 self
.log_warn('%s: invalid waitport value \'%s\''
253 %(ifaceobj
.name
, waitporttime
))
255 if waitporttime
<= 0: return
257 waitportlist
= self
.parse_port_list(waitportvals
[1])
258 except IndexError, e
:
259 # ignore error and use all bridge ports
260 waitportlist
= portlist
262 if not waitportlist
: return
263 self
.logger
.info('%s: waiting for ports %s to exist ...'
264 %(ifaceobj
.name
, str(waitportlist
)))
265 starttime
= time
.time()
266 while ((time
.time() - starttime
) < waitporttime
):
267 if all([False for p
in waitportlist
268 if not self
.ipcmd
.link_exists(p
)]):
272 self
.log_warn('%s: unable to process waitport: %s'
273 %(ifaceobj
.name
, str(e
)))
275 def _add_ports(self
, ifaceobj
):
276 bridgeports
= self
._get
_bridge
_port
_list
(ifaceobj
)
277 runningbridgeports
= []
279 self
._process
_bridge
_waitport
(ifaceobj
, bridgeports
)
280 # Delete active ports not in the new port list
281 if not self
.PERFMODE
:
282 runningbridgeports
= self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
283 if runningbridgeports
:
284 [self
.ipcmd
.link_set(bport
, 'nomaster')
285 for bport
in runningbridgeports
286 if not bridgeports
or bport
not in bridgeports
]
288 runningbridgeports
= []
292 for bridgeport
in Set(bridgeports
).difference(Set(runningbridgeports
)):
294 if not self
.DRYRUN
and not self
.ipcmd
.link_exists(bridgeport
):
295 self
.log_warn('%s: bridge port %s does not exist'
296 %(ifaceobj
.name
, bridgeport
))
299 self
.ipcmd
.link_set(bridgeport
, 'master', ifaceobj
.name
)
300 self
.write_file('/proc/sys/net/ipv6/conf/%s' %bridgeport
+
301 '/disable_ipv6', '1')
302 self
.ipcmd
.addr_flush(bridgeport
)
304 self
.log_error(str(e
))
306 self
.log_error('bridge configuration failed (missing ports)')
308 def _process_bridge_maxwait(self
, ifaceobj
, portlist
):
309 maxwait
= ifaceobj
.get_attr_value_first('bridge-maxwait')
310 if not maxwait
: return
312 maxwait
= int(maxwait
)
314 self
.log_warn('%s: invalid maxwait value \'%s\'' %(ifaceobj
.name
,
317 if not maxwait
: return
318 self
.logger
.info('%s: waiting for ports to go to fowarding state ..'
321 starttime
= time
.time()
322 while ((time
.time() - starttime
) < maxwait
):
323 if all([False for p
in portlist
324 if self
.read_file_oneline(
325 '/sys/class/net/%s/brif/%s/state'
326 %(ifaceobj
.name
, p
)) != '3']):
330 self
.log_warn('%s: unable to process maxwait: %s'
331 %(ifaceobj
.name
, str(e
)))
333 def _ints_to_ranges(self
, ints
):
334 for a
, b
in itertools
.groupby(enumerate(ints
), lambda (x
, y
): y
- x
):
336 yield b
[0][1], b
[-1][1]
338 def _ranges_to_ints(self
, rangelist
):
339 """ returns expanded list of integers given set of string ranges
340 example: ['1', '2-4', '6'] returns [1, 2, 3, 4, 6]
343 for part
in rangelist
:
345 a
, b
= part
.split('-')
346 a
, b
= int(a
), int(b
)
347 result
.extend(range(a
, b
+ 1))
353 def _diff_vids(self
, vids1
, vids2
):
357 vids1_ints
= self
._ranges
_to
_ints
(vids1
)
358 vids2_ints
= self
._ranges
_to
_ints
(vids2
)
359 vids1_diff
= Set(vids1_ints
).difference(vids2_ints
)
360 vids2_diff
= Set(vids2_ints
).difference(vids1_ints
)
362 vids_to_add
= ['%d' %start
if start
== end
else '%d-%d' %(start
, end
)
363 for start
, end
in self
._ints
_to
_ranges
(vids1_diff
)]
365 vids_to_del
= ['%d' %start
if start
== end
else '%d-%d' %(start
, end
)
366 for start
, end
in self
._ints
_to
_ranges
(vids2_diff
)]
367 return (vids_to_del
, vids_to_add
)
369 def _compare_vids(self
, vids1
, vids2
):
370 """ Returns true if the vids are same else return false """
372 vids1_ints
= self
._ranges
_to
_ints
(vids1
)
373 vids2_ints
= self
._ranges
_to
_ints
(vids2
)
374 if Set(vids1_ints
).symmetric_difference(vids2_ints
):
379 def _set_bridge_mcqv4src_compat(self
, ifaceobj
):
381 # Sets old style igmp querier
383 attrval
= ifaceobj
.get_attr_value_first('bridge-mcqv4src')
385 running_mcqv4src
= {}
386 if not self
.PERFMODE
:
387 running_mcqv4src
= self
.brctlcmd
.get_mcqv4src(ifaceobj
.name
)
389 srclist
= attrval
.split()
394 k_to_del
= Set(running_mcqv4src
.keys()).difference(mcqs
.keys())
396 self
.brctlcmd
.del_mcqv4src(ifaceobj
.name
, v
)
397 for v
in mcqs
.keys():
398 self
.brctlcmd
.set_mcqv4src(ifaceobj
.name
, v
, mcqs
[v
])
400 def _get_running_vidinfo(self
):
401 if self
._running
_vidinfo
_valid
:
402 return self
._running
_vidinfo
403 self
._running
_vidinfo
= {}
404 if not self
.PERFMODE
:
405 self
._running
_vidinfo
= self
.ipcmd
.bridge_port_vids_get_all()
406 self
._running
_vidinfo
_valid
= True
407 return self
._running
_vidinfo
409 def _flush_running_vidinfo(self
):
410 self
._running
_vidinfo
= {}
411 self
._running
_vidinfo
_valid
= False
413 def _set_bridge_vidinfo_compat(self
, ifaceobj
):
415 # Supports old style vlan vid info format
419 # Handle bridge vlan attrs
420 running_vidinfo
= self
._get
_running
_vidinfo
()
423 attrval
= ifaceobj
.get_attr_value_first('bridge-port-pvids')
425 portlist
= self
.parse_port_list(attrval
)
427 self
.log_warn('%s: could not parse \'%s %s\''
428 %(ifaceobj
.name
, attrname
, attrval
))
432 (port
, pvid
) = p
.split('=')
433 running_pvid
= running_vidinfo
.get(port
, {}).get('pvid')
435 if running_pvid
== pvid
:
438 self
.ipcmd
.bridge_port_pvid_del(port
, running_pvid
)
439 self
.ipcmd
.bridge_port_pvid_add(port
, pvid
)
441 self
.log_warn('%s: failed to set pvid `%s` (%s)'
442 %(ifaceobj
.name
, p
, str(e
)))
445 attrval
= ifaceobj
.get_attr_value_first('bridge-port-vids')
447 portlist
= self
.parse_port_list(attrval
)
449 self
.log_warn('%s: could not parse \'%s %s\''
450 %(ifaceobj
.name
, attrname
, attrval
))
454 (port
, val
) = p
.split('=')
455 vids
= val
.split(',')
456 if running_vidinfo
.get(port
):
457 (vids_to_del
, vids_to_add
) = \
458 self
._diff
_vids
(vids
,
459 running_vidinfo
.get(port
).get('vlan'))
461 self
.ipcmd
.bridge_port_vids_del(port
, vids_to_del
)
463 self
.ipcmd
.bridge_port_vids_add(port
, vids_to_add
)
465 self
.ipcmd
.bridge_port_vids_add(port
, vids
)
467 self
.log_warn('%s: failed to set vid `%s` (%s)'
468 %(ifaceobj
.name
, p
, str(e
)))
471 # XXX: Commenting out this code for now because it was decided
472 # that this is not needed
473 #attrval = ifaceobj.get_attr_value_first('bridge-vids')
475 # vids = re.split(r'[\s\t]\s*', attrval)
476 # if running_vidinfo.get(ifaceobj.name):
477 # (vids_to_del, vids_to_add) = \
478 # self._diff_vids(vids,
479 # running_vidinfo.get(ifaceobj.name).get('vlan'))
481 # self.ipcmd.bridge_vids_del(ifaceobj.name, vids_to_del)
483 # self.ipcmd.bridge_vids_add(ifaceobj.name, vids_to_add)
485 # self.ipcmd.bridge_vids_add(ifaceobj.name, vids)
487 # running_vids = running_vidinfo.get(ifaceobj.name)
489 # self.ipcmd.bridge_vids_del(ifaceobj.name, running_vids)
491 def _apply_bridge_settings(self
, ifaceobj
):
493 stp
= ifaceobj
.get_attr_value_first('bridge-stp')
495 self
.brctlcmd
.set_stp(ifaceobj
.name
, stp
)
496 # Use the brctlcmd bulk set method: first build a dictionary
498 bridgeattrs
= { k
:v
for k
,v
in
500 ifaceobj
.get_attr_value_first('bridge-ageing'),
502 ifaceobj
.get_attr_value_first(
503 'bridge-bridgeprio'),
505 ifaceobj
.get_attr_value_first('bridge-fd'),
507 ifaceobj
.get_attr_value_first('bridge-gcint'),
509 ifaceobj
.get_attr_value_first('bridge-hello'),
511 ifaceobj
.get_attr_value_first('bridge-maxage'),
513 ifaceobj
.get_attr_value_first('bridge-mclmc'),
515 ifaceobj
.get_attr_value_first(
518 ifaceobj
.get_attr_value_first('bridge-mcsnoop'),
520 ifaceobj
.get_attr_value_first('bridge-mcsqc'),
522 ifaceobj
.get_attr_value_first(
525 ifaceobj
.get_attr_value_first(
528 ifaceobj
.get_attr_value_first('bridge-hashel'),
530 ifaceobj
.get_attr_value_first('bridge-hashmax'),
532 ifaceobj
.get_attr_value_first('bridge-mclmi'),
534 ifaceobj
.get_attr_value_first('bridge-mcmi'),
536 ifaceobj
.get_attr_value_first('bridge-mcqpi'),
538 ifaceobj
.get_attr_value_first('bridge-mcqi'),
540 ifaceobj
.get_attr_value_first('bridge-mcqri'),
542 ifaceobj
.get_attr_value_first('bridge-mcsqi')
546 self
.brctlcmd
.set_bridge_attrs(ifaceobj
.name
, bridgeattrs
)
548 for attrname
, dstattrname
in {'bridge-pathcosts' : 'pathcost',
549 'bridge-portprios' : 'portprio',
550 'bridge-portmcrouter' : 'portmcrouter',
551 'bridge-portmcfl' : 'portmcfl'}.items():
552 attrval
= ifaceobj
.get_attr_value_first(attrname
)
555 portlist
= self
.parse_port_list(attrval
)
557 self
.log_warn('%s: could not parse \'%s %s\''
558 %(ifaceobj
.name
, attrname
, attrval
))
562 (port
, val
) = p
.split('=')
563 if not portattrs
.get(port
):
565 portattrs
[port
].update({dstattrname
: val
})
567 self
.log_warn('%s: could not parse %s (%s)'
568 %(ifaceobj
.name
, attrname
, str(e
)))
569 for port
, attrdict
in portattrs
.iteritems():
570 self
.brctlcmd
.set_bridgeport_attrs(ifaceobj
.name
, port
,
572 self
._set
_bridge
_vidinfo
_compat
(ifaceobj
)
574 self
._set
_bridge
_mcqv
4src
_compat
(ifaceobj
)
576 self
._process
_bridge
_maxwait
(ifaceobj
,
577 self
._get
_bridge
_port
_list
(ifaceobj
))
579 self
.log_warn(str(e
))
581 def _apply_bridge_vids(self
, bportifaceobj
, vids
, running_vids
, isbridge
):
584 (vids_to_del
, vids_to_add
) = \
585 self
._diff
_vids
(vids
, running_vids
)
587 self
.ipcmd
.bridge_vids_del(bportifaceobj
.name
,
588 vids_to_del
, isbridge
)
590 self
.ipcmd
.bridge_vids_add(bportifaceobj
.name
,
591 vids_to_add
, isbridge
)
593 self
.ipcmd
.bridge_vids_add(bportifaceobj
.name
, vids
, isbridge
)
595 self
.log_warn('%s: failed to set vid `%s` (%s)'
596 %(bportifaceobj
.name
, str(vids
), str(e
)))
598 def _apply_bridge_port_pvids(self
, bportifaceobj
, pvid
, running_pvid
):
602 if running_pvid
!= pvid
:
603 self
.ipcmd
.bridge_port_pvid_del(bportifaceobj
.name
,
605 self
.ipcmd
.bridge_port_pvid_add(bportifaceobj
.name
, pvid
)
607 self
.ipcmd
.bridge_port_pvid_add(bportifaceobj
.name
, pvid
)
609 self
.log_warn('%s: failed to set pvid `%s` (%s)'
610 %(bportifaceobj
.name
, pvid
, str(e
)))
612 def _apply_bridge_vlan_aware_port_settings_all(self
, bportifaceobj
,
615 running_vidinfo
= self
._get
_running
_vidinfo
()
618 bport_access
= bportifaceobj
.get_attr_value_first('bridge-access')
620 vids
= re
.split(r
'[\s\t]\s*', bport_access
)
623 bport_vids
= bportifaceobj
.get_attr_value_first('bridge-vids')
625 vids
= re
.split(r
'[\s\t,]\s*', bport_vids
)
627 bport_pvids
= bportifaceobj
.get_attr_value_first('bridge-pvid')
629 pvids
= re
.split(r
'[\s\t]\s*', bport_pvids
)
632 self
._apply
_bridge
_port
_pvids
(bportifaceobj
, pvids
[0],
633 running_vidinfo
.get(bportifaceobj
.name
, {}).get('pvid'))
635 self
._apply
_bridge
_port
_pvids
(bportifaceobj
,
636 bridge_pvid
, running_vidinfo
.get(bportifaceobj
.name
,
638 # XXX: default pvid is already one
640 # self._apply_bridge_port_pvids(bportifaceobj,
641 # '1', running_vidinfo.get(bportifaceobj.name,
645 self
._apply
_bridge
_vids
(bportifaceobj
, vids
,
646 running_vidinfo
.get(bportifaceobj
.name
,
647 {}).get('vlan'), False)
649 self
._apply
_bridge
_vids
(bportifaceobj
,
650 bridge_vids
, running_vidinfo
.get(
651 bportifaceobj
.name
, {}).get('vlan'), False)
654 def _apply_bridge_port_settings(self
, bportifaceobj
, bridgename
=None,
655 bridgeifaceobj
=None):
656 if not bridgename
and bridgeifaceobj
:
657 bridgename
= bridgeifaceobj
.name
658 # Set other stp and igmp attributes
660 for attrname
, dstattrname
in {
661 'bridge-pathcosts' : 'pathcost',
662 'bridge-portprios' : 'portprio',
663 'bridge-portmcrouter' : 'portmcrouter',
664 'bridge-portmcfl' : 'portmcfl'}.items():
665 attrval
= bportifaceobj
.get_attr_value_first(attrname
)
667 # Check if bridge has that attribute
669 # attrval = bridgeifaceobj.get_attr_value_first(attrname)
674 portattrs
[dstattrname
] = attrval
676 self
.brctlcmd
.set_bridgeport_attrs(bridgename
,
677 bportifaceobj
.name
, portattrs
)
679 self
.log_warn(str(e
))
681 def _apply_bridge_port_settings_all(self
, ifaceobj
,
682 ifaceobj_getfunc
=None):
683 bridge_vlan_aware
= ifaceobj
.get_attr_value_first(
685 if bridge_vlan_aware
and bridge_vlan_aware
== 'yes':
686 bridge_vlan_aware
= True
688 bridge_vlan_aware
= False
690 if (ifaceobj
.get_attr_value_first('bridge-port-vids') and
691 ifaceobj
.get_attr_value_first('bridge-port-pvids')):
692 # Old style bridge port vid info
693 # skip new style setting on ports
695 self
.logger
.info('%s: applying bridge configuration '
696 %ifaceobj
.name
+ 'specific to ports')
698 bridge_vids
= ifaceobj
.get_attr_value_first('bridge-vids')
700 bridge_vids
= re
.split(r
'[\s\t,]\s*', bridge_vids
)
704 bridge_pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
706 bridge_pvid
= re
.split(r
'[\s\t]\s*', bridge_pvid
)
710 bridgeports
= self
._get
_bridge
_port
_list
(ifaceobj
)
711 for bport
in bridgeports
:
712 # Use the brctlcmd bulk set method: first build a dictionary
714 if not self
.ipcmd
.bridge_port_exists(ifaceobj
.name
, bport
):
715 self
.logger
.info('%s: skipping bridge config' %ifaceobj
.name
+
716 ' for port %s (missing port)' %bport
)
718 self
.logger
.info('%s: processing bridge config for port %s'
719 %(ifaceobj
.name
, bport
))
720 bportifaceobjlist
= ifaceobj_getfunc(bport
)
721 if not bportifaceobjlist
:
723 for bportifaceobj
in bportifaceobjlist
:
724 # Dont process bridge port if it already has been processed
725 if bportifaceobj
.priv_flags
& self
._BRIDGE
_PORT
_PROCESSED
:
728 # Add attributes specific to the vlan aware bridge
729 if bridge_vlan_aware
:
730 self
._apply
_bridge
_vlan
_aware
_port
_settings
_all
(
731 bportifaceobj
, bridge_vids
, bridge_pvid
)
732 self
._apply
_bridge
_port
_settings
(bportifaceobj
,
733 bridgeifaceobj
=ifaceobj
)
735 def _up(self
, ifaceobj
, ifaceobj_getfunc
=None):
736 # Check if bridge port
737 bridgename
= self
.ipcmd
.bridge_port_get_bridge_name(ifaceobj
.name
)
739 if self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
740 bridge_vids
= self
._get
_bridge
_vids
(bridgename
,
742 bridge_pvid
= self
._get
_bridge
_pvid
(bridgename
,
744 self
._apply
_bridge
_vlan
_aware
_port
_settings
_all
(ifaceobj
,
747 self
._apply
_bridge
_port
_settings
(ifaceobj
, bridgename
=bridgename
)
748 ifaceobj
.priv_flags |
= self
._BRIDGE
_PORT
_PROCESSED
750 if not self
._is
_bridge
(ifaceobj
):
756 self
.ipcmd
.batch_start()
757 if not self
.PERFMODE
:
758 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
759 self
.ipcmd
.link_create(ifaceobj
.name
, 'bridge')
761 self
.ipcmd
.link_create(ifaceobj
.name
, 'bridge')
764 self
._add
_ports
(ifaceobj
)
770 self
.ipcmd
.batch_commit()
771 self
._apply
_bridge
_settings
(ifaceobj
)
772 self
._apply
_bridge
_port
_settings
_all
(ifaceobj
,
773 ifaceobj_getfunc
=ifaceobj_getfunc
)
774 #self._flush_running_vidinfo()
776 self
.log_error(str(e
))
778 if link_exists
and ifaceobj
.addr_method
== 'manual':
779 rtnetlink_api
.rtnl_api
.link_set(ifaceobj
.name
, "up")
781 raise Exception(porterrstr
)
783 def _down(self
, ifaceobj
, ifaceobj_getfunc
=None):
785 if ifaceobj
.get_attr_value_first('bridge-ports'):
786 ports
= self
.brctlcmd
.get_bridge_ports(ifaceobj
.name
)
789 proc_file
= ('/proc/sys/net/ipv6/conf/%s' %p
+
791 self
.write_file(proc_file
, '0')
792 self
.brctlcmd
.delete_bridge(ifaceobj
.name
)
794 self
.log_error(str(e
))
796 def _query_running_vidinfo_compat(self
, ifaceobjrunning
, ports
):
798 running_vidinfo
= self
._get
_running
_vidinfo
()
800 running_bridge_port_vids
= ''
803 running_vids
= running_vidinfo
.get(p
, {}).get('vlan')
805 running_bridge_port_vids
+= ' %s=%s' %(p
,
806 ','.join(running_vids
))
809 running_attrs
['bridge-port-vids'] = running_bridge_port_vids
811 running_bridge_port_pvids
= ''
814 running_pvids
= running_vidinfo
.get(p
, {}).get('pvid')
816 running_bridge_port_pvids
+= ' %s=%s' %(p
,
820 running_attrs
['bridge-port-pvids'] = running_bridge_port_pvids
822 running_bridge_vids
= running_vidinfo
.get(ifaceobjrunning
.name
,
824 if running_bridge_vids
:
825 running_attrs
['bridge-vids'] = ','.join(running_bridge_vids
)
828 def _query_running_vidinfo(self
, ifaceobjrunning
):
830 running_vidinfo
= self
._get
_running
_vidinfo
()
831 running_bridge_vids
= running_vidinfo
.get(ifaceobjrunning
.name
,
833 if running_bridge_vids
:
834 running_attrs
['bridge-vids'] = ','.join(running_bridge_vids
)
837 def _query_running_mcqv4src(self
, ifaceobjrunning
):
838 running_mcqv4src
= self
.brctlcmd
.get_mcqv4src(ifaceobjrunning
.name
)
839 mcqs
= ['%s=%s' %(v
, i
) for v
, i
in running_mcqv4src
.items()]
844 def _query_running_attrs(self
, ifaceobjrunning
, bridge_vlan_aware
=False):
848 skip_kernel_stp_attrs
= 0
850 if self
.sysctl_get('net.bridge.bridge-stp-user-space') == '1':
853 tmpbridgeattrdict
= self
.brctlcmd
.get_bridge_attrs(ifaceobjrunning
.name
)
854 if not tmpbridgeattrdict
:
855 self
.logger
.warn('%s: unable to get bridge attrs'
856 %ifaceobjrunning
.name
)
857 return bridgeattrdict
859 # Fill bridge_ports and bridge stp attributes first
860 ports
= tmpbridgeattrdict
.get('ports')
862 bridgeattrdict
['bridge-ports'] = [' '.join(ports
.keys())]
863 stp
= tmpbridgeattrdict
.get('stp', 'no')
864 if stp
!= self
.get_mod_subattr('bridge-stp', 'default'):
865 bridgeattrdict
['bridge-stp'] = [stp
]
867 if stp
== 'yes' and userspace_stp
:
868 skip_kernel_stp_attrs
= 1
870 # pick all other attributes
871 for k
,v
in tmpbridgeattrdict
.items():
874 if k
== 'ports' or k
== 'stp':
877 if skip_kernel_stp_attrs
and k
[:2] != 'mc':
878 # only include igmp attributes if kernel stp is off
880 attrname
= 'bridge-' + k
881 if v
!= self
.get_mod_subattr(attrname
, 'default'):
882 bridgeattrdict
[attrname
] = [v
]
884 if bridge_vlan_aware
:
885 bridgevidinfo
= self
._query
_running
_vidinfo
(ifaceobjrunning
)
887 bridgevidinfo
= self
._query
_running
_vidinfo
_compat
(ifaceobjrunning
,
890 bridgeattrdict
.update({k
: [v
] for k
, v
in bridgevidinfo
.items()
893 mcq
= self
._query
_running
_mcqv
4src
(ifaceobjrunning
)
895 bridgeattrdict
['bridge-mcqv4src'] = [mcq
]
897 if skip_kernel_stp_attrs
:
898 return bridgeattrdict
901 portconfig
= {'bridge-pathcosts' : '',
902 'bridge-portprios' : ''}
903 for p
, v
in ports
.items():
904 v
= self
.brctlcmd
.get_pathcost(ifaceobjrunning
.name
, p
)
905 if v
and v
!= self
.get_mod_subattr('bridge-pathcosts',
907 portconfig
['bridge-pathcosts'] += ' %s=%s' %(p
, v
)
909 v
= self
.brctlcmd
.get_portprio(ifaceobjrunning
.name
, p
)
910 if v
and v
!= self
.get_mod_subattr('bridge-portprios',
912 portconfig
['bridge-portprios'] += ' %s=%s' %(p
, v
)
914 bridgeattrdict
.update({k
: [v
] for k
, v
in portconfig
.items()
917 return bridgeattrdict
919 def _query_check_mcqv4src(self
, ifaceobj
, ifaceobjcurr
):
920 running_mcqs
= self
._query
_running
_mcqv
4src
(ifaceobj
)
921 attrval
= ifaceobj
.get_attr_value_first('bridge-mcqv4src')
923 mcqs
= attrval
.split()
925 mcqsout
= ' '.join(mcqs
)
926 ifaceobjcurr
.update_config_with_status('bridge-mcqv4src',
927 running_mcqs
, 1 if running_mcqs
!= mcqsout
else 0)
929 def _query_check_bridge_vidinfo(self
, ifaceobj
, ifaceobjcurr
):
931 running_vidinfo
= self
._get
_running
_vidinfo
()
932 attrval
= ifaceobj
.get_attr_value_first('bridge-port-vids')
934 running_bridge_port_vids
= ''
935 portlist
= self
.parse_port_list(attrval
)
937 self
.log_warn('%s: could not parse \'%s %s\''
938 %(ifaceobj
.name
, attrname
, attrval
))
943 (port
, val
) = p
.split('=')
944 vids
= val
.split(',')
945 running_vids
= running_vidinfo
.get(port
, {}).get('vlan')
947 if not self
._compare
_vids
(vids
, running_vids
):
949 running_bridge_port_vids
+= ' %s=%s' %(port
,
950 ','.join(running_vids
))
952 running_bridge_port_vids
+= ' %s' %p
956 self
.log_warn('%s: failure checking vid %s (%s)'
957 %(ifaceobj
.name
, p
, str(e
)))
959 ifaceobjcurr
.update_config_with_status('bridge-port-vids',
960 running_bridge_port_vids
, 1)
962 ifaceobjcurr
.update_config_with_status('bridge-port-vids',
965 attrval
= ifaceobj
.get_attr_value_first('bridge-port-pvids')
967 portlist
= self
.parse_port_list(attrval
)
969 self
.log_warn('%s: could not parse \'%s %s\''
970 %(ifaceobj
.name
, attrname
, attrval
))
972 running_bridge_port_pvids
= ''
976 (port
, pvid
) = p
.split('=')
977 running_pvid
= running_vidinfo
.get(port
, {}).get('pvid')
978 if running_pvid
and running_pvid
== pvid
:
979 running_bridge_port_pvids
+= ' %s' %p
982 running_bridge_port_pvids
+= ' %s=%s' %(port
,
985 self
.log_warn('%s: failure checking pvid %s (%s)'
986 %(ifaceobj
.name
, pvid
, str(e
)))
988 ifaceobjcurr
.update_config_with_status('bridge-port-pvids',
989 running_bridge_port_pvids
, 1)
991 ifaceobjcurr
.update_config_with_status('bridge-port-pvids',
992 running_bridge_port_pvids
, 0)
994 # XXX: No need to check for bridge-vids on the bridge
995 # This is used by the ports. The vids on the bridge
996 # come from the vlan interfaces on the bridge.
998 attrval
= ifaceobj
.get_attr_value_first('bridge-vids')
1000 # vids = re.split(r'[\s\t]\s*', attrval)
1001 # running_vids = running_vidinfo.get(ifaceobj.name, {}).get('vlan')
1003 # if self._compare_vids(vids, running_vids):
1004 # ifaceobjcurr.update_config_with_status('bridge-vids',
1007 # ifaceobjcurr.update_config_with_status('bridge-vids',
1008 # ','.join(running_vids), 1)
1010 # ifaceobjcurr.update_config_with_status('bridge-vids', attrval,
1013 ifaceobjcurr
.update_config_with_status('bridge-vids', attrval
, -1)
1015 def _query_check_bridge(self
, ifaceobj
, ifaceobjcurr
,
1016 ifaceobj_getfunc
=None):
1017 if not self
._is
_bridge
(ifaceobj
):
1019 if not self
.brctlcmd
.bridge_exists(ifaceobj
.name
):
1020 self
.logger
.info('%s: bridge: does not exist' %(ifaceobj
.name
))
1021 ifaceobjcurr
.status
= ifaceStatus
.NOTFOUND
1024 ifaceattrs
= self
.dict_key_subset(ifaceobj
.config
,
1025 self
.get_mod_attrs())
1029 runningattrs
= self
.brctlcmd
.get_bridge_attrs(ifaceobj
.name
)
1030 if not runningattrs
:
1031 self
.logger
.debug('%s: bridge: unable to get bridge attrs'
1034 except Exception, e
:
1035 self
.logger
.warn(str(e
))
1037 filterattrs
= ['bridge-vids', 'bridge-port-vids',
1038 'bridge-port-pvids']
1039 for k
in Set(ifaceattrs
).difference(filterattrs
):
1040 # get the corresponding ifaceobj attr
1041 v
= ifaceobj
.get_attr_value_first(k
)
1044 rv
= runningattrs
.get(k
[7:])
1045 if k
== 'bridge-mcqv4src':
1047 if k
== 'bridge-vlan-aware' and v
== 'yes':
1048 if self
.ipcmd
.bridge_is_vlan_aware(ifaceobj
.name
):
1049 ifaceobjcurr
.update_config_with_status('bridge-vlan-aware',
1052 ifaceobjcurr
.update_config_with_status('bridge-vlan-aware',
1054 elif k
== 'bridge-stp':
1055 # special case stp compare because it may
1056 # contain more than one valid values
1057 stp_on_vals
= ['on', 'yes']
1058 stp_off_vals
= ['off']
1059 if ((v
in stp_on_vals
and rv
in stp_on_vals
) or
1060 (v
in stp_off_vals
and rv
in stp_off_vals
)):
1061 ifaceobjcurr
.update_config_with_status('bridge-stp',
1064 ifaceobjcurr
.update_config_with_status('bridge-stp',
1066 elif k
== 'bridge-ports':
1067 # special case ports because it can contain regex or glob
1068 running_port_list
= rv
.keys() if rv
else []
1069 bridge_port_list
= self
._get
_bridge
_port
_list
(ifaceobj
)
1070 if not running_port_list
and not bridge_port_list
:
1073 if running_port_list
and bridge_port_list
:
1074 difference
= set(running_port_list
1075 ).symmetric_difference(bridge_port_list
)
1078 ifaceobjcurr
.update_config_with_status('bridge-ports',
1079 ' '.join(running_port_list
)
1080 if running_port_list
else '', portliststatus
)
1081 elif (k
== 'bridge-pathcosts' or
1082 k
== 'bridge-portprios' or k
== 'bridge-portmcrouter'
1083 or k
== 'bridge-portmcfl'):
1084 brctlcmdattrname
= k
[11:].rstrip('s')
1085 # for port attributes, the attributes are in a list
1086 # <portname>=<portattrvalue>
1089 vlist
= self
.parse_port_list(v
)
1092 for vlistitem
in vlist
:
1094 (p
, v
) = vlistitem
.split('=')
1095 currv
= self
.brctlcmd
.get_bridgeport_attr(
1099 currstr
+= ' %s=%s' %(p
, currv
)
1101 currstr
+= ' %s=%s' %(p
, 'None')
1104 except Exception, e
:
1105 self
.log_warn(str(e
))
1107 ifaceobjcurr
.update_config_with_status(k
, currstr
, status
)
1109 ifaceobjcurr
.update_config_with_status(k
, 'notfound', 1)
1112 ifaceobjcurr
.update_config_with_status(k
, rv
, 1)
1114 ifaceobjcurr
.update_config_with_status(k
, rv
, 0)
1116 self
._query
_check
_bridge
_vidinfo
(ifaceobj
, ifaceobjcurr
)
1118 self
._query
_check
_mcqv
4src
(ifaceobj
, ifaceobjcurr
)
1120 def _get_bridge_vids(self
, bridgename
, ifaceobj_getfunc
):
1121 ifaceobjs
= ifaceobj_getfunc(bridgename
)
1122 for ifaceobj
in ifaceobjs
:
1123 vids
= ifaceobj
.get_attr_value_first('bridge-vids')
1124 if vids
: return re
.split(r
'[\s\t,]\s*', vids
)
1127 def _get_bridge_pvid(self
, bridgename
, ifaceobj_getfunc
):
1128 ifaceobjs
= ifaceobj_getfunc(bridgename
)
1130 for ifaceobj
in ifaceobjs
:
1131 pvid
= ifaceobj
.get_attr_value_first('bridge-pvid')
1134 def _get_bridge_name(self
, ifaceobj
):
1135 return self
.ipcmd
.bridge_port_get_bridge_name(ifaceobj
.name
)
1137 def _query_check_bridge_port_vidinfo(self
, ifaceobj
, ifaceobjcurr
,
1138 ifaceobj_getfunc
, bridgename
):
1139 running_vidinfo
= self
._get
_running
_vidinfo
()
1141 attr_name
= 'bridge-access'
1142 vids
= ifaceobj
.get_attr_value_first(attr_name
)
1144 running_pvids
= running_vidinfo
.get(ifaceobj
.name
,
1146 running_vids
= running_vidinfo
.get(ifaceobj
.name
,
1148 if (not running_pvids
or running_pvids
!= vids
or
1150 ifaceobjcurr
.update_config_with_status(attr_name
,
1153 ifaceobjcurr
.update_config_with_status(attr_name
, vids
, 0)
1156 attr_name
= 'bridge-vids'
1157 vids
= ifaceobj
.get_attr_value_first(attr_name
)
1159 vids
= re
.split(r
'[\s\t]\s*', vids
)
1160 running_vids
= running_vidinfo
.get(ifaceobj
.name
,
1162 if not running_vids
or not self
._compare
_vids
(vids
, running_vids
):
1163 ifaceobjcurr
.update_config_with_status(attr_name
,
1164 ' '.join(running_vids
), 1)
1166 ifaceobjcurr
.update_config_with_status(attr_name
,
1167 ' '.join(running_vids
), 0)
1169 # check if it matches the bridge vids
1170 bridge_vids
= self
._get
_bridge
_vids
(bridgename
, ifaceobj_getfunc
)
1171 running_vids
= running_vidinfo
.get(ifaceobj
.name
,
1173 if (bridge_vids
and (not running_vids
or
1174 not self
._compare
_vids
(bridge_vids
, running_vids
))):
1175 ifaceobjcurr
.status
= ifaceStatus
.ERROR
1176 ifaceobjcurr
.status_str
= 'bridge vid error'
1178 running_pvid
= running_vidinfo
.get(ifaceobj
.name
,
1180 attr_name
= 'bridge-pvid'
1181 pvid
= ifaceobj
.get_attr_value_first(attr_name
)
1183 if running_pvid
and running_pvid
== pvid
:
1184 ifaceobjcurr
.update_config_with_status(attr_name
,
1187 ifaceobjcurr
.update_config_with_status(attr_name
,
1189 elif not running_pvid
or running_pvid
!= '1':
1190 ifaceobjcurr
.status
= ifaceStatus
.ERROR
1191 ifaceobjcurr
.status_str
= 'bridge pvid error'
1193 def _query_check_bridge_port(self
, ifaceobj
, ifaceobjcurr
,
1195 if not self
._is
_bridge
_port
(ifaceobj
):
1196 # Mark all bridge attributes as failed
1197 ifaceobj
.check_n_update_config_with_status_many(
1198 ['bridge-vids', 'bridge-pvid', 'bridge-access',
1199 'bridge-pathcosts', 'bridge-portprios',
1200 'bridge-portmcrouter',
1201 'bridge-portmcfl'], 0)
1203 bridgename
= self
._get
_bridge
_name
(ifaceobj
)
1205 self
.logger
.warn('%s: unable to determine bridge name'
1209 if self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
1210 self
._query
_check
_bridge
_port
_vidinfo
(ifaceobj
, ifaceobjcurr
,
1213 for attr
, dstattr
in {'bridge-pathcosts' : 'pathcost',
1214 'bridge-portprios' : 'priority',
1215 'bridge-portmcrouter' : 'mcrouter',
1216 'bridge-portmcfl' : 'mcfl' }.items():
1217 attrval
= ifaceobj
.get_attr_value_first(attr
)
1222 running_attrval
= self
.brctlcmd
.get_bridgeport_attr(
1223 bridgename
, ifaceobj
.name
, dstattr
)
1224 if running_attrval
!= attrval
:
1225 ifaceobjcurr
.update_config_with_status(attr
,
1228 ifaceobjcurr
.update_config_with_status(attr
,
1230 except Exception, e
:
1231 self
.log_warn('%s: %s' %(ifaceobj
.name
, str(e
)))
1233 def _query_check(self
, ifaceobj
, ifaceobjcurr
, ifaceobj_getfunc
=None):
1234 if self
._is
_bridge
(ifaceobj
):
1235 self
._query
_check
_bridge
(ifaceobj
, ifaceobjcurr
)
1237 self
._query
_check
_bridge
_port
(ifaceobj
, ifaceobjcurr
,
1240 def _query_running_bridge(self
, ifaceobjrunning
):
1241 if self
.ipcmd
.bridge_is_vlan_aware(ifaceobjrunning
.name
):
1242 ifaceobjrunning
.update_config('bridge-vlan-aware', 'yes')
1243 ifaceobjrunning
.update_config_dict(self
._query
_running
_attrs
(
1245 bridge_vlan_aware
=True))
1247 ifaceobjrunning
.update_config_dict(self
._query
_running
_attrs
(
1250 def _query_running_bridge_port_attrs(self
, ifaceobjrunning
, bridgename
):
1251 if self
.sysctl_get('net.bridge.bridge-stp-user-space') == '1':
1254 v
= self
.brctlcmd
.get_pathcost(bridgename
, ifaceobjrunning
.name
)
1255 if v
and v
!= self
.get_mod_subattr('bridge-pathcosts', 'default'):
1256 ifaceobjrunning
.update_config('bridge-pathcosts', v
)
1258 v
= self
.brctlcmd
.get_pathcost(bridgename
, ifaceobjrunning
.name
)
1259 if v
and v
!= self
.get_mod_subattr('bridge-portprios', 'default'):
1260 ifaceobjrunning
.update_config('bridge-portprios', v
)
1262 def _query_running_bridge_port(self
, ifaceobjrunning
,
1263 ifaceobj_getfunc
=None):
1264 bridgename
= self
.ipcmd
.bridge_port_get_bridge_name(
1265 ifaceobjrunning
.name
)
1267 self
.logger
.warn('%s: unable to find bridgename'
1268 %ifaceobjrunning
.name
)
1270 if not self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
1273 running_vidinfo
= self
._get
_running
_vidinfo
()
1275 bridge_vids
= running_vidinfo
.get(bridgename
, {}).get('vlan')
1277 bridge_port_vids
= running_vidinfo
.get(ifaceobjrunning
.name
,
1279 bridge_port_pvid
= running_vidinfo
.get(ifaceobjrunning
.name
,
1282 if not bridge_port_vids
and bridge_port_pvid
:
1283 # must be an access port
1284 ifaceobjrunning
.update_config('bridge-access',
1287 if bridge_port_vids
:
1288 if bridge_vids
and bridge_port_vids
!= bridge_vids
:
1289 ifaceobjrunning
.update_config('bridge-vids',
1290 ' '.join(bridge_port_vids
))
1292 if bridge_port_pvid
and bridge_port_pvid
!= '1':
1293 ifaceobjrunning
.update_config('bridge-pvid',
1296 self
._query
_running
_bridge
_port
_attrs
(ifaceobjrunning
, bridgename
)
1299 def _query_running(self
, ifaceobjrunning
, **extra_args
):
1300 if self
.brctlcmd
.bridge_exists(ifaceobjrunning
.name
):
1301 self
._query
_running
_bridge
(ifaceobjrunning
)
1302 elif self
.brctlcmd
.is_bridge_port(ifaceobjrunning
.name
):
1303 self
._query
_running
_bridge
_port
(ifaceobjrunning
)
1305 _run_ops
= {'pre-up' : _up
,
1306 'post-down' : _down
,
1307 'query-checkcurr' : _query_check
,
1308 'query-running' : _query_running
}
1311 """ returns list of ops supported by this module """
1312 return self
._run
_ops
.keys()
1314 def _init_command_handlers(self
):
1315 flags
= self
.get_flags()
1317 self
.ipcmd
= iproute2(**flags
)
1318 if not self
.brctlcmd
:
1319 self
.brctlcmd
= brctl(**flags
)
1321 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None,
1322 ifaceobj_getfunc
=None):
1323 """ run bridge configuration on the interface object passed as
1324 argument. Can create bridge interfaces if they dont exist already
1327 **ifaceobj** (object): iface object
1329 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
1333 **query_ifaceobj** (object): query check ifaceobject. This is only
1334 valid when op is 'query-checkcurr'. It is an object same as
1335 ifaceobj, but contains running attribute values and its config
1336 status. The modules can use it to return queried running state
1337 of interfaces. status is success if the running state is same
1338 as user required state in ifaceobj. error otherwise.
1340 op_handler
= self
._run
_ops
.get(operation
)
1343 self
._init
_command
_handlers
()
1344 self
._flush
_running
_vidinfo
()
1345 if operation
== 'query-checkcurr':
1346 op_handler(self
, ifaceobj
, query_ifaceobj
,
1347 ifaceobj_getfunc
=ifaceobj_getfunc
)
1349 op_handler(self
, ifaceobj
, ifaceobj_getfunc
=ifaceobj_getfunc
)