3 # Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
5 # Julien Fortin, julien@cumulusnetworks.com
16 from ipaddr
import IPNetwork
, IPv6Network
19 import ifupdown2
.ifupdown
.statemanager
as statemanager
20 import ifupdown2
.ifupdown
.ifupdownflags
as ifupdownflags
22 from ifupdown2
.nlmanager
.nlmanager
import Link
, Route
24 from ifupdown2
.ifupdown
.iface
import *
25 from ifupdown2
.ifupdown
.utils
import utils
26 from ifupdown2
.ifupdown
.netlink
import netlink
28 from ifupdown2
.ifupdownaddons
.utilsbase
import utilsBase
29 from ifupdown2
.ifupdownaddons
.cache
import linkCache
, MSTPAttrsCache
31 import ifupdown
.ifupdownflags
as ifupdownflags
32 import ifupdown
.statemanager
as statemanager
34 from nlmanager
.nlmanager
import Link
, Route
36 from ifupdown
.iface
import *
37 from ifupdown
.utils
import utils
38 from ifupdown
.netlink
import netlink
40 from ifupdownaddons
.utilsbase
import utilsBase
41 from ifupdownaddons
.cache
import linkCache
, MSTPAttrsCache
44 class LinkUtils(utilsBase
):
46 This class contains helper methods to cache and manipulate interfaces through
47 non-netlink APIs (sysfs, iproute2, brctl...)
49 _CACHE_FILL_DONE
= False
56 bridge_utils_is_installed
= os
.path
.exists(utils
.brctl_cmd
)
57 bridge_utils_missing_warning
= True
59 DEFAULT_IP_METRIC
= 1024
60 ADDR_METRIC_SUPPORT
= None
62 def __init__(self
, *args
, **kargs
):
63 utilsBase
.__init
__(self
, *args
, **kargs
)
65 self
.supported_command
= {
66 '%s -c -json vlan show' % utils
.bridge_cmd
: True,
69 self
.bridge_vlan_cache
= {}
70 self
.bridge_vlan_cache_fill_done
= False
72 if not ifupdownflags
.flags
.PERFMODE
and not LinkUtils
._CACHE
_FILL
_DONE
:
75 if LinkUtils
.ADDR_METRIC_SUPPORT
is None:
77 cmd
= [utils
.ip_cmd
, 'addr', 'help']
78 self
.logger
.info('executing %s addr help' % utils
.ip_cmd
)
80 process
= subprocess
.Popen(cmd
, stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
)
81 stdout
, stderr
= process
.communicate()
82 LinkUtils
.ADDR_METRIC_SUPPORT
= '[ metric METRIC ]' in stderr
or ''
83 self
.logger
.info('address metric support: %s' % ('OK' if LinkUtils
.ADDR_METRIC_SUPPORT
else 'KO'))
85 LinkUtils
.ADDR_METRIC_SUPPORT
= False
86 self
.logger
.info('address metric support: KO')
89 def addr_metric_support(cls
):
90 return cls
.ADDR_METRIC_SUPPORT
93 def get_default_ip_metric(cls
):
94 return cls
.DEFAULT_IP_METRIC
98 LinkUtils
._CACHE
_FILL
_DONE
= False
99 LinkUtils
.ipbatchbuf
= ''
100 LinkUtils
.ipbatch
= False
101 LinkUtils
.ipbatch_pause
= False
103 def _fill_cache(self
):
104 if not LinkUtils
._CACHE
_FILL
_DONE
:
107 LinkUtils
._CACHE
_FILL
_DONE
= True
112 def _get_vland_id(citems
, i
, warn
):
115 index
= sub
.index('id')
117 return sub
[index
+ 1]
120 raise Exception('invalid use of \'vlan\' keyword')
123 def _link_fill(self
, ifacename
=None, refresh
=False):
124 """ fills cache with link information
126 if ifacename argument given, fill cache for ifacename, else
127 fill cache for all interfaces in the system
130 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
133 # if ifacename already present, return
134 if (ifacename
and not refresh
and
135 linkCache
.get_attr([ifacename
, 'ifflag'])):
142 [linkCache
.update_attrdict([ifname
], linkattrs
)
143 for ifname
, linkattrs
in netlink
.link_dump(ifacename
).items()]
144 except Exception as e
:
145 self
.logger
.info('%s' % str(e
))
146 # this netlink call replaces the call to _link_fill_iproute2_cmd()
147 # We shouldn't have netlink calls in the iproute2 module, this will
148 # be removed in the future. We plan to release, a flexible backend
149 # (netlink+iproute2) by default we will use netlink backend but with
150 # a CLI arg we can switch to iproute2 backend.
151 # Until we decide to create this "backend" switch capability,
152 # we have to put the netlink call inside the iproute2 module.
154 self
._link
_fill
_iproute
2_cmd
(ifacename
, refresh
)
156 self
._fill
_bond
_info
(ifacename
)
157 self
._fill
_bridge
_info
(ifacename
)
159 def _fill_bridge_info(self
, ifacename
):
165 cache_dict
= {ifacename
: linkCache
.links
.get(ifacename
, {})}
167 cache_dict
= linkCache
.links
169 for ifname
, obj
in cache_dict
.items():
170 slave_kind
= obj
.get('slave_kind')
171 if not slave_kind
and slave_kind
!= 'bridge':
174 info_slave_data
= obj
.get('info_slave_data')
175 if not info_slave_data
:
178 ifla_master
= obj
.get('master')
180 raise Exception('No master associated with bridge port %s' % ifname
)
183 Link
.IFLA_BRPORT_STATE
,
184 Link
.IFLA_BRPORT_COST
,
185 Link
.IFLA_BRPORT_PRIORITY
,
187 if nl_attr
not in info_slave_data
and LinkUtils
.bridge_utils_is_installed
:
188 self
._fill
_bridge
_info
_brctl
()
192 'pathcost': str(info_slave_data
.get(Link
.IFLA_BRPORT_COST
, 0)),
193 'fdelay': format(float(info_slave_data
.get(Link
.IFLA_BRPORT_FORWARD_DELAY_TIMER
, 0) / 100), '.2f'),
194 'portmcrouter': str(info_slave_data
.get(Link
.IFLA_BRPORT_MULTICAST_ROUTER
, 0)),
195 'portmcfl': str(info_slave_data
.get(Link
.IFLA_BRPORT_FAST_LEAVE
, 0)),
196 'portprio': str(info_slave_data
.get(Link
.IFLA_BRPORT_PRIORITY
, 0)),
197 'unicast-flood': str(info_slave_data
.get(Link
.IFLA_BRPORT_UNICAST_FLOOD
, 0)),
198 'multicast-flood': str(info_slave_data
.get(Link
.IFLA_BRPORT_MCAST_FLOOD
, 0)),
199 'learning': str(info_slave_data
.get(Link
.IFLA_BRPORT_LEARNING
, 0)),
200 'arp-nd-suppress': str(info_slave_data
.get(Link
.IFLA_BRPORT_ARP_SUPPRESS
, 0))
203 if ifla_master
in brports
:
204 brports
[ifla_master
][ifname
] = brport_attrs
206 brports
[ifla_master
] = {ifname
: brport_attrs
}
208 linkCache
.update_attrdict([ifla_master
, 'linkinfo', 'ports'], brports
[ifla_master
])
210 if LinkUtils
.bridge_utils_is_installed
:
211 self
._fill
_bridge
_info
_brctl
()
213 def _fill_bridge_info_brctl(self
):
214 brctlout
= utils
.exec_command('%s show' % utils
.brctl_cmd
)
218 for bline
in brctlout
.splitlines()[1:]:
219 bitems
= bline
.split()
223 linkCache
.update_attrdict([bitems
[0], 'linkinfo'],
226 linkCache
.update_attrdict([bitems
[0]],
227 {'linkinfo': {'stp': bitems
[2]}})
228 self
._bridge
_attrs
_fill
(bitems
[0])
230 def _bridge_attrs_fill(self
, bridgename
):
235 # Get all bridge attributes
236 # battrs['pathcost'] = broutlines[3].split('path cost')[1].strip()
239 battrs
['maxage'] = self
.read_file_oneline(
240 '/sys/class/net/%s/bridge/max_age' % bridgename
)
246 battrs
['hello'] = self
.read_file_oneline(
247 '/sys/class/net/%s/bridge/hello_time' % bridgename
)
252 battrs
['fd'] = self
.read_file_oneline(
253 '/sys/class/net/%s/bridge/forward_delay' % bridgename
)
258 battrs
['ageing'] = self
.read_file_oneline(
259 '/sys/class/net/%s/bridge/ageing_time' % bridgename
)
264 battrs
['mcrouter'] = self
.read_file_oneline(
265 '/sys/class/net/%s/bridge/multicast_router' % bridgename
)
270 battrs
['bridgeprio'] = self
.read_file_oneline(
271 '/sys/class/net/%s/bridge/priority' % bridgename
)
276 battrs
['vlan-protocol'] = VlanProtocols
.ID_TO_ETHERTYPES
[
277 self
.read_file_oneline(
278 '/sys/class/net/%s/bridge/vlan_protocol' % bridgename
)]
283 battrs
.update(self
._bridge
_get
_mcattrs
_from
_sysfs
(bridgename
))
287 # XXX: comment this out until mc attributes become available
290 # battrs['mciqc'] = broutlines[11].split('mc init query count')[1].strip()
291 # battrs['mclmt'] = broutlines[13].split('mc last member timer')[1].split()[0].strip()
293 self
.logger
.warn('%s: error while processing bridge attributes: %s' % (bridgename
, str(e
)))
296 linkCache
.update_attrdict([bridgename
, 'linkinfo'], battrs
)
298 names
= [os
.path
.basename(x
) for x
in glob
.glob("/sys/class/net/%s/brif/*" % bridgename
)]
303 bportattrs
['pathcost'] = self
.read_file_oneline(
304 '/sys/class/net/%s/brport/path_cost' % pname
)
305 bportattrs
['fdelay'] = self
.read_file_oneline(
306 '/sys/class/net/%s/brport/forward_delay_timer' % pname
)
307 bportattrs
['portmcrouter'] = self
.read_file_oneline(
308 '/sys/class/net/%s/brport/multicast_router' % pname
)
309 bportattrs
['portmcfl'] = self
.read_file_oneline(
310 '/sys/class/net/%s/brport/multicast_fast_leave' % pname
)
311 bportattrs
['portprio'] = self
.read_file_oneline(
312 '/sys/class/net/%s/brport/priority' % pname
)
313 bportattrs
['unicast-flood'] = self
.read_file_oneline(
314 '/sys/class/net/%s/brport/unicast_flood' % pname
)
315 bportattrs
['multicast-flood'] = self
.read_file_oneline(
316 '/sys/class/net/%s/brport/multicast_flood' % pname
)
317 bportattrs
['learning'] = self
.read_file_oneline(
318 '/sys/class/net/%s/brport/learning' % pname
)
319 bportattrs
['arp-nd-suppress'] = self
.read_file_oneline(
320 '/sys/class/net/%s/brport/neigh_suppress' % pname
)
322 #bportattrs['mcrouters'] = self.read_file_oneline(
323 # '/sys/class/net/%s/brport/multicast_router' % pname)
324 #bportattrs['mc fast leave'] = self.read_file_oneline(
325 # '/sys/class/net/%s/brport/multicast_fast_leave' % pname)
328 self
.logger
.warn('%s: error while processing bridge attributes: %s' % (bridgename
, str(e
)))
329 bports
[pname
] = bportattrs
330 linkCache
.update_attrdict([bridgename
, 'linkinfo', 'ports'], bports
)
332 _bridge_sysfs_mcattrs
= {
333 'mclmc': 'multicast_last_member_count',
334 'mcrouter': 'multicast_router',
335 'mcsnoop': 'multicast_snooping',
336 'mcsqc': 'multicast_startup_query_count',
337 'mcqifaddr': 'multicast_query_use_ifaddr',
338 'mcquerier': 'multicast_querier',
339 'hashel': 'hash_elasticity',
340 'hashmax': 'hash_max',
341 'mclmi': 'multicast_last_member_interval',
342 'mcmi': 'multicast_membership_interval',
343 'mcqpi': 'multicast_querier_interval',
344 'mcqi': 'multicast_query_interval',
345 'mcqri': 'multicast_query_response_interval',
346 'mcsqi': 'multicast_startup_query_interval',
347 'igmp-version': 'multicast_igmp_version',
348 'mld-version': 'multicast_mld_version',
349 'vlan-stats': 'vlan_stats_enabled',
350 'mcstats': 'multicast_stats_enabled',
353 def _bridge_get_mcattrs_from_sysfs(self
, bridgename
):
354 mcattrsdivby100
= ['mclmi', 'mcmi', 'mcqpi', 'mcqi', 'mcqri', 'mcsqi']
357 for m
, s
in self
._bridge
_sysfs
_mcattrs
.items():
358 n
= self
.read_file_oneline('/sys/class/net/%s/bridge/%s' % (bridgename
, s
))
359 if m
in mcattrsdivby100
:
364 self
.logger
.warn('error getting mc attr %s (%s)' % (m
, str(e
)))
370 def _fill_bond_info(self
, ifacename
):
371 bonding_masters
= self
.read_file_oneline('/sys/class/net/bonding_masters')
372 if not bonding_masters
:
375 bond_masters_list
= bonding_masters
.split()
378 if ifacename
in bond_masters_list
:
379 bond_masters_list
= [ifacename
]
381 # we want to refresh this interface only if it's a bond master
384 for bondname
in bond_masters_list
:
386 if bondname
not in linkCache
.links
:
387 linkCache
.set_attr([bondname
], {'linkinfo': {}})
388 linkCache
.set_attr([bondname
, 'linkinfo', 'slaves'],
389 self
.read_file_oneline('/sys/class/net/%s/bonding/slaves'
392 # if some attribute are missing we try to get the bond attributes via sysfs
393 bond_linkinfo
= linkCache
.links
[bondname
]['linkinfo']
394 for attr
in [Link
.IFLA_BOND_MODE
, Link
.IFLA_BOND_XMIT_HASH_POLICY
, Link
.IFLA_BOND_MIN_LINKS
]:
395 if attr
not in bond_linkinfo
:
396 self
._fill
_bond
_info
_sysfs
(bondname
)
397 # after we fill in the cache we can continue to the next bond
400 self
._fill
_bond
_info
_sysfs
(bondname
)
402 except Exception as e
:
403 self
.logger
.debug('LinkUtils: bond cache error: %s' % str(e
))
405 def _fill_bond_info_sysfs(self
, bondname
):
407 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_MIN_LINKS
],
408 self
.read_file_oneline(
409 '/sys/class/net/%s/bonding/min_links'
411 except Exception as e
:
412 self
.logger
.debug(str(e
))
415 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_MODE
],
416 self
.read_file_oneline('/sys/class/net/%s/bonding/mode'
417 % bondname
).split()[0])
418 except Exception as e
:
419 self
.logger
.debug(str(e
))
421 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_XMIT_HASH_POLICY
],
422 self
.read_file_oneline(
423 '/sys/class/net/%s/bonding/xmit_hash_policy'
424 % bondname
).split()[0])
425 except Exception as e
:
426 self
.logger
.debug(str(e
))
428 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_RATE
],
429 self
.read_file_oneline('/sys/class/net/%s/bonding/lacp_rate'
430 % bondname
).split()[1])
431 except Exception as e
:
432 self
.logger
.debug(str(e
))
434 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
],
435 self
.read_file_oneline('/sys/class/net/%s/bonding/ad_actor_sys_prio'
437 except Exception as e
:
438 self
.logger
.debug(str(e
))
440 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYSTEM
],
441 self
.read_file_oneline('/sys/class/net/%s/bonding/ad_actor_system'
443 except Exception as e
:
444 self
.logger
.debug(str(e
))
446 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_BYPASS
],
447 self
.read_file_oneline('/sys/class/net/%s/bonding/lacp_bypass'
448 % bondname
).split()[1])
449 except Exception as e
:
450 self
.logger
.debug(str(e
))
452 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_UPDELAY
],
453 self
.read_file_oneline('/sys/class/net/%s/bonding/updelay'
455 except Exception as e
:
456 self
.logger
.debug(str(e
))
458 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_DOWNDELAY
],
459 self
.read_file_oneline('/sys/class/net/%s/bonding/downdelay'
461 except Exception as e
:
462 self
.logger
.debug(str(e
))
465 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_USE_CARRIER
],
466 self
.read_file_oneline('/sys/class/net/%s/bonding/use_carrier' % bondname
))
467 except Exception as e
:
468 self
.logger
.debug(str(e
))
471 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_MIIMON
],
472 self
.read_file_oneline('/sys/class/net/%s/bonding/miimon' % bondname
))
473 except Exception as e
:
474 self
.logger
.debug(str(e
))
477 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
],
478 self
.read_file_oneline('/sys/class/net/%s/bonding/num_unsol_na' % bondname
))
479 except Exception as e
:
480 self
.logger
.debug(str(e
))
483 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
],
484 self
.read_file_oneline('/sys/class/net/%s/bonding/num_grat_arp' % bondname
))
485 except Exception as e
:
486 self
.logger
.debug(str(e
))
489 def _link_fill_iproute2_cmd(self
, ifacename
=None, refresh
=False):
492 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
495 # if ifacename already present, return
496 if (ifacename
and not refresh
and
497 linkCache
.get_attr([ifacename
, 'ifflag'])):
501 cmdout
= self
.link_show(ifacename
=ifacename
)
504 for c
in cmdout
.splitlines():
506 ifnamenlink
= citems
[1].split('@')
507 if len(ifnamenlink
) > 1:
508 ifname
= ifnamenlink
[0]
509 iflink
= ifnamenlink
[1].strip(':')
511 ifname
= ifnamenlink
[0].strip(':')
514 linkattrs
['link'] = iflink
515 linkattrs
['ifindex'] = citems
[0].strip(':')
516 flags
= citems
[2].strip('<>').split(',')
517 linkattrs
['flags'] = flags
518 linkattrs
['ifflag'] = 'UP' if 'UP' in flags
else 'DOWN'
519 for i
in range(0, len(citems
)):
521 if citems
[i
] == 'mtu':
522 linkattrs
['mtu'] = citems
[i
+ 1]
523 elif citems
[i
] == 'state':
524 linkattrs
['state'] = citems
[i
+ 1]
525 elif citems
[i
] == 'link/ether':
526 linkattrs
['hwaddress'] = citems
[i
+ 1]
527 elif citems
[i
] in ['link/gre', 'link/ipip', 'link/sit', 'link/gre6', 'link/tunnel6', 'gretap']:
528 linkattrs
['kind'] = 'tunnel'
529 tunattrs
= {'mode': citems
[i
].split('/')[-1],
534 for j
in range(i
, len(citems
)):
535 if citems
[j
] == 'local':
536 tunattrs
['local'] = citems
[j
+ 1]
537 elif citems
[j
] == 'remote':
538 tunattrs
['endpoint'] = citems
[j
+ 1]
539 elif citems
[j
] == 'ttl':
540 tunattrs
['ttl'] = citems
[j
+ 1]
541 elif citems
[j
] == 'dev':
542 tunattrs
['physdev'] = citems
[j
+ 1]
543 elif citems
[j
] in ['vti', 'vti6', 'ip6gre', 'ipip6', 'ip6ip6']:
544 tunattrs
['mode'] = citems
[j
]
545 linkattrs
['linkinfo'] = tunattrs
547 elif citems
[i
] == 'link/ppp':
548 linkattrs
['kind'] = 'ppp'
549 elif citems
[i
] == 'vlan':
550 vlanid
= self
._get
_vland
_id
(citems
, i
, warn
)
552 linkattrs
['linkinfo'] = {'vlanid': vlanid
}
553 linkattrs
['kind'] = 'vlan'
554 elif citems
[i
] == 'dummy':
555 linkattrs
['kind'] = 'dummy'
556 elif citems
[i
] == 'vxlan' and citems
[i
+ 1] == 'id':
557 linkattrs
['kind'] = 'vxlan'
558 vattrs
= {'vxlanid': citems
[i
+ 2],
561 'ageing': citems
[i
+ 2],
563 for j
in range(i
+ 2, len(citems
)):
564 if citems
[j
] == 'local':
565 vattrs
['local'] = citems
[j
+ 1]
566 elif citems
[j
] == 'remote':
567 vattrs
['svcnode'] = citems
[j
+ 1]
568 elif citems
[j
] == 'ageing':
569 vattrs
['ageing'] = citems
[j
+ 1]
570 elif citems
[j
] == 'nolearning':
571 vattrs
['learning'] = 'off'
572 elif citems
[j
] == 'dev':
573 vattrs
['physdev'] = citems
[j
+ 1]
574 linkattrs
['linkinfo'] = vattrs
576 elif citems
[i
] == 'vrf' and citems
[i
+ 1] == 'table':
577 vattrs
= {'table': citems
[i
+ 2]}
578 linkattrs
['linkinfo'] = vattrs
579 linkattrs
['kind'] = 'vrf'
580 linkCache
.vrfs
[ifname
] = vattrs
582 elif citems
[i
] == 'veth':
583 linkattrs
['kind'] = 'veth'
584 elif citems
[i
] == 'vrf_slave':
585 linkattrs
['slave_kind'] = 'vrf_slave'
587 elif citems
[i
] == 'macvlan' and citems
[i
+ 1] == 'mode':
588 linkattrs
['kind'] = 'macvlan'
589 except Exception as e
:
591 self
.logger
.debug('%s: parsing error: id, mtu, state, '
592 'link/ether, vlan, dummy, vxlan, local, '
593 'remote, ageing, nolearning, vrf, table, '
594 'vrf_slave are reserved keywords: %s' %
597 # linkattrs['alias'] = self.read_file_oneline(
598 # '/sys/class/net/%s/ifalias' %ifname)
599 linkout
[ifname
] = linkattrs
600 [linkCache
.update_attrdict([ifname
], linkattrs
)
601 for ifname
, linkattrs
in linkout
.items()]
604 def _addr_filter(ifname
, addr
, scope
=None):
605 default_addrs
= ['127.0.0.1/8', '::1/128', '0.0.0.0']
606 if ifname
== 'lo' and addr
in default_addrs
:
608 if scope
and scope
== 'link':
612 def _addr_fill(self
, ifacename
=None, refresh
=False):
613 """ fills cache with address information
615 if ifacename argument given, fill cache for ifacename, else
616 fill cache for all interfaces in the system
618 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
621 # Check if ifacename is already full, in which case, return
622 if ifacename
and not refresh
:
623 linkCache
.get_attr([ifacename
, 'addrs'])
630 [linkCache
.update_attrdict([ifname
], linkattrs
)
631 for ifname
, linkattrs
in netlink
.addr_dump(ifname
=ifacename
).items()]
632 except Exception as e
:
633 self
.logger
.info(str(e
))
635 # this netlink call replaces the call to _addr_fill_iproute2_cmd()
636 # We shouldn't have netlink calls in the iproute2 module, this will
637 # be removed in the future. We plan to release, a flexible backend
638 # (netlink+iproute2) by default we will use netlink backend but with
639 # a CLI arg we can switch to iproute2 backend.
640 # Until we decide to create this "backend" switch capability,
641 # we have to put the netlink call inside the iproute2 module.
644 self
._addr
_fill
_iproute
2_cmd
(ifacename
, refresh
)
646 def _addr_fill_iproute2_cmd(self
, ifacename
=None, refresh
=False):
647 """ fills cache with address information
649 if ifacename argument given, fill cache for ifacename, else
650 fill cache for all interfaces in the system
653 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
656 # Check if ifacename is already full, in which case, return
657 if ifacename
and not refresh
:
658 linkCache
.get_attr([ifacename
, 'addrs'])
662 cmdout
= self
.addr_show(ifacename
=ifacename
)
665 for c
in cmdout
.splitlines():
667 ifnamenlink
= citems
[1].split('@')
668 if len(ifnamenlink
) > 1:
669 ifname
= ifnamenlink
[0]
671 ifname
= ifnamenlink
[0].strip(':')
672 if not linkout
.get(ifname
):
674 linkattrs
['addrs'] = OrderedDict({})
676 linkout
[ifname
].update(linkattrs
)
678 linkout
[ifname
] = linkattrs
679 if citems
[2] == 'inet':
680 if self
._addr
_filter
(ifname
, citems
[3], scope
=citems
[5]):
683 addrattrs
['scope'] = citems
[5]
684 addrattrs
['type'] = 'inet'
685 linkout
[ifname
]['addrs'][citems
[3]] = addrattrs
686 elif citems
[2] == 'inet6':
687 if self
._addr
_filter
(ifname
, citems
[3], scope
=citems
[5]):
689 if citems
[5] == 'link':
690 continue # skip 'link' addresses
692 addrattrs
['scope'] = citems
[5]
693 addrattrs
['type'] = 'inet6'
694 linkout
[ifname
]['addrs'][citems
[3]] = addrattrs
695 [linkCache
.update_attrdict([ifname
], linkattrs
)
696 for ifname
, linkattrs
in linkout
.items()]
698 def del_cache_entry(self
, ifname
):
700 del linkCache
.links
[ifname
]
704 def cache_get(self
, t
, attrlist
, refresh
=False):
705 return self
._cache
_get
(t
, attrlist
, refresh
)
707 def _cache_get(self
, t
, attrlist
, refresh
=False):
709 if ifupdownflags
.flags
.DRYRUN
:
711 if ifupdownflags
.flags
.CACHE
:
712 if self
._fill
_cache
():
713 # if we filled the cache, return new data
714 return linkCache
.get_attr(attrlist
)
716 return linkCache
.get_attr(attrlist
)
718 self
._link
_fill
(attrlist
[0], refresh
)
720 self
._addr
_fill
(attrlist
[0], refresh
)
722 self
._link
_fill
(attrlist
[0], refresh
)
723 self
._addr
_fill
(attrlist
[0], refresh
)
724 return linkCache
.get_attr(attrlist
)
726 self
.logger
.debug('_cache_get(%s) : [%s]' % (str(attrlist
), str(e
)))
729 def cache_check(self
, attrlist
, value
, refresh
=False):
730 return self
._cache
_check
('link', attrlist
, value
, refresh
=refresh
)
732 def _cache_check(self
, t
, attrlist
, value
, refresh
=False):
734 return self
._cache
_get
(t
, attrlist
, refresh
) == value
736 self
.logger
.debug('_cache_check(%s) : [%s]'
737 % (str(attrlist
), str(e
)))
740 def cache_update(self
, attrlist
, value
):
741 return self
._cache
_update
(attrlist
, value
)
744 def _cache_update(attrlist
, value
):
745 if ifupdownflags
.flags
.DRYRUN
:
748 if attrlist
[-1] == 'slaves':
749 linkCache
.append_to_attrlist(attrlist
, value
)
751 linkCache
.set_attr(attrlist
, value
)
756 def _cache_delete(attrlist
, value
=None):
757 if ifupdownflags
.flags
.DRYRUN
:
761 linkCache
.remove_from_attrlist(attrlist
, value
)
763 linkCache
.del_attr(attrlist
)
768 def _cache_invalidate():
769 linkCache
.invalidate()
770 LinkUtils
._CACHE
_FILL
_DONE
= False
774 LinkUtils
.ipbatcbuf
= ''
775 LinkUtils
.ipbatch
= True
776 LinkUtils
.ipbatch_pause
= False
779 def add_to_batch(cmd
):
780 LinkUtils
.ipbatchbuf
+= cmd
+ '\n'
784 LinkUtils
.ipbatch_pause
= True
788 LinkUtils
.ipbatch_pause
= False
790 def batch_commit(self
):
791 if not LinkUtils
.ipbatchbuf
:
792 LinkUtils
.ipbatchbuf
= ''
793 LinkUtils
.ipbatch
= False
794 LinkUtils
.ipbatch_pause
= False
797 utils
.exec_command('%s -force -batch -' % utils
.ip_cmd
,
798 stdin
=self
.ipbatchbuf
)
802 LinkUtils
.ipbatchbuf
= ''
803 LinkUtils
.ipbatch
= False
804 LinkUtils
.ipbatch_pause
= False
806 def bridge_batch_commit(self
):
807 if not LinkUtils
.ipbatchbuf
:
808 LinkUtils
.ipbatchbuf
= ''
809 LinkUtils
.ipbatch
= False
810 LinkUtils
.ipbatch_pause
= False
813 utils
.exec_command('%s -force -batch -'
814 % utils
.bridge_cmd
, stdin
=self
.ipbatchbuf
)
818 LinkUtils
.ipbatchbuf
= ''
819 LinkUtils
.ipbatch
= False
820 LinkUtils
.ipbatch_pause
= False
822 def addr_show(self
, ifacename
=None):
824 if not self
.link_exists(ifacename
):
826 return utils
.exec_commandl([utils
.ip_cmd
,
827 '-o', 'addr', 'show', 'dev', ifacename
])
829 return utils
.exec_commandl([utils
.ip_cmd
,
830 '-o', 'addr', 'show'])
833 def link_show(ifacename
=None):
835 return utils
.exec_commandl([utils
.ip_cmd
,
836 '-o', '-d', 'link', 'show', 'dev', ifacename
])
838 return utils
.exec_commandl([utils
.ip_cmd
,
839 '-o', '-d', 'link', 'show'])
841 def addr_add(self
, ifacename
, address
, broadcast
=None,
842 peer
=None, scope
=None, preferred_lifetime
=None, metric
=None):
845 cmd
= 'addr add %s' % address
847 cmd
+= ' broadcast %s' % broadcast
849 cmd
+= ' peer %s' % peer
851 cmd
+= ' scope %s' % scope
852 if preferred_lifetime
:
853 cmd
+= ' preferred_lft %s' % preferred_lifetime
854 cmd
+= ' dev %s' % ifacename
857 cmd
+= ' metric %s' % metric
859 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
860 self
.add_to_batch(cmd
)
862 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
863 self
._cache
_update
([ifacename
, 'addrs', address
], {})
865 def addr_del(self
, ifacename
, address
, broadcast
=None,
866 peer
=None, scope
=None):
867 """ Delete ipv4 address """
870 if not self
._cache
_get
('addr', [ifacename
, 'addrs', address
]):
872 cmd
= 'addr del %s' % address
874 cmd
+= 'broadcast %s' % broadcast
876 cmd
+= 'peer %s' % peer
878 cmd
+= 'scope %s' % scope
879 cmd
+= ' dev %s' % ifacename
880 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
881 self
._cache
_delete
([ifacename
, 'addrs', address
])
883 def addr_flush(self
, ifacename
):
884 cmd
= 'addr flush dev %s' % ifacename
885 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
886 self
.add_to_batch(cmd
)
888 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
889 self
._cache
_delete
([ifacename
, 'addrs'])
891 def del_addr_all(self
, ifacename
, skip_addrs
=[]):
894 runningaddrsdict
= self
.get_running_addrs(ifname
=ifacename
)
896 # XXX: ignore errors. Fix this to delete secondary addresses
898 [self
.addr_del(ifacename
, a
) for a
in
899 set(runningaddrsdict
.keys()).difference(skip_addrs
)]
904 def addr_get(self
, ifacename
, details
=True, refresh
=False):
905 addrs
= self
._cache
_get
('addr', [ifacename
, 'addrs'], refresh
=refresh
)
912 def get_running_addrs(self
, ifaceobj
=None, ifname
=None, details
=True, addr_virtual_ifaceobj
=None):
914 We now support addr with link scope. Since the kernel may add it's
915 own link address to some interfaces we need to filter them out and
916 make sure we only deal with the addresses set by ifupdown2.
918 To do so we look at the previous configuration made by ifupdown2
919 (with the help of the statemanager) together with the addresses
920 specified by the user in /etc/network/interfaces, these addresses
921 are then compared to the running state of the intf (ip addr show)
922 made via a netlink addr dump.
923 For each configured addresses of scope link, we check if it was
924 previously configured by ifupdown2 to create a final set of the
925 addresses watched by ifupdown2
927 if not ifaceobj
and not ifname
:
933 interface_name
= ifaceobj
.name
935 interface_name
= ifname
937 if addr_virtual_ifaceobj
:
938 for attr_name
in ["address-virtual", "vrrp"]:
939 for virtual
in addr_virtual_ifaceobj
.get_attr_value(attr_name
) or []:
940 for ip
in virtual
.split():
947 saved_ifaceobjs
= statemanager
.statemanager_api
.get_ifaceobjs(addr_virtual_ifaceobj
.name
)
948 for saved_ifaceobj
in saved_ifaceobjs
or []:
949 for virtual
in saved_ifaceobj
.get_attr_value(attr_name
) or []:
950 for ip
in virtual
.split():
958 for addr
in ifaceobj
.get_attr_value('address') or []:
959 config_addrs
.add(addr
)
961 saved_ifaceobjs
= statemanager
.statemanager_api
.get_ifaceobjs(interface_name
)
962 for saved_ifaceobj
in saved_ifaceobjs
or []:
963 for addr
in saved_ifaceobj
.get_attr_value('address') or []:
964 config_addrs
.add(addr
)
966 running_addrs
= OrderedDict()
967 cached_addrs
= self
.addr_get(interface_name
)
969 for addr
, addr_details
in cached_addrs
.items():
971 scope
= int(addr_details
['scope'])
975 addr_obj
= IPNetwork(addr
)
976 if isinstance(addr_obj
, IPv6Network
):
977 d
['family'] = 'inet6'
980 running_addrs
[addr
] = d
982 running_addrs
[addr
] = {}
984 if (scope
& Route
.RT_SCOPE_LINK
and addr
in config_addrs
) or not scope
& Route
.RT_SCOPE_LINK
:
985 running_addrs
[addr
] = addr_details
991 return running_addrs
.keys()
994 def compare_user_config_vs_running_state(running_addrs
, user_addrs
):
998 for ip
in user_addrs
or []:
1001 if type(obj
) == IPv6Network
:
1007 for ip
in running_addrs
or []:
1008 running_ipobj
.append(IPNetwork(ip
))
1010 return running_ipobj
== (ip4
+ ip6
)
1012 def addr_add_multiple(self
, ifaceobj
, ifacename
, addrs
, purge_existing
=False, metric
=None):
1015 # if perfmode is not set and also if iface has no sibling
1016 # objects, purge addresses that are not present in the new
1018 runningaddrs
= self
.get_running_addrs(
1021 addr_virtual_ifaceobj
=ifaceobj
1023 addrs
= utils
.get_normalized_ip_addr(ifacename
, addrs
)
1025 if self
.compare_user_config_vs_running_state(runningaddrs
, addrs
):
1028 # if primary address is not same, there is no need to keep any.
1029 # reset all addresses
1030 if (addrs
and runningaddrs
and
1031 (addrs
[0] != runningaddrs
[0])):
1032 self
.del_addr_all(ifacename
)
1034 self
.del_addr_all(ifacename
, addrs
)
1035 except Exception, e
:
1036 self
.logger
.warning('%s: %s' % (ifacename
, str(e
)))
1039 self
.addr_add(ifacename
, a
, metric
=metric
)
1040 except Exception, e
:
1041 self
.logger
.error(str(e
))
1043 def _link_set_ifflag(self
, ifacename
, value
):
1044 # Dont look at the cache, the cache may have stale value
1045 # because link status can be changed by external
1046 # entity (One such entity is ifupdown main program)
1047 cmd
= 'link set dev %s %s' % (ifacename
, value
.lower())
1048 if LinkUtils
.ipbatch
:
1049 self
.add_to_batch(cmd
)
1051 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1053 def link_up(self
, ifacename
):
1054 self
._link
_set
_ifflag
(ifacename
, 'UP')
1056 def link_down(self
, ifacename
):
1057 self
._link
_set
_ifflag
(ifacename
, 'DOWN')
1059 def link_set(self
, ifacename
, key
, value
=None,
1060 force
=False, t
=None, state
=None):
1062 if (key
not in ['master', 'nomaster'] and
1063 self
._cache
_check
('link', [ifacename
, key
], value
)):
1065 cmd
= 'link set dev %s' % ifacename
1067 cmd
+= ' type %s' % t
1070 cmd
+= ' %s' % value
1072 cmd
+= ' %s' % state
1073 if LinkUtils
.ipbatch
:
1074 self
.add_to_batch(cmd
)
1076 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1077 if key
not in ['master', 'nomaster']:
1078 self
._cache
_update
([ifacename
, key
], value
)
1080 def link_set_hwaddress(self
, ifacename
, hwaddress
, force
=False):
1082 if self
._cache
_check
('link', [ifacename
, 'hwaddress'], hwaddress
):
1084 self
.link_down(ifacename
)
1085 cmd
= 'link set dev %s address %s' % (ifacename
, hwaddress
)
1086 if LinkUtils
.ipbatch
:
1087 self
.add_to_batch(cmd
)
1089 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1090 self
.link_up(ifacename
)
1091 self
._cache
_update
([ifacename
, 'hwaddress'], hwaddress
)
1093 def link_set_mtu(self
, ifacename
, mtu
):
1094 if ifupdownflags
.flags
.DRYRUN
:
1096 if not mtu
or not ifacename
: return
1097 self
.write_file('/sys/class/net/%s/mtu' % ifacename
, mtu
)
1098 self
._cache
_update
([ifacename
, 'mtu'], mtu
)
1100 def link_set_alias(self
, ifacename
, alias
):
1101 self
.write_file('/sys/class/net/%s/ifalias' % ifacename
,
1102 '\n' if not alias
else alias
)
1104 def link_get_alias(self
, ifacename
):
1105 return self
.read_file_oneline('/sys/class/net/%s/ifalias'
1108 def link_isloopback(self
, ifacename
):
1109 flags
= self
._cache
_get
('link', [ifacename
, 'flags'])
1112 if 'LOOPBACK' in flags
:
1116 def link_get_status(self
, ifacename
):
1117 return self
._cache
_get
('link', [ifacename
, 'ifflag'], refresh
=True)
1120 def route_add_gateway(ifacename
, gateway
, vrf
=None, metric
=None, onlink
=True):
1124 cmd
= '%s route add default via %s proto kernel' % (utils
.ip_cmd
,
1127 cmd
= ('%s route add table %s default via %s proto kernel' %
1128 (utils
.ip_cmd
, vrf
, gateway
))
1131 cmd
+= 'metric %s' % metric
1132 cmd
+= ' dev %s' % ifacename
1137 utils
.exec_command(cmd
)
1140 def route_del_gateway(ifacename
, gateway
, vrf
=None, metric
=None):
1145 cmd
= ('%s route del default via %s proto kernel' %
1146 (utils
.ip_cmd
, gateway
))
1148 cmd
= ('%s route del table %s default via %s proto kernel' %
1149 (utils
.ip_cmd
, vrf
, gateway
))
1151 cmd
+= ' metric %s' % metric
1152 cmd
+= ' dev %s' % ifacename
1153 utils
.exec_command(cmd
)
1156 def _get_vrf_id(ifacename
):
1158 return linkCache
.vrfs
[ifacename
]['table']
1160 dump
= netlink
.link_dump(ifacename
)
1162 [linkCache
.update_attrdict([ifname
], linkattrs
)
1163 for ifname
, linkattrs
in dump
.items()]
1165 if dump
and dump
.get(ifacename
, {}).get('kind') == 'vrf':
1166 vrf_table
= dump
.get(ifacename
, {}).get('linkinfo', {}).get('table')
1167 linkCache
.vrfs
[ifacename
] = {'table': vrf_table
}
1172 def fix_ipv6_route_metric(self
, ifaceobj
, macvlan_ifacename
, ips
):
1175 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
:
1177 for upper_iface
in ifaceobj
.upperifaces
:
1178 vrf_table
= self
._get
_vrf
_id
(upper_iface
)
1186 ip_network_obj
= IPNetwork(ip
)
1188 if type(ip_network_obj
) == IPv6Network
:
1189 route_prefix
= '%s/%d' % (ip_network_obj
.network
, ip_network_obj
.prefixlen
)
1192 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1193 LinkUtils
.add_to_batch('route del %s table %s dev %s' % (route_prefix
, vrf_table
, macvlan_ifacename
))
1195 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'del', route_prefix
, 'table', vrf_table
, 'dev', macvlan_ifacename
])
1197 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1198 LinkUtils
.add_to_batch('route del %s dev %s' % (route_prefix
, macvlan_ifacename
))
1200 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'del', route_prefix
, 'dev', macvlan_ifacename
])
1201 ip_route_del
.append((route_prefix
, vrf_table
))
1203 for ip
, vrf_table
in ip_route_del
:
1205 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1206 LinkUtils
.add_to_batch('route add %s table %s dev %s proto kernel metric 9999' % (ip
, vrf_table
, macvlan_ifacename
))
1208 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'add', ip
, 'table', vrf_table
, 'dev', macvlan_ifacename
, 'proto', 'kernel' 'metric', '9999'])
1210 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1211 LinkUtils
.add_to_batch('route add %s dev %s proto kernel metric 9999' % (ip
, macvlan_ifacename
))
1213 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'add', ip
, 'dev', macvlan_ifacename
, 'proto', 'kernel' 'metric', '9999'])
1215 def link_create_vlan(self
, vlan_device_name
, vlan_raw_device
, vlanid
):
1216 if self
.link_exists(vlan_device_name
):
1218 utils
.exec_command('%s link add link %s name %s type vlan id %d' %
1220 vlan_raw_device
, vlan_device_name
, vlanid
))
1221 self
._cache
_update
([vlan_device_name
], {})
1223 def link_create_vlan_from_name(self
, vlan_device_name
):
1224 v
= vlan_device_name
.split('.')
1226 self
.logger
.warn('invalid vlan device name %s' % vlan_device_name
)
1228 self
.link_create_vlan(vlan_device_name
, v
[0], v
[1])
1230 def link_create_macvlan(self
, name
, linkdev
, mode
='private'):
1231 if self
.link_exists(name
):
1233 cmd
= ('link add link %s' % linkdev
+
1235 ' type macvlan mode %s' % mode
)
1236 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1237 self
.add_to_batch(cmd
)
1239 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1240 self
._cache
_update
([name
], {})
1242 def get_vxlan_peers(self
, dev
, svcnodeip
):
1243 cmd
= '%s fdb show brport %s' % (utils
.bridge_cmd
,
1247 ps
= subprocess
.Popen(shlex
.split(cmd
), stdout
=subprocess
.PIPE
, close_fds
=False)
1248 utils
.enable_subprocess_signal_forwarding(ps
, signal
.SIGINT
)
1249 output
= subprocess
.check_output(('grep', '00:00:00:00:00:00'), stdin
=ps
.stdout
)
1251 utils
.disable_subprocess_signal_forwarding(signal
.SIGINT
)
1253 ppat
= re
.compile('\s+dst\s+(\d+.\d+.\d+.\d+)\s+')
1254 for l
in output
.split('\n'):
1256 if m
and m
.group(1) != svcnodeip
:
1257 cur_peers
.append(m
.group(1))
1259 self
.logger
.warn('error parsing ip link output')
1260 except subprocess
.CalledProcessError
as e
:
1261 if e
.returncode
!= 1:
1262 self
.logger
.error(str(e
))
1264 utils
.disable_subprocess_signal_forwarding(signal
.SIGINT
)
1268 def tunnel_create(self
, tunnelname
, mode
, attrs
={}):
1269 """ generic link_create function """
1270 if self
.link_exists(tunnelname
):
1277 if mode
in ['gretap']:
1278 cmd
+= 'link add %s type %s' % (tunnelname
, mode
)
1280 cmd
+= 'tunnel add %s mode %s' % (tunnelname
, mode
)
1283 for k
, v
in attrs
.iteritems():
1287 if self
.ipbatch
and not self
.ipbatch_pause
:
1288 self
.add_to_batch(cmd
)
1290 utils
.exec_command('ip %s' % cmd
)
1291 self
._cache
_update
([tunnelname
], {})
1293 def tunnel_change(self
, tunnelname
, attrs
={}):
1294 """ tunnel change function """
1295 if not self
.link_exists(tunnelname
):
1297 cmd
= 'tunnel change'
1298 cmd
+= ' %s' %(tunnelname)
1300 for k
, v
in attrs
.iteritems():
1304 if self
.ipbatch
and not self
.ipbatch_pause
:
1305 self
.add_to_batch(cmd
)
1307 utils
.exec_command('ip %s' % cmd
)
1309 def link_create_vxlan(self
, name
, vxlanid
,
1317 if svcnodeip
and remoteips
:
1318 raise Exception("svcnodeip and remoteip is mutually exclusive")
1321 args
+= ' remote %s' % svcnodeip
1323 args
+= ' ageing %s' % ageing
1324 if learning
== 'off':
1325 args
+= ' nolearning'
1327 args
+= ' ttl %s' % ttl
1329 if self
.link_exists(name
):
1330 cmd
= 'link set dev %s type vxlan dstport %d' % (name
, LinkUtils
.VXLAN_UDP_PORT
)
1331 vxlanattrs
= self
.get_vxlandev_attrs(name
)
1332 # on ifreload do not overwrite anycast_ip to individual ip if clagd
1335 running_localtunnelip
= vxlanattrs
.get('local')
1336 if anycastip
and running_localtunnelip
and anycastip
== running_localtunnelip
:
1337 localtunnelip
= running_localtunnelip
1338 running_svcnode
= vxlanattrs
.get('svcnode')
1339 if running_svcnode
and not svcnodeip
:
1342 cmd
= 'link add dev %s type vxlan id %s dstport %d' % (name
, vxlanid
, LinkUtils
.VXLAN_UDP_PORT
)
1345 args
+= ' local %s' % localtunnelip
1348 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1349 self
.add_to_batch(cmd
)
1351 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1353 # XXX: update linkinfo correctly
1354 #self._cache_update([name], {})
1357 def link_exists(ifacename
):
1358 if ifupdownflags
.flags
.DRYRUN
:
1360 return os
.path
.exists('/sys/class/net/%s' % ifacename
)
1363 def link_exists_nodryrun(ifname
):
1364 return os
.path
.exists('/sys/class/net/%s' % ifname
)
1366 def link_get_ifindex(self
, ifacename
):
1367 if ifupdownflags
.flags
.DRYRUN
:
1369 return self
.read_file_oneline('/sys/class/net/%s/ifindex' % ifacename
)
1371 def is_vlan_device_by_name(self
, ifacename
):
1372 if re
.search(r
'\.', ifacename
):
1377 def link_add_macvlan(ifname
, macvlan_ifacename
, mode
):
1378 utils
.exec_commandl(['ip', 'link', 'add', 'link', ifname
, 'name', macvlan_ifacename
, 'type', 'macvlan', 'mode', mode
])
1381 def route_add(route
):
1382 utils
.exec_command('%s route add %s' % (utils
.ip_cmd
,
1386 def route6_add(route
):
1387 utils
.exec_command('%s -6 route add %s' % (utils
.ip_cmd
,
1390 def get_vlandev_attrs(self
, ifacename
):
1391 return (self
._cache
_get
('link', [ifacename
, 'link']),
1392 self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlanid']),
1393 self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlan_protocol']))
1395 def get_vlan_protocol(self
, ifacename
):
1396 return self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlan_protocol'])
1398 def get_vxlandev_attrs(self
, ifacename
):
1399 return self
._cache
_get
('link', [ifacename
, 'linkinfo'])
1401 def get_vxlandev_learning(self
, ifacename
):
1402 return self
._cache
_get
('link', [ifacename
, 'linkinfo', Link
.IFLA_VXLAN_LEARNING
])
1404 def set_vxlandev_learning(self
, ifacename
, learn
):
1406 utils
.exec_command('%s link set dev %s type vxlan learning' %
1407 (utils
.ip_cmd
, ifacename
))
1408 self
._cache
_update
([ifacename
, 'linkinfo', 'learning'], 'on')
1410 utils
.exec_command('%s link set dev %s type vxlan nolearning' %
1411 (utils
.ip_cmd
, ifacename
))
1412 self
._cache
_update
([ifacename
, 'linkinfo', 'learning'], 'off')
1414 def link_get_linkinfo_attrs(self
, ifacename
):
1415 return self
._cache
_get
('link', [ifacename
, 'linkinfo'])
1417 def link_get_mtu(self
, ifacename
, refresh
=False):
1418 return self
._cache
_get
('link', [ifacename
, 'mtu'], refresh
=refresh
)
1420 def link_get_mtu_sysfs(self
, ifacename
):
1421 return self
.read_file_oneline('/sys/class/net/%s/mtu'
1424 def link_get_kind(self
, ifacename
):
1425 return self
._cache
_get
('link', [ifacename
, 'kind'])
1427 def link_get_slave_kind(self
, ifacename
):
1428 return self
._cache
_get
('link', [ifacename
, 'slave_kind'])
1430 def link_get_hwaddress(self
, ifacename
):
1431 address
= self
._cache
_get
('link', [ifacename
, 'hwaddress'])
1432 # newly created logical interface addresses dont end up in the cache
1433 # read hwaddress from sysfs file for these interfaces
1435 address
= self
.read_file_oneline('/sys/class/net/%s/address'
1439 def link_create(self
, ifacename
, t
, attrs
={}):
1440 """ generic link_create function """
1441 if self
.link_exists(ifacename
):
1444 cmd
+= ' name %s type %s' % (ifacename
, t
)
1446 for k
, v
in attrs
.iteritems():
1450 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1451 self
.add_to_batch(cmd
)
1453 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1454 self
._cache
_update
([ifacename
], {})
1456 def link_delete(self
, ifacename
):
1457 if not self
.link_exists(ifacename
):
1459 cmd
= 'link del %s' % ifacename
1460 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1461 self
.add_to_batch(cmd
)
1463 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1464 self
._cache
_invalidate
()
1466 def link_get_master(self
, ifacename
):
1467 sysfs_master_path
= '/sys/class/net/%s/master' % ifacename
1468 if os
.path
.exists(sysfs_master_path
):
1469 link_path
= os
.readlink(sysfs_master_path
)
1471 return os
.path
.basename(link_path
)
1475 return self
._cache
_get
('link', [ifacename
, 'master'])
1477 def get_brport_peer_link(self
, bridgename
):
1479 return self
._cache
_get
('link', [bridgename
, 'info_slave_data', Link
.IFLA_BRPORT_PEER_LINK
])
1484 def bridge_port_vids_add(bridgeportname
, vids
):
1485 [utils
.exec_command('%s vlan add vid %s dev %s' %
1487 v
, bridgeportname
)) for v
in vids
]
1490 def bridge_port_vids_del(bridgeportname
, vids
):
1493 [utils
.exec_command('%s vlan del vid %s dev %s' %
1495 v
, bridgeportname
)) for v
in vids
]
1498 def bridge_port_vids_flush(bridgeportname
, vid
):
1499 utils
.exec_command('%s vlan del vid %s dev %s' %
1501 vid
, bridgeportname
))
1504 def bridge_port_vids_get(bridgeportname
):
1505 bridgeout
= utils
.exec_command('%s vlan show dev %s' %
1510 brvlanlines
= bridgeout
.readlines()[2:]
1511 vids
= [l
.strip() for l
in brvlanlines
]
1512 return [v
for v
in vids
if v
]
1515 def bridge_port_vids_get_all():
1517 bridgeout
= utils
.exec_command('%s -c vlan show'
1521 brvlanlines
= bridgeout
.splitlines()
1523 for l
in brvlanlines
[1:]:
1524 if l
and not l
.startswith(' ') and not l
.startswith('\t'):
1526 brportname
= attrs
[0].strip()
1527 brvlaninfo
[brportname
] = {'pvid': None, 'vlan': []}
1528 l
= ' '.join(attrs
[1:])
1529 if not brportname
or not l
:
1533 brvlaninfo
[brportname
]['pvid'] = l
.split()[0]
1534 elif 'Egress Untagged' not in l
:
1535 brvlaninfo
[brportname
]['vlan'].append(l
)
1538 def bridge_port_vids_get_all_json(self
):
1539 if not self
.supported_command
['%s -c -json vlan show'
1540 % utils
.bridge_cmd
]:
1544 bridgeout
= utils
.exec_command('%s -c -json vlan show'
1547 self
.supported_command
['%s -c -json vlan show'
1548 % utils
.bridge_cmd
] = False
1549 self
.logger
.info('%s -c -json vlan show: skipping unsupported command'
1552 return self
.get_bridge_vlan_nojson()
1553 except Exception as e
:
1554 self
.logger
.info('bridge: get_bridge_vlan_nojson: %s' % str(e
))
1557 if not bridgeout
: return brvlaninfo
1559 vlan_json
= json
.loads(bridgeout
, encoding
="utf-8")
1560 except Exception, e
:
1561 self
.logger
.info('json loads failed with (%s)' % str(e
))
1565 if isinstance(vlan_json
, list):
1566 # newer iproute2 version changed the bridge vlan show output
1567 # ifupdown2 relies on the previous format, we have the convert
1568 # data into old format
1569 bridge_port_vids
= dict()
1571 for intf
in vlan_json
:
1572 bridge_port_vids
[intf
["ifname"]] = intf
["vlans"]
1574 return bridge_port_vids
1576 # older iproute2 version have different ways to dump vlans
1577 # ifupdown2 prefers the following syntax:
1581 # "flags": ["PVID", "Egress Untagged"]
1586 # "flags": ["PVID", "Egress Untagged"]
1590 except Exception as e
:
1591 self
.logger
.debug("bridge vlan show: Unknown json output: %s" % str(e
))
1595 def get_bridge_vlan_nojson():
1597 bridgeout
= utils
.exec_commandl([utils
.bridge_cmd
, '-c', 'vlan', 'show'])
1599 output
= [line
.split('\n') for line
in bridgeout
.split('\n\n')]
1600 output
[0] = output
[0][1:]
1608 prefix
, vlan
= entry
.split('\t')
1610 current_swp
= prefix
1611 vlan_json
[prefix
] = []
1615 v
['vlan'] = int(vlan
)
1619 start
, end
= vlan
.split('-')
1621 end
= end
[0:end
.index(' ')]
1622 v
['vlan'] = int(start
)
1623 v
['vlanEnd'] = int(end
)
1625 v
['vlan'] = int(vlan
[0:vlan
.index(' ')])
1628 flags
.append('PVID')
1629 if 'Egress Untagged' in vlan
:
1630 flags
.append('Egress Untagged')
1634 vlan_json
[current_swp
].append(v
)
1637 def bridge_vlan_cache_get(self
, ifacename
, refresh
=False):
1638 if not self
.bridge_vlan_cache_fill_done
or refresh
:
1639 self
.bridge_vlan_cache
= self
.bridge_port_vids_get_all_json()
1640 self
.bridge_vlan_cache_fill_done
= True
1641 return self
.bridge_vlan_cache
.get(ifacename
, {})
1643 def bridge_vlan_get_pvid(self
, ifacename
, refresh
=False):
1646 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1647 v
= vinfo
.get('vlan')
1648 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1653 def bridge_vlan_get_vids(self
, ifacename
, refresh
=False):
1656 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1657 v
= vinfo
.get('vlan')
1658 ispvid
= True if 'PVID' in vinfo
.get('flags', []) else False
1660 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1663 vEnd
= vinfo
.get('vlanEnd')
1665 vids
.extend(range(v
, vEnd
+ 1))
1670 def bridge_vlan_get_vids_n_pvid(self
, ifacename
, refresh
=False):
1674 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1675 v
= vinfo
.get('vlan')
1676 ispvid
= True if 'PVID' in vinfo
.get('flags', []) else False
1678 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1679 vEnd
= vinfo
.get('vlanEnd')
1681 vids
.extend(range(v
, vEnd
+ 1))
1686 def bridge_port_pvid_add(self
, bridgeportname
, pvid
):
1687 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1688 self
.add_to_batch('vlan add vid %s untagged pvid dev %s' %
1689 (pvid
, bridgeportname
))
1691 utils
.exec_command('%s vlan add vid %s untagged pvid dev %s' %
1693 pvid
, bridgeportname
))
1695 def bridge_port_pvid_del(self
, bridgeportname
, pvid
):
1696 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1697 self
.add_to_batch('vlan del vid %s untagged pvid dev %s' %
1698 (pvid
, bridgeportname
))
1700 utils
.exec_command('%s vlan del vid %s untagged pvid dev %s' %
1702 pvid
, bridgeportname
))
1704 def bridge_port_pvids_get(self
, bridgeportname
):
1705 return self
.read_file_oneline('/sys/class/net/%s/brport/pvid'
1708 def bridge_vids_add(self
, bridgeportname
, vids
, bridge
=True):
1709 target
= 'self' if bridge
else ''
1710 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1711 [self
.add_to_batch('vlan add vid %s dev %s %s' %
1712 (v
, bridgeportname
, target
)) for v
in vids
]
1714 [utils
.exec_command('%s vlan add vid %s dev %s %s' %
1716 v
, bridgeportname
, target
)) for v
in vids
]
1718 def bridge_vids_del(self
, bridgeportname
, vids
, bridge
=True):
1719 target
= 'self' if bridge
else ''
1720 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1721 [self
.add_to_batch('vlan del vid %s dev %s %s' %
1722 (v
, bridgeportname
, target
)) for v
in vids
]
1724 [utils
.exec_command('%s vlan del vid %s dev %s %s' %
1726 v
, bridgeportname
, target
)) for v
in vids
]
1729 def bridge_fdb_add(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1730 target
= 'self' if bridge
else ''
1733 vlan_str
= 'vlan %s ' % vlan
1737 dst_str
= 'dst %s ' % remote
1739 utils
.exec_command('%s fdb replace %s dev %s %s %s %s' %
1741 address
, dev
, vlan_str
, target
, dst_str
))
1744 def bridge_fdb_append(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1745 target
= 'self' if bridge
else ''
1748 vlan_str
= 'vlan %s ' % vlan
1752 dst_str
= 'dst %s ' % remote
1754 utils
.exec_command('%s fdb append %s dev %s %s %s %s' %
1756 address
, dev
, vlan_str
, target
, dst_str
))
1759 def bridge_fdb_del(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1760 target
= 'self' if bridge
else ''
1763 vlan_str
= 'vlan %s ' % vlan
1767 dst_str
= 'dst %s ' % remote
1768 utils
.exec_command('%s fdb del %s dev %s %s %s %s' %
1770 address
, dev
, vlan_str
, target
, dst_str
))
1772 def bridge_is_vlan_aware(self
, bridgename
):
1773 filename
= '/sys/class/net/%s/bridge/vlan_filtering' % bridgename
1774 if os
.path
.exists(filename
) and self
.read_file_oneline(filename
) == '1':
1779 def bridge_port_get_bridge_name(bridgeport
):
1780 filename
= '/sys/class/net/%s/brport/bridge' % bridgeport
1782 return os
.path
.basename(os
.readlink(filename
))
1787 def bridge_port_exists(bridge
, bridgeportname
):
1789 return os
.path
.exists('/sys/class/net/%s/brif/%s'
1790 % (bridge
, bridgeportname
))
1794 def bridge_fdb_show_dev(self
, dev
):
1797 output
= utils
.exec_command('%s fdb show dev %s'
1798 % (utils
.bridge_cmd
, dev
))
1800 for fdb_entry
in output
.splitlines():
1802 entries
= fdb_entry
.split()
1803 fdbs
.setdefault(entries
[2], []).append(entries
[0])
1805 self
.logger
.debug('%s: invalid fdb line \'%s\''
1812 def is_bridge(bridge
):
1813 return os
.path
.exists('/sys/class/net/%s/bridge' % bridge
)
1815 def is_link_up(self
, ifacename
):
1818 flags
= self
.read_file_oneline('/sys/class/net/%s/flags' % ifacename
)
1819 iflags
= int(flags
, 16)
1826 def ip_route_get_dev(self
, prefix
, vrf_master
=None):
1829 cmd
= '%s route get %s vrf %s' % (utils
.ip_cmd
, prefix
, vrf_master
)
1831 cmd
= '%s route get %s' % (utils
.ip_cmd
, prefix
)
1833 output
= utils
.exec_command(cmd
)
1835 rline
= output
.splitlines()[0]
1837 rattrs
= rline
.split()
1838 return rattrs
[rattrs
.index('dev') + 1]
1839 except Exception, e
:
1840 self
.logger
.debug('ip_route_get_dev: failed .. %s' % str(e
))
1844 def link_get_lowers(ifacename
):
1846 lowers
= glob
.glob("/sys/class/net/%s/lower_*" % ifacename
)
1849 return [os
.path
.basename(l
)[6:] for l
in lowers
]
1854 def link_get_uppers(ifacename
):
1856 uppers
= glob
.glob("/sys/class/net/%s/upper_*" % ifacename
)
1859 return [os
.path
.basename(u
)[6:] for u
in uppers
]
1863 def link_get_vrfs(self
):
1864 if not LinkUtils
._CACHE
_FILL
_DONE
:
1866 return linkCache
.vrfs
1869 def cache_get_info_slave(attrlist
):
1871 return linkCache
.get_attr(attrlist
)
1875 def get_brport_learning(self
, ifacename
):
1876 learn
= self
.read_file_oneline('/sys/class/net/%s/brport/learning'
1878 if learn
and learn
== '1':
1883 def get_brport_learning_bool(self
, ifacename
):
1884 return utils
.get_boolean_from_string(self
.read_file_oneline('/sys/class/net/%s/brport/learning' % ifacename
))
1886 def set_brport_learning(self
, ifacename
, learn
):
1888 return self
.write_file('/sys/class/net/%s/brport/learning'
1891 return self
.write_file('/sys/class/net/%s/brport/learning'
1894 #################################################################################
1895 ################################### BOND UTILS ##################################
1896 #################################################################################
1898 def _link_cache_get(self
, attrlist
, refresh
=False):
1899 return self
._cache
_get
('link', attrlist
, refresh
)
1901 def cache_delete(self
, attrlist
, value
=None):
1902 return self
._cache
_delete
(attrlist
, value
)
1904 def link_cache_get(self
, attrlist
, refresh
=False):
1905 return self
._link
_cache
_get
(attrlist
, refresh
)
1907 def link_cache_check(self
, attrlist
, value
, refresh
=False):
1908 return self
._link
_cache
_check
(attrlist
, value
, refresh
)
1910 def _link_cache_check(self
, attrlist
, value
, refresh
=False):
1912 return self
._link
_cache
_get
(attrlist
, refresh
) == value
1913 except Exception, e
:
1914 self
.logger
.debug('_cache_check(%s) : [%s]'
1915 % (str(attrlist
), str(e
)))
1920 Link
.IFLA_BOND_MODE
: 'mode',
1921 Link
.IFLA_BOND_MIIMON
: 'miimon',
1922 Link
.IFLA_BOND_USE_CARRIER
: 'use_carrier',
1923 Link
.IFLA_BOND_AD_LACP_RATE
: 'lacp_rate',
1924 Link
.IFLA_BOND_XMIT_HASH_POLICY
: 'xmit_hash_policy',
1925 Link
.IFLA_BOND_MIN_LINKS
: 'min_links',
1926 Link
.IFLA_BOND_NUM_PEER_NOTIF
: 'num_grat_arp',
1927 Link
.IFLA_BOND_AD_ACTOR_SYSTEM
: 'ad_actor_system',
1928 Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
: 'ad_actor_sys_prio',
1929 Link
.IFLA_BOND_AD_LACP_BYPASS
: 'lacp_bypass',
1930 Link
.IFLA_BOND_UPDELAY
: 'updelay',
1931 Link
.IFLA_BOND_DOWNDELAY
: 'downdelay',
1934 def bond_set_attrs_nl(self
, bondname
, ifla_info_data
):
1935 bond_attr_name
= 'None' # for log purpose (in case an exception raised)
1936 for nl_attr
, value
in ifla_info_data
.items():
1938 bond_attr_name
= self
.bondcmd_attrmap
[nl_attr
]
1939 file_path
= '/sys/class/net/%s/bonding/%s' % (bondname
, bond_attr_name
)
1940 if os
.path
.exists(file_path
):
1941 self
.write_file(file_path
, str(value
))
1942 except Exception as e
:
1943 exception_str
= '%s: %s %s: %s' % (bondname
, bond_attr_name
, value
, str(e
))
1944 if ifupdownflags
.flags
.FORCE
:
1945 self
.logger
.warning(exception_str
)
1947 self
.logger
.debug(exception_str
)
1949 def bond_set_attrs(self
, bondname
, attrdict
, prehook
):
1950 for attrname
, attrval
in attrdict
.items():
1951 if (self
._link
_cache
_check
([bondname
, 'linkinfo',
1952 attrname
], attrval
)):
1954 if (attrname
== 'mode'
1955 or attrname
== 'xmit_hash_policy'
1956 or attrname
== 'lacp_rate' or attrname
== 'min_links'):
1960 if ((attrname
not in ['lacp_rate',
1962 self
._link
_cache
_check
([bondname
, 'linkinfo', 'mode'], '802.3ad',
1964 self
.write_file('/sys/class/net/%s/bonding/%s'
1965 % (bondname
, attrname
), attrval
)
1966 except Exception, e
:
1967 if ifupdownflags
.flags
.FORCE
:
1968 self
.logger
.warn(str(e
))
1973 def bond_set_use_carrier(self
, bondname
, use_carrier
):
1974 if not use_carrier
or (use_carrier
!= '0' and use_carrier
!= '1'):
1976 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'use_carrier'],
1979 self
.write_file('/sys/class/net/%s' % bondname
+
1980 '/bonding/use_carrier', use_carrier
)
1981 self
._cache
_update
([bondname
, 'linkinfo',
1982 'use_carrier'], use_carrier
)
1984 def bond_get_use_carrier(self
, bondname
):
1985 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'use_carrier'])
1987 def bond_get_use_carrier_nl(self
, bondname
):
1988 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_USE_CARRIER
])
1990 def bond_set_xmit_hash_policy(self
, bondname
, hash_policy
, prehook
=None):
1991 valid_values
= ['layer2', 'layer3+4', 'layer2+3']
1994 if hash_policy
not in valid_values
:
1995 raise Exception('invalid hash policy value %s' % hash_policy
)
1996 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'xmit_hash_policy'],
2001 self
.write_file('/sys/class/net/%s' % bondname
+
2002 '/bonding/xmit_hash_policy', hash_policy
)
2003 self
._cache
_update
([bondname
, 'linkinfo', 'xmit_hash_policy'],
2006 def bond_get_xmit_hash_policy(self
, bondname
):
2007 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'xmit_hash_policy'])
2009 def bond_get_xmit_hash_policy_nl(self
, bondname
):
2010 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_XMIT_HASH_POLICY
])
2012 def bond_set_miimon(self
, bondname
, miimon
):
2013 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'miimon'],
2016 self
.write_file('/sys/class/net/%s' % bondname
+
2017 '/bonding/miimon', miimon
)
2018 self
._cache
_update
([bondname
, 'linkinfo', 'miimon'], miimon
)
2020 def bond_get_miimon(self
, bondname
):
2021 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'miimon'])
2023 def bond_get_miimon_nl(self
, bondname
):
2024 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MIIMON
])
2026 def bond_set_mode(self
, bondname
, mode
, prehook
=None):
2027 valid_modes
= ['balance-rr', 'active-backup', 'balance-xor',
2028 'broadcast', '802.3ad', 'balance-tlb', 'balance-alb']
2031 if mode
not in valid_modes
:
2032 raise Exception('invalid mode %s' % mode
)
2033 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'mode'],
2038 self
.write_file('/sys/class/net/%s' % bondname
+ '/bonding/mode', mode
)
2039 self
._cache
_update
([bondname
, 'linkinfo', 'mode'], mode
)
2041 def bond_get_mode(self
, bondname
):
2042 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'mode'])
2044 def bond_get_mode_nl(self
, bondname
):
2045 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MODE
])
2047 def bond_set_lacp_rate(self
, bondname
, lacp_rate
, prehook
=None, posthook
=None):
2048 if not lacp_rate
or (lacp_rate
!= '0' and lacp_rate
!= '1'):
2050 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'lacp_rate'],
2056 self
.write_file('/sys/class/net/%s' % bondname
+
2057 '/bonding/lacp_rate', lacp_rate
)
2063 self
._cache
_update
([bondname
, 'linkinfo',
2064 'lacp_rate'], lacp_rate
)
2066 def bond_get_lacp_rate(self
, bondname
):
2067 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'lacp_rate'])
2069 def bond_get_lacp_rate_nl(self
, bondname
):
2070 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_RATE
])
2072 def bond_set_lacp_bypass_allow(self
, bondname
, allow
, prehook
=None, posthook
=None):
2073 if self
._link
_cache
_check
([bondname
, 'linkinfo', 'lacp_bypass'], allow
):
2078 self
.write_file('/sys/class/net/%s' % bondname
+
2079 '/bonding/lacp_bypass', allow
)
2085 self
._cache
_update
([bondname
, 'linkinfo',
2086 'lacp_bypass'], allow
)
2088 def bond_get_lacp_bypass_allow(self
, bondname
):
2089 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'lacp_bypass'])
2091 def bond_get_lacp_bypass_allow_nl(self
, bondname
):
2092 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_BYPASS
])
2094 def bond_set_min_links(self
, bondname
, min_links
, prehook
=None):
2095 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'min_links'],
2100 self
.write_file('/sys/class/net/%s/bonding/min_links' % bondname
,
2102 self
._cache
_update
([bondname
, 'linkinfo', 'min_links'], min_links
)
2104 def bond_get_min_links(self
, bondname
):
2105 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'min_links'])
2107 def get_min_links_nl(self
, bondname
):
2108 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MIN_LINKS
])
2110 def bond_get_ad_actor_system(self
, bondname
):
2111 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'ad_actor_system'])
2113 def bond_get_ad_actor_system_nl(self
, bondname
):
2114 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYSTEM
])
2116 def bond_get_ad_actor_sys_prio(self
, bondname
):
2117 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'ad_actor_sys_prio'])
2119 def bond_get_ad_actor_sys_prio_nl(self
, bondname
):
2120 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
])
2122 def bond_get_num_unsol_na(self
, bondname
):
2123 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'num_unsol_na'])
2125 def bond_get_num_unsol_na_nl(self
, bondname
):
2126 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
])
2128 def bond_get_num_grat_arp(self
, bondname
):
2129 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'num_grat_arp'])
2131 def bond_get_num_grat_arp_nl(self
, bondname
):
2132 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
])
2134 def bond_get_updelay(self
, bondname
):
2135 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'updelay'])
2137 def bond_get_updelay_nl(self
, bondname
):
2138 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_UPDELAY
])
2140 def bond_get_downdelay(self
, bondname
):
2141 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'downdelay'])
2143 def bond_get_downdelay_nl(self
, bondname
):
2144 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_DOWNDELAY
])
2146 def bond_enslave_slave(self
, bondname
, slave
, prehook
=None, posthook
=None):
2147 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2148 if slaves
and slave
in slaves
:
2152 self
.write_file('/sys/class/net/%s' % bondname
+
2153 '/bonding/slaves', '+' + slave
)
2156 self
._cache
_update
([bondname
, 'linkinfo', 'slaves'], slave
)
2158 def bond_remove_slave(self
, bondname
, slave
):
2159 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2160 if not slaves
or slave
not in slaves
:
2162 sysfs_bond_path
= ('/sys/class/net/%s' % bondname
+
2164 if not os
.path
.exists(sysfs_bond_path
):
2166 self
.write_file(sysfs_bond_path
, '-' + slave
)
2167 self
._cache
_delete
([bondname
, 'linkinfo', 'slaves'], slave
)
2169 def bond_remove_slaves_all(self
, bondname
):
2170 if not self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves']):
2173 sysfs_bond_path
= ('/sys/class/net/%s' % bondname
+
2176 with
open(sysfs_bond_path
, 'r') as f
:
2177 slaves
= f
.readline().strip().split()
2179 raise Exception('error reading slaves of bond %s (%s)' % (bondname
, str(e
)))
2180 for slave
in slaves
:
2181 self
.link_down(slave
)
2183 self
.bond_remove_slave(bondname
, slave
)
2184 except Exception, e
:
2185 if not ifupdownflags
.flags
.FORCE
:
2186 raise Exception('error removing slave %s from bond %s (%s)' % (slave
, bondname
, str(e
)))
2189 self
._cache
_delete
([bondname
, 'linkinfo', 'slaves'])
2192 def bond_load_bonding_module():
2193 return utils
.exec_command('%s -q bonding' % utils
.modprobe_cmd
)
2195 def create_bond(self
, bondname
):
2196 if self
.bond_exists(bondname
):
2198 # load_bonding_module() has already been run
2199 self
.write_file('/sys/class/net/bonding_masters', '+' + bondname
)
2200 self
._cache
_update
([bondname
], {})
2202 def delete_bond(self
, bondname
):
2203 if not os
.path
.exists('/sys/class/net/%s' % bondname
):
2205 self
.write_file('/sys/class/net/bonding_masters', '-' + bondname
)
2206 self
._cache
_delete
([bondname
])
2208 def bond_get_slaves(self
, bondname
):
2209 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2212 slavefile
= '/sys/class/net/%s/bonding/slaves' % bondname
2213 if os
.path
.exists(slavefile
):
2214 buf
= self
.read_file_oneline(slavefile
)
2216 slaves
= buf
.split()
2219 self
._cache
_update
([bondname
, 'linkinfo', 'slaves'], slaves
)
2222 def bond_slave_exists(self
, bond
, slave
):
2223 slaves
= self
.bond_get_slaves(bond
)
2226 return slave
in slaves
2229 def bond_exists(bondname
):
2230 return os
.path
.exists('/sys/class/net/%s/bonding' % bondname
)
2232 #################################################################################
2233 ################################## BRIDGE UTILS #################################
2234 #################################################################################
2236 def create_bridge(self
, bridgename
):
2237 if not LinkUtils
.bridge_utils_is_installed
:
2239 if self
.bridge_exists(bridgename
):
2241 utils
.exec_command('%s addbr %s' % (utils
.brctl_cmd
, bridgename
))
2242 self
._cache
_update
([bridgename
], {})
2244 def delete_bridge(self
, bridgename
):
2245 if not LinkUtils
.bridge_utils_is_installed
:
2247 if not self
.bridge_exists(bridgename
):
2249 utils
.exec_command('%s delbr %s' % (utils
.brctl_cmd
, bridgename
))
2250 self
._cache
_invalidate
()
2252 def add_bridge_port(self
, bridgename
, bridgeportname
):
2253 """ Add port to bridge """
2254 if not LinkUtils
.bridge_utils_is_installed
:
2256 ports
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports'])
2257 if ports
and ports
.get(bridgeportname
):
2259 utils
.exec_command('%s addif %s %s' % (utils
.brctl_cmd
, bridgename
, bridgeportname
))
2260 self
._cache
_update
([bridgename
, 'linkinfo', 'ports', bridgeportname
], {})
2262 def delete_bridge_port(self
, bridgename
, bridgeportname
):
2263 """ Delete port from bridge """
2264 if not LinkUtils
.bridge_utils_is_installed
:
2266 ports
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports'])
2267 if not ports
or not ports
.get(bridgeportname
):
2269 utils
.exec_command('%s delif %s %s' % (utils
.brctl_cmd
, bridgename
, bridgeportname
))
2270 self
._cache
_delete
([bridgename
, 'linkinfo', 'ports', 'bridgeportname'])
2272 def set_bridgeport_attrs(self
, bridgename
, bridgeportname
, attrdict
):
2273 portattrs
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports', bridgeportname
])
2274 if portattrs
== None:
2276 for k
, v
in attrdict
.iteritems():
2277 if ifupdownflags
.flags
.CACHE
:
2278 curval
= portattrs
.get(k
)
2279 if curval
and curval
== v
:
2281 if k
== 'unicast-flood':
2282 self
.write_file('/sys/class/net/%s/brport/unicast_flood' % bridgeportname
, v
)
2283 elif k
== 'multicast-flood':
2284 self
.write_file('/sys/class/net/%s/brport/multicast_flood' % bridgeportname
, v
)
2285 elif k
== 'learning':
2286 self
.write_file('/sys/class/net/%s/brport/learning' % bridgeportname
, v
)
2287 elif k
== 'arp-nd-suppress':
2288 self
.write_file('/sys/class/net/%s/brport/neigh_suppress' % bridgeportname
, v
)
2290 if not LinkUtils
.bridge_utils_is_installed
:
2292 utils
.exec_command('%s set%s %s %s %s' % (utils
.brctl_cmd
, k
, bridgename
, bridgeportname
, v
))
2294 def set_bridgeport_attr(self
, bridgename
, bridgeportname
,
2296 if not LinkUtils
.bridge_utils_is_installed
:
2298 if self
._link
_cache
_check
([bridgename
, 'linkinfo', 'ports', bridgeportname
, attrname
], attrval
):
2300 utils
.exec_command('%s set%s %s %s %s' %
2307 def set_bridge_attrs(self
, bridgename
, attrdict
):
2308 for k
, v
in attrdict
.iteritems():
2311 if self
._link
_cache
_check
([bridgename
, 'linkinfo', k
], v
):
2314 if k
== 'igmp-version':
2315 self
.write_file('/sys/class/net/%s/bridge/'
2316 'multicast_igmp_version' % bridgename
, v
)
2317 elif k
== 'mld-version':
2318 self
.write_file('/sys/class/net/%s/bridge/'
2319 'multicast_mld_version' % bridgename
, v
)
2320 elif k
== 'vlan-protocol':
2321 self
.write_file('/sys/class/net/%s/bridge/'
2322 'vlan_protocol' % bridgename
,
2323 VlanProtocols
.ETHERTYPES_TO_ID
.get(v
.upper(),
2325 elif k
== 'vlan-stats':
2326 self
.write_file('/sys/class/net/%s/bridge/'
2327 'vlan_stats_enabled' % bridgename
, v
)
2328 elif k
== 'mcstats':
2329 self
.write_file('/sys/class/net/%s/bridge/'
2330 'multicast_stats_enabled' % bridgename
, v
)
2332 if not LinkUtils
.bridge_utils_is_installed
:
2334 cmd
= ('%s set%s %s %s' %
2335 (utils
.brctl_cmd
, k
, bridgename
, v
))
2336 utils
.exec_command(cmd
)
2337 except Exception, e
:
2338 self
.logger
.warn('%s: %s' % (bridgename
, str(e
)))
2341 def set_bridge_attr(self
, bridgename
, attrname
, attrval
):
2342 if self
._link
_cache
_check
([bridgename
, 'linkinfo', attrname
], attrval
):
2344 if attrname
== 'igmp-version':
2345 self
.write_file('/sys/class/net/%s/bridge/multicast_igmp_version'
2346 % bridgename
, attrval
)
2347 elif attrname
== 'mld-version':
2348 self
.write_file('/sys/class/net/%s/bridge/multicast_mld_version'
2349 % bridgename
, attrval
)
2350 elif attrname
== 'vlan-protocol':
2351 self
.write_file('/sys/class/net/%s/bridge/vlan_protocol'
2352 % bridgename
, VlanProtocols
.ETHERTYPES_TO_ID
[attrval
.upper()])
2353 elif attrname
== 'vlan-stats':
2354 self
.write_file('/sys/class/net/%s/bridge/vlan_stats_enabled'
2355 % bridgename
, attrval
)
2356 elif attrname
== 'mcstats':
2357 self
.write_file('/sys/class/net/%s/bridge/multicast_stats_enabled'
2358 % bridgename
, attrval
)
2360 if not LinkUtils
.bridge_utils_is_installed
:
2362 cmd
= '%s set%s %s %s' % (utils
.brctl_cmd
,
2363 attrname
, bridgename
, attrval
)
2364 utils
.exec_command(cmd
)
2366 def get_bridge_attrs(self
, bridgename
):
2367 attrs
= self
._link
_cache
_get
([bridgename
, 'linkinfo'])
2369 for key
, value
in attrs
.items():
2370 if type(key
) == str:
2371 no_ints_attrs
[key
] = value
2372 return no_ints_attrs
2374 def get_bridgeport_attrs(self
, bridgename
, bridgeportname
):
2375 return self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports',
2378 def get_bridgeport_attr(self
, bridgename
, bridgeportname
, attrname
):
2379 return self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports',
2380 bridgeportname
, attrname
])
2383 def bridge_set_stp(bridge
, stp_state
):
2384 if not LinkUtils
.bridge_utils_is_installed
:
2386 utils
.exec_command('%s stp %s %s' % (utils
.brctl_cmd
, bridge
, stp_state
))
2388 def bridge_get_stp(self
, bridge
):
2389 sysfs_stpstate
= '/sys/class/net/%s/bridge/stp_state' % bridge
2390 if not os
.path
.exists(sysfs_stpstate
):
2392 stpstate
= self
.read_file_oneline(sysfs_stpstate
)
2396 if int(stpstate
) > 0:
2398 elif int(stpstate
) == 0:
2404 def _conv_value_to_user(s
):
2411 def read_value_from_sysfs(self
, filename
, preprocess_func
):
2412 value
= self
.read_file_oneline(filename
)
2415 return preprocess_func(value
)
2418 def bridge_set_ageing(bridge
, ageing
):
2419 if not LinkUtils
.bridge_utils_is_installed
:
2421 utils
.exec_command('%s setageing %s %s' % (utils
.brctl_cmd
, bridge
, ageing
))
2423 def bridge_get_ageing(self
, bridge
):
2424 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/ageing_time'
2425 % bridge
, self
._conv
_value
_to
_user
)
2428 def set_bridgeprio(bridge
, prio
):
2429 if not LinkUtils
.bridge_utils_is_installed
:
2431 utils
.exec_command('%s setbridgeprio %s %s' % (utils
.brctl_cmd
, bridge
, prio
))
2433 def get_bridgeprio(self
, bridge
):
2434 return self
.read_file_oneline(
2435 '/sys/class/net/%s/bridge/priority' % bridge
)
2438 def bridge_set_fd(bridge
, fd
):
2439 if not LinkUtils
.bridge_utils_is_installed
:
2441 utils
.exec_command('%s setfd %s %s' % (utils
.brctl_cmd
, bridge
, fd
))
2443 def bridge_get_fd(self
, bridge
):
2444 return self
.read_value_from_sysfs(
2445 '/sys/class/net/%s/bridge/forward_delay'
2446 % bridge
, self
._conv
_value
_to
_user
)
2448 def bridge_set_gcint(self
, bridge
, gcint
):
2449 raise Exception('set_gcint not implemented')
2452 def bridge_set_hello(bridge
, hello
):
2453 if not LinkUtils
.bridge_utils_is_installed
:
2455 utils
.exec_command('%s sethello %s %s' % (utils
.brctl_cmd
, bridge
, hello
))
2457 def bridge_get_hello(self
, bridge
):
2458 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/hello_time'
2459 % bridge
, self
._conv
_value
_to
_user
)
2462 def bridge_set_maxage(bridge
, maxage
):
2463 if not LinkUtils
.bridge_utils_is_installed
:
2465 utils
.exec_command('%s setmaxage %s %s' % (utils
.brctl_cmd
, bridge
, maxage
))
2467 def bridge_get_maxage(self
, bridge
):
2468 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/max_age'
2469 % bridge
, self
._conv
_value
_to
_user
)
2472 def bridge_set_pathcost(bridge
, port
, pathcost
):
2473 if not LinkUtils
.bridge_utils_is_installed
:
2475 utils
.exec_command('%s setpathcost %s %s %s' % (utils
.brctl_cmd
, bridge
, port
, pathcost
))
2477 def bridge_get_pathcost(self
, bridge
, port
):
2478 return self
.read_file_oneline('/sys/class/net/%s/brport/path_cost'
2482 def bridge_set_portprio(bridge
, port
, prio
):
2483 if not LinkUtils
.bridge_utils_is_installed
:
2485 utils
.exec_command('%s setportprio %s %s %s' % (utils
.brctl_cmd
, bridge
, port
, prio
))
2487 def bridge_get_portprio(self
, bridge
, port
):
2488 return self
.read_file_oneline('/sys/class/net/%s/brport/priority'
2492 def bridge_set_hashmax(bridge
, hashmax
):
2493 if not LinkUtils
.bridge_utils_is_installed
:
2495 utils
.exec_command('%s sethashmax %s %s' % (utils
.brctl_cmd
, bridge
, hashmax
))
2497 def bridge_get_hashmax(self
, bridge
):
2498 return self
.read_file_oneline('/sys/class/net/%s/bridge/hash_max'
2502 def bridge_set_hashel(bridge
, hashel
):
2503 if not LinkUtils
.bridge_utils_is_installed
:
2505 utils
.exec_command('%s sethashel %s %s' % (utils
.brctl_cmd
, bridge
, hashel
))
2507 def bridge_get_hashel(self
, bridge
):
2508 return self
.read_file_oneline('/sys/class/net/%s/bridge/hash_elasticity'
2512 def bridge_set_mclmc(bridge
, mclmc
):
2513 if not LinkUtils
.bridge_utils_is_installed
:
2515 utils
.exec_command('%s setmclmc %s %s' % (utils
.brctl_cmd
, bridge
, mclmc
))
2517 def bridge_get_mclmc(self
, bridge
):
2518 return self
.read_file_oneline(
2519 '/sys/class/net/%s/bridge/multicast_last_member_count'
2523 def bridge_set_mcrouter(bridge
, mcrouter
):
2524 if not LinkUtils
.bridge_utils_is_installed
:
2526 utils
.exec_command('%s setmcrouter %s %s' % (utils
.brctl_cmd
, bridge
, mcrouter
))
2528 def bridge_get_mcrouter(self
, bridge
):
2529 return self
.read_file_oneline(
2530 '/sys/class/net/%s/bridge/multicast_router' % bridge
)
2533 def bridge_set_mcsnoop(bridge
, mcsnoop
):
2534 if not LinkUtils
.bridge_utils_is_installed
:
2536 utils
.exec_command('%s setmcsnoop %s %s' % (utils
.brctl_cmd
, bridge
, mcsnoop
))
2538 def bridge_get_mcsnoop(self
, bridge
):
2539 return self
.read_file_oneline(
2540 '/sys/class/net/%s/bridge/multicast_snooping' % bridge
)
2543 def bridge_set_mcsqc(bridge
, mcsqc
):
2544 if not LinkUtils
.bridge_utils_is_installed
:
2546 utils
.exec_command('%s setmcsqc %s %s' % (utils
.brctl_cmd
, bridge
, mcsqc
))
2548 def bridge_get_mcsqc(self
, bridge
):
2549 return self
.read_file_oneline(
2550 '/sys/class/net/%s/bridge/multicast_startup_query_count'
2554 def bridge_set_mcqifaddr(bridge
, mcqifaddr
):
2555 if not LinkUtils
.bridge_utils_is_installed
:
2557 utils
.exec_command('%s setmcqifaddr %s %s' % (utils
.brctl_cmd
, bridge
, mcqifaddr
))
2559 def bridge_get_mcqifaddr(self
, bridge
):
2560 return self
.read_file_oneline(
2561 '/sys/class/net/%s/bridge/multicast_startup_query_use_ifaddr'
2565 def bridge_set_mcquerier(bridge
, mcquerier
):
2566 if not LinkUtils
.bridge_utils_is_installed
:
2568 utils
.exec_command('%s setmcquerier %s %s' % (utils
.brctl_cmd
, bridge
, mcquerier
))
2570 def bridge_get_mcquerier(self
, bridge
):
2571 return self
.read_file_oneline(
2572 '/sys/class/net/%s/bridge/multicast_querier' % bridge
)
2574 def bridge_set_mcqv4src(self
, bridge
, vlan
, mcquerier
):
2578 self
.logger
.info('%s: set mcqv4src vlan: invalid parameter %s: %s' %(bridge
, vlan
, str(e
)))
2580 if vlan
== 0 or vlan
> 4095:
2581 self
.logger
.warn('mcqv4src vlan \'%d\' invalid range' % vlan
)
2584 ip
= mcquerier
.split('.')
2586 self
.logger
.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier
)
2589 if not k
.isdigit() or int(k
, 10) < 0 or int(k
, 10) > 255:
2590 self
.logger
.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier
)
2593 if not LinkUtils
.bridge_utils_is_installed
:
2596 utils
.exec_command('%s setmcqv4src %s %d %s' %
2597 (utils
.brctl_cmd
, bridge
, vlan
, mcquerier
))
2599 def bridge_del_mcqv4src(self
, bridge
, vlan
):
2600 if not LinkUtils
.bridge_utils_is_installed
:
2605 self
.logger
.info('%s: del mcqv4src vlan: invalid parameter %s: %s' %(bridge
, vlan
, str(e
)))
2607 utils
.exec_command('%s delmcqv4src %s %d' % (utils
.brctl_cmd
, bridge
, vlan
))
2609 def bridge_get_mcqv4src(self
, bridge
, vlan
=None):
2610 if not LinkUtils
.bridge_utils_is_installed
:
2612 if not self
.supported_command
['showmcqv4src']:
2616 mcqout
= utils
.exec_command('%s showmcqv4src %s' %
2617 (utils
.brctl_cmd
, bridge
))
2618 except Exception as e
:
2620 if 'never heard' in s
:
2621 msg
= ('%s showmcqv4src: skipping unsupported command'
2623 self
.logger
.info(msg
)
2624 self
.supported_command
['showmcqv4src'] = False
2629 mcqlines
= mcqout
.splitlines()
2630 for l
in mcqlines
[1:]:
2632 k
, d
, v
= l
.split('\t')
2637 return mcqv4src
.get(vlan
)
2640 def bridge_get_mcqv4src_sysfs(self
, bridge
, vlan
=None):
2641 if not LinkUtils
.bridge_utils_is_installed
:
2643 if not self
.supported_command
['showmcqv4src']:
2645 if ifupdownflags
.flags
.PERFMODE
:
2649 filename
= '/sys/class/net/%s/bridge/multicast_v4_queriers' % bridge
2650 if os
.path
.exists(filename
):
2651 for line
in self
.read_file(filename
) or []:
2652 vlan_id
, ip
= line
.split('=')
2653 mcqv4src
[vlan_id
] = ip
.strip()
2654 except Exception as e
:
2656 msg
= ('%s showmcqv4src: skipping unsupported command'
2658 self
.logger
.info(msg
)
2659 self
.supported_command
['showmcqv4src'] = False
2662 return mcqv4src
.get(vlan
)
2666 def bridge_set_mclmi(bridge
, mclmi
):
2667 if not LinkUtils
.bridge_utils_is_installed
:
2669 utils
.exec_command('%s setmclmi %s %s' % (utils
.brctl_cmd
, bridge
, mclmi
))
2671 def bridge_get_mclmi(self
, bridge
):
2672 return self
.read_file_oneline(
2673 '/sys/class/net/%s/bridge/multicast_last_member_interval'
2677 def bridge_set_mcmi(bridge
, mcmi
):
2678 if not LinkUtils
.bridge_utils_is_installed
:
2680 utils
.exec_command('%s setmcmi %s %s' % (utils
.brctl_cmd
, bridge
, mcmi
))
2682 def bridge_get_mcmi(self
, bridge
):
2683 return self
.read_file_oneline(
2684 '/sys/class/net/%s/bridge/multicast_membership_interval'
2688 def bridge_exists(bridge
):
2689 return os
.path
.exists('/sys/class/net/%s/bridge' % bridge
)
2692 def is_bridge_port(ifacename
):
2693 return os
.path
.exists('/sys/class/net/%s/brport' % ifacename
)
2696 def bridge_port_exists(bridge
, bridgeportname
):
2698 return os
.path
.exists('/sys/class/net/%s/brif/%s' % (bridge
, bridgeportname
))
2703 def get_bridge_ports(bridgename
):
2705 return os
.listdir('/sys/class/net/%s/brif/' % bridgename
)
2709 def reset_addr_cache(self
, ifname
):
2711 linkCache
.links
[ifname
]['addrs'] = {}
2712 self
.logger
.debug('%s: reset address cache' % ifname
)
2716 def get_ipv6_addrgen_mode(self
, ifname
):
2718 return self
._cache
_get
('link', [ifname
, 'af_spec', socket
.AF_INET6
])[Link
.IFLA_INET6_ADDR_GEN_MODE
]
2720 # default to 0 (eui64)
2723 def ipv6_addrgen(self
, ifname
, addrgen
, link_created
):
2725 # IFLA_INET6_ADDR_GEN_MODE values:
2728 if self
._link
_cache
_get
([ifname
, 'af_spec', socket
.AF_INET6
])[Link
.IFLA_INET6_ADDR_GEN_MODE
] == addrgen
:
2729 self
.logger
.debug('%s: ipv6 addrgen already %s' % (ifname
, 'off' if addrgen
else 'on'))
2732 disabled_ipv6
= self
.read_file_oneline('/proc/sys/net/ipv6/conf/%s/disable_ipv6' % ifname
)
2733 if not disabled_ipv6
or int(disabled_ipv6
) == 1:
2734 self
.logger
.info('%s: cannot set addrgen: ipv6 is disabled on this device' % ifname
)
2737 if int(self
._link
_cache
_get
([ifname
, 'mtu'])) < 1280:
2738 self
.logger
.info('%s: ipv6 addrgen is disabled on device with MTU '
2739 'lower than 1280: cannot set addrgen %s' % (ifname
, 'off' if addrgen
else 'on'))
2741 except (KeyError, TypeError):
2742 self
.logger
.debug('%s: ipv6 addrgen probably not supported or disabled on this device' % ifname
)
2747 if not link_created
:
2748 # When setting addrgenmode it is necessary to flap the macvlan
2749 # device. After flapping the device we also need to re-add all
2750 # the user configuration. The best way to add the user config
2751 # is to flush our internal address cache
2752 self
.reset_addr_cache(ifname
)
2754 cmd
= 'link set dev %s addrgenmode %s' % (ifname
, Link
.ifla_inet6_addr_gen_mode_dict
.get(addrgen
))
2756 is_link_up
= self
.is_link_up(ifname
)
2759 self
.link_down(ifname
)
2761 #if LinkUtils.ipbatch:
2762 # self.add_to_batch(cmd)
2764 # because this command might fail on older kernel its better to not batch it
2765 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
2768 self
.link_up(ifname
)