3 # Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
5 # Julien Fortin, julien@cumulusnetworks.com
15 from ipaddr
import IPNetwork
, IPv6Network
18 import ifupdown2
.ifupdown
.statemanager
as statemanager
19 import ifupdown2
.ifupdown
.ifupdownflags
as ifupdownflags
21 from ifupdown2
.nlmanager
.nlmanager
import Link
, Route
23 from ifupdown2
.ifupdown
.iface
import *
24 from ifupdown2
.ifupdown
.utils
import utils
25 from ifupdown2
.ifupdown
.netlink
import netlink
27 from ifupdown2
.ifupdownaddons
.utilsbase
import utilsBase
28 from ifupdown2
.ifupdownaddons
.cache
import linkCache
, MSTPAttrsCache
30 import ifupdown
.ifupdownflags
as ifupdownflags
31 import ifupdown
.statemanager
as statemanager
33 from nlmanager
.nlmanager
import Link
, Route
35 from ifupdown
.iface
import *
36 from ifupdown
.utils
import utils
37 from ifupdown
.netlink
import netlink
39 from ifupdownaddons
.utilsbase
import utilsBase
40 from ifupdownaddons
.cache
import linkCache
, MSTPAttrsCache
43 class LinkUtils(utilsBase
):
45 This class contains helper methods to cache and manipulate interfaces through
46 non-netlink APIs (sysfs, iproute2, brctl...)
48 _CACHE_FILL_DONE
= False
55 bridge_utils_is_installed
= os
.path
.exists(utils
.brctl_cmd
)
56 bridge_utils_missing_warning
= True
58 def __init__(self
, *args
, **kargs
):
59 utilsBase
.__init
__(self
, *args
, **kargs
)
61 self
.supported_command
= {
62 '%s -c -json vlan show' % utils
.bridge_cmd
: True,
65 self
.bridge_vlan_cache
= {}
66 self
.bridge_vlan_cache_fill_done
= False
68 if not ifupdownflags
.flags
.PERFMODE
and not LinkUtils
._CACHE
_FILL
_DONE
:
73 LinkUtils
._CACHE
_FILL
_DONE
= False
74 LinkUtils
.ipbatchbuf
= ''
75 LinkUtils
.ipbatch
= False
76 LinkUtils
.ipbatch_pause
= False
78 def _fill_cache(self
):
79 if not LinkUtils
._CACHE
_FILL
_DONE
:
82 LinkUtils
._CACHE
_FILL
_DONE
= True
87 def _get_vland_id(citems
, i
, warn
):
90 index
= sub
.index('id')
95 raise Exception('invalid use of \'vlan\' keyword')
98 def _link_fill(self
, ifacename
=None, refresh
=False):
99 """ fills cache with link information
101 if ifacename argument given, fill cache for ifacename, else
102 fill cache for all interfaces in the system
105 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
108 # if ifacename already present, return
109 if (ifacename
and not refresh
and
110 linkCache
.get_attr([ifacename
, 'ifflag'])):
117 [linkCache
.update_attrdict([ifname
], linkattrs
)
118 for ifname
, linkattrs
in netlink
.link_dump(ifacename
).items()]
119 except Exception as e
:
120 self
.logger
.info('%s' % str(e
))
121 # this netlink call replaces the call to _link_fill_iproute2_cmd()
122 # We shouldn't have netlink calls in the iproute2 module, this will
123 # be removed in the future. We plan to release, a flexible backend
124 # (netlink+iproute2) by default we will use netlink backend but with
125 # a CLI arg we can switch to iproute2 backend.
126 # Until we decide to create this "backend" switch capability,
127 # we have to put the netlink call inside the iproute2 module.
129 self
._link
_fill
_iproute
2_cmd
(ifacename
, refresh
)
131 self
._fill
_bond
_info
(ifacename
)
132 self
._fill
_bridge
_info
(ifacename
)
134 def _fill_bridge_info(self
, ifacename
):
140 cache_dict
= {ifacename
: linkCache
.links
.get(ifacename
, {})}
142 cache_dict
= linkCache
.links
144 for ifname
, obj
in cache_dict
.items():
145 slave_kind
= obj
.get('slave_kind')
146 if not slave_kind
and slave_kind
!= 'bridge':
149 info_slave_data
= obj
.get('info_slave_data')
150 if not info_slave_data
:
153 ifla_master
= obj
.get('master')
155 raise Exception('No master associated with bridge port %s' % ifname
)
158 Link
.IFLA_BRPORT_STATE
,
159 Link
.IFLA_BRPORT_COST
,
160 Link
.IFLA_BRPORT_PRIORITY
,
162 if nl_attr
not in info_slave_data
and LinkUtils
.bridge_utils_is_installed
:
163 self
._fill
_bridge
_info
_brctl
()
167 'pathcost': str(info_slave_data
.get(Link
.IFLA_BRPORT_COST
, 0)),
168 'fdelay': format(float(info_slave_data
.get(Link
.IFLA_BRPORT_FORWARD_DELAY_TIMER
, 0) / 100), '.2f'),
169 'portmcrouter': str(info_slave_data
.get(Link
.IFLA_BRPORT_MULTICAST_ROUTER
, 0)),
170 'portmcfl': str(info_slave_data
.get(Link
.IFLA_BRPORT_FAST_LEAVE
, 0)),
171 'portprio': str(info_slave_data
.get(Link
.IFLA_BRPORT_PRIORITY
, 0)),
172 'unicast-flood': str(info_slave_data
.get(Link
.IFLA_BRPORT_UNICAST_FLOOD
, 0)),
173 'multicast-flood': str(info_slave_data
.get(Link
.IFLA_BRPORT_MCAST_FLOOD
, 0)),
174 'learning': str(info_slave_data
.get(Link
.IFLA_BRPORT_LEARNING
, 0)),
175 'arp-nd-suppress': str(info_slave_data
.get(Link
.IFLA_BRPORT_ARP_SUPPRESS
, 0))
178 if ifla_master
in brports
:
179 brports
[ifla_master
][ifname
] = brport_attrs
181 brports
[ifla_master
] = {ifname
: brport_attrs
}
183 linkCache
.update_attrdict([ifla_master
, 'linkinfo', 'ports'], brports
[ifla_master
])
185 if LinkUtils
.bridge_utils_is_installed
:
186 self
._fill
_bridge
_info
_brctl
()
188 def _fill_bridge_info_brctl(self
):
189 brctlout
= utils
.exec_command('%s show' % utils
.brctl_cmd
)
193 for bline
in brctlout
.splitlines()[1:]:
194 bitems
= bline
.split()
198 linkCache
.update_attrdict([bitems
[0], 'linkinfo'],
201 linkCache
.update_attrdict([bitems
[0]],
202 {'linkinfo': {'stp': bitems
[2]}})
203 self
._bridge
_attrs
_fill
(bitems
[0])
205 def _bridge_attrs_fill(self
, bridgename
):
209 brout
= utils
.exec_command('%s showstp %s' % (utils
.brctl_cmd
, bridgename
))
210 chunks
= re
.split(r
'\n\n', brout
, maxsplit
=0, flags
=re
.MULTILINE
)
213 # Get all bridge attributes
214 broutlines
= chunks
[0].splitlines()
215 # battrs['pathcost'] = broutlines[3].split('path cost')[1].strip()
218 battrs
['maxage'] = broutlines
[4].split('bridge max age')[
219 1].strip().replace('.00', '')
224 battrs
['hello'] = broutlines
[5].split('bridge hello time')[
225 1].strip().replace('.00', '')
230 battrs
['fd'] = broutlines
[6].split('bridge forward delay')[
231 1].strip().replace('.00', '')
236 battrs
['ageing'] = broutlines
[7].split('ageing time')[
237 1].strip().replace('.00', '')
242 battrs
['mcrouter'] = broutlines
[12].split('mc router')[
243 1].strip().split('\t\t\t')[0]
248 battrs
['bridgeprio'] = self
.read_file_oneline(
249 '/sys/class/net/%s/bridge/priority' % bridgename
)
254 battrs
['vlan-protocol'] = VlanProtocols
.ID_TO_ETHERTYPES
[
255 self
.read_file_oneline(
256 '/sys/class/net/%s/bridge/vlan_protocol' % bridgename
)]
261 battrs
.update(self
._bridge
_get
_mcattrs
_from
_sysfs
(bridgename
))
265 # XXX: comment this out until mc attributes become available
267 # battrs['hashel'] = broutlines[10].split('hash elasticity')[1].split()[0].strip()
268 # battrs['hashmax'] = broutlines[10].split('hash max')[1].strip()
269 # battrs['mclmc'] = broutlines[11].split('mc last member count')[1].split()[0].strip()
270 # battrs['mciqc'] = broutlines[11].split('mc init query count')[1].strip()
271 # battrs['mcrouter'] = broutlines[12].split('mc router')[1].split()[0].strip()
272 ##battrs['mcsnoop'] = broutlines[12].split('mc snooping')[1].strip()
273 # battrs['mclmt'] = broutlines[13].split('mc last member timer')[1].split()[0].strip()
275 self
.logger
.warn('%s: error while processing bridge attributes: %s' % (bridgename
, str(e
)))
278 linkCache
.update_attrdict([bridgename
, 'linkinfo'], battrs
)
279 for cidx
in range(1, len(chunks
)):
280 bpout
= chunks
[cidx
].lstrip('\n')
281 if not bpout
or bpout
[0] == ' ':
283 bplines
= bpout
.splitlines()
284 pname
= bplines
[0].split()[0]
287 bportattrs
['pathcost'] = bplines
[2].split(
288 'path cost')[1].strip()
289 bportattrs
['fdelay'] = bplines
[4].split(
290 'forward delay timer')[1].strip()
291 bportattrs
['portmcrouter'] = self
.read_file_oneline(
292 '/sys/class/net/%s/brport/multicast_router' % pname
)
293 bportattrs
['portmcfl'] = self
.read_file_oneline(
294 '/sys/class/net/%s/brport/multicast_fast_leave' % pname
)
295 bportattrs
['portprio'] = self
.read_file_oneline(
296 '/sys/class/net/%s/brport/priority' % pname
)
297 bportattrs
['unicast-flood'] = self
.read_file_oneline(
298 '/sys/class/net/%s/brport/unicast_flood' % pname
)
299 bportattrs
['multicast-flood'] = self
.read_file_oneline(
300 '/sys/class/net/%s/brport/multicast_flood' % pname
)
301 bportattrs
['learning'] = self
.read_file_oneline(
302 '/sys/class/net/%s/brport/learning' % pname
)
303 bportattrs
['arp-nd-suppress'] = self
.read_file_oneline(
304 '/sys/class/net/%s/brport/neigh_suppress' % pname
)
305 # bportattrs['mcrouters'] = bplines[6].split('mc router')[1].split()[0].strip()
306 # bportattrs['mc fast leave'] = bplines[6].split('mc fast leave')[1].strip()
308 self
.logger
.warn('%s: error while processing bridge attributes: %s' % (bridgename
, str(e
)))
309 bports
[pname
] = bportattrs
310 linkCache
.update_attrdict([bridgename
, 'linkinfo', 'ports'], bports
)
312 _bridge_sysfs_mcattrs
= {
313 'mclmc': 'multicast_last_member_count',
314 'mcrouter': 'multicast_router',
315 'mcsnoop': 'multicast_snooping',
316 'mcsqc': 'multicast_startup_query_count',
317 'mcqifaddr': 'multicast_query_use_ifaddr',
318 'mcquerier': 'multicast_querier',
319 'hashel': 'hash_elasticity',
320 'hashmax': 'hash_max',
321 'mclmi': 'multicast_last_member_interval',
322 'mcmi': 'multicast_membership_interval',
323 'mcqpi': 'multicast_querier_interval',
324 'mcqi': 'multicast_query_interval',
325 'mcqri': 'multicast_query_response_interval',
326 'mcsqi': 'multicast_startup_query_interval',
327 'igmp-version': 'multicast_igmp_version',
328 'mld-version': 'multicast_mld_version',
329 'vlan-stats': 'vlan_stats_enabled',
330 'mcstats': 'multicast_stats_enabled',
333 def _bridge_get_mcattrs_from_sysfs(self
, bridgename
):
334 mcattrsdivby100
= ['mclmi', 'mcmi', 'mcqpi', 'mcqi', 'mcqri', 'mcsqi']
337 for m
, s
in self
._bridge
_sysfs
_mcattrs
.items():
338 n
= self
.read_file_oneline('/sys/class/net/%s/bridge/%s' % (bridgename
, s
))
339 if m
in mcattrsdivby100
:
344 self
.logger
.warn('error getting mc attr %s (%s)' % (m
, str(e
)))
350 def _fill_bond_info(self
, ifacename
):
351 bonding_masters
= self
.read_file_oneline('/sys/class/net/bonding_masters')
352 if not bonding_masters
:
355 bond_masters_list
= bonding_masters
.split()
358 if ifacename
in bond_masters_list
:
359 bond_masters_list
= [ifacename
]
361 # we want to refresh this interface only if it's a bond master
364 for bondname
in bond_masters_list
:
366 if bondname
not in linkCache
.links
:
367 linkCache
.set_attr([bondname
], {'linkinfo': {}})
368 linkCache
.set_attr([bondname
, 'linkinfo', 'slaves'],
369 self
.read_file_oneline('/sys/class/net/%s/bonding/slaves'
372 # if some attribute are missing we try to get the bond attributes via sysfs
373 bond_linkinfo
= linkCache
.links
[bondname
]['linkinfo']
374 for attr
in [Link
.IFLA_BOND_MODE
, Link
.IFLA_BOND_XMIT_HASH_POLICY
, Link
.IFLA_BOND_MIN_LINKS
]:
375 if attr
not in bond_linkinfo
:
376 self
._fill
_bond
_info
_sysfs
(bondname
)
377 # after we fill in the cache we can continue to the next bond
380 self
._fill
_bond
_info
_sysfs
(bondname
)
382 except Exception as e
:
383 self
.logger
.debug('LinkUtils: bond cache error: %s' % str(e
))
385 def _fill_bond_info_sysfs(self
, bondname
):
387 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_MIN_LINKS
],
388 self
.read_file_oneline(
389 '/sys/class/net/%s/bonding/min_links'
391 except Exception as e
:
392 self
.logger
.debug(str(e
))
395 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_MODE
],
396 self
.read_file_oneline('/sys/class/net/%s/bonding/mode'
397 % bondname
).split()[0])
398 except Exception as e
:
399 self
.logger
.debug(str(e
))
401 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_XMIT_HASH_POLICY
],
402 self
.read_file_oneline(
403 '/sys/class/net/%s/bonding/xmit_hash_policy'
404 % bondname
).split()[0])
405 except Exception as e
:
406 self
.logger
.debug(str(e
))
408 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_RATE
],
409 self
.read_file_oneline('/sys/class/net/%s/bonding/lacp_rate'
410 % bondname
).split()[1])
411 except Exception as e
:
412 self
.logger
.debug(str(e
))
414 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
],
415 self
.read_file_oneline('/sys/class/net/%s/bonding/ad_actor_sys_prio'
417 except Exception as e
:
418 self
.logger
.debug(str(e
))
420 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYSTEM
],
421 self
.read_file_oneline('/sys/class/net/%s/bonding/ad_actor_system'
423 except Exception as e
:
424 self
.logger
.debug(str(e
))
426 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_BYPASS
],
427 self
.read_file_oneline('/sys/class/net/%s/bonding/lacp_bypass'
428 % bondname
).split()[1])
429 except Exception as e
:
430 self
.logger
.debug(str(e
))
432 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_UPDELAY
],
433 self
.read_file_oneline('/sys/class/net/%s/bonding/updelay'
435 except Exception as e
:
436 self
.logger
.debug(str(e
))
438 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_DOWNDELAY
],
439 self
.read_file_oneline('/sys/class/net/%s/bonding/downdelay'
441 except Exception as e
:
442 self
.logger
.debug(str(e
))
445 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_USE_CARRIER
],
446 self
.read_file_oneline('/sys/class/net/%s/bonding/use_carrier' % bondname
))
447 except Exception as e
:
448 self
.logger
.debug(str(e
))
451 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_MIIMON
],
452 self
.read_file_oneline('/sys/class/net/%s/bonding/miimon' % bondname
))
453 except Exception as e
:
454 self
.logger
.debug(str(e
))
457 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
],
458 self
.read_file_oneline('/sys/class/net/%s/bonding/num_unsol_na' % bondname
))
459 except Exception as e
:
460 self
.logger
.debug(str(e
))
463 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
],
464 self
.read_file_oneline('/sys/class/net/%s/bonding/num_grat_arp' % bondname
))
465 except Exception as e
:
466 self
.logger
.debug(str(e
))
469 def _link_fill_iproute2_cmd(self
, ifacename
=None, refresh
=False):
472 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
475 # if ifacename already present, return
476 if (ifacename
and not refresh
and
477 linkCache
.get_attr([ifacename
, 'ifflag'])):
481 cmdout
= self
.link_show(ifacename
=ifacename
)
484 for c
in cmdout
.splitlines():
486 ifnamenlink
= citems
[1].split('@')
487 if len(ifnamenlink
) > 1:
488 ifname
= ifnamenlink
[0]
489 iflink
= ifnamenlink
[1].strip(':')
491 ifname
= ifnamenlink
[0].strip(':')
494 linkattrs
['link'] = iflink
495 linkattrs
['ifindex'] = citems
[0].strip(':')
496 flags
= citems
[2].strip('<>').split(',')
497 linkattrs
['flags'] = flags
498 linkattrs
['ifflag'] = 'UP' if 'UP' in flags
else 'DOWN'
499 for i
in range(0, len(citems
)):
501 if citems
[i
] == 'mtu':
502 linkattrs
['mtu'] = citems
[i
+ 1]
503 elif citems
[i
] == 'state':
504 linkattrs
['state'] = citems
[i
+ 1]
505 elif citems
[i
] == 'link/ether':
506 linkattrs
['hwaddress'] = citems
[i
+ 1]
507 elif citems
[i
] == 'vlan':
508 vlanid
= self
._get
_vland
_id
(citems
, i
, warn
)
510 linkattrs
['linkinfo'] = {'vlanid': vlanid
}
511 linkattrs
['kind'] = 'vlan'
512 elif citems
[i
] == 'dummy':
513 linkattrs
['kind'] = 'dummy'
514 elif citems
[i
] == 'vxlan' and citems
[i
+ 1] == 'id':
515 linkattrs
['kind'] = 'vxlan'
516 vattrs
= {'vxlanid': citems
[i
+ 2],
519 'ageing': citems
[i
+ 2],
521 for j
in range(i
+ 2, len(citems
)):
522 if citems
[j
] == 'local':
523 vattrs
['local'] = citems
[j
+ 1]
524 elif citems
[j
] == 'remote':
525 vattrs
['svcnode'] = citems
[j
+ 1]
526 elif citems
[j
] == 'ageing':
527 vattrs
['ageing'] = citems
[j
+ 1]
528 elif citems
[j
] == 'nolearning':
529 vattrs
['learning'] = 'off'
530 linkattrs
['linkinfo'] = vattrs
532 elif citems
[i
] == 'vrf' and citems
[i
+ 1] == 'table':
533 vattrs
= {'table': citems
[i
+ 2]}
534 linkattrs
['linkinfo'] = vattrs
535 linkattrs
['kind'] = 'vrf'
536 linkCache
.vrfs
[ifname
] = vattrs
538 elif citems
[i
] == 'veth':
539 linkattrs
['kind'] = 'veth'
540 elif citems
[i
] == 'vrf_slave':
541 linkattrs
['slave_kind'] = 'vrf_slave'
543 elif citems
[i
] == 'macvlan' and citems
[i
+ 1] == 'mode':
544 linkattrs
['kind'] = 'macvlan'
545 except Exception as e
:
547 self
.logger
.debug('%s: parsing error: id, mtu, state, '
548 'link/ether, vlan, dummy, vxlan, local, '
549 'remote, ageing, nolearning, vrf, table, '
550 'vrf_slave are reserved keywords: %s' %
553 # linkattrs['alias'] = self.read_file_oneline(
554 # '/sys/class/net/%s/ifalias' %ifname)
555 linkout
[ifname
] = linkattrs
556 [linkCache
.update_attrdict([ifname
], linkattrs
)
557 for ifname
, linkattrs
in linkout
.items()]
560 def _addr_filter(ifname
, addr
, scope
=None):
561 default_addrs
= ['127.0.0.1/8', '::1/128', '0.0.0.0']
562 if ifname
== 'lo' and addr
in default_addrs
:
564 if scope
and scope
== 'link':
568 def _addr_fill(self
, ifacename
=None, refresh
=False):
569 """ fills cache with address information
571 if ifacename argument given, fill cache for ifacename, else
572 fill cache for all interfaces in the system
574 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
577 # Check if ifacename is already full, in which case, return
578 if ifacename
and not refresh
:
579 linkCache
.get_attr([ifacename
, 'addrs'])
586 [linkCache
.update_attrdict([ifname
], linkattrs
)
587 for ifname
, linkattrs
in netlink
.addr_dump(ifname
=ifacename
).items()]
588 except Exception as e
:
589 self
.logger
.info(str(e
))
591 # this netlink call replaces the call to _addr_fill_iproute2_cmd()
592 # We shouldn't have netlink calls in the iproute2 module, this will
593 # be removed in the future. We plan to release, a flexible backend
594 # (netlink+iproute2) by default we will use netlink backend but with
595 # a CLI arg we can switch to iproute2 backend.
596 # Until we decide to create this "backend" switch capability,
597 # we have to put the netlink call inside the iproute2 module.
600 self
._addr
_fill
_iproute
2_cmd
(ifacename
, refresh
)
602 def _addr_fill_iproute2_cmd(self
, ifacename
=None, refresh
=False):
603 """ fills cache with address information
605 if ifacename argument given, fill cache for ifacename, else
606 fill cache for all interfaces in the system
609 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
612 # Check if ifacename is already full, in which case, return
613 if ifacename
and not refresh
:
614 linkCache
.get_attr([ifacename
, 'addrs'])
618 cmdout
= self
.addr_show(ifacename
=ifacename
)
621 for c
in cmdout
.splitlines():
623 ifnamenlink
= citems
[1].split('@')
624 if len(ifnamenlink
) > 1:
625 ifname
= ifnamenlink
[0]
627 ifname
= ifnamenlink
[0].strip(':')
628 if not linkout
.get(ifname
):
630 linkattrs
['addrs'] = OrderedDict({})
632 linkout
[ifname
].update(linkattrs
)
634 linkout
[ifname
] = linkattrs
635 if citems
[2] == 'inet':
636 if self
._addr
_filter
(ifname
, citems
[3], scope
=citems
[5]):
639 addrattrs
['scope'] = citems
[5]
640 addrattrs
['type'] = 'inet'
641 linkout
[ifname
]['addrs'][citems
[3]] = addrattrs
642 elif citems
[2] == 'inet6':
643 if self
._addr
_filter
(ifname
, citems
[3], scope
=citems
[5]):
645 if citems
[5] == 'link':
646 continue # skip 'link' addresses
648 addrattrs
['scope'] = citems
[5]
649 addrattrs
['type'] = 'inet6'
650 linkout
[ifname
]['addrs'][citems
[3]] = addrattrs
651 [linkCache
.update_attrdict([ifname
], linkattrs
)
652 for ifname
, linkattrs
in linkout
.items()]
654 def cache_get(self
, t
, attrlist
, refresh
=False):
655 return self
._cache
_get
(t
, attrlist
, refresh
)
657 def _cache_get(self
, t
, attrlist
, refresh
=False):
659 if ifupdownflags
.flags
.DRYRUN
:
661 if ifupdownflags
.flags
.CACHE
:
662 if self
._fill
_cache
():
663 # if we filled the cache, return new data
664 return linkCache
.get_attr(attrlist
)
666 return linkCache
.get_attr(attrlist
)
668 self
._link
_fill
(attrlist
[0], refresh
)
670 self
._addr
_fill
(attrlist
[0], refresh
)
672 self
._link
_fill
(attrlist
[0], refresh
)
673 self
._addr
_fill
(attrlist
[0], refresh
)
674 return linkCache
.get_attr(attrlist
)
676 self
.logger
.debug('_cache_get(%s) : [%s]' % (str(attrlist
), str(e
)))
679 def cache_check(self
, attrlist
, value
, refresh
=False):
680 return self
._cache
_check
('link', attrlist
, value
, refresh
=refresh
)
682 def _cache_check(self
, t
, attrlist
, value
, refresh
=False):
684 return self
._cache
_get
(t
, attrlist
, refresh
) == value
686 self
.logger
.debug('_cache_check(%s) : [%s]'
687 % (str(attrlist
), str(e
)))
690 def cache_update(self
, attrlist
, value
):
691 return self
._cache
_update
(attrlist
, value
)
694 def _cache_update(attrlist
, value
):
695 if ifupdownflags
.flags
.DRYRUN
:
698 if attrlist
[-1] == 'slaves':
699 linkCache
.append_to_attrlist(attrlist
, value
)
701 linkCache
.set_attr(attrlist
, value
)
706 def _cache_delete(attrlist
, value
=None):
707 if ifupdownflags
.flags
.DRYRUN
:
711 linkCache
.remove_from_attrlist(attrlist
, value
)
713 linkCache
.del_attr(attrlist
)
718 def _cache_invalidate():
719 linkCache
.invalidate()
720 LinkUtils
._CACHE
_FILL
_DONE
= False
724 LinkUtils
.ipbatcbuf
= ''
725 LinkUtils
.ipbatch
= True
726 LinkUtils
.ipbatch_pause
= False
729 def add_to_batch(cmd
):
730 LinkUtils
.ipbatchbuf
+= cmd
+ '\n'
734 LinkUtils
.ipbatch_pause
= True
738 LinkUtils
.ipbatch_pause
= False
740 def batch_commit(self
):
741 if not LinkUtils
.ipbatchbuf
:
742 LinkUtils
.ipbatchbuf
= ''
743 LinkUtils
.ipbatch
= False
744 LinkUtils
.ipbatch_pause
= False
747 utils
.exec_command('%s -force -batch -' % utils
.ip_cmd
,
748 stdin
=self
.ipbatchbuf
)
752 LinkUtils
.ipbatchbuf
= ''
753 LinkUtils
.ipbatch
= False
754 LinkUtils
.ipbatch_pause
= False
756 def bridge_batch_commit(self
):
757 if not LinkUtils
.ipbatchbuf
:
758 LinkUtils
.ipbatchbuf
= ''
759 LinkUtils
.ipbatch
= False
760 LinkUtils
.ipbatch_pause
= False
763 utils
.exec_command('%s -force -batch -'
764 % utils
.bridge_cmd
, stdin
=self
.ipbatchbuf
)
768 LinkUtils
.ipbatchbuf
= ''
769 LinkUtils
.ipbatch
= False
770 LinkUtils
.ipbatch_pause
= False
772 def addr_show(self
, ifacename
=None):
774 if not self
.link_exists(ifacename
):
776 return utils
.exec_commandl([utils
.ip_cmd
,
777 '-o', 'addr', 'show', 'dev', ifacename
])
779 return utils
.exec_commandl([utils
.ip_cmd
,
780 '-o', 'addr', 'show'])
783 def link_show(ifacename
=None):
785 return utils
.exec_commandl([utils
.ip_cmd
,
786 '-o', '-d', 'link', 'show', 'dev', ifacename
])
788 return utils
.exec_commandl([utils
.ip_cmd
,
789 '-o', '-d', 'link', 'show'])
791 def addr_add(self
, ifacename
, address
, broadcast
=None,
792 peer
=None, scope
=None, preferred_lifetime
=None):
795 cmd
= 'addr add %s' % address
797 cmd
+= ' broadcast %s' % broadcast
799 cmd
+= ' peer %s' % peer
801 cmd
+= ' scope %s' % scope
802 if preferred_lifetime
:
803 cmd
+= ' preferred_lft %s' % preferred_lifetime
804 cmd
+= ' dev %s' % ifacename
805 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
806 self
.add_to_batch(cmd
)
808 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
809 self
._cache
_update
([ifacename
, 'addrs', address
], {})
811 def addr_del(self
, ifacename
, address
, broadcast
=None,
812 peer
=None, scope
=None):
813 """ Delete ipv4 address """
816 if not self
._cache
_get
('addr', [ifacename
, 'addrs', address
]):
818 cmd
= 'addr del %s' % address
820 cmd
+= 'broadcast %s' % broadcast
822 cmd
+= 'peer %s' % peer
824 cmd
+= 'scope %s' % scope
825 cmd
+= ' dev %s' % ifacename
826 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
827 self
._cache
_delete
([ifacename
, 'addrs', address
])
829 def addr_flush(self
, ifacename
):
830 cmd
= 'addr flush dev %s' % ifacename
831 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
832 self
.add_to_batch(cmd
)
834 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
835 self
._cache
_delete
([ifacename
, 'addrs'])
837 def del_addr_all(self
, ifacename
, skip_addrs
=[]):
840 runningaddrsdict
= self
.get_running_addrs(ifname
=ifacename
)
842 # XXX: ignore errors. Fix this to delete secondary addresses
844 [self
.addr_del(ifacename
, a
) for a
in
845 set(runningaddrsdict
.keys()).difference(skip_addrs
)]
850 def addr_get(self
, ifacename
, details
=True, refresh
=False):
851 addrs
= self
._cache
_get
('addr', [ifacename
, 'addrs'], refresh
=refresh
)
858 def get_running_addrs(self
, ifaceobj
=None, ifname
=None, details
=True, addr_virtual_ifaceobj
=None):
860 We now support addr with link scope. Since the kernel may add it's
861 own link address to some interfaces we need to filter them out and
862 make sure we only deal with the addresses set by ifupdown2.
864 To do so we look at the previous configuration made by ifupdown2
865 (with the help of the statemanager) together with the addresses
866 specified by the user in /etc/network/interfaces, these addresses
867 are then compared to the running state of the intf (ip addr show)
868 made via a netlink addr dump.
869 For each configured addresses of scope link, we check if it was
870 previously configured by ifupdown2 to create a final set of the
871 addresses watched by ifupdown2
873 if not ifaceobj
and not ifname
:
879 interface_name
= ifaceobj
.name
881 interface_name
= ifname
883 if addr_virtual_ifaceobj
:
884 for virtual
in addr_virtual_ifaceobj
.get_attr_value('address-virtual') or []:
885 for ip
in virtual
.split():
892 saved_ifaceobjs
= statemanager
.statemanager_api
.get_ifaceobjs(addr_virtual_ifaceobj
.name
)
893 for saved_ifaceobj
in saved_ifaceobjs
or []:
894 for virtual
in saved_ifaceobj
.get_attr_value('address-virtual') or []:
895 for ip
in virtual
.split():
903 for addr
in ifaceobj
.get_attr_value('address') or []:
904 config_addrs
.add(addr
)
906 saved_ifaceobjs
= statemanager
.statemanager_api
.get_ifaceobjs(interface_name
)
907 for saved_ifaceobj
in saved_ifaceobjs
or []:
908 for addr
in saved_ifaceobj
.get_attr_value('address') or []:
909 config_addrs
.add(addr
)
911 running_addrs
= OrderedDict()
912 cached_addrs
= self
.addr_get(interface_name
)
914 for addr
, addr_details
in cached_addrs
.items():
916 scope
= int(addr_details
['scope'])
920 addr_obj
= IPNetwork(addr
)
921 if isinstance(addr_obj
, IPv6Network
):
922 d
['family'] = 'inet6'
925 running_addrs
[addr
] = d
927 running_addrs
[addr
] = {}
929 if (scope
& Route
.RT_SCOPE_LINK
and addr
in config_addrs
) or not scope
& Route
.RT_SCOPE_LINK
:
930 running_addrs
[addr
] = addr_details
936 return running_addrs
.keys()
939 def compare_user_config_vs_running_state(running_addrs
, user_addrs
):
943 for ip
in user_addrs
or []:
946 if type(obj
) == IPv6Network
:
952 for ip
in running_addrs
or []:
953 running_ipobj
.append(IPNetwork(ip
))
955 return running_ipobj
== (ip4
+ ip6
)
957 def addr_add_multiple(self
, ifaceobj
, ifacename
, addrs
, purge_existing
=False):
960 # if perfmode is not set and also if iface has no sibling
961 # objects, purge addresses that are not present in the new
963 runningaddrs
= self
.get_running_addrs(
966 addr_virtual_ifaceobj
=ifaceobj
968 addrs
= utils
.get_normalized_ip_addr(ifacename
, addrs
)
970 if self
.compare_user_config_vs_running_state(runningaddrs
, addrs
):
973 # if primary address is not same, there is no need to keep any.
974 # reset all addresses
975 if (addrs
and runningaddrs
and
976 (addrs
[0] != runningaddrs
[0])):
977 self
.del_addr_all(ifacename
)
979 self
.del_addr_all(ifacename
, addrs
)
981 self
.logger
.warning('%s: %s' % (ifacename
, str(e
)))
984 self
.addr_add(ifacename
, a
)
986 self
.logger
.error(str(e
))
988 def _link_set_ifflag(self
, ifacename
, value
):
989 # Dont look at the cache, the cache may have stale value
990 # because link status can be changed by external
991 # entity (One such entity is ifupdown main program)
992 cmd
= 'link set dev %s %s' % (ifacename
, value
.lower())
993 if LinkUtils
.ipbatch
:
994 self
.add_to_batch(cmd
)
996 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
998 def link_up(self
, ifacename
):
999 self
._link
_set
_ifflag
(ifacename
, 'UP')
1001 def link_down(self
, ifacename
):
1002 self
._link
_set
_ifflag
(ifacename
, 'DOWN')
1004 def link_set(self
, ifacename
, key
, value
=None,
1005 force
=False, t
=None, state
=None):
1007 if (key
not in ['master', 'nomaster'] and
1008 self
._cache
_check
('link', [ifacename
, key
], value
)):
1010 cmd
= 'link set dev %s' % ifacename
1012 cmd
+= ' type %s' % t
1015 cmd
+= ' %s' % value
1017 cmd
+= ' %s' % state
1018 if LinkUtils
.ipbatch
:
1019 self
.add_to_batch(cmd
)
1021 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1022 if key
not in ['master', 'nomaster']:
1023 self
._cache
_update
([ifacename
, key
], value
)
1025 def link_set_hwaddress(self
, ifacename
, hwaddress
, force
=False):
1027 if self
._cache
_check
('link', [ifacename
, 'hwaddress'], hwaddress
):
1029 self
.link_down(ifacename
)
1030 cmd
= 'link set dev %s address %s' % (ifacename
, hwaddress
)
1031 if LinkUtils
.ipbatch
:
1032 self
.add_to_batch(cmd
)
1034 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1035 self
.link_up(ifacename
)
1036 self
._cache
_update
([ifacename
, 'hwaddress'], hwaddress
)
1038 def link_set_mtu(self
, ifacename
, mtu
):
1039 if ifupdownflags
.flags
.DRYRUN
:
1041 if not mtu
or not ifacename
: return
1042 self
.write_file('/sys/class/net/%s/mtu' % ifacename
, mtu
)
1043 self
._cache
_update
([ifacename
, 'mtu'], mtu
)
1045 def link_set_alias(self
, ifacename
, alias
):
1046 self
.write_file('/sys/class/net/%s/ifalias' % ifacename
,
1047 '\n' if not alias
else alias
)
1049 def link_get_alias(self
, ifacename
):
1050 return self
.read_file_oneline('/sys/class/net/%s/ifalias'
1053 def link_isloopback(self
, ifacename
):
1054 flags
= self
._cache
_get
('link', [ifacename
, 'flags'])
1057 if 'LOOPBACK' in flags
:
1061 def link_get_status(self
, ifacename
):
1062 return self
._cache
_get
('link', [ifacename
, 'ifflag'], refresh
=True)
1065 def route_add_gateway(ifacename
, gateway
, vrf
=None, metric
=None):
1069 cmd
= '%s route add default via %s proto kernel' % (utils
.ip_cmd
,
1072 cmd
= ('%s route add table %s default via %s proto kernel' %
1073 (utils
.ip_cmd
, vrf
, gateway
))
1076 cmd
+= 'metric %s' % metric
1077 cmd
+= ' dev %s' % ifacename
1078 utils
.exec_command(cmd
)
1081 def route_del_gateway(ifacename
, gateway
, vrf
=None, metric
=None):
1086 cmd
= ('%s route del default via %s proto kernel' %
1087 (utils
.ip_cmd
, gateway
))
1089 cmd
= ('%s route del table %s default via %s proto kernel' %
1090 (utils
.ip_cmd
, vrf
, gateway
))
1092 cmd
+= ' metric %s' % metric
1093 cmd
+= ' dev %s' % ifacename
1094 utils
.exec_command(cmd
)
1097 def _get_vrf_id(ifacename
):
1099 return linkCache
.vrfs
[ifacename
]['table']
1101 dump
= netlink
.link_dump(ifacename
)
1103 [linkCache
.update_attrdict([ifname
], linkattrs
)
1104 for ifname
, linkattrs
in dump
.items()]
1106 if dump
and dump
.get(ifacename
, {}).get('kind') == 'vrf':
1107 vrf_table
= dump
.get(ifacename
, {}).get('linkinfo', {}).get('table')
1108 linkCache
.vrfs
[ifacename
] = {'table': vrf_table
}
1113 def fix_ipv6_route_metric(self
, ifaceobj
, macvlan_ifacename
, ips
):
1116 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
:
1118 for upper_iface
in ifaceobj
.upperifaces
:
1119 vrf_table
= self
._get
_vrf
_id
(upper_iface
)
1127 ip_network_obj
= IPNetwork(ip
)
1129 if type(ip_network_obj
) == IPv6Network
:
1130 route_prefix
= '%s/%d' % (ip_network_obj
.network
, ip_network_obj
.prefixlen
)
1133 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1134 LinkUtils
.add_to_batch('route del %s table %s dev %s' % (route_prefix
, vrf_table
, macvlan_ifacename
))
1136 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'del', route_prefix
, 'table', vrf_table
, 'dev', macvlan_ifacename
])
1138 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1139 LinkUtils
.add_to_batch('route del %s dev %s' % (route_prefix
, macvlan_ifacename
))
1141 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'del', route_prefix
, 'dev', macvlan_ifacename
])
1142 ip_route_del
.append((route_prefix
, vrf_table
))
1144 for ip
, vrf_table
in ip_route_del
:
1146 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1147 LinkUtils
.add_to_batch('route add %s table %s dev %s proto kernel metric 9999' % (ip
, vrf_table
, macvlan_ifacename
))
1149 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'add', ip
, 'table', vrf_table
, 'dev', macvlan_ifacename
, 'proto', 'kernel' 'metric', '9999'])
1151 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1152 LinkUtils
.add_to_batch('route add %s dev %s proto kernel metric 9999' % (ip
, macvlan_ifacename
))
1154 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'add', ip
, 'dev', macvlan_ifacename
, 'proto', 'kernel' 'metric', '9999'])
1156 def link_create_vlan(self
, vlan_device_name
, vlan_raw_device
, vlanid
):
1157 if self
.link_exists(vlan_device_name
):
1159 utils
.exec_command('%s link add link %s name %s type vlan id %d' %
1161 vlan_raw_device
, vlan_device_name
, vlanid
))
1162 self
._cache
_update
([vlan_device_name
], {})
1164 def link_create_vlan_from_name(self
, vlan_device_name
):
1165 v
= vlan_device_name
.split('.')
1167 self
.logger
.warn('invalid vlan device name %s' % vlan_device_name
)
1169 self
.link_create_vlan(vlan_device_name
, v
[0], v
[1])
1171 def link_create_macvlan(self
, name
, linkdev
, mode
='private'):
1172 if self
.link_exists(name
):
1174 cmd
= ('link add link %s' % linkdev
+
1176 ' type macvlan mode %s' % mode
)
1177 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1178 self
.add_to_batch(cmd
)
1180 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1181 self
._cache
_update
([name
], {})
1183 def get_vxlan_peers(self
, dev
, svcnodeip
):
1184 cmd
= '%s fdb show brport %s' % (utils
.bridge_cmd
,
1188 ps
= subprocess
.Popen(shlex
.split(cmd
), stdout
=subprocess
.PIPE
, close_fds
=False)
1189 utils
.enable_subprocess_signal_forwarding(ps
, signal
.SIGINT
)
1190 output
= subprocess
.check_output(('grep', '00:00:00:00:00:00'), stdin
=ps
.stdout
)
1192 utils
.disable_subprocess_signal_forwarding(signal
.SIGINT
)
1194 ppat
= re
.compile('\s+dst\s+(\d+.\d+.\d+.\d+)\s+')
1195 for l
in output
.split('\n'):
1197 if m
and m
.group(1) != svcnodeip
:
1198 cur_peers
.append(m
.group(1))
1200 self
.logger
.warn('error parsing ip link output')
1201 except subprocess
.CalledProcessError
as e
:
1202 if e
.returncode
!= 1:
1203 self
.logger
.error(str(e
))
1205 utils
.disable_subprocess_signal_forwarding(signal
.SIGINT
)
1209 def link_create_vxlan(self
, name
, vxlanid
,
1216 if svcnodeip
and remoteips
:
1217 raise Exception("svcnodeip and remoteip is mutually exclusive")
1220 args
+= ' remote %s' % svcnodeip
1222 args
+= ' ageing %s' % ageing
1223 if learning
== 'off':
1224 args
+= ' nolearning'
1226 if self
.link_exists(name
):
1227 cmd
= 'link set dev %s type vxlan dstport %d' % (name
, LinkUtils
.VXLAN_UDP_PORT
)
1228 vxlanattrs
= self
.get_vxlandev_attrs(name
)
1229 # on ifreload do not overwrite anycast_ip to individual ip if clagd
1232 running_localtunnelip
= vxlanattrs
.get('local')
1233 if anycastip
and running_localtunnelip
and anycastip
== running_localtunnelip
:
1234 localtunnelip
= running_localtunnelip
1235 running_svcnode
= vxlanattrs
.get('svcnode')
1236 if running_svcnode
and not svcnodeip
:
1239 cmd
= 'link add dev %s type vxlan id %s dstport %d' % (name
, vxlanid
, LinkUtils
.VXLAN_UDP_PORT
)
1242 args
+= ' local %s' % localtunnelip
1245 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1246 self
.add_to_batch(cmd
)
1248 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1250 # XXX: update linkinfo correctly
1251 #self._cache_update([name], {})
1254 def link_exists(ifacename
):
1255 if ifupdownflags
.flags
.DRYRUN
:
1257 return os
.path
.exists('/sys/class/net/%s' % ifacename
)
1259 def link_get_ifindex(self
, ifacename
):
1260 if ifupdownflags
.flags
.DRYRUN
:
1262 return self
.read_file_oneline('/sys/class/net/%s/ifindex' % ifacename
)
1264 def is_vlan_device_by_name(self
, ifacename
):
1265 if re
.search(r
'\.', ifacename
):
1270 def link_add_macvlan(ifname
, macvlan_ifacename
):
1271 utils
.exec_commandl(['ip', 'link', 'add', 'link', ifname
, 'name', macvlan_ifacename
, 'type', 'macvlan', 'mode', 'private'])
1274 def route_add(route
):
1275 utils
.exec_command('%s route add %s' % (utils
.ip_cmd
,
1279 def route6_add(route
):
1280 utils
.exec_command('%s -6 route add %s' % (utils
.ip_cmd
,
1283 def get_vlandev_attrs(self
, ifacename
):
1284 return (self
._cache
_get
('link', [ifacename
, 'link']),
1285 self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlanid']),
1286 self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlan_protocol']))
1288 def get_vlan_protocol(self
, ifacename
):
1289 return self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlan_protocol'])
1291 def get_vxlandev_attrs(self
, ifacename
):
1292 return self
._cache
_get
('link', [ifacename
, 'linkinfo'])
1294 def get_vxlandev_learning(self
, ifacename
):
1295 return self
._cache
_get
('link', [ifacename
, 'linkinfo', Link
.IFLA_VXLAN_LEARNING
])
1297 def set_vxlandev_learning(self
, ifacename
, learn
):
1299 utils
.exec_command('%s link set dev %s type vxlan learning' %
1300 (utils
.ip_cmd
, ifacename
))
1301 self
._cache
_update
([ifacename
, 'linkinfo', 'learning'], 'on')
1303 utils
.exec_command('%s link set dev %s type vxlan nolearning' %
1304 (utils
.ip_cmd
, ifacename
))
1305 self
._cache
_update
([ifacename
, 'linkinfo', 'learning'], 'off')
1307 def link_get_linkinfo_attrs(self
, ifacename
):
1308 return self
._cache
_get
('link', [ifacename
, 'linkinfo'])
1310 def link_get_mtu(self
, ifacename
, refresh
=False):
1311 return self
._cache
_get
('link', [ifacename
, 'mtu'], refresh
=refresh
)
1313 def link_get_mtu_sysfs(self
, ifacename
):
1314 return self
.read_file_oneline('/sys/class/net/%s/mtu'
1317 def link_get_kind(self
, ifacename
):
1318 return self
._cache
_get
('link', [ifacename
, 'kind'])
1320 def link_get_slave_kind(self
, ifacename
):
1321 return self
._cache
_get
('link', [ifacename
, 'slave_kind'])
1323 def link_get_hwaddress(self
, ifacename
):
1324 address
= self
._cache
_get
('link', [ifacename
, 'hwaddress'])
1325 # newly created logical interface addresses dont end up in the cache
1326 # read hwaddress from sysfs file for these interfaces
1328 address
= self
.read_file_oneline('/sys/class/net/%s/address'
1332 def link_create(self
, ifacename
, t
, attrs
={}):
1333 """ generic link_create function """
1334 if self
.link_exists(ifacename
):
1337 cmd
+= ' name %s type %s' % (ifacename
, t
)
1339 for k
, v
in attrs
.iteritems():
1343 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1344 self
.add_to_batch(cmd
)
1346 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1347 self
._cache
_update
([ifacename
], {})
1349 def link_delete(self
, ifacename
):
1350 if not self
.link_exists(ifacename
):
1352 cmd
= 'link del %s' % ifacename
1353 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1354 self
.add_to_batch(cmd
)
1356 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1357 self
._cache
_invalidate
()
1359 def link_get_master(self
, ifacename
):
1360 sysfs_master_path
= '/sys/class/net/%s/master' % ifacename
1361 if os
.path
.exists(sysfs_master_path
):
1362 link_path
= os
.readlink(sysfs_master_path
)
1364 return os
.path
.basename(link_path
)
1368 return self
._cache
_get
('link', [ifacename
, 'master'])
1370 def get_brport_peer_link(self
, bridgename
):
1372 return self
._cache
_get
('link', [bridgename
, 'info_slave_data', Link
.IFLA_BRPORT_PEER_LINK
])
1377 def bridge_port_vids_add(bridgeportname
, vids
):
1378 [utils
.exec_command('%s vlan add vid %s dev %s' %
1380 v
, bridgeportname
)) for v
in vids
]
1383 def bridge_port_vids_del(bridgeportname
, vids
):
1386 [utils
.exec_command('%s vlan del vid %s dev %s' %
1388 v
, bridgeportname
)) for v
in vids
]
1391 def bridge_port_vids_flush(bridgeportname
, vid
):
1392 utils
.exec_command('%s vlan del vid %s dev %s' %
1394 vid
, bridgeportname
))
1397 def bridge_port_vids_get(bridgeportname
):
1398 bridgeout
= utils
.exec_command('%s vlan show dev %s' %
1403 brvlanlines
= bridgeout
.readlines()[2:]
1404 vids
= [l
.strip() for l
in brvlanlines
]
1405 return [v
for v
in vids
if v
]
1408 def bridge_port_vids_get_all():
1410 bridgeout
= utils
.exec_command('%s -c vlan show'
1414 brvlanlines
= bridgeout
.splitlines()
1416 for l
in brvlanlines
[1:]:
1417 if l
and not l
.startswith(' ') and not l
.startswith('\t'):
1419 brportname
= attrs
[0].strip()
1420 brvlaninfo
[brportname
] = {'pvid': None, 'vlan': []}
1421 l
= ' '.join(attrs
[1:])
1422 if not brportname
or not l
:
1426 brvlaninfo
[brportname
]['pvid'] = l
.split()[0]
1427 elif 'Egress Untagged' not in l
:
1428 brvlaninfo
[brportname
]['vlan'].append(l
)
1431 def bridge_port_vids_get_all_json(self
):
1432 if not self
.supported_command
['%s -c -json vlan show'
1433 % utils
.bridge_cmd
]:
1437 bridgeout
= utils
.exec_command('%s -c -json vlan show'
1440 self
.supported_command
['%s -c -json vlan show'
1441 % utils
.bridge_cmd
] = False
1442 self
.logger
.info('%s -c -json vlan show: skipping unsupported command'
1445 return self
.get_bridge_vlan_nojson()
1446 except Exception as e
:
1447 self
.logger
.info('bridge: get_bridge_vlan_nojson: %s' % str(e
))
1450 if not bridgeout
: return brvlaninfo
1452 vlan_json_dict
= json
.loads(bridgeout
, encoding
="utf-8")
1453 except Exception, e
:
1454 self
.logger
.info('json loads failed with (%s)' % str(e
))
1456 return vlan_json_dict
1459 def get_bridge_vlan_nojson():
1461 bridgeout
= utils
.exec_commandl([utils
.bridge_cmd
, '-c', 'vlan', 'show'])
1463 output
= [line
.split('\n') for line
in bridgeout
.split('\n\n')]
1464 output
[0] = output
[0][1:]
1472 prefix
, vlan
= entry
.split('\t')
1474 current_swp
= prefix
1475 vlan_json
[prefix
] = []
1479 v
['vlan'] = int(vlan
)
1483 start
, end
= vlan
.split('-')
1485 end
= end
[0:end
.index(' ')]
1486 v
['vlan'] = int(start
)
1487 v
['vlanEnd'] = int(end
)
1489 v
['vlan'] = int(vlan
[0:vlan
.index(' ')])
1492 flags
.append('PVID')
1493 if 'Egress Untagged' in vlan
:
1494 flags
.append('Egress Untagged')
1498 vlan_json
[current_swp
].append(v
)
1501 def bridge_vlan_cache_get(self
, ifacename
, refresh
=False):
1502 if not self
.bridge_vlan_cache_fill_done
or refresh
:
1503 self
.bridge_vlan_cache
= self
.bridge_port_vids_get_all_json()
1504 self
.bridge_vlan_cache_fill_done
= True
1505 return self
.bridge_vlan_cache
.get(ifacename
, {})
1507 def bridge_vlan_get_pvid(self
, ifacename
, refresh
=False):
1510 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1511 v
= vinfo
.get('vlan')
1512 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1517 def bridge_vlan_get_vids(self
, ifacename
, refresh
=False):
1520 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1521 v
= vinfo
.get('vlan')
1522 ispvid
= True if 'PVID' in vinfo
.get('flags', []) else False
1524 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1527 vEnd
= vinfo
.get('vlanEnd')
1529 vids
.extend(range(v
, vEnd
+ 1))
1534 def bridge_vlan_get_vids_n_pvid(self
, ifacename
, refresh
=False):
1538 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1539 v
= vinfo
.get('vlan')
1540 ispvid
= True if 'PVID' in vinfo
.get('flags', []) else False
1542 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1543 vEnd
= vinfo
.get('vlanEnd')
1545 vids
.extend(range(v
, vEnd
+ 1))
1550 def bridge_port_pvid_add(self
, bridgeportname
, pvid
):
1551 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1552 self
.add_to_batch('vlan add vid %s untagged pvid dev %s' %
1553 (pvid
, bridgeportname
))
1555 utils
.exec_command('%s vlan add vid %s untagged pvid dev %s' %
1557 pvid
, bridgeportname
))
1559 def bridge_port_pvid_del(self
, bridgeportname
, pvid
):
1560 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1561 self
.add_to_batch('vlan del vid %s untagged pvid dev %s' %
1562 (pvid
, bridgeportname
))
1564 utils
.exec_command('%s vlan del vid %s untagged pvid dev %s' %
1566 pvid
, bridgeportname
))
1568 def bridge_port_pvids_get(self
, bridgeportname
):
1569 return self
.read_file_oneline('/sys/class/net/%s/brport/pvid'
1572 def bridge_vids_add(self
, bridgeportname
, vids
, bridge
=True):
1573 target
= 'self' if bridge
else ''
1574 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1575 [self
.add_to_batch('vlan add vid %s dev %s %s' %
1576 (v
, bridgeportname
, target
)) for v
in vids
]
1578 [utils
.exec_command('%s vlan add vid %s dev %s %s' %
1580 v
, bridgeportname
, target
)) for v
in vids
]
1582 def bridge_vids_del(self
, bridgeportname
, vids
, bridge
=True):
1583 target
= 'self' if bridge
else ''
1584 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1585 [self
.add_to_batch('vlan del vid %s dev %s %s' %
1586 (v
, bridgeportname
, target
)) for v
in vids
]
1588 [utils
.exec_command('%s vlan del vid %s dev %s %s' %
1590 v
, bridgeportname
, target
)) for v
in vids
]
1593 def bridge_fdb_add(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1594 target
= 'self' if bridge
else ''
1597 vlan_str
= 'vlan %s ' % vlan
1601 dst_str
= 'dst %s ' % remote
1603 utils
.exec_command('%s fdb replace %s dev %s %s %s %s' %
1605 address
, dev
, vlan_str
, target
, dst_str
))
1608 def bridge_fdb_append(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1609 target
= 'self' if bridge
else ''
1612 vlan_str
= 'vlan %s ' % vlan
1616 dst_str
= 'dst %s ' % remote
1618 utils
.exec_command('%s fdb append %s dev %s %s %s %s' %
1620 address
, dev
, vlan_str
, target
, dst_str
))
1623 def bridge_fdb_del(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1624 target
= 'self' if bridge
else ''
1627 vlan_str
= 'vlan %s ' % vlan
1631 dst_str
= 'dst %s ' % remote
1632 utils
.exec_command('%s fdb del %s dev %s %s %s %s' %
1634 address
, dev
, vlan_str
, target
, dst_str
))
1636 def bridge_is_vlan_aware(self
, bridgename
):
1637 filename
= '/sys/class/net/%s/bridge/vlan_filtering' % bridgename
1638 if os
.path
.exists(filename
) and self
.read_file_oneline(filename
) == '1':
1643 def bridge_port_get_bridge_name(bridgeport
):
1644 filename
= '/sys/class/net/%s/brport/bridge' % bridgeport
1646 return os
.path
.basename(os
.readlink(filename
))
1651 def bridge_port_exists(bridge
, bridgeportname
):
1653 return os
.path
.exists('/sys/class/net/%s/brif/%s'
1654 % (bridge
, bridgeportname
))
1658 def bridge_fdb_show_dev(self
, dev
):
1661 output
= utils
.exec_command('%s fdb show dev %s'
1662 % (utils
.bridge_cmd
, dev
))
1664 for fdb_entry
in output
.splitlines():
1666 entries
= fdb_entry
.split()
1667 fdbs
.setdefault(entries
[2], []).append(entries
[0])
1669 self
.logger
.debug('%s: invalid fdb line \'%s\''
1676 def is_bridge(bridge
):
1677 return os
.path
.exists('/sys/class/net/%s/bridge' % bridge
)
1679 def is_link_up(self
, ifacename
):
1682 flags
= self
.read_file_oneline('/sys/class/net/%s/flags' % ifacename
)
1683 iflags
= int(flags
, 16)
1690 def ip_route_get_dev(self
, prefix
, vrf_master
=None):
1693 cmd
= '%s route get %s vrf %s' % (utils
.ip_cmd
, prefix
, vrf_master
)
1695 cmd
= '%s route get %s' % (utils
.ip_cmd
, prefix
)
1697 output
= utils
.exec_command(cmd
)
1699 rline
= output
.splitlines()[0]
1701 rattrs
= rline
.split()
1702 return rattrs
[rattrs
.index('dev') + 1]
1703 except Exception, e
:
1704 self
.logger
.debug('ip_route_get_dev: failed .. %s' % str(e
))
1708 def link_get_lowers(ifacename
):
1710 lowers
= glob
.glob("/sys/class/net/%s/lower_*" % ifacename
)
1713 return [os
.path
.basename(l
)[6:] for l
in lowers
]
1718 def link_get_uppers(ifacename
):
1720 uppers
= glob
.glob("/sys/class/net/%s/upper_*" % ifacename
)
1723 return [os
.path
.basename(u
)[6:] for u
in uppers
]
1727 def link_get_vrfs(self
):
1728 if not LinkUtils
._CACHE
_FILL
_DONE
:
1730 return linkCache
.vrfs
1733 def cache_get_info_slave(attrlist
):
1735 return linkCache
.get_attr(attrlist
)
1739 def get_brport_learning(self
, ifacename
):
1740 learn
= self
.read_file_oneline('/sys/class/net/%s/brport/learning'
1742 if learn
and learn
== '1':
1747 def get_brport_learning_bool(self
, ifacename
):
1748 return utils
.get_boolean_from_string(self
.read_file_oneline('/sys/class/net/%s/brport/learning' % ifacename
))
1750 def set_brport_learning(self
, ifacename
, learn
):
1752 return self
.write_file('/sys/class/net/%s/brport/learning'
1755 return self
.write_file('/sys/class/net/%s/brport/learning'
1758 #################################################################################
1759 ################################### BOND UTILS ##################################
1760 #################################################################################
1762 def _link_cache_get(self
, attrlist
, refresh
=False):
1763 return self
._cache
_get
('link', attrlist
, refresh
)
1765 def cache_delete(self
, attrlist
, value
=None):
1766 return self
._cache
_delete
(attrlist
, value
)
1768 def link_cache_get(self
, attrlist
, refresh
=False):
1769 return self
._link
_cache
_get
(attrlist
, refresh
)
1771 def link_cache_check(self
, attrlist
, value
, refresh
=False):
1772 return self
._link
_cache
_check
(attrlist
, value
, refresh
)
1774 def _link_cache_check(self
, attrlist
, value
, refresh
=False):
1776 return self
._link
_cache
_get
(attrlist
, refresh
) == value
1777 except Exception, e
:
1778 self
.logger
.debug('_cache_check(%s) : [%s]'
1779 % (str(attrlist
), str(e
)))
1784 Link
.IFLA_BOND_MODE
: 'mode',
1785 Link
.IFLA_BOND_MIIMON
: 'miimon',
1786 Link
.IFLA_BOND_USE_CARRIER
: 'use_carrier',
1787 Link
.IFLA_BOND_AD_LACP_RATE
: 'lacp_rate',
1788 Link
.IFLA_BOND_XMIT_HASH_POLICY
: 'xmit_hash_policy',
1789 Link
.IFLA_BOND_MIN_LINKS
: 'min_links',
1790 Link
.IFLA_BOND_NUM_PEER_NOTIF
: 'num_grat_arp',
1791 Link
.IFLA_BOND_AD_ACTOR_SYSTEM
: 'ad_actor_system',
1792 Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
: 'ad_actor_sys_prio',
1793 Link
.IFLA_BOND_AD_LACP_BYPASS
: 'lacp_bypass',
1794 Link
.IFLA_BOND_UPDELAY
: 'updelay',
1795 Link
.IFLA_BOND_DOWNDELAY
: 'downdelay',
1798 def bond_set_attrs_nl(self
, bondname
, ifla_info_data
):
1799 bond_attr_name
= 'None' # for log purpose (in case an exception raised)
1800 for nl_attr
, value
in ifla_info_data
.items():
1802 bond_attr_name
= self
.bondcmd_attrmap
[nl_attr
]
1803 file_path
= '/sys/class/net/%s/bonding/%s' % (bondname
, bond_attr_name
)
1804 if os
.path
.exists(file_path
):
1805 self
.write_file(file_path
, str(value
))
1806 except Exception as e
:
1807 exception_str
= '%s: %s %s: %s' % (bondname
, bond_attr_name
, value
, str(e
))
1808 if ifupdownflags
.flags
.FORCE
:
1809 self
.logger
.warning(exception_str
)
1811 self
.logger
.debug(exception_str
)
1813 def bond_set_attrs(self
, bondname
, attrdict
, prehook
):
1814 for attrname
, attrval
in attrdict
.items():
1815 if (self
._link
_cache
_check
([bondname
, 'linkinfo',
1816 attrname
], attrval
)):
1818 if (attrname
== 'mode'
1819 or attrname
== 'xmit_hash_policy'
1820 or attrname
== 'lacp_rate' or attrname
== 'min_links'):
1824 if ((attrname
not in ['lacp_rate',
1826 self
._link
_cache
_check
([bondname
, 'linkinfo', 'mode'], '802.3ad',
1828 self
.write_file('/sys/class/net/%s/bonding/%s'
1829 % (bondname
, attrname
), attrval
)
1830 except Exception, e
:
1831 if ifupdownflags
.flags
.FORCE
:
1832 self
.logger
.warn(str(e
))
1837 def bond_set_use_carrier(self
, bondname
, use_carrier
):
1838 if not use_carrier
or (use_carrier
!= '0' and use_carrier
!= '1'):
1840 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'use_carrier'],
1843 self
.write_file('/sys/class/net/%s' % bondname
+
1844 '/bonding/use_carrier', use_carrier
)
1845 self
._cache
_update
([bondname
, 'linkinfo',
1846 'use_carrier'], use_carrier
)
1848 def bond_get_use_carrier(self
, bondname
):
1849 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'use_carrier'])
1851 def bond_get_use_carrier_nl(self
, bondname
):
1852 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_USE_CARRIER
])
1854 def bond_set_xmit_hash_policy(self
, bondname
, hash_policy
, prehook
=None):
1855 valid_values
= ['layer2', 'layer3+4', 'layer2+3']
1858 if hash_policy
not in valid_values
:
1859 raise Exception('invalid hash policy value %s' % hash_policy
)
1860 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'xmit_hash_policy'],
1865 self
.write_file('/sys/class/net/%s' % bondname
+
1866 '/bonding/xmit_hash_policy', hash_policy
)
1867 self
._cache
_update
([bondname
, 'linkinfo', 'xmit_hash_policy'],
1870 def bond_get_xmit_hash_policy(self
, bondname
):
1871 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'xmit_hash_policy'])
1873 def bond_get_xmit_hash_policy_nl(self
, bondname
):
1874 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_XMIT_HASH_POLICY
])
1876 def bond_set_miimon(self
, bondname
, miimon
):
1877 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'miimon'],
1880 self
.write_file('/sys/class/net/%s' % bondname
+
1881 '/bonding/miimon', miimon
)
1882 self
._cache
_update
([bondname
, 'linkinfo', 'miimon'], miimon
)
1884 def bond_get_miimon(self
, bondname
):
1885 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'miimon'])
1887 def bond_get_miimon_nl(self
, bondname
):
1888 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MIIMON
])
1890 def bond_set_mode(self
, bondname
, mode
, prehook
=None):
1891 valid_modes
= ['balance-rr', 'active-backup', 'balance-xor',
1892 'broadcast', '802.3ad', 'balance-tlb', 'balance-alb']
1895 if mode
not in valid_modes
:
1896 raise Exception('invalid mode %s' % mode
)
1897 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'mode'],
1902 self
.write_file('/sys/class/net/%s' % bondname
+ '/bonding/mode', mode
)
1903 self
._cache
_update
([bondname
, 'linkinfo', 'mode'], mode
)
1905 def bond_get_mode(self
, bondname
):
1906 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'mode'])
1908 def bond_get_mode_nl(self
, bondname
):
1909 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MODE
])
1911 def bond_set_lacp_rate(self
, bondname
, lacp_rate
, prehook
=None, posthook
=None):
1912 if not lacp_rate
or (lacp_rate
!= '0' and lacp_rate
!= '1'):
1914 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'lacp_rate'],
1920 self
.write_file('/sys/class/net/%s' % bondname
+
1921 '/bonding/lacp_rate', lacp_rate
)
1927 self
._cache
_update
([bondname
, 'linkinfo',
1928 'lacp_rate'], lacp_rate
)
1930 def bond_get_lacp_rate(self
, bondname
):
1931 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'lacp_rate'])
1933 def bond_get_lacp_rate_nl(self
, bondname
):
1934 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_RATE
])
1936 def bond_set_lacp_bypass_allow(self
, bondname
, allow
, prehook
=None, posthook
=None):
1937 if self
._link
_cache
_check
([bondname
, 'linkinfo', 'lacp_bypass'], allow
):
1942 self
.write_file('/sys/class/net/%s' % bondname
+
1943 '/bonding/lacp_bypass', allow
)
1949 self
._cache
_update
([bondname
, 'linkinfo',
1950 'lacp_bypass'], allow
)
1952 def bond_get_lacp_bypass_allow(self
, bondname
):
1953 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'lacp_bypass'])
1955 def bond_get_lacp_bypass_allow_nl(self
, bondname
):
1956 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_BYPASS
])
1958 def bond_set_min_links(self
, bondname
, min_links
, prehook
=None):
1959 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'min_links'],
1964 self
.write_file('/sys/class/net/%s/bonding/min_links' % bondname
,
1966 self
._cache
_update
([bondname
, 'linkinfo', 'min_links'], min_links
)
1968 def bond_get_min_links(self
, bondname
):
1969 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'min_links'])
1971 def get_min_links_nl(self
, bondname
):
1972 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MIN_LINKS
])
1974 def bond_get_ad_actor_system(self
, bondname
):
1975 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'ad_actor_system'])
1977 def bond_get_ad_actor_system_nl(self
, bondname
):
1978 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYSTEM
])
1980 def bond_get_ad_actor_sys_prio(self
, bondname
):
1981 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'ad_actor_sys_prio'])
1983 def bond_get_ad_actor_sys_prio_nl(self
, bondname
):
1984 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
])
1986 def bond_get_num_unsol_na(self
, bondname
):
1987 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'num_unsol_na'])
1989 def bond_get_num_unsol_na_nl(self
, bondname
):
1990 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
])
1992 def bond_get_num_grat_arp(self
, bondname
):
1993 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'num_grat_arp'])
1995 def bond_get_num_grat_arp_nl(self
, bondname
):
1996 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
])
1998 def bond_get_updelay(self
, bondname
):
1999 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'updelay'])
2001 def bond_get_updelay_nl(self
, bondname
):
2002 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_UPDELAY
])
2004 def bond_get_downdelay(self
, bondname
):
2005 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'downdelay'])
2007 def bond_get_downdelay_nl(self
, bondname
):
2008 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_DOWNDELAY
])
2010 def bond_enslave_slave(self
, bondname
, slave
, prehook
=None, posthook
=None):
2011 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2012 if slaves
and slave
in slaves
:
2016 self
.write_file('/sys/class/net/%s' % bondname
+
2017 '/bonding/slaves', '+' + slave
)
2020 self
._cache
_update
([bondname
, 'linkinfo', 'slaves'], slave
)
2022 def bond_remove_slave(self
, bondname
, slave
):
2023 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2024 if not slaves
or slave
not in slaves
:
2026 sysfs_bond_path
= ('/sys/class/net/%s' % bondname
+
2028 if not os
.path
.exists(sysfs_bond_path
):
2030 self
.write_file(sysfs_bond_path
, '-' + slave
)
2031 self
._cache
_delete
([bondname
, 'linkinfo', 'slaves'], slave
)
2033 def bond_remove_slaves_all(self
, bondname
):
2034 if not self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves']):
2037 sysfs_bond_path
= ('/sys/class/net/%s' % bondname
+
2040 with
open(sysfs_bond_path
, 'r') as f
:
2041 slaves
= f
.readline().strip().split()
2043 raise Exception('error reading slaves of bond %s (%s)' % (bondname
, str(e
)))
2044 for slave
in slaves
:
2045 self
.link_down(slave
)
2047 self
.bond_remove_slave(bondname
, slave
)
2048 except Exception, e
:
2049 if not ifupdownflags
.flags
.FORCE
:
2050 raise Exception('error removing slave %s from bond %s (%s)' % (slave
, bondname
, str(e
)))
2053 self
._cache
_delete
([bondname
, 'linkinfo', 'slaves'])
2056 def bond_load_bonding_module():
2057 return utils
.exec_command('%s -q bonding' % utils
.modprobe_cmd
)
2059 def create_bond(self
, bondname
):
2060 if self
.bond_exists(bondname
):
2062 # load_bonding_module() has already been run
2063 self
.write_file('/sys/class/net/bonding_masters', '+' + bondname
)
2064 self
._cache
_update
([bondname
], {})
2066 def delete_bond(self
, bondname
):
2067 if not os
.path
.exists('/sys/class/net/%s' % bondname
):
2069 self
.write_file('/sys/class/net/bonding_masters', '-' + bondname
)
2070 self
._cache
_delete
([bondname
])
2072 def bond_get_slaves(self
, bondname
):
2073 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2076 slavefile
= '/sys/class/net/%s/bonding/slaves' % bondname
2077 if os
.path
.exists(slavefile
):
2078 buf
= self
.read_file_oneline(slavefile
)
2080 slaves
= buf
.split()
2083 self
._cache
_update
([bondname
, 'linkinfo', 'slaves'], slaves
)
2086 def bond_slave_exists(self
, bond
, slave
):
2087 slaves
= self
.bond_get_slaves(bond
)
2090 return slave
in slaves
2093 def bond_exists(bondname
):
2094 return os
.path
.exists('/sys/class/net/%s/bonding' % bondname
)
2096 #################################################################################
2097 ################################## BRIDGE UTILS #################################
2098 #################################################################################
2100 def create_bridge(self
, bridgename
):
2101 if not LinkUtils
.bridge_utils_is_installed
:
2103 if self
.bridge_exists(bridgename
):
2105 utils
.exec_command('%s addbr %s' % (utils
.brctl_cmd
, bridgename
))
2106 self
._cache
_update
([bridgename
], {})
2108 def delete_bridge(self
, bridgename
):
2109 if not LinkUtils
.bridge_utils_is_installed
:
2111 if not self
.bridge_exists(bridgename
):
2113 utils
.exec_command('%s delbr %s' % (utils
.brctl_cmd
, bridgename
))
2114 self
._cache
_invalidate
()
2116 def add_bridge_port(self
, bridgename
, bridgeportname
):
2117 """ Add port to bridge """
2118 if not LinkUtils
.bridge_utils_is_installed
:
2120 ports
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports'])
2121 if ports
and ports
.get(bridgeportname
):
2123 utils
.exec_command('%s addif %s %s' % (utils
.brctl_cmd
, bridgename
, bridgeportname
))
2124 self
._cache
_update
([bridgename
, 'linkinfo', 'ports', bridgeportname
], {})
2126 def delete_bridge_port(self
, bridgename
, bridgeportname
):
2127 """ Delete port from bridge """
2128 if not LinkUtils
.bridge_utils_is_installed
:
2130 ports
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports'])
2131 if not ports
or not ports
.get(bridgeportname
):
2133 utils
.exec_command('%s delif %s %s' % (utils
.brctl_cmd
, bridgename
, bridgeportname
))
2134 self
._cache
_delete
([bridgename
, 'linkinfo', 'ports', 'bridgeportname'])
2136 def set_bridgeport_attrs(self
, bridgename
, bridgeportname
, attrdict
):
2137 portattrs
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports', bridgeportname
])
2138 if portattrs
== None:
2140 for k
, v
in attrdict
.iteritems():
2141 if ifupdownflags
.flags
.CACHE
:
2142 curval
= portattrs
.get(k
)
2143 if curval
and curval
== v
:
2145 if k
== 'unicast-flood':
2146 self
.write_file('/sys/class/net/%s/brport/unicast_flood' % bridgeportname
, v
)
2147 elif k
== 'multicast-flood':
2148 self
.write_file('/sys/class/net/%s/brport/multicast_flood' % bridgeportname
, v
)
2149 elif k
== 'learning':
2150 self
.write_file('/sys/class/net/%s/brport/learning' % bridgeportname
, v
)
2151 elif k
== 'arp-nd-suppress':
2152 self
.write_file('/sys/class/net/%s/brport/neigh_suppress' % bridgeportname
, v
)
2154 if not LinkUtils
.bridge_utils_is_installed
:
2156 utils
.exec_command('%s set%s %s %s %s' % (utils
.brctl_cmd
, k
, bridgename
, bridgeportname
, v
))
2158 def set_bridgeport_attr(self
, bridgename
, bridgeportname
,
2160 if not LinkUtils
.bridge_utils_is_installed
:
2162 if self
._link
_cache
_check
([bridgename
, 'linkinfo', 'ports', bridgeportname
, attrname
], attrval
):
2164 utils
.exec_command('%s set%s %s %s %s' %
2171 def set_bridge_attrs(self
, bridgename
, attrdict
):
2172 for k
, v
in attrdict
.iteritems():
2175 if self
._link
_cache
_check
([bridgename
, 'linkinfo', k
], v
):
2178 if k
== 'igmp-version':
2179 self
.write_file('/sys/class/net/%s/bridge/'
2180 'multicast_igmp_version' % bridgename
, v
)
2181 elif k
== 'mld-version':
2182 self
.write_file('/sys/class/net/%s/bridge/'
2183 'multicast_mld_version' % bridgename
, v
)
2184 elif k
== 'vlan-protocol':
2185 self
.write_file('/sys/class/net/%s/bridge/'
2186 'vlan_protocol' % bridgename
,
2187 VlanProtocols
.ETHERTYPES_TO_ID
.get(v
.upper(),
2189 elif k
== 'vlan-stats':
2190 self
.write_file('/sys/class/net/%s/bridge/'
2191 'vlan_stats_enabled' % bridgename
, v
)
2192 elif k
== 'mcstats':
2193 self
.write_file('/sys/class/net/%s/bridge/'
2194 'multicast_stats_enabled' % bridgename
, v
)
2196 if not LinkUtils
.bridge_utils_is_installed
:
2198 cmd
= ('%s set%s %s %s' %
2199 (utils
.brctl_cmd
, k
, bridgename
, v
))
2200 utils
.exec_command(cmd
)
2201 except Exception, e
:
2202 self
.logger
.warn('%s: %s' % (bridgename
, str(e
)))
2205 def set_bridge_attr(self
, bridgename
, attrname
, attrval
):
2206 if self
._link
_cache
_check
([bridgename
, 'linkinfo', attrname
], attrval
):
2208 if attrname
== 'igmp-version':
2209 self
.write_file('/sys/class/net/%s/bridge/multicast_igmp_version'
2210 % bridgename
, attrval
)
2211 elif attrname
== 'mld-version':
2212 self
.write_file('/sys/class/net/%s/bridge/multicast_mld_version'
2213 % bridgename
, attrval
)
2214 elif attrname
== 'vlan-protocol':
2215 self
.write_file('/sys/class/net/%s/bridge/vlan_protocol'
2216 % bridgename
, VlanProtocols
.ETHERTYPES_TO_ID
[attrval
.upper()])
2217 elif attrname
== 'vlan-stats':
2218 self
.write_file('/sys/class/net/%s/bridge/vlan_stats_enabled'
2219 % bridgename
, attrval
)
2220 elif attrname
== 'mcstats':
2221 self
.write_file('/sys/class/net/%s/bridge/multicast_stats_enabled'
2222 % bridgename
, attrval
)
2224 if not LinkUtils
.bridge_utils_is_installed
:
2226 cmd
= '%s set%s %s %s' % (utils
.brctl_cmd
,
2227 attrname
, bridgename
, attrval
)
2228 utils
.exec_command(cmd
)
2230 def get_bridge_attrs(self
, bridgename
):
2231 attrs
= self
._link
_cache
_get
([bridgename
, 'linkinfo'])
2233 for key
, value
in attrs
.items():
2234 if type(key
) == str:
2235 no_ints_attrs
[key
] = value
2236 return no_ints_attrs
2238 def get_bridgeport_attrs(self
, bridgename
, bridgeportname
):
2239 return self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports',
2242 def get_bridgeport_attr(self
, bridgename
, bridgeportname
, attrname
):
2243 return self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports',
2244 bridgeportname
, attrname
])
2247 def bridge_set_stp(bridge
, stp_state
):
2248 if not LinkUtils
.bridge_utils_is_installed
:
2250 utils
.exec_command('%s stp %s %s' % (utils
.brctl_cmd
, bridge
, stp_state
))
2252 def bridge_get_stp(self
, bridge
):
2253 sysfs_stpstate
= '/sys/class/net/%s/bridge/stp_state' % bridge
2254 if not os
.path
.exists(sysfs_stpstate
):
2256 stpstate
= self
.read_file_oneline(sysfs_stpstate
)
2260 if int(stpstate
) > 0:
2262 elif int(stpstate
) == 0:
2268 def _conv_value_to_user(s
):
2275 def read_value_from_sysfs(self
, filename
, preprocess_func
):
2276 value
= self
.read_file_oneline(filename
)
2279 return preprocess_func(value
)
2282 def bridge_set_ageing(bridge
, ageing
):
2283 if not LinkUtils
.bridge_utils_is_installed
:
2285 utils
.exec_command('%s setageing %s %s' % (utils
.brctl_cmd
, bridge
, ageing
))
2287 def bridge_get_ageing(self
, bridge
):
2288 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/ageing_time'
2289 % bridge
, self
._conv
_value
_to
_user
)
2292 def set_bridgeprio(bridge
, prio
):
2293 if not LinkUtils
.bridge_utils_is_installed
:
2295 utils
.exec_command('%s setbridgeprio %s %s' % (utils
.brctl_cmd
, bridge
, prio
))
2297 def get_bridgeprio(self
, bridge
):
2298 return self
.read_file_oneline(
2299 '/sys/class/net/%s/bridge/priority' % bridge
)
2302 def bridge_set_fd(bridge
, fd
):
2303 if not LinkUtils
.bridge_utils_is_installed
:
2305 utils
.exec_command('%s setfd %s %s' % (utils
.brctl_cmd
, bridge
, fd
))
2307 def bridge_get_fd(self
, bridge
):
2308 return self
.read_value_from_sysfs(
2309 '/sys/class/net/%s/bridge/forward_delay'
2310 % bridge
, self
._conv
_value
_to
_user
)
2312 def bridge_set_gcint(self
, bridge
, gcint
):
2313 raise Exception('set_gcint not implemented')
2316 def bridge_set_hello(bridge
, hello
):
2317 if not LinkUtils
.bridge_utils_is_installed
:
2319 utils
.exec_command('%s sethello %s %s' % (utils
.brctl_cmd
, bridge
, hello
))
2321 def bridge_get_hello(self
, bridge
):
2322 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/hello_time'
2323 % bridge
, self
._conv
_value
_to
_user
)
2326 def bridge_set_maxage(bridge
, maxage
):
2327 if not LinkUtils
.bridge_utils_is_installed
:
2329 utils
.exec_command('%s setmaxage %s %s' % (utils
.brctl_cmd
, bridge
, maxage
))
2331 def bridge_get_maxage(self
, bridge
):
2332 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/max_age'
2333 % bridge
, self
._conv
_value
_to
_user
)
2336 def bridge_set_pathcost(bridge
, port
, pathcost
):
2337 if not LinkUtils
.bridge_utils_is_installed
:
2339 utils
.exec_command('%s setpathcost %s %s %s' % (utils
.brctl_cmd
, bridge
, port
, pathcost
))
2341 def bridge_get_pathcost(self
, bridge
, port
):
2342 return self
.read_file_oneline('/sys/class/net/%s/brport/path_cost'
2346 def bridge_set_portprio(bridge
, port
, prio
):
2347 if not LinkUtils
.bridge_utils_is_installed
:
2349 utils
.exec_command('%s setportprio %s %s %s' % (utils
.brctl_cmd
, bridge
, port
, prio
))
2351 def bridge_get_portprio(self
, bridge
, port
):
2352 return self
.read_file_oneline('/sys/class/net/%s/brport/priority'
2356 def bridge_set_hashmax(bridge
, hashmax
):
2357 if not LinkUtils
.bridge_utils_is_installed
:
2359 utils
.exec_command('%s sethashmax %s %s' % (utils
.brctl_cmd
, bridge
, hashmax
))
2361 def bridge_get_hashmax(self
, bridge
):
2362 return self
.read_file_oneline('/sys/class/net/%s/bridge/hash_max'
2366 def bridge_set_hashel(bridge
, hashel
):
2367 if not LinkUtils
.bridge_utils_is_installed
:
2369 utils
.exec_command('%s sethashel %s %s' % (utils
.brctl_cmd
, bridge
, hashel
))
2371 def bridge_get_hashel(self
, bridge
):
2372 return self
.read_file_oneline('/sys/class/net/%s/bridge/hash_elasticity'
2376 def bridge_set_mclmc(bridge
, mclmc
):
2377 if not LinkUtils
.bridge_utils_is_installed
:
2379 utils
.exec_command('%s setmclmc %s %s' % (utils
.brctl_cmd
, bridge
, mclmc
))
2381 def bridge_get_mclmc(self
, bridge
):
2382 return self
.read_file_oneline(
2383 '/sys/class/net/%s/bridge/multicast_last_member_count'
2387 def bridge_set_mcrouter(bridge
, mcrouter
):
2388 if not LinkUtils
.bridge_utils_is_installed
:
2390 utils
.exec_command('%s setmcrouter %s %s' % (utils
.brctl_cmd
, bridge
, mcrouter
))
2392 def bridge_get_mcrouter(self
, bridge
):
2393 return self
.read_file_oneline(
2394 '/sys/class/net/%s/bridge/multicast_router' % bridge
)
2397 def bridge_set_mcsnoop(bridge
, mcsnoop
):
2398 if not LinkUtils
.bridge_utils_is_installed
:
2400 utils
.exec_command('%s setmcsnoop %s %s' % (utils
.brctl_cmd
, bridge
, mcsnoop
))
2402 def bridge_get_mcsnoop(self
, bridge
):
2403 return self
.read_file_oneline(
2404 '/sys/class/net/%s/bridge/multicast_snooping' % bridge
)
2407 def bridge_set_mcsqc(bridge
, mcsqc
):
2408 if not LinkUtils
.bridge_utils_is_installed
:
2410 utils
.exec_command('%s setmcsqc %s %s' % (utils
.brctl_cmd
, bridge
, mcsqc
))
2412 def bridge_get_mcsqc(self
, bridge
):
2413 return self
.read_file_oneline(
2414 '/sys/class/net/%s/bridge/multicast_startup_query_count'
2418 def bridge_set_mcqifaddr(bridge
, mcqifaddr
):
2419 if not LinkUtils
.bridge_utils_is_installed
:
2421 utils
.exec_command('%s setmcqifaddr %s %s' % (utils
.brctl_cmd
, bridge
, mcqifaddr
))
2423 def bridge_get_mcqifaddr(self
, bridge
):
2424 return self
.read_file_oneline(
2425 '/sys/class/net/%s/bridge/multicast_startup_query_use_ifaddr'
2429 def bridge_set_mcquerier(bridge
, mcquerier
):
2430 if not LinkUtils
.bridge_utils_is_installed
:
2432 utils
.exec_command('%s setmcquerier %s %s' % (utils
.brctl_cmd
, bridge
, mcquerier
))
2434 def bridge_get_mcquerier(self
, bridge
):
2435 return self
.read_file_oneline(
2436 '/sys/class/net/%s/bridge/multicast_querier' % bridge
)
2438 def bridge_set_mcqv4src(self
, bridge
, vlan
, mcquerier
):
2442 self
.logger
.info('%s: set mcqv4src vlan: invalid parameter %s: %s' %(bridge
, vlan
, str(e
)))
2444 if vlan
== 0 or vlan
> 4095:
2445 self
.logger
.warn('mcqv4src vlan \'%d\' invalid range' % vlan
)
2448 ip
= mcquerier
.split('.')
2450 self
.logger
.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier
)
2453 if not k
.isdigit() or int(k
, 10) < 0 or int(k
, 10) > 255:
2454 self
.logger
.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier
)
2457 if not LinkUtils
.bridge_utils_is_installed
:
2460 utils
.exec_command('%s setmcqv4src %s %d %s' %
2461 (utils
.brctl_cmd
, bridge
, vlan
, mcquerier
))
2463 def bridge_del_mcqv4src(self
, bridge
, vlan
):
2464 if not LinkUtils
.bridge_utils_is_installed
:
2469 self
.logger
.info('%s: del mcqv4src vlan: invalid parameter %s: %s' %(bridge
, vlan
, str(e
)))
2471 utils
.exec_command('%s delmcqv4src %s %d' % (utils
.brctl_cmd
, bridge
, vlan
))
2473 def bridge_get_mcqv4src(self
, bridge
, vlan
=None):
2474 if not LinkUtils
.bridge_utils_is_installed
:
2476 if not self
.supported_command
['showmcqv4src']:
2480 mcqout
= utils
.exec_command('%s showmcqv4src %s' %
2481 (utils
.brctl_cmd
, bridge
))
2482 except Exception as e
:
2484 if 'never heard' in s
:
2485 msg
= ('%s showmcqv4src: skipping unsupported command'
2487 self
.logger
.info(msg
)
2488 self
.supported_command
['showmcqv4src'] = False
2493 mcqlines
= mcqout
.splitlines()
2494 for l
in mcqlines
[1:]:
2496 k
, d
, v
= l
.split('\t')
2501 return mcqv4src
.get(vlan
)
2505 def bridge_set_mclmi(bridge
, mclmi
):
2506 if not LinkUtils
.bridge_utils_is_installed
:
2508 utils
.exec_command('%s setmclmi %s %s' % (utils
.brctl_cmd
, bridge
, mclmi
))
2510 def bridge_get_mclmi(self
, bridge
):
2511 return self
.read_file_oneline(
2512 '/sys/class/net/%s/bridge/multicast_last_member_interval'
2516 def bridge_set_mcmi(bridge
, mcmi
):
2517 if not LinkUtils
.bridge_utils_is_installed
:
2519 utils
.exec_command('%s setmcmi %s %s' % (utils
.brctl_cmd
, bridge
, mcmi
))
2521 def bridge_get_mcmi(self
, bridge
):
2522 return self
.read_file_oneline(
2523 '/sys/class/net/%s/bridge/multicast_membership_interval'
2527 def bridge_exists(bridge
):
2528 return os
.path
.exists('/sys/class/net/%s/bridge' % bridge
)
2531 def is_bridge_port(ifacename
):
2532 return os
.path
.exists('/sys/class/net/%s/brport' % ifacename
)
2535 def bridge_port_exists(bridge
, bridgeportname
):
2537 return os
.path
.exists('/sys/class/net/%s/brif/%s' % (bridge
, bridgeportname
))
2542 def get_bridge_ports(bridgename
):
2544 return os
.listdir('/sys/class/net/%s/brif/' % bridgename
)