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 elif citems
[i
] == 'xfrm':
590 linkattrs
['kind'] = 'xfrm'
591 except Exception as e
:
593 self
.logger
.debug('%s: parsing error: id, mtu, state, '
594 'link/ether, vlan, dummy, vxlan, local, '
595 'remote, ageing, nolearning, vrf, table, '
596 'vrf_slave are reserved keywords: %s' %
599 # linkattrs['alias'] = self.read_file_oneline(
600 # '/sys/class/net/%s/ifalias' %ifname)
601 linkout
[ifname
] = linkattrs
602 [linkCache
.update_attrdict([ifname
], linkattrs
)
603 for ifname
, linkattrs
in linkout
.items()]
606 def _addr_filter(ifname
, addr
, scope
=None):
607 default_addrs
= ['127.0.0.1/8', '::1/128', '0.0.0.0']
608 if ifname
== 'lo' and addr
in default_addrs
:
610 if scope
and scope
== 'link':
614 def _addr_fill(self
, ifacename
=None, refresh
=False):
615 """ fills cache with address information
617 if ifacename argument given, fill cache for ifacename, else
618 fill cache for all interfaces in the system
620 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
623 # Check if ifacename is already full, in which case, return
624 if ifacename
and not refresh
:
625 linkCache
.get_attr([ifacename
, 'addrs'])
632 [linkCache
.update_attrdict([ifname
], linkattrs
)
633 for ifname
, linkattrs
in netlink
.addr_dump(ifname
=ifacename
).items()]
634 except Exception as e
:
635 self
.logger
.info(str(e
))
637 # this netlink call replaces the call to _addr_fill_iproute2_cmd()
638 # We shouldn't have netlink calls in the iproute2 module, this will
639 # be removed in the future. We plan to release, a flexible backend
640 # (netlink+iproute2) by default we will use netlink backend but with
641 # a CLI arg we can switch to iproute2 backend.
642 # Until we decide to create this "backend" switch capability,
643 # we have to put the netlink call inside the iproute2 module.
646 self
._addr
_fill
_iproute
2_cmd
(ifacename
, refresh
)
648 def _addr_fill_iproute2_cmd(self
, ifacename
=None, refresh
=False):
649 """ fills cache with address information
651 if ifacename argument given, fill cache for ifacename, else
652 fill cache for all interfaces in the system
655 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
658 # Check if ifacename is already full, in which case, return
659 if ifacename
and not refresh
:
660 linkCache
.get_attr([ifacename
, 'addrs'])
664 cmdout
= self
.addr_show(ifacename
=ifacename
)
667 for c
in cmdout
.splitlines():
669 ifnamenlink
= citems
[1].split('@')
670 if len(ifnamenlink
) > 1:
671 ifname
= ifnamenlink
[0]
673 ifname
= ifnamenlink
[0].strip(':')
674 if not linkout
.get(ifname
):
676 linkattrs
['addrs'] = OrderedDict({})
678 linkout
[ifname
].update(linkattrs
)
680 linkout
[ifname
] = linkattrs
681 if citems
[2] == 'inet':
682 if self
._addr
_filter
(ifname
, citems
[3], scope
=citems
[5]):
685 addrattrs
['scope'] = citems
[5]
686 addrattrs
['type'] = 'inet'
687 linkout
[ifname
]['addrs'][citems
[3]] = addrattrs
688 elif citems
[2] == 'inet6':
689 if self
._addr
_filter
(ifname
, citems
[3], scope
=citems
[5]):
691 if citems
[5] == 'link':
692 continue # skip 'link' addresses
694 addrattrs
['scope'] = citems
[5]
695 addrattrs
['type'] = 'inet6'
696 linkout
[ifname
]['addrs'][citems
[3]] = addrattrs
697 [linkCache
.update_attrdict([ifname
], linkattrs
)
698 for ifname
, linkattrs
in linkout
.items()]
700 def del_cache_entry(self
, ifname
):
702 del linkCache
.links
[ifname
]
706 def cache_get(self
, t
, attrlist
, refresh
=False):
707 return self
._cache
_get
(t
, attrlist
, refresh
)
709 def _cache_get(self
, t
, attrlist
, refresh
=False):
711 if ifupdownflags
.flags
.DRYRUN
:
713 if ifupdownflags
.flags
.CACHE
:
714 if self
._fill
_cache
():
715 # if we filled the cache, return new data
716 return linkCache
.get_attr(attrlist
)
718 return linkCache
.get_attr(attrlist
)
720 self
._link
_fill
(attrlist
[0], refresh
)
722 self
._addr
_fill
(attrlist
[0], refresh
)
724 self
._link
_fill
(attrlist
[0], refresh
)
725 self
._addr
_fill
(attrlist
[0], refresh
)
726 return linkCache
.get_attr(attrlist
)
728 self
.logger
.debug('_cache_get(%s) : [%s]' % (str(attrlist
), str(e
)))
731 def cache_check(self
, attrlist
, value
, refresh
=False):
732 return self
._cache
_check
('link', attrlist
, value
, refresh
=refresh
)
734 def _cache_check(self
, t
, attrlist
, value
, refresh
=False):
736 return self
._cache
_get
(t
, attrlist
, refresh
) == value
738 self
.logger
.debug('_cache_check(%s) : [%s]'
739 % (str(attrlist
), str(e
)))
742 def cache_update(self
, attrlist
, value
):
743 return self
._cache
_update
(attrlist
, value
)
746 def _cache_update(attrlist
, value
):
747 if ifupdownflags
.flags
.DRYRUN
:
750 if attrlist
[-1] == 'slaves':
751 linkCache
.append_to_attrlist(attrlist
, value
)
753 linkCache
.set_attr(attrlist
, value
)
758 def _cache_delete(attrlist
, value
=None):
759 if ifupdownflags
.flags
.DRYRUN
:
763 linkCache
.remove_from_attrlist(attrlist
, value
)
765 linkCache
.del_attr(attrlist
)
770 def _cache_invalidate():
771 linkCache
.invalidate()
772 LinkUtils
._CACHE
_FILL
_DONE
= False
776 LinkUtils
.ipbatcbuf
= ''
777 LinkUtils
.ipbatch
= True
778 LinkUtils
.ipbatch_pause
= False
781 def add_to_batch(cmd
):
782 LinkUtils
.ipbatchbuf
+= cmd
+ '\n'
786 LinkUtils
.ipbatch_pause
= True
790 LinkUtils
.ipbatch_pause
= False
792 def batch_commit(self
):
793 if not LinkUtils
.ipbatchbuf
:
794 LinkUtils
.ipbatchbuf
= ''
795 LinkUtils
.ipbatch
= False
796 LinkUtils
.ipbatch_pause
= False
799 utils
.exec_command('%s -force -batch -' % utils
.ip_cmd
,
800 stdin
=self
.ipbatchbuf
)
804 LinkUtils
.ipbatchbuf
= ''
805 LinkUtils
.ipbatch
= False
806 LinkUtils
.ipbatch_pause
= False
808 def bridge_batch_commit(self
):
809 if not LinkUtils
.ipbatchbuf
:
810 LinkUtils
.ipbatchbuf
= ''
811 LinkUtils
.ipbatch
= False
812 LinkUtils
.ipbatch_pause
= False
815 utils
.exec_command('%s -force -batch -'
816 % utils
.bridge_cmd
, stdin
=self
.ipbatchbuf
)
820 LinkUtils
.ipbatchbuf
= ''
821 LinkUtils
.ipbatch
= False
822 LinkUtils
.ipbatch_pause
= False
824 def addr_show(self
, ifacename
=None):
826 if not self
.link_exists(ifacename
):
828 return utils
.exec_commandl([utils
.ip_cmd
,
829 '-o', 'addr', 'show', 'dev', ifacename
])
831 return utils
.exec_commandl([utils
.ip_cmd
,
832 '-o', 'addr', 'show'])
835 def link_show(ifacename
=None):
837 return utils
.exec_commandl([utils
.ip_cmd
,
838 '-o', '-d', 'link', 'show', 'dev', ifacename
])
840 return utils
.exec_commandl([utils
.ip_cmd
,
841 '-o', '-d', 'link', 'show'])
843 def addr_add(self
, ifacename
, address
, broadcast
=None,
844 peer
=None, scope
=None, preferred_lifetime
=None, metric
=None):
847 cmd
= 'addr add %s' % address
849 cmd
+= ' broadcast %s' % broadcast
851 cmd
+= ' peer %s' % peer
853 cmd
+= ' scope %s' % scope
854 if preferred_lifetime
:
855 cmd
+= ' preferred_lft %s' % preferred_lifetime
856 cmd
+= ' dev %s' % ifacename
859 cmd
+= ' metric %s' % metric
861 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
862 self
.add_to_batch(cmd
)
864 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
865 self
._cache
_update
([ifacename
, 'addrs', address
], {})
867 def addr_del(self
, ifacename
, address
, broadcast
=None,
868 peer
=None, scope
=None):
869 """ Delete ipv4 address """
872 if not self
._cache
_get
('addr', [ifacename
, 'addrs', address
]):
874 cmd
= 'addr del %s' % address
876 cmd
+= 'broadcast %s' % broadcast
878 cmd
+= 'peer %s' % peer
880 cmd
+= 'scope %s' % scope
881 cmd
+= ' dev %s' % ifacename
882 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
883 self
._cache
_delete
([ifacename
, 'addrs', address
])
885 def addr_flush(self
, ifacename
):
886 cmd
= 'addr flush dev %s' % ifacename
887 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
888 self
.add_to_batch(cmd
)
890 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
891 self
._cache
_delete
([ifacename
, 'addrs'])
893 def del_addr_all(self
, ifacename
, skip_addrs
=[]):
896 runningaddrsdict
= self
.get_running_addrs(ifname
=ifacename
)
898 # XXX: ignore errors. Fix this to delete secondary addresses
900 [self
.addr_del(ifacename
, a
) for a
in
901 set(runningaddrsdict
.keys()).difference(skip_addrs
)]
906 def addr_get(self
, ifacename
, details
=True, refresh
=False):
907 addrs
= self
._cache
_get
('addr', [ifacename
, 'addrs'], refresh
=refresh
)
914 def get_running_addrs(self
, ifaceobj
=None, ifname
=None, details
=True, addr_virtual_ifaceobj
=None):
916 We now support addr with link scope. Since the kernel may add it's
917 own link address to some interfaces we need to filter them out and
918 make sure we only deal with the addresses set by ifupdown2.
920 To do so we look at the previous configuration made by ifupdown2
921 (with the help of the statemanager) together with the addresses
922 specified by the user in /etc/network/interfaces, these addresses
923 are then compared to the running state of the intf (ip addr show)
924 made via a netlink addr dump.
925 For each configured addresses of scope link, we check if it was
926 previously configured by ifupdown2 to create a final set of the
927 addresses watched by ifupdown2
929 if not ifaceobj
and not ifname
:
935 interface_name
= ifaceobj
.name
937 interface_name
= ifname
939 if addr_virtual_ifaceobj
:
940 for attr_name
in ["address-virtual", "vrrp"]:
941 for virtual
in addr_virtual_ifaceobj
.get_attr_value(attr_name
) or []:
942 for ip
in virtual
.split():
949 saved_ifaceobjs
= statemanager
.statemanager_api
.get_ifaceobjs(addr_virtual_ifaceobj
.name
)
950 for saved_ifaceobj
in saved_ifaceobjs
or []:
951 for virtual
in saved_ifaceobj
.get_attr_value(attr_name
) or []:
952 for ip
in virtual
.split():
960 for addr
in ifaceobj
.get_attr_value('address') or []:
961 config_addrs
.add(addr
)
963 saved_ifaceobjs
= statemanager
.statemanager_api
.get_ifaceobjs(interface_name
)
964 for saved_ifaceobj
in saved_ifaceobjs
or []:
965 for addr
in saved_ifaceobj
.get_attr_value('address') or []:
966 config_addrs
.add(addr
)
968 running_addrs
= OrderedDict()
969 cached_addrs
= self
.addr_get(interface_name
)
971 for addr
, addr_details
in cached_addrs
.items():
973 scope
= int(addr_details
['scope'])
977 addr_obj
= IPNetwork(addr
)
978 if isinstance(addr_obj
, IPv6Network
):
979 d
['family'] = 'inet6'
982 running_addrs
[addr
] = d
984 running_addrs
[addr
] = {}
986 if (scope
& Route
.RT_SCOPE_LINK
and addr
in config_addrs
) or not scope
& Route
.RT_SCOPE_LINK
:
987 running_addrs
[addr
] = addr_details
993 return running_addrs
.keys()
996 def compare_user_config_vs_running_state(running_addrs
, user_addrs
):
1000 for ip
in user_addrs
or []:
1003 if type(obj
) == IPv6Network
:
1009 for ip
in running_addrs
or []:
1010 running_ipobj
.append(IPNetwork(ip
))
1012 return running_ipobj
== (ip4
+ ip6
)
1014 def addr_add_multiple(self
, ifaceobj
, ifacename
, addrs
, purge_existing
=False, metric
=None):
1017 # if perfmode is not set and also if iface has no sibling
1018 # objects, purge addresses that are not present in the new
1020 runningaddrs
= self
.get_running_addrs(
1023 addr_virtual_ifaceobj
=ifaceobj
1025 addrs
= utils
.get_normalized_ip_addr(ifacename
, addrs
)
1027 if self
.compare_user_config_vs_running_state(runningaddrs
, addrs
):
1030 # if primary address is not same, there is no need to keep any.
1031 # reset all addresses
1032 if (addrs
and runningaddrs
and
1033 (addrs
[0] != runningaddrs
[0])):
1034 self
.del_addr_all(ifacename
)
1036 self
.del_addr_all(ifacename
, addrs
)
1037 except Exception, e
:
1038 self
.logger
.warning('%s: %s' % (ifacename
, str(e
)))
1041 self
.addr_add(ifacename
, a
, metric
=metric
)
1042 except Exception, e
:
1043 self
.logger
.error(str(e
))
1045 def _link_set_ifflag(self
, ifacename
, value
):
1046 # Dont look at the cache, the cache may have stale value
1047 # because link status can be changed by external
1048 # entity (One such entity is ifupdown main program)
1049 cmd
= 'link set dev %s %s' % (ifacename
, value
.lower())
1050 if LinkUtils
.ipbatch
:
1051 self
.add_to_batch(cmd
)
1053 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1055 def link_up(self
, ifacename
):
1056 self
._link
_set
_ifflag
(ifacename
, 'UP')
1058 def link_down(self
, ifacename
):
1059 self
._link
_set
_ifflag
(ifacename
, 'DOWN')
1061 def link_set(self
, ifacename
, key
, value
=None,
1062 force
=False, t
=None, state
=None):
1064 if (key
not in ['master', 'nomaster'] and
1065 self
._cache
_check
('link', [ifacename
, key
], value
)):
1067 cmd
= 'link set dev %s' % ifacename
1069 cmd
+= ' type %s' % t
1072 cmd
+= ' %s' % value
1074 cmd
+= ' %s' % state
1075 if LinkUtils
.ipbatch
:
1076 self
.add_to_batch(cmd
)
1078 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1079 if key
not in ['master', 'nomaster']:
1080 self
._cache
_update
([ifacename
, key
], value
)
1082 def link_set_hwaddress(self
, ifacename
, hwaddress
, force
=False):
1084 if self
._cache
_check
('link', [ifacename
, 'hwaddress'], hwaddress
):
1086 self
.link_down(ifacename
)
1087 cmd
= 'link set dev %s address %s' % (ifacename
, hwaddress
)
1088 if LinkUtils
.ipbatch
:
1089 self
.add_to_batch(cmd
)
1091 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1092 self
.link_up(ifacename
)
1093 self
._cache
_update
([ifacename
, 'hwaddress'], hwaddress
)
1095 def link_set_mtu(self
, ifacename
, mtu
):
1096 if ifupdownflags
.flags
.DRYRUN
:
1098 if not mtu
or not ifacename
: return
1099 self
.write_file('/sys/class/net/%s/mtu' % ifacename
, mtu
)
1100 self
._cache
_update
([ifacename
, 'mtu'], mtu
)
1102 def link_set_alias(self
, ifacename
, alias
):
1103 self
.write_file('/sys/class/net/%s/ifalias' % ifacename
,
1104 '\n' if not alias
else alias
)
1106 def link_get_alias(self
, ifacename
):
1107 return self
.read_file_oneline('/sys/class/net/%s/ifalias'
1110 def link_isloopback(self
, ifacename
):
1111 flags
= self
._cache
_get
('link', [ifacename
, 'flags'])
1114 if 'LOOPBACK' in flags
:
1118 def link_get_status(self
, ifacename
):
1119 return self
._cache
_get
('link', [ifacename
, 'ifflag'], refresh
=True)
1122 def route_add_gateway(ifacename
, gateway
, vrf
=None, metric
=None, onlink
=True):
1126 cmd
= '%s route add default via %s proto kernel' % (utils
.ip_cmd
,
1129 cmd
= ('%s route add table %s default via %s proto kernel' %
1130 (utils
.ip_cmd
, vrf
, gateway
))
1133 cmd
+= 'metric %s' % metric
1134 cmd
+= ' dev %s' % ifacename
1139 utils
.exec_command(cmd
)
1142 def route_del_gateway(ifacename
, gateway
, vrf
=None, metric
=None):
1147 cmd
= ('%s route del default via %s proto kernel' %
1148 (utils
.ip_cmd
, gateway
))
1150 cmd
= ('%s route del table %s default via %s proto kernel' %
1151 (utils
.ip_cmd
, vrf
, gateway
))
1153 cmd
+= ' metric %s' % metric
1154 cmd
+= ' dev %s' % ifacename
1155 utils
.exec_command(cmd
)
1158 def _get_vrf_id(ifacename
):
1160 return linkCache
.vrfs
[ifacename
]['table']
1162 dump
= netlink
.link_dump(ifacename
)
1164 [linkCache
.update_attrdict([ifname
], linkattrs
)
1165 for ifname
, linkattrs
in dump
.items()]
1167 if dump
and dump
.get(ifacename
, {}).get('kind') == 'vrf':
1168 vrf_table
= dump
.get(ifacename
, {}).get('linkinfo', {}).get('table')
1169 linkCache
.vrfs
[ifacename
] = {'table': vrf_table
}
1174 def fix_ipv6_route_metric(self
, ifaceobj
, macvlan_ifacename
, ips
):
1177 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
:
1179 for upper_iface
in ifaceobj
.upperifaces
:
1180 vrf_table
= self
._get
_vrf
_id
(upper_iface
)
1188 ip_network_obj
= IPNetwork(ip
)
1190 if type(ip_network_obj
) == IPv6Network
:
1191 route_prefix
= '%s/%d' % (ip_network_obj
.network
, ip_network_obj
.prefixlen
)
1194 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1195 LinkUtils
.add_to_batch('route del %s table %s dev %s' % (route_prefix
, vrf_table
, macvlan_ifacename
))
1197 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'del', route_prefix
, 'table', vrf_table
, 'dev', macvlan_ifacename
])
1199 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1200 LinkUtils
.add_to_batch('route del %s dev %s' % (route_prefix
, macvlan_ifacename
))
1202 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'del', route_prefix
, 'dev', macvlan_ifacename
])
1203 ip_route_del
.append((route_prefix
, vrf_table
))
1205 for ip
, vrf_table
in ip_route_del
:
1207 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1208 LinkUtils
.add_to_batch('route add %s table %s dev %s proto kernel metric 9999' % (ip
, vrf_table
, macvlan_ifacename
))
1210 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'add', ip
, 'table', vrf_table
, 'dev', macvlan_ifacename
, 'proto', 'kernel' 'metric', '9999'])
1212 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1213 LinkUtils
.add_to_batch('route add %s dev %s proto kernel metric 9999' % (ip
, macvlan_ifacename
))
1215 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'add', ip
, 'dev', macvlan_ifacename
, 'proto', 'kernel' 'metric', '9999'])
1217 def link_create_vlan(self
, vlan_device_name
, vlan_raw_device
, vlanid
):
1218 if self
.link_exists(vlan_device_name
):
1220 utils
.exec_command('%s link add link %s name %s type vlan id %d' %
1222 vlan_raw_device
, vlan_device_name
, vlanid
))
1223 self
._cache
_update
([vlan_device_name
], {})
1225 def link_create_vlan_from_name(self
, vlan_device_name
):
1226 v
= vlan_device_name
.split('.')
1228 self
.logger
.warn('invalid vlan device name %s' % vlan_device_name
)
1230 self
.link_create_vlan(vlan_device_name
, v
[0], v
[1])
1232 def link_create_macvlan(self
, name
, linkdev
, mode
='private'):
1233 if self
.link_exists(name
):
1235 cmd
= ('link add link %s' % linkdev
+
1237 ' type macvlan mode %s' % mode
)
1238 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1239 self
.add_to_batch(cmd
)
1241 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1242 self
._cache
_update
([name
], {})
1244 def get_vxlan_peers(self
, dev
, svcnodeip
):
1245 cmd
= '%s fdb show brport %s' % (utils
.bridge_cmd
,
1249 ps
= subprocess
.Popen(shlex
.split(cmd
), stdout
=subprocess
.PIPE
, close_fds
=False)
1250 utils
.enable_subprocess_signal_forwarding(ps
, signal
.SIGINT
)
1251 output
= subprocess
.check_output(('grep', '00:00:00:00:00:00'), stdin
=ps
.stdout
)
1253 utils
.disable_subprocess_signal_forwarding(signal
.SIGINT
)
1255 ppat
= re
.compile('\s+dst\s+(\d+.\d+.\d+.\d+)\s+')
1256 for l
in output
.split('\n'):
1258 if m
and m
.group(1) != svcnodeip
:
1259 cur_peers
.append(m
.group(1))
1261 self
.logger
.warn('error parsing ip link output')
1262 except subprocess
.CalledProcessError
as e
:
1263 if e
.returncode
!= 1:
1264 self
.logger
.error(str(e
))
1266 utils
.disable_subprocess_signal_forwarding(signal
.SIGINT
)
1270 def tunnel_create(self
, tunnelname
, mode
, attrs
={}):
1271 """ generic link_create function """
1272 if self
.link_exists(tunnelname
):
1279 if mode
in ['gretap']:
1280 cmd
+= 'link add %s type %s' % (tunnelname
, mode
)
1282 cmd
+= 'tunnel add %s mode %s' % (tunnelname
, mode
)
1285 for k
, v
in attrs
.iteritems():
1289 if self
.ipbatch
and not self
.ipbatch_pause
:
1290 self
.add_to_batch(cmd
)
1292 utils
.exec_command('ip %s' % cmd
)
1293 self
._cache
_update
([tunnelname
], {})
1295 def tunnel_change(self
, tunnelname
, attrs
={}):
1296 """ tunnel change function """
1297 if not self
.link_exists(tunnelname
):
1299 cmd
= 'tunnel change'
1300 cmd
+= ' %s' %(tunnelname)
1302 for k
, v
in attrs
.iteritems():
1306 if self
.ipbatch
and not self
.ipbatch_pause
:
1307 self
.add_to_batch(cmd
)
1309 utils
.exec_command('ip %s' % cmd
)
1311 def link_create_vxlan(self
, name
, vxlanid
,
1319 if svcnodeip
and remoteips
:
1320 raise Exception("svcnodeip and remoteip is mutually exclusive")
1323 args
+= ' remote %s' % svcnodeip
1325 args
+= ' ageing %s' % ageing
1326 if learning
== 'off':
1327 args
+= ' nolearning'
1329 args
+= ' ttl %s' % ttl
1331 if self
.link_exists(name
):
1332 cmd
= 'link set dev %s type vxlan dstport %d' % (name
, LinkUtils
.VXLAN_UDP_PORT
)
1333 vxlanattrs
= self
.get_vxlandev_attrs(name
)
1334 # on ifreload do not overwrite anycast_ip to individual ip if clagd
1337 running_localtunnelip
= vxlanattrs
.get('local')
1338 if anycastip
and running_localtunnelip
and anycastip
== running_localtunnelip
:
1339 localtunnelip
= running_localtunnelip
1340 running_svcnode
= vxlanattrs
.get('svcnode')
1341 if running_svcnode
and not svcnodeip
:
1344 cmd
= 'link add dev %s type vxlan id %s dstport %d' % (name
, vxlanid
, LinkUtils
.VXLAN_UDP_PORT
)
1347 args
+= ' local %s' % localtunnelip
1350 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1351 self
.add_to_batch(cmd
)
1353 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1355 # XXX: update linkinfo correctly
1356 #self._cache_update([name], {})
1359 def link_exists(ifacename
):
1360 if ifupdownflags
.flags
.DRYRUN
:
1362 return os
.path
.exists('/sys/class/net/%s' % ifacename
)
1365 def link_exists_nodryrun(ifname
):
1366 return os
.path
.exists('/sys/class/net/%s' % ifname
)
1368 def link_get_ifindex(self
, ifacename
):
1369 if ifupdownflags
.flags
.DRYRUN
:
1371 return self
.read_file_oneline('/sys/class/net/%s/ifindex' % ifacename
)
1373 def is_vlan_device_by_name(self
, ifacename
):
1374 if re
.search(r
'\.', ifacename
):
1379 def link_add_macvlan(ifname
, macvlan_ifacename
, mode
):
1380 utils
.exec_commandl(['ip', 'link', 'add', 'link', ifname
, 'name', macvlan_ifacename
, 'type', 'macvlan', 'mode', mode
])
1383 def link_add_xfrm(ifname
, xfrm_name
, xfrm_id
):
1384 utils
.exec_commandl(['ip', 'link', 'add', xfrm_name
, 'type', 'xfrm', 'dev', ifname
, 'if_id', xfrm_id
])
1387 def route_add(route
):
1388 utils
.exec_command('%s route add %s' % (utils
.ip_cmd
,
1392 def route6_add(route
):
1393 utils
.exec_command('%s -6 route add %s' % (utils
.ip_cmd
,
1396 def get_vlandev_attrs(self
, ifacename
):
1397 return (self
._cache
_get
('link', [ifacename
, 'link']),
1398 self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlanid']),
1399 self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlan_protocol']))
1401 def get_vlan_protocol(self
, ifacename
):
1402 return self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlan_protocol'])
1404 def get_vxlandev_attrs(self
, ifacename
):
1405 return self
._cache
_get
('link', [ifacename
, 'linkinfo'])
1407 def get_vxlandev_learning(self
, ifacename
):
1408 return self
._cache
_get
('link', [ifacename
, 'linkinfo', Link
.IFLA_VXLAN_LEARNING
])
1410 def set_vxlandev_learning(self
, ifacename
, learn
):
1412 utils
.exec_command('%s link set dev %s type vxlan learning' %
1413 (utils
.ip_cmd
, ifacename
))
1414 self
._cache
_update
([ifacename
, 'linkinfo', 'learning'], 'on')
1416 utils
.exec_command('%s link set dev %s type vxlan nolearning' %
1417 (utils
.ip_cmd
, ifacename
))
1418 self
._cache
_update
([ifacename
, 'linkinfo', 'learning'], 'off')
1420 def link_get_linkinfo_attrs(self
, ifacename
):
1421 return self
._cache
_get
('link', [ifacename
, 'linkinfo'])
1423 def link_get_mtu(self
, ifacename
, refresh
=False):
1424 return self
._cache
_get
('link', [ifacename
, 'mtu'], refresh
=refresh
)
1426 def link_get_mtu_sysfs(self
, ifacename
):
1427 return self
.read_file_oneline('/sys/class/net/%s/mtu'
1430 def link_get_kind(self
, ifacename
):
1431 return self
._cache
_get
('link', [ifacename
, 'kind'])
1433 def link_get_slave_kind(self
, ifacename
):
1434 return self
._cache
_get
('link', [ifacename
, 'slave_kind'])
1436 def link_get_hwaddress(self
, ifacename
):
1437 address
= self
._cache
_get
('link', [ifacename
, 'hwaddress'])
1438 # newly created logical interface addresses dont end up in the cache
1439 # read hwaddress from sysfs file for these interfaces
1441 address
= self
.read_file_oneline('/sys/class/net/%s/address'
1445 def link_create(self
, ifacename
, t
, attrs
={}):
1446 """ generic link_create function """
1447 if self
.link_exists(ifacename
):
1450 cmd
+= ' name %s type %s' % (ifacename
, t
)
1452 for k
, v
in attrs
.iteritems():
1456 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1457 self
.add_to_batch(cmd
)
1459 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1460 self
._cache
_update
([ifacename
], {})
1462 def link_delete(self
, ifacename
):
1463 if not self
.link_exists(ifacename
):
1465 cmd
= 'link del %s' % ifacename
1466 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1467 self
.add_to_batch(cmd
)
1469 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1470 self
._cache
_invalidate
()
1472 def link_get_master(self
, ifacename
):
1473 sysfs_master_path
= '/sys/class/net/%s/master' % ifacename
1474 if os
.path
.exists(sysfs_master_path
):
1475 link_path
= os
.readlink(sysfs_master_path
)
1477 return os
.path
.basename(link_path
)
1481 return self
._cache
_get
('link', [ifacename
, 'master'])
1483 def get_brport_peer_link(self
, bridgename
):
1485 return self
._cache
_get
('link', [bridgename
, 'info_slave_data', Link
.IFLA_BRPORT_PEER_LINK
])
1490 def bridge_port_vids_add(bridgeportname
, vids
):
1491 [utils
.exec_command('%s vlan add vid %s dev %s' %
1493 v
, bridgeportname
)) for v
in vids
]
1496 def bridge_port_vids_del(bridgeportname
, vids
):
1499 [utils
.exec_command('%s vlan del vid %s dev %s' %
1501 v
, bridgeportname
)) for v
in vids
]
1504 def bridge_port_vids_flush(bridgeportname
, vid
):
1505 utils
.exec_command('%s vlan del vid %s dev %s' %
1507 vid
, bridgeportname
))
1510 def bridge_port_vids_get(bridgeportname
):
1511 bridgeout
= utils
.exec_command('%s vlan show dev %s' %
1516 brvlanlines
= bridgeout
.readlines()[2:]
1517 vids
= [l
.strip() for l
in brvlanlines
]
1518 return [v
for v
in vids
if v
]
1521 def bridge_port_vids_get_all():
1523 bridgeout
= utils
.exec_command('%s -c vlan show'
1527 brvlanlines
= bridgeout
.splitlines()
1529 for l
in brvlanlines
[1:]:
1530 if l
and not l
.startswith(' ') and not l
.startswith('\t'):
1532 brportname
= attrs
[0].strip()
1533 brvlaninfo
[brportname
] = {'pvid': None, 'vlan': []}
1534 l
= ' '.join(attrs
[1:])
1535 if not brportname
or not l
:
1539 brvlaninfo
[brportname
]['pvid'] = l
.split()[0]
1540 elif 'Egress Untagged' not in l
:
1541 brvlaninfo
[brportname
]['vlan'].append(l
)
1544 def bridge_port_vids_get_all_json(self
):
1545 if not self
.supported_command
['%s -c -json vlan show'
1546 % utils
.bridge_cmd
]:
1550 bridgeout
= utils
.exec_command('%s -c -json vlan show'
1553 self
.supported_command
['%s -c -json vlan show'
1554 % utils
.bridge_cmd
] = False
1555 self
.logger
.info('%s -c -json vlan show: skipping unsupported command'
1558 return self
.get_bridge_vlan_nojson()
1559 except Exception as e
:
1560 self
.logger
.info('bridge: get_bridge_vlan_nojson: %s' % str(e
))
1563 if not bridgeout
: return brvlaninfo
1565 vlan_json
= json
.loads(bridgeout
, encoding
="utf-8")
1566 except Exception, e
:
1567 self
.logger
.info('json loads failed with (%s)' % str(e
))
1571 if isinstance(vlan_json
, list):
1572 # newer iproute2 version changed the bridge vlan show output
1573 # ifupdown2 relies on the previous format, we have the convert
1574 # data into old format
1575 bridge_port_vids
= dict()
1577 for intf
in vlan_json
:
1578 bridge_port_vids
[intf
["ifname"]] = intf
["vlans"]
1580 return bridge_port_vids
1582 # older iproute2 version have different ways to dump vlans
1583 # ifupdown2 prefers the following syntax:
1587 # "flags": ["PVID", "Egress Untagged"]
1592 # "flags": ["PVID", "Egress Untagged"]
1596 except Exception as e
:
1597 self
.logger
.debug("bridge vlan show: Unknown json output: %s" % str(e
))
1601 def get_bridge_vlan_nojson():
1603 bridgeout
= utils
.exec_commandl([utils
.bridge_cmd
, '-c', 'vlan', 'show'])
1605 output
= [line
.split('\n') for line
in bridgeout
.split('\n\n')]
1606 output
[0] = output
[0][1:]
1614 prefix
, vlan
= entry
.split('\t')
1616 current_swp
= prefix
1617 vlan_json
[prefix
] = []
1621 v
['vlan'] = int(vlan
)
1625 start
, end
= vlan
.split('-')
1627 end
= end
[0:end
.index(' ')]
1628 v
['vlan'] = int(start
)
1629 v
['vlanEnd'] = int(end
)
1631 v
['vlan'] = int(vlan
[0:vlan
.index(' ')])
1634 flags
.append('PVID')
1635 if 'Egress Untagged' in vlan
:
1636 flags
.append('Egress Untagged')
1640 vlan_json
[current_swp
].append(v
)
1643 def bridge_vlan_cache_get(self
, ifacename
, refresh
=False):
1644 if not self
.bridge_vlan_cache_fill_done
or refresh
:
1645 self
.bridge_vlan_cache
= self
.bridge_port_vids_get_all_json()
1646 self
.bridge_vlan_cache_fill_done
= True
1647 return self
.bridge_vlan_cache
.get(ifacename
, {})
1649 def bridge_vlan_get_pvid(self
, ifacename
, refresh
=False):
1652 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1653 v
= vinfo
.get('vlan')
1654 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1659 def bridge_vlan_get_vids(self
, ifacename
, refresh
=False):
1662 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1663 v
= vinfo
.get('vlan')
1664 ispvid
= True if 'PVID' in vinfo
.get('flags', []) else False
1666 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1669 vEnd
= vinfo
.get('vlanEnd')
1671 vids
.extend(range(v
, vEnd
+ 1))
1676 def bridge_vlan_get_vids_n_pvid(self
, ifacename
, refresh
=False):
1680 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1681 v
= vinfo
.get('vlan')
1682 ispvid
= True if 'PVID' in vinfo
.get('flags', []) else False
1684 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1685 vEnd
= vinfo
.get('vlanEnd')
1687 vids
.extend(range(v
, vEnd
+ 1))
1692 def bridge_port_pvid_add(self
, bridgeportname
, pvid
):
1693 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1694 self
.add_to_batch('vlan add vid %s untagged pvid dev %s' %
1695 (pvid
, bridgeportname
))
1697 utils
.exec_command('%s vlan add vid %s untagged pvid dev %s' %
1699 pvid
, bridgeportname
))
1701 def bridge_port_pvid_del(self
, bridgeportname
, pvid
):
1702 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1703 self
.add_to_batch('vlan del vid %s untagged pvid dev %s' %
1704 (pvid
, bridgeportname
))
1706 utils
.exec_command('%s vlan del vid %s untagged pvid dev %s' %
1708 pvid
, bridgeportname
))
1710 def bridge_port_pvids_get(self
, bridgeportname
):
1711 return self
.read_file_oneline('/sys/class/net/%s/brport/pvid'
1714 def bridge_vids_add(self
, bridgeportname
, vids
, bridge
=True):
1715 target
= 'self' if bridge
else ''
1716 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1717 [self
.add_to_batch('vlan add vid %s dev %s %s' %
1718 (v
, bridgeportname
, target
)) for v
in vids
]
1720 [utils
.exec_command('%s vlan add vid %s dev %s %s' %
1722 v
, bridgeportname
, target
)) for v
in vids
]
1724 def bridge_vids_del(self
, bridgeportname
, vids
, bridge
=True):
1725 target
= 'self' if bridge
else ''
1726 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1727 [self
.add_to_batch('vlan del vid %s dev %s %s' %
1728 (v
, bridgeportname
, target
)) for v
in vids
]
1730 [utils
.exec_command('%s vlan del vid %s dev %s %s' %
1732 v
, bridgeportname
, target
)) for v
in vids
]
1735 def bridge_fdb_add(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1736 target
= 'self' if bridge
else ''
1739 vlan_str
= 'vlan %s ' % vlan
1743 dst_str
= 'dst %s ' % remote
1745 utils
.exec_command('%s fdb replace %s dev %s %s %s %s' %
1747 address
, dev
, vlan_str
, target
, dst_str
))
1750 def bridge_fdb_append(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1751 target
= 'self' if bridge
else ''
1754 vlan_str
= 'vlan %s ' % vlan
1758 dst_str
= 'dst %s ' % remote
1760 utils
.exec_command('%s fdb append %s dev %s %s %s %s' %
1762 address
, dev
, vlan_str
, target
, dst_str
))
1765 def bridge_fdb_del(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1766 target
= 'self' if bridge
else ''
1769 vlan_str
= 'vlan %s ' % vlan
1773 dst_str
= 'dst %s ' % remote
1774 utils
.exec_command('%s fdb del %s dev %s %s %s %s' %
1776 address
, dev
, vlan_str
, target
, dst_str
))
1778 def bridge_is_vlan_aware(self
, bridgename
):
1779 filename
= '/sys/class/net/%s/bridge/vlan_filtering' % bridgename
1780 if os
.path
.exists(filename
) and self
.read_file_oneline(filename
) == '1':
1785 def bridge_port_get_bridge_name(bridgeport
):
1786 filename
= '/sys/class/net/%s/brport/bridge' % bridgeport
1788 return os
.path
.basename(os
.readlink(filename
))
1793 def bridge_port_exists(bridge
, bridgeportname
):
1795 return os
.path
.exists('/sys/class/net/%s/brif/%s'
1796 % (bridge
, bridgeportname
))
1800 def bridge_fdb_show_dev(self
, dev
):
1803 output
= utils
.exec_command('%s fdb show dev %s'
1804 % (utils
.bridge_cmd
, dev
))
1806 for fdb_entry
in output
.splitlines():
1808 entries
= fdb_entry
.split()
1809 fdbs
.setdefault(entries
[2], []).append(entries
[0])
1811 self
.logger
.debug('%s: invalid fdb line \'%s\''
1818 def is_bridge(bridge
):
1819 return os
.path
.exists('/sys/class/net/%s/bridge' % bridge
)
1821 def is_link_up(self
, ifacename
):
1824 flags
= self
.read_file_oneline('/sys/class/net/%s/flags' % ifacename
)
1825 iflags
= int(flags
, 16)
1832 def ip_route_get_dev(self
, prefix
, vrf_master
=None):
1835 cmd
= '%s route get %s vrf %s' % (utils
.ip_cmd
, prefix
, vrf_master
)
1837 cmd
= '%s route get %s' % (utils
.ip_cmd
, prefix
)
1839 output
= utils
.exec_command(cmd
)
1841 rline
= output
.splitlines()[0]
1843 rattrs
= rline
.split()
1844 return rattrs
[rattrs
.index('dev') + 1]
1845 except Exception, e
:
1846 self
.logger
.debug('ip_route_get_dev: failed .. %s' % str(e
))
1850 def link_get_lowers(ifacename
):
1852 lowers
= glob
.glob("/sys/class/net/%s/lower_*" % ifacename
)
1855 return [os
.path
.basename(l
)[6:] for l
in lowers
]
1860 def link_get_uppers(ifacename
):
1862 uppers
= glob
.glob("/sys/class/net/%s/upper_*" % ifacename
)
1865 return [os
.path
.basename(u
)[6:] for u
in uppers
]
1869 def link_get_vrfs(self
):
1870 if not LinkUtils
._CACHE
_FILL
_DONE
:
1872 return linkCache
.vrfs
1875 def cache_get_info_slave(attrlist
):
1877 return linkCache
.get_attr(attrlist
)
1881 def get_brport_learning(self
, ifacename
):
1882 learn
= self
.read_file_oneline('/sys/class/net/%s/brport/learning'
1884 if learn
and learn
== '1':
1889 def get_brport_learning_bool(self
, ifacename
):
1890 return utils
.get_boolean_from_string(self
.read_file_oneline('/sys/class/net/%s/brport/learning' % ifacename
))
1892 def set_brport_learning(self
, ifacename
, learn
):
1894 return self
.write_file('/sys/class/net/%s/brport/learning'
1897 return self
.write_file('/sys/class/net/%s/brport/learning'
1900 #################################################################################
1901 ################################### BOND UTILS ##################################
1902 #################################################################################
1904 def _link_cache_get(self
, attrlist
, refresh
=False):
1905 return self
._cache
_get
('link', attrlist
, refresh
)
1907 def cache_delete(self
, attrlist
, value
=None):
1908 return self
._cache
_delete
(attrlist
, value
)
1910 def link_cache_get(self
, attrlist
, refresh
=False):
1911 return self
._link
_cache
_get
(attrlist
, refresh
)
1913 def link_cache_check(self
, attrlist
, value
, refresh
=False):
1914 return self
._link
_cache
_check
(attrlist
, value
, refresh
)
1916 def _link_cache_check(self
, attrlist
, value
, refresh
=False):
1918 return self
._link
_cache
_get
(attrlist
, refresh
) == value
1919 except Exception, e
:
1920 self
.logger
.debug('_cache_check(%s) : [%s]'
1921 % (str(attrlist
), str(e
)))
1926 Link
.IFLA_BOND_MODE
: 'mode',
1927 Link
.IFLA_BOND_MIIMON
: 'miimon',
1928 Link
.IFLA_BOND_USE_CARRIER
: 'use_carrier',
1929 Link
.IFLA_BOND_AD_LACP_RATE
: 'lacp_rate',
1930 Link
.IFLA_BOND_XMIT_HASH_POLICY
: 'xmit_hash_policy',
1931 Link
.IFLA_BOND_MIN_LINKS
: 'min_links',
1932 Link
.IFLA_BOND_NUM_PEER_NOTIF
: 'num_grat_arp',
1933 Link
.IFLA_BOND_AD_ACTOR_SYSTEM
: 'ad_actor_system',
1934 Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
: 'ad_actor_sys_prio',
1935 Link
.IFLA_BOND_AD_LACP_BYPASS
: 'lacp_bypass',
1936 Link
.IFLA_BOND_UPDELAY
: 'updelay',
1937 Link
.IFLA_BOND_DOWNDELAY
: 'downdelay',
1940 def bond_set_attrs_nl(self
, bondname
, ifla_info_data
):
1941 bond_attr_name
= 'None' # for log purpose (in case an exception raised)
1942 for nl_attr
, value
in ifla_info_data
.items():
1944 bond_attr_name
= self
.bondcmd_attrmap
[nl_attr
]
1945 file_path
= '/sys/class/net/%s/bonding/%s' % (bondname
, bond_attr_name
)
1946 if os
.path
.exists(file_path
):
1947 self
.write_file(file_path
, str(value
))
1948 except Exception as e
:
1949 exception_str
= '%s: %s %s: %s' % (bondname
, bond_attr_name
, value
, str(e
))
1950 if ifupdownflags
.flags
.FORCE
:
1951 self
.logger
.warning(exception_str
)
1953 self
.logger
.debug(exception_str
)
1955 def bond_set_attrs(self
, bondname
, attrdict
, prehook
):
1956 for attrname
, attrval
in attrdict
.items():
1957 if (self
._link
_cache
_check
([bondname
, 'linkinfo',
1958 attrname
], attrval
)):
1960 if (attrname
== 'mode'
1961 or attrname
== 'xmit_hash_policy'
1962 or attrname
== 'lacp_rate' or attrname
== 'min_links'):
1966 if ((attrname
not in ['lacp_rate',
1968 self
._link
_cache
_check
([bondname
, 'linkinfo', 'mode'], '802.3ad',
1970 self
.write_file('/sys/class/net/%s/bonding/%s'
1971 % (bondname
, attrname
), attrval
)
1972 except Exception, e
:
1973 if ifupdownflags
.flags
.FORCE
:
1974 self
.logger
.warn(str(e
))
1979 def bond_set_use_carrier(self
, bondname
, use_carrier
):
1980 if not use_carrier
or (use_carrier
!= '0' and use_carrier
!= '1'):
1982 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'use_carrier'],
1985 self
.write_file('/sys/class/net/%s' % bondname
+
1986 '/bonding/use_carrier', use_carrier
)
1987 self
._cache
_update
([bondname
, 'linkinfo',
1988 'use_carrier'], use_carrier
)
1990 def bond_get_use_carrier(self
, bondname
):
1991 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'use_carrier'])
1993 def bond_get_use_carrier_nl(self
, bondname
):
1994 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_USE_CARRIER
])
1996 def bond_set_xmit_hash_policy(self
, bondname
, hash_policy
, prehook
=None):
1997 valid_values
= ['layer2', 'layer3+4', 'layer2+3']
2000 if hash_policy
not in valid_values
:
2001 raise Exception('invalid hash policy value %s' % hash_policy
)
2002 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'xmit_hash_policy'],
2007 self
.write_file('/sys/class/net/%s' % bondname
+
2008 '/bonding/xmit_hash_policy', hash_policy
)
2009 self
._cache
_update
([bondname
, 'linkinfo', 'xmit_hash_policy'],
2012 def bond_get_xmit_hash_policy(self
, bondname
):
2013 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'xmit_hash_policy'])
2015 def bond_get_xmit_hash_policy_nl(self
, bondname
):
2016 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_XMIT_HASH_POLICY
])
2018 def bond_set_miimon(self
, bondname
, miimon
):
2019 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'miimon'],
2022 self
.write_file('/sys/class/net/%s' % bondname
+
2023 '/bonding/miimon', miimon
)
2024 self
._cache
_update
([bondname
, 'linkinfo', 'miimon'], miimon
)
2026 def bond_get_miimon(self
, bondname
):
2027 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'miimon'])
2029 def bond_get_miimon_nl(self
, bondname
):
2030 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MIIMON
])
2032 def bond_set_mode(self
, bondname
, mode
, prehook
=None):
2033 valid_modes
= ['balance-rr', 'active-backup', 'balance-xor',
2034 'broadcast', '802.3ad', 'balance-tlb', 'balance-alb']
2037 if mode
not in valid_modes
:
2038 raise Exception('invalid mode %s' % mode
)
2039 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'mode'],
2044 self
.write_file('/sys/class/net/%s' % bondname
+ '/bonding/mode', mode
)
2045 self
._cache
_update
([bondname
, 'linkinfo', 'mode'], mode
)
2047 def bond_get_mode(self
, bondname
):
2048 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'mode'])
2050 def bond_get_mode_nl(self
, bondname
):
2051 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MODE
])
2053 def bond_set_lacp_rate(self
, bondname
, lacp_rate
, prehook
=None, posthook
=None):
2054 if not lacp_rate
or (lacp_rate
!= '0' and lacp_rate
!= '1'):
2056 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'lacp_rate'],
2062 self
.write_file('/sys/class/net/%s' % bondname
+
2063 '/bonding/lacp_rate', lacp_rate
)
2069 self
._cache
_update
([bondname
, 'linkinfo',
2070 'lacp_rate'], lacp_rate
)
2072 def bond_get_lacp_rate(self
, bondname
):
2073 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'lacp_rate'])
2075 def bond_get_lacp_rate_nl(self
, bondname
):
2076 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_RATE
])
2078 def bond_set_lacp_bypass_allow(self
, bondname
, allow
, prehook
=None, posthook
=None):
2079 if self
._link
_cache
_check
([bondname
, 'linkinfo', 'lacp_bypass'], allow
):
2084 self
.write_file('/sys/class/net/%s' % bondname
+
2085 '/bonding/lacp_bypass', allow
)
2091 self
._cache
_update
([bondname
, 'linkinfo',
2092 'lacp_bypass'], allow
)
2094 def bond_get_lacp_bypass_allow(self
, bondname
):
2095 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'lacp_bypass'])
2097 def bond_get_lacp_bypass_allow_nl(self
, bondname
):
2098 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_BYPASS
])
2100 def bond_set_min_links(self
, bondname
, min_links
, prehook
=None):
2101 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'min_links'],
2106 self
.write_file('/sys/class/net/%s/bonding/min_links' % bondname
,
2108 self
._cache
_update
([bondname
, 'linkinfo', 'min_links'], min_links
)
2110 def bond_get_min_links(self
, bondname
):
2111 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'min_links'])
2113 def get_min_links_nl(self
, bondname
):
2114 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MIN_LINKS
])
2116 def bond_get_ad_actor_system(self
, bondname
):
2117 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'ad_actor_system'])
2119 def bond_get_ad_actor_system_nl(self
, bondname
):
2120 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYSTEM
])
2122 def bond_get_ad_actor_sys_prio(self
, bondname
):
2123 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'ad_actor_sys_prio'])
2125 def bond_get_ad_actor_sys_prio_nl(self
, bondname
):
2126 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
])
2128 def bond_get_num_unsol_na(self
, bondname
):
2129 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'num_unsol_na'])
2131 def bond_get_num_unsol_na_nl(self
, bondname
):
2132 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
])
2134 def bond_get_num_grat_arp(self
, bondname
):
2135 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'num_grat_arp'])
2137 def bond_get_num_grat_arp_nl(self
, bondname
):
2138 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
])
2140 def bond_get_updelay(self
, bondname
):
2141 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'updelay'])
2143 def bond_get_updelay_nl(self
, bondname
):
2144 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_UPDELAY
])
2146 def bond_get_downdelay(self
, bondname
):
2147 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'downdelay'])
2149 def bond_get_downdelay_nl(self
, bondname
):
2150 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_DOWNDELAY
])
2152 def bond_enslave_slave(self
, bondname
, slave
, prehook
=None, posthook
=None):
2153 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2154 if slaves
and slave
in slaves
:
2158 self
.write_file('/sys/class/net/%s' % bondname
+
2159 '/bonding/slaves', '+' + slave
)
2162 self
._cache
_update
([bondname
, 'linkinfo', 'slaves'], slave
)
2164 def bond_remove_slave(self
, bondname
, slave
):
2165 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2166 if not slaves
or slave
not in slaves
:
2168 sysfs_bond_path
= ('/sys/class/net/%s' % bondname
+
2170 if not os
.path
.exists(sysfs_bond_path
):
2172 self
.write_file(sysfs_bond_path
, '-' + slave
)
2173 self
._cache
_delete
([bondname
, 'linkinfo', 'slaves'], slave
)
2175 def bond_remove_slaves_all(self
, bondname
):
2176 if not self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves']):
2179 sysfs_bond_path
= ('/sys/class/net/%s' % bondname
+
2182 with
open(sysfs_bond_path
, 'r') as f
:
2183 slaves
= f
.readline().strip().split()
2185 raise Exception('error reading slaves of bond %s (%s)' % (bondname
, str(e
)))
2186 for slave
in slaves
:
2187 self
.link_down(slave
)
2189 self
.bond_remove_slave(bondname
, slave
)
2190 except Exception, e
:
2191 if not ifupdownflags
.flags
.FORCE
:
2192 raise Exception('error removing slave %s from bond %s (%s)' % (slave
, bondname
, str(e
)))
2195 self
._cache
_delete
([bondname
, 'linkinfo', 'slaves'])
2198 def bond_load_bonding_module():
2199 return utils
.exec_command('%s -q bonding' % utils
.modprobe_cmd
)
2201 def create_bond(self
, bondname
):
2202 if self
.bond_exists(bondname
):
2204 # load_bonding_module() has already been run
2205 self
.write_file('/sys/class/net/bonding_masters', '+' + bondname
)
2206 self
._cache
_update
([bondname
], {})
2208 def delete_bond(self
, bondname
):
2209 if not os
.path
.exists('/sys/class/net/%s' % bondname
):
2211 self
.write_file('/sys/class/net/bonding_masters', '-' + bondname
)
2212 self
._cache
_delete
([bondname
])
2214 def bond_get_slaves(self
, bondname
):
2215 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2218 slavefile
= '/sys/class/net/%s/bonding/slaves' % bondname
2219 if os
.path
.exists(slavefile
):
2220 buf
= self
.read_file_oneline(slavefile
)
2222 slaves
= buf
.split()
2225 self
._cache
_update
([bondname
, 'linkinfo', 'slaves'], slaves
)
2228 def bond_slave_exists(self
, bond
, slave
):
2229 slaves
= self
.bond_get_slaves(bond
)
2232 return slave
in slaves
2235 def bond_exists(bondname
):
2236 return os
.path
.exists('/sys/class/net/%s/bonding' % bondname
)
2238 #################################################################################
2239 ################################## BRIDGE UTILS #################################
2240 #################################################################################
2242 def create_bridge(self
, bridgename
):
2243 if not LinkUtils
.bridge_utils_is_installed
:
2245 if self
.bridge_exists(bridgename
):
2247 utils
.exec_command('%s addbr %s' % (utils
.brctl_cmd
, bridgename
))
2248 self
._cache
_update
([bridgename
], {})
2250 def delete_bridge(self
, bridgename
):
2251 if not LinkUtils
.bridge_utils_is_installed
:
2253 if not self
.bridge_exists(bridgename
):
2255 utils
.exec_command('%s delbr %s' % (utils
.brctl_cmd
, bridgename
))
2256 self
._cache
_invalidate
()
2258 def add_bridge_port(self
, bridgename
, bridgeportname
):
2259 """ Add port to bridge """
2260 if not LinkUtils
.bridge_utils_is_installed
:
2262 ports
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports'])
2263 if ports
and ports
.get(bridgeportname
):
2265 utils
.exec_command('%s addif %s %s' % (utils
.brctl_cmd
, bridgename
, bridgeportname
))
2266 self
._cache
_update
([bridgename
, 'linkinfo', 'ports', bridgeportname
], {})
2268 def delete_bridge_port(self
, bridgename
, bridgeportname
):
2269 """ Delete port from bridge """
2270 if not LinkUtils
.bridge_utils_is_installed
:
2272 ports
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports'])
2273 if not ports
or not ports
.get(bridgeportname
):
2275 utils
.exec_command('%s delif %s %s' % (utils
.brctl_cmd
, bridgename
, bridgeportname
))
2276 self
._cache
_delete
([bridgename
, 'linkinfo', 'ports', 'bridgeportname'])
2278 def set_bridgeport_attrs(self
, bridgename
, bridgeportname
, attrdict
):
2279 portattrs
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports', bridgeportname
])
2280 if portattrs
== None:
2282 for k
, v
in attrdict
.iteritems():
2283 if ifupdownflags
.flags
.CACHE
:
2284 curval
= portattrs
.get(k
)
2285 if curval
and curval
== v
:
2287 if k
== 'unicast-flood':
2288 self
.write_file('/sys/class/net/%s/brport/unicast_flood' % bridgeportname
, v
)
2289 elif k
== 'multicast-flood':
2290 self
.write_file('/sys/class/net/%s/brport/multicast_flood' % bridgeportname
, v
)
2291 elif k
== 'learning':
2292 self
.write_file('/sys/class/net/%s/brport/learning' % bridgeportname
, v
)
2293 elif k
== 'arp-nd-suppress':
2294 self
.write_file('/sys/class/net/%s/brport/neigh_suppress' % bridgeportname
, v
)
2296 if not LinkUtils
.bridge_utils_is_installed
:
2298 utils
.exec_command('%s set%s %s %s %s' % (utils
.brctl_cmd
, k
, bridgename
, bridgeportname
, v
))
2300 def set_bridgeport_attr(self
, bridgename
, bridgeportname
,
2302 if not LinkUtils
.bridge_utils_is_installed
:
2304 if self
._link
_cache
_check
([bridgename
, 'linkinfo', 'ports', bridgeportname
, attrname
], attrval
):
2306 utils
.exec_command('%s set%s %s %s %s' %
2313 def set_bridge_attrs(self
, bridgename
, attrdict
):
2314 for k
, v
in attrdict
.iteritems():
2317 if self
._link
_cache
_check
([bridgename
, 'linkinfo', k
], v
):
2320 if k
== 'igmp-version':
2321 self
.write_file('/sys/class/net/%s/bridge/'
2322 'multicast_igmp_version' % bridgename
, v
)
2323 elif k
== 'mld-version':
2324 self
.write_file('/sys/class/net/%s/bridge/'
2325 'multicast_mld_version' % bridgename
, v
)
2326 elif k
== 'vlan-protocol':
2327 self
.write_file('/sys/class/net/%s/bridge/'
2328 'vlan_protocol' % bridgename
,
2329 VlanProtocols
.ETHERTYPES_TO_ID
.get(v
.upper(),
2331 elif k
== 'vlan-stats':
2332 self
.write_file('/sys/class/net/%s/bridge/'
2333 'vlan_stats_enabled' % bridgename
, v
)
2334 elif k
== 'mcstats':
2335 self
.write_file('/sys/class/net/%s/bridge/'
2336 'multicast_stats_enabled' % bridgename
, v
)
2338 if not LinkUtils
.bridge_utils_is_installed
:
2340 cmd
= ('%s set%s %s %s' %
2341 (utils
.brctl_cmd
, k
, bridgename
, v
))
2342 utils
.exec_command(cmd
)
2343 except Exception, e
:
2344 self
.logger
.warn('%s: %s' % (bridgename
, str(e
)))
2347 def set_bridge_attr(self
, bridgename
, attrname
, attrval
):
2348 if self
._link
_cache
_check
([bridgename
, 'linkinfo', attrname
], attrval
):
2350 if attrname
== 'igmp-version':
2351 self
.write_file('/sys/class/net/%s/bridge/multicast_igmp_version'
2352 % bridgename
, attrval
)
2353 elif attrname
== 'mld-version':
2354 self
.write_file('/sys/class/net/%s/bridge/multicast_mld_version'
2355 % bridgename
, attrval
)
2356 elif attrname
== 'vlan-protocol':
2357 self
.write_file('/sys/class/net/%s/bridge/vlan_protocol'
2358 % bridgename
, VlanProtocols
.ETHERTYPES_TO_ID
[attrval
.upper()])
2359 elif attrname
== 'vlan-stats':
2360 self
.write_file('/sys/class/net/%s/bridge/vlan_stats_enabled'
2361 % bridgename
, attrval
)
2362 elif attrname
== 'mcstats':
2363 self
.write_file('/sys/class/net/%s/bridge/multicast_stats_enabled'
2364 % bridgename
, attrval
)
2366 if not LinkUtils
.bridge_utils_is_installed
:
2368 cmd
= '%s set%s %s %s' % (utils
.brctl_cmd
,
2369 attrname
, bridgename
, attrval
)
2370 utils
.exec_command(cmd
)
2372 def get_bridge_attrs(self
, bridgename
):
2373 attrs
= self
._link
_cache
_get
([bridgename
, 'linkinfo'])
2375 for key
, value
in attrs
.items():
2376 if type(key
) == str:
2377 no_ints_attrs
[key
] = value
2378 return no_ints_attrs
2380 def get_bridgeport_attrs(self
, bridgename
, bridgeportname
):
2381 return self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports',
2384 def get_bridgeport_attr(self
, bridgename
, bridgeportname
, attrname
):
2385 return self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports',
2386 bridgeportname
, attrname
])
2389 def bridge_set_stp(bridge
, stp_state
):
2390 if not LinkUtils
.bridge_utils_is_installed
:
2392 utils
.exec_command('%s stp %s %s' % (utils
.brctl_cmd
, bridge
, stp_state
))
2394 def bridge_get_stp(self
, bridge
):
2395 sysfs_stpstate
= '/sys/class/net/%s/bridge/stp_state' % bridge
2396 if not os
.path
.exists(sysfs_stpstate
):
2398 stpstate
= self
.read_file_oneline(sysfs_stpstate
)
2402 if int(stpstate
) > 0:
2404 elif int(stpstate
) == 0:
2410 def _conv_value_to_user(s
):
2417 def read_value_from_sysfs(self
, filename
, preprocess_func
):
2418 value
= self
.read_file_oneline(filename
)
2421 return preprocess_func(value
)
2424 def bridge_set_ageing(bridge
, ageing
):
2425 if not LinkUtils
.bridge_utils_is_installed
:
2427 utils
.exec_command('%s setageing %s %s' % (utils
.brctl_cmd
, bridge
, ageing
))
2429 def bridge_get_ageing(self
, bridge
):
2430 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/ageing_time'
2431 % bridge
, self
._conv
_value
_to
_user
)
2434 def set_bridgeprio(bridge
, prio
):
2435 if not LinkUtils
.bridge_utils_is_installed
:
2437 utils
.exec_command('%s setbridgeprio %s %s' % (utils
.brctl_cmd
, bridge
, prio
))
2439 def get_bridgeprio(self
, bridge
):
2440 return self
.read_file_oneline(
2441 '/sys/class/net/%s/bridge/priority' % bridge
)
2444 def bridge_set_fd(bridge
, fd
):
2445 if not LinkUtils
.bridge_utils_is_installed
:
2447 utils
.exec_command('%s setfd %s %s' % (utils
.brctl_cmd
, bridge
, fd
))
2449 def bridge_get_fd(self
, bridge
):
2450 return self
.read_value_from_sysfs(
2451 '/sys/class/net/%s/bridge/forward_delay'
2452 % bridge
, self
._conv
_value
_to
_user
)
2454 def bridge_set_gcint(self
, bridge
, gcint
):
2455 raise Exception('set_gcint not implemented')
2458 def bridge_set_hello(bridge
, hello
):
2459 if not LinkUtils
.bridge_utils_is_installed
:
2461 utils
.exec_command('%s sethello %s %s' % (utils
.brctl_cmd
, bridge
, hello
))
2463 def bridge_get_hello(self
, bridge
):
2464 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/hello_time'
2465 % bridge
, self
._conv
_value
_to
_user
)
2468 def bridge_set_maxage(bridge
, maxage
):
2469 if not LinkUtils
.bridge_utils_is_installed
:
2471 utils
.exec_command('%s setmaxage %s %s' % (utils
.brctl_cmd
, bridge
, maxage
))
2473 def bridge_get_maxage(self
, bridge
):
2474 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/max_age'
2475 % bridge
, self
._conv
_value
_to
_user
)
2478 def bridge_set_pathcost(bridge
, port
, pathcost
):
2479 if not LinkUtils
.bridge_utils_is_installed
:
2481 utils
.exec_command('%s setpathcost %s %s %s' % (utils
.brctl_cmd
, bridge
, port
, pathcost
))
2483 def bridge_get_pathcost(self
, bridge
, port
):
2484 return self
.read_file_oneline('/sys/class/net/%s/brport/path_cost'
2488 def bridge_set_portprio(bridge
, port
, prio
):
2489 if not LinkUtils
.bridge_utils_is_installed
:
2491 utils
.exec_command('%s setportprio %s %s %s' % (utils
.brctl_cmd
, bridge
, port
, prio
))
2493 def bridge_get_portprio(self
, bridge
, port
):
2494 return self
.read_file_oneline('/sys/class/net/%s/brport/priority'
2498 def bridge_set_hashmax(bridge
, hashmax
):
2499 if not LinkUtils
.bridge_utils_is_installed
:
2501 utils
.exec_command('%s sethashmax %s %s' % (utils
.brctl_cmd
, bridge
, hashmax
))
2503 def bridge_get_hashmax(self
, bridge
):
2504 return self
.read_file_oneline('/sys/class/net/%s/bridge/hash_max'
2508 def bridge_set_hashel(bridge
, hashel
):
2509 if not LinkUtils
.bridge_utils_is_installed
:
2511 utils
.exec_command('%s sethashel %s %s' % (utils
.brctl_cmd
, bridge
, hashel
))
2513 def bridge_get_hashel(self
, bridge
):
2514 return self
.read_file_oneline('/sys/class/net/%s/bridge/hash_elasticity'
2518 def bridge_set_mclmc(bridge
, mclmc
):
2519 if not LinkUtils
.bridge_utils_is_installed
:
2521 utils
.exec_command('%s setmclmc %s %s' % (utils
.brctl_cmd
, bridge
, mclmc
))
2523 def bridge_get_mclmc(self
, bridge
):
2524 return self
.read_file_oneline(
2525 '/sys/class/net/%s/bridge/multicast_last_member_count'
2529 def bridge_set_mcrouter(bridge
, mcrouter
):
2530 if not LinkUtils
.bridge_utils_is_installed
:
2532 utils
.exec_command('%s setmcrouter %s %s' % (utils
.brctl_cmd
, bridge
, mcrouter
))
2534 def bridge_get_mcrouter(self
, bridge
):
2535 return self
.read_file_oneline(
2536 '/sys/class/net/%s/bridge/multicast_router' % bridge
)
2539 def bridge_set_mcsnoop(bridge
, mcsnoop
):
2540 if not LinkUtils
.bridge_utils_is_installed
:
2542 utils
.exec_command('%s setmcsnoop %s %s' % (utils
.brctl_cmd
, bridge
, mcsnoop
))
2544 def bridge_get_mcsnoop(self
, bridge
):
2545 return self
.read_file_oneline(
2546 '/sys/class/net/%s/bridge/multicast_snooping' % bridge
)
2549 def bridge_set_mcsqc(bridge
, mcsqc
):
2550 if not LinkUtils
.bridge_utils_is_installed
:
2552 utils
.exec_command('%s setmcsqc %s %s' % (utils
.brctl_cmd
, bridge
, mcsqc
))
2554 def bridge_get_mcsqc(self
, bridge
):
2555 return self
.read_file_oneline(
2556 '/sys/class/net/%s/bridge/multicast_startup_query_count'
2560 def bridge_set_mcqifaddr(bridge
, mcqifaddr
):
2561 if not LinkUtils
.bridge_utils_is_installed
:
2563 utils
.exec_command('%s setmcqifaddr %s %s' % (utils
.brctl_cmd
, bridge
, mcqifaddr
))
2565 def bridge_get_mcqifaddr(self
, bridge
):
2566 return self
.read_file_oneline(
2567 '/sys/class/net/%s/bridge/multicast_startup_query_use_ifaddr'
2571 def bridge_set_mcquerier(bridge
, mcquerier
):
2572 if not LinkUtils
.bridge_utils_is_installed
:
2574 utils
.exec_command('%s setmcquerier %s %s' % (utils
.brctl_cmd
, bridge
, mcquerier
))
2576 def bridge_get_mcquerier(self
, bridge
):
2577 return self
.read_file_oneline(
2578 '/sys/class/net/%s/bridge/multicast_querier' % bridge
)
2580 def bridge_set_mcqv4src(self
, bridge
, vlan
, mcquerier
):
2584 self
.logger
.info('%s: set mcqv4src vlan: invalid parameter %s: %s' %(bridge
, vlan
, str(e
)))
2586 if vlan
== 0 or vlan
> 4095:
2587 self
.logger
.warn('mcqv4src vlan \'%d\' invalid range' % vlan
)
2590 ip
= mcquerier
.split('.')
2592 self
.logger
.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier
)
2595 if not k
.isdigit() or int(k
, 10) < 0 or int(k
, 10) > 255:
2596 self
.logger
.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier
)
2599 if not LinkUtils
.bridge_utils_is_installed
:
2602 utils
.exec_command('%s setmcqv4src %s %d %s' %
2603 (utils
.brctl_cmd
, bridge
, vlan
, mcquerier
))
2605 def bridge_del_mcqv4src(self
, bridge
, vlan
):
2606 if not LinkUtils
.bridge_utils_is_installed
:
2611 self
.logger
.info('%s: del mcqv4src vlan: invalid parameter %s: %s' %(bridge
, vlan
, str(e
)))
2613 utils
.exec_command('%s delmcqv4src %s %d' % (utils
.brctl_cmd
, bridge
, vlan
))
2615 def bridge_get_mcqv4src(self
, bridge
, vlan
=None):
2616 if not LinkUtils
.bridge_utils_is_installed
:
2618 if not self
.supported_command
['showmcqv4src']:
2622 mcqout
= utils
.exec_command('%s showmcqv4src %s' %
2623 (utils
.brctl_cmd
, bridge
))
2624 except Exception as e
:
2626 if 'never heard' in s
:
2627 msg
= ('%s showmcqv4src: skipping unsupported command'
2629 self
.logger
.info(msg
)
2630 self
.supported_command
['showmcqv4src'] = False
2635 mcqlines
= mcqout
.splitlines()
2636 for l
in mcqlines
[1:]:
2638 k
, d
, v
= l
.split('\t')
2643 return mcqv4src
.get(vlan
)
2646 def bridge_get_mcqv4src_sysfs(self
, bridge
, vlan
=None):
2647 if not LinkUtils
.bridge_utils_is_installed
:
2649 if not self
.supported_command
['showmcqv4src']:
2651 if ifupdownflags
.flags
.PERFMODE
:
2655 filename
= '/sys/class/net/%s/bridge/multicast_v4_queriers' % bridge
2656 if os
.path
.exists(filename
):
2657 for line
in self
.read_file(filename
) or []:
2658 vlan_id
, ip
= line
.split('=')
2659 mcqv4src
[vlan_id
] = ip
.strip()
2660 except Exception as e
:
2662 msg
= ('%s showmcqv4src: skipping unsupported command'
2664 self
.logger
.info(msg
)
2665 self
.supported_command
['showmcqv4src'] = False
2668 return mcqv4src
.get(vlan
)
2672 def bridge_set_mclmi(bridge
, mclmi
):
2673 if not LinkUtils
.bridge_utils_is_installed
:
2675 utils
.exec_command('%s setmclmi %s %s' % (utils
.brctl_cmd
, bridge
, mclmi
))
2677 def bridge_get_mclmi(self
, bridge
):
2678 return self
.read_file_oneline(
2679 '/sys/class/net/%s/bridge/multicast_last_member_interval'
2683 def bridge_set_mcmi(bridge
, mcmi
):
2684 if not LinkUtils
.bridge_utils_is_installed
:
2686 utils
.exec_command('%s setmcmi %s %s' % (utils
.brctl_cmd
, bridge
, mcmi
))
2688 def bridge_get_mcmi(self
, bridge
):
2689 return self
.read_file_oneline(
2690 '/sys/class/net/%s/bridge/multicast_membership_interval'
2694 def bridge_exists(bridge
):
2695 return os
.path
.exists('/sys/class/net/%s/bridge' % bridge
)
2698 def is_bridge_port(ifacename
):
2699 return os
.path
.exists('/sys/class/net/%s/brport' % ifacename
)
2702 def bridge_port_exists(bridge
, bridgeportname
):
2704 return os
.path
.exists('/sys/class/net/%s/brif/%s' % (bridge
, bridgeportname
))
2709 def get_bridge_ports(bridgename
):
2711 return os
.listdir('/sys/class/net/%s/brif/' % bridgename
)
2715 def reset_addr_cache(self
, ifname
):
2717 linkCache
.links
[ifname
]['addrs'] = {}
2718 self
.logger
.debug('%s: reset address cache' % ifname
)
2722 def get_ipv6_addrgen_mode(self
, ifname
):
2724 return self
._cache
_get
('link', [ifname
, 'af_spec', socket
.AF_INET6
])[Link
.IFLA_INET6_ADDR_GEN_MODE
]
2726 # default to 0 (eui64)
2729 def ipv6_addrgen(self
, ifname
, addrgen
, link_created
):
2731 # IFLA_INET6_ADDR_GEN_MODE values:
2734 if self
._link
_cache
_get
([ifname
, 'af_spec', socket
.AF_INET6
])[Link
.IFLA_INET6_ADDR_GEN_MODE
] == addrgen
:
2735 self
.logger
.debug('%s: ipv6 addrgen already %s' % (ifname
, 'off' if addrgen
else 'on'))
2738 disabled_ipv6
= self
.read_file_oneline('/proc/sys/net/ipv6/conf/%s/disable_ipv6' % ifname
)
2739 if not disabled_ipv6
or int(disabled_ipv6
) == 1:
2740 self
.logger
.info('%s: cannot set addrgen: ipv6 is disabled on this device' % ifname
)
2743 if int(self
._link
_cache
_get
([ifname
, 'mtu'])) < 1280:
2744 self
.logger
.info('%s: ipv6 addrgen is disabled on device with MTU '
2745 'lower than 1280: cannot set addrgen %s' % (ifname
, 'off' if addrgen
else 'on'))
2747 except (KeyError, TypeError):
2748 self
.logger
.debug('%s: ipv6 addrgen probably not supported or disabled on this device' % ifname
)
2753 if not link_created
:
2754 # When setting addrgenmode it is necessary to flap the macvlan
2755 # device. After flapping the device we also need to re-add all
2756 # the user configuration. The best way to add the user config
2757 # is to flush our internal address cache
2758 self
.reset_addr_cache(ifname
)
2760 cmd
= 'link set dev %s addrgenmode %s' % (ifname
, Link
.ifla_inet6_addr_gen_mode_dict
.get(addrgen
))
2762 is_link_up
= self
.is_link_up(ifname
)
2765 self
.link_down(ifname
)
2767 #if LinkUtils.ipbatch:
2768 # self.add_to_batch(cmd)
2770 # because this command might fail on older kernel its better to not batch it
2771 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
2774 self
.link_up(ifname
)