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
):
234 brout
= utils
.exec_command('%s showstp %s' % (utils
.brctl_cmd
, bridgename
))
235 chunks
= re
.split(r
'\n\n', brout
, maxsplit
=0, flags
=re
.MULTILINE
)
238 # Get all bridge attributes
239 broutlines
= chunks
[0].splitlines()
240 # battrs['pathcost'] = broutlines[3].split('path cost')[1].strip()
243 battrs
['maxage'] = broutlines
[4].split('bridge max age')[
244 1].strip().replace('.00', '')
249 battrs
['hello'] = broutlines
[5].split('bridge hello time')[
250 1].strip().replace('.00', '')
255 battrs
['fd'] = broutlines
[6].split('bridge forward delay')[
256 1].strip().replace('.00', '')
261 battrs
['ageing'] = broutlines
[7].split('ageing time')[
262 1].strip().replace('.00', '')
267 battrs
['mcrouter'] = broutlines
[12].split('mc router')[
268 1].strip().split('\t\t\t')[0]
273 battrs
['bridgeprio'] = self
.read_file_oneline(
274 '/sys/class/net/%s/bridge/priority' % bridgename
)
279 battrs
['vlan-protocol'] = VlanProtocols
.ID_TO_ETHERTYPES
[
280 self
.read_file_oneline(
281 '/sys/class/net/%s/bridge/vlan_protocol' % bridgename
)]
286 battrs
.update(self
._bridge
_get
_mcattrs
_from
_sysfs
(bridgename
))
290 # XXX: comment this out until mc attributes become available
292 # battrs['hashel'] = broutlines[10].split('hash elasticity')[1].split()[0].strip()
293 # battrs['hashmax'] = broutlines[10].split('hash max')[1].strip()
294 # battrs['mclmc'] = broutlines[11].split('mc last member count')[1].split()[0].strip()
295 # battrs['mciqc'] = broutlines[11].split('mc init query count')[1].strip()
296 # battrs['mcrouter'] = broutlines[12].split('mc router')[1].split()[0].strip()
297 ##battrs['mcsnoop'] = broutlines[12].split('mc snooping')[1].strip()
298 # battrs['mclmt'] = broutlines[13].split('mc last member timer')[1].split()[0].strip()
300 self
.logger
.warn('%s: error while processing bridge attributes: %s' % (bridgename
, str(e
)))
303 linkCache
.update_attrdict([bridgename
, 'linkinfo'], battrs
)
304 for cidx
in range(1, len(chunks
)):
305 bpout
= chunks
[cidx
].lstrip('\n')
306 if not bpout
or bpout
[0] == ' ':
308 bplines
= bpout
.splitlines()
309 pname
= bplines
[0].split()[0]
312 bportattrs
['pathcost'] = bplines
[2].split(
313 'path cost')[1].strip()
314 bportattrs
['fdelay'] = bplines
[4].split(
315 'forward delay timer')[1].strip()
316 bportattrs
['portmcrouter'] = self
.read_file_oneline(
317 '/sys/class/net/%s/brport/multicast_router' % pname
)
318 bportattrs
['portmcfl'] = self
.read_file_oneline(
319 '/sys/class/net/%s/brport/multicast_fast_leave' % pname
)
320 bportattrs
['portprio'] = self
.read_file_oneline(
321 '/sys/class/net/%s/brport/priority' % pname
)
322 bportattrs
['unicast-flood'] = self
.read_file_oneline(
323 '/sys/class/net/%s/brport/unicast_flood' % pname
)
324 bportattrs
['multicast-flood'] = self
.read_file_oneline(
325 '/sys/class/net/%s/brport/multicast_flood' % pname
)
326 bportattrs
['learning'] = self
.read_file_oneline(
327 '/sys/class/net/%s/brport/learning' % pname
)
328 bportattrs
['arp-nd-suppress'] = self
.read_file_oneline(
329 '/sys/class/net/%s/brport/neigh_suppress' % pname
)
330 # bportattrs['mcrouters'] = bplines[6].split('mc router')[1].split()[0].strip()
331 # bportattrs['mc fast leave'] = bplines[6].split('mc fast leave')[1].strip()
333 self
.logger
.warn('%s: error while processing bridge attributes: %s' % (bridgename
, str(e
)))
334 bports
[pname
] = bportattrs
335 linkCache
.update_attrdict([bridgename
, 'linkinfo', 'ports'], bports
)
337 _bridge_sysfs_mcattrs
= {
338 'mclmc': 'multicast_last_member_count',
339 'mcrouter': 'multicast_router',
340 'mcsnoop': 'multicast_snooping',
341 'mcsqc': 'multicast_startup_query_count',
342 'mcqifaddr': 'multicast_query_use_ifaddr',
343 'mcquerier': 'multicast_querier',
344 'hashel': 'hash_elasticity',
345 'hashmax': 'hash_max',
346 'mclmi': 'multicast_last_member_interval',
347 'mcmi': 'multicast_membership_interval',
348 'mcqpi': 'multicast_querier_interval',
349 'mcqi': 'multicast_query_interval',
350 'mcqri': 'multicast_query_response_interval',
351 'mcsqi': 'multicast_startup_query_interval',
352 'igmp-version': 'multicast_igmp_version',
353 'mld-version': 'multicast_mld_version',
354 'vlan-stats': 'vlan_stats_enabled',
355 'mcstats': 'multicast_stats_enabled',
358 def _bridge_get_mcattrs_from_sysfs(self
, bridgename
):
359 mcattrsdivby100
= ['mclmi', 'mcmi', 'mcqpi', 'mcqi', 'mcqri', 'mcsqi']
362 for m
, s
in self
._bridge
_sysfs
_mcattrs
.items():
363 n
= self
.read_file_oneline('/sys/class/net/%s/bridge/%s' % (bridgename
, s
))
364 if m
in mcattrsdivby100
:
369 self
.logger
.warn('error getting mc attr %s (%s)' % (m
, str(e
)))
375 def _fill_bond_info(self
, ifacename
):
376 bonding_masters
= self
.read_file_oneline('/sys/class/net/bonding_masters')
377 if not bonding_masters
:
380 bond_masters_list
= bonding_masters
.split()
383 if ifacename
in bond_masters_list
:
384 bond_masters_list
= [ifacename
]
386 # we want to refresh this interface only if it's a bond master
389 for bondname
in bond_masters_list
:
391 if bondname
not in linkCache
.links
:
392 linkCache
.set_attr([bondname
], {'linkinfo': {}})
393 linkCache
.set_attr([bondname
, 'linkinfo', 'slaves'],
394 self
.read_file_oneline('/sys/class/net/%s/bonding/slaves'
397 # if some attribute are missing we try to get the bond attributes via sysfs
398 bond_linkinfo
= linkCache
.links
[bondname
]['linkinfo']
399 for attr
in [Link
.IFLA_BOND_MODE
, Link
.IFLA_BOND_XMIT_HASH_POLICY
, Link
.IFLA_BOND_MIN_LINKS
]:
400 if attr
not in bond_linkinfo
:
401 self
._fill
_bond
_info
_sysfs
(bondname
)
402 # after we fill in the cache we can continue to the next bond
405 self
._fill
_bond
_info
_sysfs
(bondname
)
407 except Exception as e
:
408 self
.logger
.debug('LinkUtils: bond cache error: %s' % str(e
))
410 def _fill_bond_info_sysfs(self
, bondname
):
412 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_MIN_LINKS
],
413 self
.read_file_oneline(
414 '/sys/class/net/%s/bonding/min_links'
416 except Exception as e
:
417 self
.logger
.debug(str(e
))
420 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_MODE
],
421 self
.read_file_oneline('/sys/class/net/%s/bonding/mode'
422 % bondname
).split()[0])
423 except Exception as e
:
424 self
.logger
.debug(str(e
))
426 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_XMIT_HASH_POLICY
],
427 self
.read_file_oneline(
428 '/sys/class/net/%s/bonding/xmit_hash_policy'
429 % bondname
).split()[0])
430 except Exception as e
:
431 self
.logger
.debug(str(e
))
433 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_RATE
],
434 self
.read_file_oneline('/sys/class/net/%s/bonding/lacp_rate'
435 % bondname
).split()[1])
436 except Exception as e
:
437 self
.logger
.debug(str(e
))
439 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
],
440 self
.read_file_oneline('/sys/class/net/%s/bonding/ad_actor_sys_prio'
442 except Exception as e
:
443 self
.logger
.debug(str(e
))
445 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYSTEM
],
446 self
.read_file_oneline('/sys/class/net/%s/bonding/ad_actor_system'
448 except Exception as e
:
449 self
.logger
.debug(str(e
))
451 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_BYPASS
],
452 self
.read_file_oneline('/sys/class/net/%s/bonding/lacp_bypass'
453 % bondname
).split()[1])
454 except Exception as e
:
455 self
.logger
.debug(str(e
))
457 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_UPDELAY
],
458 self
.read_file_oneline('/sys/class/net/%s/bonding/updelay'
460 except Exception as e
:
461 self
.logger
.debug(str(e
))
463 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_DOWNDELAY
],
464 self
.read_file_oneline('/sys/class/net/%s/bonding/downdelay'
466 except Exception as e
:
467 self
.logger
.debug(str(e
))
470 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_USE_CARRIER
],
471 self
.read_file_oneline('/sys/class/net/%s/bonding/use_carrier' % bondname
))
472 except Exception as e
:
473 self
.logger
.debug(str(e
))
476 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_MIIMON
],
477 self
.read_file_oneline('/sys/class/net/%s/bonding/miimon' % bondname
))
478 except Exception as e
:
479 self
.logger
.debug(str(e
))
482 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
],
483 self
.read_file_oneline('/sys/class/net/%s/bonding/num_unsol_na' % bondname
))
484 except Exception as e
:
485 self
.logger
.debug(str(e
))
488 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
],
489 self
.read_file_oneline('/sys/class/net/%s/bonding/num_grat_arp' % bondname
))
490 except Exception as e
:
491 self
.logger
.debug(str(e
))
494 def _link_fill_iproute2_cmd(self
, ifacename
=None, refresh
=False):
497 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
500 # if ifacename already present, return
501 if (ifacename
and not refresh
and
502 linkCache
.get_attr([ifacename
, 'ifflag'])):
506 cmdout
= self
.link_show(ifacename
=ifacename
)
509 for c
in cmdout
.splitlines():
511 ifnamenlink
= citems
[1].split('@')
512 if len(ifnamenlink
) > 1:
513 ifname
= ifnamenlink
[0]
514 iflink
= ifnamenlink
[1].strip(':')
516 ifname
= ifnamenlink
[0].strip(':')
519 linkattrs
['link'] = iflink
520 linkattrs
['ifindex'] = citems
[0].strip(':')
521 flags
= citems
[2].strip('<>').split(',')
522 linkattrs
['flags'] = flags
523 linkattrs
['ifflag'] = 'UP' if 'UP' in flags
else 'DOWN'
524 for i
in range(0, len(citems
)):
526 if citems
[i
] == 'mtu':
527 linkattrs
['mtu'] = citems
[i
+ 1]
528 elif citems
[i
] == 'state':
529 linkattrs
['state'] = citems
[i
+ 1]
530 elif citems
[i
] == 'link/ether':
531 linkattrs
['hwaddress'] = citems
[i
+ 1]
532 elif citems
[i
] in ['link/gre', 'link/ipip', 'link/sit', 'link/gre6', 'link/tunnel6', 'gretap']:
533 linkattrs
['kind'] = 'tunnel'
534 tunattrs
= {'mode': citems
[i
].split('/')[-1],
539 for j
in range(i
, len(citems
)):
540 if citems
[j
] == 'local':
541 tunattrs
['local'] = citems
[j
+ 1]
542 elif citems
[j
] == 'remote':
543 tunattrs
['endpoint'] = citems
[j
+ 1]
544 elif citems
[j
] == 'ttl':
545 tunattrs
['ttl'] = citems
[j
+ 1]
546 elif citems
[j
] == 'dev':
547 tunattrs
['physdev'] = citems
[j
+ 1]
548 linkattrs
['linkinfo'] = tunattrs
550 elif citems
[i
] == 'link/ppp':
551 linkattrs
['kind'] = 'ppp'
552 elif citems
[i
] == 'vlan':
553 vlanid
= self
._get
_vland
_id
(citems
, i
, warn
)
555 linkattrs
['linkinfo'] = {'vlanid': vlanid
}
556 linkattrs
['kind'] = 'vlan'
557 elif citems
[i
] == 'dummy':
558 linkattrs
['kind'] = 'dummy'
559 elif citems
[i
] == 'vxlan' and citems
[i
+ 1] == 'id':
560 linkattrs
['kind'] = 'vxlan'
561 vattrs
= {'vxlanid': citems
[i
+ 2],
564 'ageing': citems
[i
+ 2],
566 for j
in range(i
+ 2, len(citems
)):
567 if citems
[j
] == 'local':
568 vattrs
['local'] = citems
[j
+ 1]
569 elif citems
[j
] == 'remote':
570 vattrs
['svcnode'] = citems
[j
+ 1]
571 elif citems
[j
] == 'ageing':
572 vattrs
['ageing'] = citems
[j
+ 1]
573 elif citems
[j
] == 'nolearning':
574 vattrs
['learning'] = 'off'
575 elif citems
[j
] == 'dev':
576 vattrs
['physdev'] = citems
[j
+ 1]
577 linkattrs
['linkinfo'] = vattrs
579 elif citems
[i
] == 'vrf' and citems
[i
+ 1] == 'table':
580 vattrs
= {'table': citems
[i
+ 2]}
581 linkattrs
['linkinfo'] = vattrs
582 linkattrs
['kind'] = 'vrf'
583 linkCache
.vrfs
[ifname
] = vattrs
585 elif citems
[i
] == 'veth':
586 linkattrs
['kind'] = 'veth'
587 elif citems
[i
] == 'vrf_slave':
588 linkattrs
['slave_kind'] = 'vrf_slave'
590 elif citems
[i
] == 'macvlan' and citems
[i
+ 1] == 'mode':
591 linkattrs
['kind'] = 'macvlan'
592 except Exception as e
:
594 self
.logger
.debug('%s: parsing error: id, mtu, state, '
595 'link/ether, vlan, dummy, vxlan, local, '
596 'remote, ageing, nolearning, vrf, table, '
597 'vrf_slave are reserved keywords: %s' %
600 # linkattrs['alias'] = self.read_file_oneline(
601 # '/sys/class/net/%s/ifalias' %ifname)
602 linkout
[ifname
] = linkattrs
603 [linkCache
.update_attrdict([ifname
], linkattrs
)
604 for ifname
, linkattrs
in linkout
.items()]
607 def _addr_filter(ifname
, addr
, scope
=None):
608 default_addrs
= ['127.0.0.1/8', '::1/128', '0.0.0.0']
609 if ifname
== 'lo' and addr
in default_addrs
:
611 if scope
and scope
== 'link':
615 def _addr_fill(self
, ifacename
=None, refresh
=False):
616 """ fills cache with address information
618 if ifacename argument given, fill cache for ifacename, else
619 fill cache for all interfaces in the system
621 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
624 # Check if ifacename is already full, in which case, return
625 if ifacename
and not refresh
:
626 linkCache
.get_attr([ifacename
, 'addrs'])
633 [linkCache
.update_attrdict([ifname
], linkattrs
)
634 for ifname
, linkattrs
in netlink
.addr_dump(ifname
=ifacename
).items()]
635 except Exception as e
:
636 self
.logger
.info(str(e
))
638 # this netlink call replaces the call to _addr_fill_iproute2_cmd()
639 # We shouldn't have netlink calls in the iproute2 module, this will
640 # be removed in the future. We plan to release, a flexible backend
641 # (netlink+iproute2) by default we will use netlink backend but with
642 # a CLI arg we can switch to iproute2 backend.
643 # Until we decide to create this "backend" switch capability,
644 # we have to put the netlink call inside the iproute2 module.
647 self
._addr
_fill
_iproute
2_cmd
(ifacename
, refresh
)
649 def _addr_fill_iproute2_cmd(self
, ifacename
=None, refresh
=False):
650 """ fills cache with address information
652 if ifacename argument given, fill cache for ifacename, else
653 fill cache for all interfaces in the system
656 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
659 # Check if ifacename is already full, in which case, return
660 if ifacename
and not refresh
:
661 linkCache
.get_attr([ifacename
, 'addrs'])
665 cmdout
= self
.addr_show(ifacename
=ifacename
)
668 for c
in cmdout
.splitlines():
670 ifnamenlink
= citems
[1].split('@')
671 if len(ifnamenlink
) > 1:
672 ifname
= ifnamenlink
[0]
674 ifname
= ifnamenlink
[0].strip(':')
675 if not linkout
.get(ifname
):
677 linkattrs
['addrs'] = OrderedDict({})
679 linkout
[ifname
].update(linkattrs
)
681 linkout
[ifname
] = linkattrs
682 if citems
[2] == 'inet':
683 if self
._addr
_filter
(ifname
, citems
[3], scope
=citems
[5]):
686 addrattrs
['scope'] = citems
[5]
687 addrattrs
['type'] = 'inet'
688 linkout
[ifname
]['addrs'][citems
[3]] = addrattrs
689 elif citems
[2] == 'inet6':
690 if self
._addr
_filter
(ifname
, citems
[3], scope
=citems
[5]):
692 if citems
[5] == 'link':
693 continue # skip 'link' addresses
695 addrattrs
['scope'] = citems
[5]
696 addrattrs
['type'] = 'inet6'
697 linkout
[ifname
]['addrs'][citems
[3]] = addrattrs
698 [linkCache
.update_attrdict([ifname
], linkattrs
)
699 for ifname
, linkattrs
in linkout
.items()]
701 def cache_get(self
, t
, attrlist
, refresh
=False):
702 return self
._cache
_get
(t
, attrlist
, refresh
)
704 def _cache_get(self
, t
, attrlist
, refresh
=False):
706 if ifupdownflags
.flags
.DRYRUN
:
708 if ifupdownflags
.flags
.CACHE
:
709 if self
._fill
_cache
():
710 # if we filled the cache, return new data
711 return linkCache
.get_attr(attrlist
)
713 return linkCache
.get_attr(attrlist
)
715 self
._link
_fill
(attrlist
[0], refresh
)
717 self
._addr
_fill
(attrlist
[0], refresh
)
719 self
._link
_fill
(attrlist
[0], refresh
)
720 self
._addr
_fill
(attrlist
[0], refresh
)
721 return linkCache
.get_attr(attrlist
)
723 self
.logger
.debug('_cache_get(%s) : [%s]' % (str(attrlist
), str(e
)))
726 def cache_check(self
, attrlist
, value
, refresh
=False):
727 return self
._cache
_check
('link', attrlist
, value
, refresh
=refresh
)
729 def _cache_check(self
, t
, attrlist
, value
, refresh
=False):
731 return self
._cache
_get
(t
, attrlist
, refresh
) == value
733 self
.logger
.debug('_cache_check(%s) : [%s]'
734 % (str(attrlist
), str(e
)))
737 def cache_update(self
, attrlist
, value
):
738 return self
._cache
_update
(attrlist
, value
)
741 def _cache_update(attrlist
, value
):
742 if ifupdownflags
.flags
.DRYRUN
:
745 if attrlist
[-1] == 'slaves':
746 linkCache
.append_to_attrlist(attrlist
, value
)
748 linkCache
.set_attr(attrlist
, value
)
753 def _cache_delete(attrlist
, value
=None):
754 if ifupdownflags
.flags
.DRYRUN
:
758 linkCache
.remove_from_attrlist(attrlist
, value
)
760 linkCache
.del_attr(attrlist
)
765 def _cache_invalidate():
766 linkCache
.invalidate()
767 LinkUtils
._CACHE
_FILL
_DONE
= False
771 LinkUtils
.ipbatcbuf
= ''
772 LinkUtils
.ipbatch
= True
773 LinkUtils
.ipbatch_pause
= False
776 def add_to_batch(cmd
):
777 LinkUtils
.ipbatchbuf
+= cmd
+ '\n'
781 LinkUtils
.ipbatch_pause
= True
785 LinkUtils
.ipbatch_pause
= False
787 def batch_commit(self
):
788 if not LinkUtils
.ipbatchbuf
:
789 LinkUtils
.ipbatchbuf
= ''
790 LinkUtils
.ipbatch
= False
791 LinkUtils
.ipbatch_pause
= False
794 utils
.exec_command('%s -force -batch -' % utils
.ip_cmd
,
795 stdin
=self
.ipbatchbuf
)
799 LinkUtils
.ipbatchbuf
= ''
800 LinkUtils
.ipbatch
= False
801 LinkUtils
.ipbatch_pause
= False
803 def bridge_batch_commit(self
):
804 if not LinkUtils
.ipbatchbuf
:
805 LinkUtils
.ipbatchbuf
= ''
806 LinkUtils
.ipbatch
= False
807 LinkUtils
.ipbatch_pause
= False
810 utils
.exec_command('%s -force -batch -'
811 % utils
.bridge_cmd
, stdin
=self
.ipbatchbuf
)
815 LinkUtils
.ipbatchbuf
= ''
816 LinkUtils
.ipbatch
= False
817 LinkUtils
.ipbatch_pause
= False
819 def addr_show(self
, ifacename
=None):
821 if not self
.link_exists(ifacename
):
823 return utils
.exec_commandl([utils
.ip_cmd
,
824 '-o', 'addr', 'show', 'dev', ifacename
])
826 return utils
.exec_commandl([utils
.ip_cmd
,
827 '-o', 'addr', 'show'])
830 def link_show(ifacename
=None):
832 return utils
.exec_commandl([utils
.ip_cmd
,
833 '-o', '-d', 'link', 'show', 'dev', ifacename
])
835 return utils
.exec_commandl([utils
.ip_cmd
,
836 '-o', '-d', 'link', 'show'])
838 def addr_add(self
, ifacename
, address
, broadcast
=None,
839 peer
=None, scope
=None, preferred_lifetime
=None, metric
=None):
842 cmd
= 'addr add %s' % address
844 cmd
+= ' broadcast %s' % broadcast
846 cmd
+= ' peer %s' % peer
848 cmd
+= ' scope %s' % scope
849 if preferred_lifetime
:
850 cmd
+= ' preferred_lft %s' % preferred_lifetime
851 cmd
+= ' dev %s' % ifacename
854 cmd
+= ' metric %s' % metric
856 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
857 self
.add_to_batch(cmd
)
859 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
860 self
._cache
_update
([ifacename
, 'addrs', address
], {})
862 def addr_del(self
, ifacename
, address
, broadcast
=None,
863 peer
=None, scope
=None):
864 """ Delete ipv4 address """
867 if not self
._cache
_get
('addr', [ifacename
, 'addrs', address
]):
869 cmd
= 'addr del %s' % address
871 cmd
+= 'broadcast %s' % broadcast
873 cmd
+= 'peer %s' % peer
875 cmd
+= 'scope %s' % scope
876 cmd
+= ' dev %s' % ifacename
877 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
878 self
._cache
_delete
([ifacename
, 'addrs', address
])
880 def addr_flush(self
, ifacename
):
881 cmd
= 'addr flush dev %s' % ifacename
882 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
883 self
.add_to_batch(cmd
)
885 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
886 self
._cache
_delete
([ifacename
, 'addrs'])
888 def del_addr_all(self
, ifacename
, skip_addrs
=[]):
891 runningaddrsdict
= self
.get_running_addrs(ifname
=ifacename
)
893 # XXX: ignore errors. Fix this to delete secondary addresses
895 [self
.addr_del(ifacename
, a
) for a
in
896 set(runningaddrsdict
.keys()).difference(skip_addrs
)]
901 def addr_get(self
, ifacename
, details
=True, refresh
=False):
902 addrs
= self
._cache
_get
('addr', [ifacename
, 'addrs'], refresh
=refresh
)
909 def get_running_addrs(self
, ifaceobj
=None, ifname
=None, details
=True, addr_virtual_ifaceobj
=None):
911 We now support addr with link scope. Since the kernel may add it's
912 own link address to some interfaces we need to filter them out and
913 make sure we only deal with the addresses set by ifupdown2.
915 To do so we look at the previous configuration made by ifupdown2
916 (with the help of the statemanager) together with the addresses
917 specified by the user in /etc/network/interfaces, these addresses
918 are then compared to the running state of the intf (ip addr show)
919 made via a netlink addr dump.
920 For each configured addresses of scope link, we check if it was
921 previously configured by ifupdown2 to create a final set of the
922 addresses watched by ifupdown2
924 if not ifaceobj
and not ifname
:
930 interface_name
= ifaceobj
.name
932 interface_name
= ifname
934 if addr_virtual_ifaceobj
:
935 for virtual
in addr_virtual_ifaceobj
.get_attr_value('address-virtual') or []:
936 for ip
in virtual
.split():
943 saved_ifaceobjs
= statemanager
.statemanager_api
.get_ifaceobjs(addr_virtual_ifaceobj
.name
)
944 for saved_ifaceobj
in saved_ifaceobjs
or []:
945 for virtual
in saved_ifaceobj
.get_attr_value('address-virtual') or []:
946 for ip
in virtual
.split():
954 for addr
in ifaceobj
.get_attr_value('address') or []:
955 config_addrs
.add(addr
)
957 saved_ifaceobjs
= statemanager
.statemanager_api
.get_ifaceobjs(interface_name
)
958 for saved_ifaceobj
in saved_ifaceobjs
or []:
959 for addr
in saved_ifaceobj
.get_attr_value('address') or []:
960 config_addrs
.add(addr
)
962 running_addrs
= OrderedDict()
963 cached_addrs
= self
.addr_get(interface_name
)
965 for addr
, addr_details
in cached_addrs
.items():
967 scope
= int(addr_details
['scope'])
971 addr_obj
= IPNetwork(addr
)
972 if isinstance(addr_obj
, IPv6Network
):
973 d
['family'] = 'inet6'
976 running_addrs
[addr
] = d
978 running_addrs
[addr
] = {}
980 if (scope
& Route
.RT_SCOPE_LINK
and addr
in config_addrs
) or not scope
& Route
.RT_SCOPE_LINK
:
981 running_addrs
[addr
] = addr_details
987 return running_addrs
.keys()
990 def compare_user_config_vs_running_state(running_addrs
, user_addrs
):
994 for ip
in user_addrs
or []:
997 if type(obj
) == IPv6Network
:
1003 for ip
in running_addrs
or []:
1004 running_ipobj
.append(IPNetwork(ip
))
1006 return running_ipobj
== (ip4
+ ip6
)
1008 def addr_add_multiple(self
, ifaceobj
, ifacename
, addrs
, purge_existing
=False, metric
=None):
1011 # if perfmode is not set and also if iface has no sibling
1012 # objects, purge addresses that are not present in the new
1014 runningaddrs
= self
.get_running_addrs(
1017 addr_virtual_ifaceobj
=ifaceobj
1019 addrs
= utils
.get_normalized_ip_addr(ifacename
, addrs
)
1021 if self
.compare_user_config_vs_running_state(runningaddrs
, addrs
):
1024 # if primary address is not same, there is no need to keep any.
1025 # reset all addresses
1026 if (addrs
and runningaddrs
and
1027 (addrs
[0] != runningaddrs
[0])):
1028 self
.del_addr_all(ifacename
)
1030 self
.del_addr_all(ifacename
, addrs
)
1031 except Exception, e
:
1032 self
.logger
.warning('%s: %s' % (ifacename
, str(e
)))
1035 self
.addr_add(ifacename
, a
, metric
=metric
)
1036 except Exception, e
:
1037 self
.logger
.error(str(e
))
1039 def _link_set_ifflag(self
, ifacename
, value
):
1040 # Dont look at the cache, the cache may have stale value
1041 # because link status can be changed by external
1042 # entity (One such entity is ifupdown main program)
1043 cmd
= 'link set dev %s %s' % (ifacename
, value
.lower())
1044 if LinkUtils
.ipbatch
:
1045 self
.add_to_batch(cmd
)
1047 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1049 def link_up(self
, ifacename
):
1050 self
._link
_set
_ifflag
(ifacename
, 'UP')
1052 def link_down(self
, ifacename
):
1053 self
._link
_set
_ifflag
(ifacename
, 'DOWN')
1055 def link_set(self
, ifacename
, key
, value
=None,
1056 force
=False, t
=None, state
=None):
1058 if (key
not in ['master', 'nomaster'] and
1059 self
._cache
_check
('link', [ifacename
, key
], value
)):
1061 cmd
= 'link set dev %s' % ifacename
1063 cmd
+= ' type %s' % t
1066 cmd
+= ' %s' % value
1068 cmd
+= ' %s' % state
1069 if LinkUtils
.ipbatch
:
1070 self
.add_to_batch(cmd
)
1072 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1073 if key
not in ['master', 'nomaster']:
1074 self
._cache
_update
([ifacename
, key
], value
)
1076 def link_set_hwaddress(self
, ifacename
, hwaddress
, force
=False):
1078 if self
._cache
_check
('link', [ifacename
, 'hwaddress'], hwaddress
):
1080 self
.link_down(ifacename
)
1081 cmd
= 'link set dev %s address %s' % (ifacename
, hwaddress
)
1082 if LinkUtils
.ipbatch
:
1083 self
.add_to_batch(cmd
)
1085 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1086 self
.link_up(ifacename
)
1087 self
._cache
_update
([ifacename
, 'hwaddress'], hwaddress
)
1089 def link_set_mtu(self
, ifacename
, mtu
):
1090 if ifupdownflags
.flags
.DRYRUN
:
1092 if not mtu
or not ifacename
: return
1093 self
.write_file('/sys/class/net/%s/mtu' % ifacename
, mtu
)
1094 self
._cache
_update
([ifacename
, 'mtu'], mtu
)
1096 def link_set_alias(self
, ifacename
, alias
):
1097 self
.write_file('/sys/class/net/%s/ifalias' % ifacename
,
1098 '\n' if not alias
else alias
)
1100 def link_get_alias(self
, ifacename
):
1101 return self
.read_file_oneline('/sys/class/net/%s/ifalias'
1104 def link_isloopback(self
, ifacename
):
1105 flags
= self
._cache
_get
('link', [ifacename
, 'flags'])
1108 if 'LOOPBACK' in flags
:
1112 def link_get_status(self
, ifacename
):
1113 return self
._cache
_get
('link', [ifacename
, 'ifflag'], refresh
=True)
1116 def route_add_gateway(ifacename
, gateway
, vrf
=None, metric
=None, onlink
=True):
1120 cmd
= '%s route add default via %s proto kernel' % (utils
.ip_cmd
,
1123 cmd
= ('%s route add table %s default via %s proto kernel' %
1124 (utils
.ip_cmd
, vrf
, gateway
))
1127 cmd
+= 'metric %s' % metric
1128 cmd
+= ' dev %s' % ifacename
1133 utils
.exec_command(cmd
)
1136 def route_del_gateway(ifacename
, gateway
, vrf
=None, metric
=None):
1141 cmd
= ('%s route del default via %s proto kernel' %
1142 (utils
.ip_cmd
, gateway
))
1144 cmd
= ('%s route del table %s default via %s proto kernel' %
1145 (utils
.ip_cmd
, vrf
, gateway
))
1147 cmd
+= ' metric %s' % metric
1148 cmd
+= ' dev %s' % ifacename
1149 utils
.exec_command(cmd
)
1152 def _get_vrf_id(ifacename
):
1154 return linkCache
.vrfs
[ifacename
]['table']
1156 dump
= netlink
.link_dump(ifacename
)
1158 [linkCache
.update_attrdict([ifname
], linkattrs
)
1159 for ifname
, linkattrs
in dump
.items()]
1161 if dump
and dump
.get(ifacename
, {}).get('kind') == 'vrf':
1162 vrf_table
= dump
.get(ifacename
, {}).get('linkinfo', {}).get('table')
1163 linkCache
.vrfs
[ifacename
] = {'table': vrf_table
}
1168 def fix_ipv6_route_metric(self
, ifaceobj
, macvlan_ifacename
, ips
):
1171 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
:
1173 for upper_iface
in ifaceobj
.upperifaces
:
1174 vrf_table
= self
._get
_vrf
_id
(upper_iface
)
1182 ip_network_obj
= IPNetwork(ip
)
1184 if type(ip_network_obj
) == IPv6Network
:
1185 route_prefix
= '%s/%d' % (ip_network_obj
.network
, ip_network_obj
.prefixlen
)
1188 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1189 LinkUtils
.add_to_batch('route del %s table %s dev %s' % (route_prefix
, vrf_table
, macvlan_ifacename
))
1191 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'del', route_prefix
, 'table', vrf_table
, 'dev', macvlan_ifacename
])
1193 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1194 LinkUtils
.add_to_batch('route del %s dev %s' % (route_prefix
, macvlan_ifacename
))
1196 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'del', route_prefix
, 'dev', macvlan_ifacename
])
1197 ip_route_del
.append((route_prefix
, vrf_table
))
1199 for ip
, vrf_table
in ip_route_del
:
1201 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1202 LinkUtils
.add_to_batch('route add %s table %s dev %s proto kernel metric 9999' % (ip
, vrf_table
, macvlan_ifacename
))
1204 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'add', ip
, 'table', vrf_table
, 'dev', macvlan_ifacename
, 'proto', 'kernel' 'metric', '9999'])
1206 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1207 LinkUtils
.add_to_batch('route add %s dev %s proto kernel metric 9999' % (ip
, macvlan_ifacename
))
1209 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'add', ip
, 'dev', macvlan_ifacename
, 'proto', 'kernel' 'metric', '9999'])
1211 def link_create_vlan(self
, vlan_device_name
, vlan_raw_device
, vlanid
):
1212 if self
.link_exists(vlan_device_name
):
1214 utils
.exec_command('%s link add link %s name %s type vlan id %d' %
1216 vlan_raw_device
, vlan_device_name
, vlanid
))
1217 self
._cache
_update
([vlan_device_name
], {})
1219 def link_create_vlan_from_name(self
, vlan_device_name
):
1220 v
= vlan_device_name
.split('.')
1222 self
.logger
.warn('invalid vlan device name %s' % vlan_device_name
)
1224 self
.link_create_vlan(vlan_device_name
, v
[0], v
[1])
1226 def link_create_macvlan(self
, name
, linkdev
, mode
='private'):
1227 if self
.link_exists(name
):
1229 cmd
= ('link add link %s' % linkdev
+
1231 ' type macvlan mode %s' % mode
)
1232 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1233 self
.add_to_batch(cmd
)
1235 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1236 self
._cache
_update
([name
], {})
1238 def get_vxlan_peers(self
, dev
, svcnodeip
):
1239 cmd
= '%s fdb show brport %s' % (utils
.bridge_cmd
,
1243 ps
= subprocess
.Popen(shlex
.split(cmd
), stdout
=subprocess
.PIPE
, close_fds
=False)
1244 utils
.enable_subprocess_signal_forwarding(ps
, signal
.SIGINT
)
1245 output
= subprocess
.check_output(('grep', '00:00:00:00:00:00'), stdin
=ps
.stdout
)
1247 utils
.disable_subprocess_signal_forwarding(signal
.SIGINT
)
1249 ppat
= re
.compile('\s+dst\s+(\d+.\d+.\d+.\d+)\s+')
1250 for l
in output
.split('\n'):
1252 if m
and m
.group(1) != svcnodeip
:
1253 cur_peers
.append(m
.group(1))
1255 self
.logger
.warn('error parsing ip link output')
1256 except subprocess
.CalledProcessError
as e
:
1257 if e
.returncode
!= 1:
1258 self
.logger
.error(str(e
))
1260 utils
.disable_subprocess_signal_forwarding(signal
.SIGINT
)
1264 def tunnel_create(self
, tunnelname
, mode
, attrs
={}):
1265 """ generic link_create function """
1266 if self
.link_exists(tunnelname
):
1273 if mode
== 'gretap':
1275 cmd
+= ' %s type %s' %(tunnelname
, mode
)
1278 cmd
+= ' %s mode %s' %(tunnelname
, mode
)
1281 for k
, v
in attrs
.iteritems():
1285 if self
.ipbatch
and not self
.ipbatch_pause
:
1286 self
.add_to_batch(cmd
)
1288 utils
.exec_command('ip %s' % cmd
)
1289 self
._cache
_update
([tunnelname
], {})
1291 def tunnel_change(self
, tunnelname
, attrs
={}):
1292 """ tunnel change function """
1293 if not self
.link_exists(tunnelname
):
1295 cmd
= 'tunnel change'
1296 cmd
+= ' %s' %(tunnelname)
1298 for k
, v
in attrs
.iteritems():
1302 if self
.ipbatch
and not self
.ipbatch_pause
:
1303 self
.add_to_batch(cmd
)
1305 utils
.exec_command('ip %s' % cmd
)
1306 self
._cache
_update
([tunnelname
], {})
1308 def link_create_vxlan(self
, name
, vxlanid
,
1315 if svcnodeip
and remoteips
:
1316 raise Exception("svcnodeip and remoteip is mutually exclusive")
1319 args
+= ' remote %s' % svcnodeip
1321 args
+= ' ageing %s' % ageing
1322 if learning
== 'off':
1323 args
+= ' nolearning'
1325 if self
.link_exists(name
):
1326 cmd
= 'link set dev %s type vxlan dstport %d' % (name
, LinkUtils
.VXLAN_UDP_PORT
)
1327 vxlanattrs
= self
.get_vxlandev_attrs(name
)
1328 # on ifreload do not overwrite anycast_ip to individual ip if clagd
1331 running_localtunnelip
= vxlanattrs
.get('local')
1332 if anycastip
and running_localtunnelip
and anycastip
== running_localtunnelip
:
1333 localtunnelip
= running_localtunnelip
1334 running_svcnode
= vxlanattrs
.get('svcnode')
1335 if running_svcnode
and not svcnodeip
:
1338 cmd
= 'link add dev %s type vxlan id %s dstport %d' % (name
, vxlanid
, LinkUtils
.VXLAN_UDP_PORT
)
1341 args
+= ' local %s' % localtunnelip
1344 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1345 self
.add_to_batch(cmd
)
1347 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1349 # XXX: update linkinfo correctly
1350 #self._cache_update([name], {})
1353 def link_exists(ifacename
):
1354 if ifupdownflags
.flags
.DRYRUN
:
1356 return os
.path
.exists('/sys/class/net/%s' % ifacename
)
1359 def link_exists_nodryrun(ifname
):
1360 return os
.path
.exists('/sys/class/net/%s' % ifname
)
1362 def link_get_ifindex(self
, ifacename
):
1363 if ifupdownflags
.flags
.DRYRUN
:
1365 return self
.read_file_oneline('/sys/class/net/%s/ifindex' % ifacename
)
1367 def is_vlan_device_by_name(self
, ifacename
):
1368 if re
.search(r
'\.', ifacename
):
1373 def link_add_macvlan(ifname
, macvlan_ifacename
):
1374 utils
.exec_commandl(['ip', 'link', 'add', 'link', ifname
, 'name', macvlan_ifacename
, 'type', 'macvlan', 'mode', 'private'])
1377 def route_add(route
):
1378 utils
.exec_command('%s route add %s' % (utils
.ip_cmd
,
1382 def route6_add(route
):
1383 utils
.exec_command('%s -6 route add %s' % (utils
.ip_cmd
,
1386 def get_vlandev_attrs(self
, ifacename
):
1387 return (self
._cache
_get
('link', [ifacename
, 'link']),
1388 self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlanid']),
1389 self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlan_protocol']))
1391 def get_vlan_protocol(self
, ifacename
):
1392 return self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlan_protocol'])
1394 def get_vxlandev_attrs(self
, ifacename
):
1395 return self
._cache
_get
('link', [ifacename
, 'linkinfo'])
1397 def get_vxlandev_learning(self
, ifacename
):
1398 return self
._cache
_get
('link', [ifacename
, 'linkinfo', Link
.IFLA_VXLAN_LEARNING
])
1400 def set_vxlandev_learning(self
, ifacename
, learn
):
1402 utils
.exec_command('%s link set dev %s type vxlan learning' %
1403 (utils
.ip_cmd
, ifacename
))
1404 self
._cache
_update
([ifacename
, 'linkinfo', 'learning'], 'on')
1406 utils
.exec_command('%s link set dev %s type vxlan nolearning' %
1407 (utils
.ip_cmd
, ifacename
))
1408 self
._cache
_update
([ifacename
, 'linkinfo', 'learning'], 'off')
1410 def link_get_linkinfo_attrs(self
, ifacename
):
1411 return self
._cache
_get
('link', [ifacename
, 'linkinfo'])
1413 def link_get_mtu(self
, ifacename
, refresh
=False):
1414 return self
._cache
_get
('link', [ifacename
, 'mtu'], refresh
=refresh
)
1416 def link_get_mtu_sysfs(self
, ifacename
):
1417 return self
.read_file_oneline('/sys/class/net/%s/mtu'
1420 def link_get_kind(self
, ifacename
):
1421 return self
._cache
_get
('link', [ifacename
, 'kind'])
1423 def link_get_slave_kind(self
, ifacename
):
1424 return self
._cache
_get
('link', [ifacename
, 'slave_kind'])
1426 def link_get_hwaddress(self
, ifacename
):
1427 address
= self
._cache
_get
('link', [ifacename
, 'hwaddress'])
1428 # newly created logical interface addresses dont end up in the cache
1429 # read hwaddress from sysfs file for these interfaces
1431 address
= self
.read_file_oneline('/sys/class/net/%s/address'
1435 def link_create(self
, ifacename
, t
, attrs
={}):
1436 """ generic link_create function """
1437 if self
.link_exists(ifacename
):
1440 cmd
+= ' name %s type %s' % (ifacename
, t
)
1442 for k
, v
in attrs
.iteritems():
1446 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1447 self
.add_to_batch(cmd
)
1449 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1450 self
._cache
_update
([ifacename
], {})
1452 def link_delete(self
, ifacename
):
1453 if not self
.link_exists(ifacename
):
1455 cmd
= 'link del %s' % ifacename
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
_invalidate
()
1462 def link_get_master(self
, ifacename
):
1463 sysfs_master_path
= '/sys/class/net/%s/master' % ifacename
1464 if os
.path
.exists(sysfs_master_path
):
1465 link_path
= os
.readlink(sysfs_master_path
)
1467 return os
.path
.basename(link_path
)
1471 return self
._cache
_get
('link', [ifacename
, 'master'])
1473 def get_brport_peer_link(self
, bridgename
):
1475 return self
._cache
_get
('link', [bridgename
, 'info_slave_data', Link
.IFLA_BRPORT_PEER_LINK
])
1480 def bridge_port_vids_add(bridgeportname
, vids
):
1481 [utils
.exec_command('%s vlan add vid %s dev %s' %
1483 v
, bridgeportname
)) for v
in vids
]
1486 def bridge_port_vids_del(bridgeportname
, vids
):
1489 [utils
.exec_command('%s vlan del vid %s dev %s' %
1491 v
, bridgeportname
)) for v
in vids
]
1494 def bridge_port_vids_flush(bridgeportname
, vid
):
1495 utils
.exec_command('%s vlan del vid %s dev %s' %
1497 vid
, bridgeportname
))
1500 def bridge_port_vids_get(bridgeportname
):
1501 bridgeout
= utils
.exec_command('%s vlan show dev %s' %
1506 brvlanlines
= bridgeout
.readlines()[2:]
1507 vids
= [l
.strip() for l
in brvlanlines
]
1508 return [v
for v
in vids
if v
]
1511 def bridge_port_vids_get_all():
1513 bridgeout
= utils
.exec_command('%s -c vlan show'
1517 brvlanlines
= bridgeout
.splitlines()
1519 for l
in brvlanlines
[1:]:
1520 if l
and not l
.startswith(' ') and not l
.startswith('\t'):
1522 brportname
= attrs
[0].strip()
1523 brvlaninfo
[brportname
] = {'pvid': None, 'vlan': []}
1524 l
= ' '.join(attrs
[1:])
1525 if not brportname
or not l
:
1529 brvlaninfo
[brportname
]['pvid'] = l
.split()[0]
1530 elif 'Egress Untagged' not in l
:
1531 brvlaninfo
[brportname
]['vlan'].append(l
)
1534 def bridge_port_vids_get_all_json(self
):
1535 if not self
.supported_command
['%s -c -json vlan show'
1536 % utils
.bridge_cmd
]:
1540 bridgeout
= utils
.exec_command('%s -c -json vlan show'
1543 self
.supported_command
['%s -c -json vlan show'
1544 % utils
.bridge_cmd
] = False
1545 self
.logger
.info('%s -c -json vlan show: skipping unsupported command'
1548 return self
.get_bridge_vlan_nojson()
1549 except Exception as e
:
1550 self
.logger
.info('bridge: get_bridge_vlan_nojson: %s' % str(e
))
1553 if not bridgeout
: return brvlaninfo
1555 vlan_json
= json
.loads(bridgeout
, encoding
="utf-8")
1556 except Exception, e
:
1557 self
.logger
.info('json loads failed with (%s)' % str(e
))
1561 if isinstance(vlan_json
, list):
1562 # newer iproute2 version changed the bridge vlan show output
1563 # ifupdown2 relies on the previous format, we have the convert
1564 # data into old format
1565 bridge_port_vids
= dict()
1567 for intf
in vlan_json
:
1568 bridge_port_vids
[intf
["ifname"]] = intf
["vlans"]
1570 return bridge_port_vids
1572 # older iproute2 version have different ways to dump vlans
1573 # ifupdown2 prefers the following syntax:
1577 # "flags": ["PVID", "Egress Untagged"]
1582 # "flags": ["PVID", "Egress Untagged"]
1586 except Exception as e
:
1587 self
.logger
.debug("bridge vlan show: Unknown json output: %s" % str(e
))
1591 def get_bridge_vlan_nojson():
1593 bridgeout
= utils
.exec_commandl([utils
.bridge_cmd
, '-c', 'vlan', 'show'])
1595 output
= [line
.split('\n') for line
in bridgeout
.split('\n\n')]
1596 output
[0] = output
[0][1:]
1604 prefix
, vlan
= entry
.split('\t')
1606 current_swp
= prefix
1607 vlan_json
[prefix
] = []
1611 v
['vlan'] = int(vlan
)
1615 start
, end
= vlan
.split('-')
1617 end
= end
[0:end
.index(' ')]
1618 v
['vlan'] = int(start
)
1619 v
['vlanEnd'] = int(end
)
1621 v
['vlan'] = int(vlan
[0:vlan
.index(' ')])
1624 flags
.append('PVID')
1625 if 'Egress Untagged' in vlan
:
1626 flags
.append('Egress Untagged')
1630 vlan_json
[current_swp
].append(v
)
1633 def bridge_vlan_cache_get(self
, ifacename
, refresh
=False):
1634 if not self
.bridge_vlan_cache_fill_done
or refresh
:
1635 self
.bridge_vlan_cache
= self
.bridge_port_vids_get_all_json()
1636 self
.bridge_vlan_cache_fill_done
= True
1637 return self
.bridge_vlan_cache
.get(ifacename
, {})
1639 def bridge_vlan_get_pvid(self
, ifacename
, refresh
=False):
1642 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1643 v
= vinfo
.get('vlan')
1644 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1649 def bridge_vlan_get_vids(self
, ifacename
, refresh
=False):
1652 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1653 v
= vinfo
.get('vlan')
1654 ispvid
= True if 'PVID' in vinfo
.get('flags', []) else False
1656 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1659 vEnd
= vinfo
.get('vlanEnd')
1661 vids
.extend(range(v
, vEnd
+ 1))
1666 def bridge_vlan_get_vids_n_pvid(self
, ifacename
, refresh
=False):
1670 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1671 v
= vinfo
.get('vlan')
1672 ispvid
= True if 'PVID' in vinfo
.get('flags', []) else False
1674 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1675 vEnd
= vinfo
.get('vlanEnd')
1677 vids
.extend(range(v
, vEnd
+ 1))
1682 def bridge_port_pvid_add(self
, bridgeportname
, pvid
):
1683 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1684 self
.add_to_batch('vlan add vid %s untagged pvid dev %s' %
1685 (pvid
, bridgeportname
))
1687 utils
.exec_command('%s vlan add vid %s untagged pvid dev %s' %
1689 pvid
, bridgeportname
))
1691 def bridge_port_pvid_del(self
, bridgeportname
, pvid
):
1692 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1693 self
.add_to_batch('vlan del vid %s untagged pvid dev %s' %
1694 (pvid
, bridgeportname
))
1696 utils
.exec_command('%s vlan del vid %s untagged pvid dev %s' %
1698 pvid
, bridgeportname
))
1700 def bridge_port_pvids_get(self
, bridgeportname
):
1701 return self
.read_file_oneline('/sys/class/net/%s/brport/pvid'
1704 def bridge_vids_add(self
, bridgeportname
, vids
, bridge
=True):
1705 target
= 'self' if bridge
else ''
1706 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1707 [self
.add_to_batch('vlan add vid %s dev %s %s' %
1708 (v
, bridgeportname
, target
)) for v
in vids
]
1710 [utils
.exec_command('%s vlan add vid %s dev %s %s' %
1712 v
, bridgeportname
, target
)) for v
in vids
]
1714 def bridge_vids_del(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 del vid %s dev %s %s' %
1718 (v
, bridgeportname
, target
)) for v
in vids
]
1720 [utils
.exec_command('%s vlan del vid %s dev %s %s' %
1722 v
, bridgeportname
, target
)) for v
in vids
]
1725 def bridge_fdb_add(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1726 target
= 'self' if bridge
else ''
1729 vlan_str
= 'vlan %s ' % vlan
1733 dst_str
= 'dst %s ' % remote
1735 utils
.exec_command('%s fdb replace %s dev %s %s %s %s' %
1737 address
, dev
, vlan_str
, target
, dst_str
))
1740 def bridge_fdb_append(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1741 target
= 'self' if bridge
else ''
1744 vlan_str
= 'vlan %s ' % vlan
1748 dst_str
= 'dst %s ' % remote
1750 utils
.exec_command('%s fdb append %s dev %s %s %s %s' %
1752 address
, dev
, vlan_str
, target
, dst_str
))
1755 def bridge_fdb_del(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1756 target
= 'self' if bridge
else ''
1759 vlan_str
= 'vlan %s ' % vlan
1763 dst_str
= 'dst %s ' % remote
1764 utils
.exec_command('%s fdb del %s dev %s %s %s %s' %
1766 address
, dev
, vlan_str
, target
, dst_str
))
1768 def bridge_is_vlan_aware(self
, bridgename
):
1769 filename
= '/sys/class/net/%s/bridge/vlan_filtering' % bridgename
1770 if os
.path
.exists(filename
) and self
.read_file_oneline(filename
) == '1':
1775 def bridge_port_get_bridge_name(bridgeport
):
1776 filename
= '/sys/class/net/%s/brport/bridge' % bridgeport
1778 return os
.path
.basename(os
.readlink(filename
))
1783 def bridge_port_exists(bridge
, bridgeportname
):
1785 return os
.path
.exists('/sys/class/net/%s/brif/%s'
1786 % (bridge
, bridgeportname
))
1790 def bridge_fdb_show_dev(self
, dev
):
1793 output
= utils
.exec_command('%s fdb show dev %s'
1794 % (utils
.bridge_cmd
, dev
))
1796 for fdb_entry
in output
.splitlines():
1798 entries
= fdb_entry
.split()
1799 fdbs
.setdefault(entries
[2], []).append(entries
[0])
1801 self
.logger
.debug('%s: invalid fdb line \'%s\''
1808 def is_bridge(bridge
):
1809 return os
.path
.exists('/sys/class/net/%s/bridge' % bridge
)
1811 def is_link_up(self
, ifacename
):
1814 flags
= self
.read_file_oneline('/sys/class/net/%s/flags' % ifacename
)
1815 iflags
= int(flags
, 16)
1822 def ip_route_get_dev(self
, prefix
, vrf_master
=None):
1825 cmd
= '%s route get %s vrf %s' % (utils
.ip_cmd
, prefix
, vrf_master
)
1827 cmd
= '%s route get %s' % (utils
.ip_cmd
, prefix
)
1829 output
= utils
.exec_command(cmd
)
1831 rline
= output
.splitlines()[0]
1833 rattrs
= rline
.split()
1834 return rattrs
[rattrs
.index('dev') + 1]
1835 except Exception, e
:
1836 self
.logger
.debug('ip_route_get_dev: failed .. %s' % str(e
))
1840 def link_get_lowers(ifacename
):
1842 lowers
= glob
.glob("/sys/class/net/%s/lower_*" % ifacename
)
1845 return [os
.path
.basename(l
)[6:] for l
in lowers
]
1850 def link_get_uppers(ifacename
):
1852 uppers
= glob
.glob("/sys/class/net/%s/upper_*" % ifacename
)
1855 return [os
.path
.basename(u
)[6:] for u
in uppers
]
1859 def link_get_vrfs(self
):
1860 if not LinkUtils
._CACHE
_FILL
_DONE
:
1862 return linkCache
.vrfs
1865 def cache_get_info_slave(attrlist
):
1867 return linkCache
.get_attr(attrlist
)
1871 def get_brport_learning(self
, ifacename
):
1872 learn
= self
.read_file_oneline('/sys/class/net/%s/brport/learning'
1874 if learn
and learn
== '1':
1879 def get_brport_learning_bool(self
, ifacename
):
1880 return utils
.get_boolean_from_string(self
.read_file_oneline('/sys/class/net/%s/brport/learning' % ifacename
))
1882 def set_brport_learning(self
, ifacename
, learn
):
1884 return self
.write_file('/sys/class/net/%s/brport/learning'
1887 return self
.write_file('/sys/class/net/%s/brport/learning'
1890 #################################################################################
1891 ################################### BOND UTILS ##################################
1892 #################################################################################
1894 def _link_cache_get(self
, attrlist
, refresh
=False):
1895 return self
._cache
_get
('link', attrlist
, refresh
)
1897 def cache_delete(self
, attrlist
, value
=None):
1898 return self
._cache
_delete
(attrlist
, value
)
1900 def link_cache_get(self
, attrlist
, refresh
=False):
1901 return self
._link
_cache
_get
(attrlist
, refresh
)
1903 def link_cache_check(self
, attrlist
, value
, refresh
=False):
1904 return self
._link
_cache
_check
(attrlist
, value
, refresh
)
1906 def _link_cache_check(self
, attrlist
, value
, refresh
=False):
1908 return self
._link
_cache
_get
(attrlist
, refresh
) == value
1909 except Exception, e
:
1910 self
.logger
.debug('_cache_check(%s) : [%s]'
1911 % (str(attrlist
), str(e
)))
1916 Link
.IFLA_BOND_MODE
: 'mode',
1917 Link
.IFLA_BOND_MIIMON
: 'miimon',
1918 Link
.IFLA_BOND_USE_CARRIER
: 'use_carrier',
1919 Link
.IFLA_BOND_AD_LACP_RATE
: 'lacp_rate',
1920 Link
.IFLA_BOND_XMIT_HASH_POLICY
: 'xmit_hash_policy',
1921 Link
.IFLA_BOND_MIN_LINKS
: 'min_links',
1922 Link
.IFLA_BOND_NUM_PEER_NOTIF
: 'num_grat_arp',
1923 Link
.IFLA_BOND_AD_ACTOR_SYSTEM
: 'ad_actor_system',
1924 Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
: 'ad_actor_sys_prio',
1925 Link
.IFLA_BOND_AD_LACP_BYPASS
: 'lacp_bypass',
1926 Link
.IFLA_BOND_UPDELAY
: 'updelay',
1927 Link
.IFLA_BOND_DOWNDELAY
: 'downdelay',
1930 def bond_set_attrs_nl(self
, bondname
, ifla_info_data
):
1931 bond_attr_name
= 'None' # for log purpose (in case an exception raised)
1932 for nl_attr
, value
in ifla_info_data
.items():
1934 bond_attr_name
= self
.bondcmd_attrmap
[nl_attr
]
1935 file_path
= '/sys/class/net/%s/bonding/%s' % (bondname
, bond_attr_name
)
1936 if os
.path
.exists(file_path
):
1937 self
.write_file(file_path
, str(value
))
1938 except Exception as e
:
1939 exception_str
= '%s: %s %s: %s' % (bondname
, bond_attr_name
, value
, str(e
))
1940 if ifupdownflags
.flags
.FORCE
:
1941 self
.logger
.warning(exception_str
)
1943 self
.logger
.debug(exception_str
)
1945 def bond_set_attrs(self
, bondname
, attrdict
, prehook
):
1946 for attrname
, attrval
in attrdict
.items():
1947 if (self
._link
_cache
_check
([bondname
, 'linkinfo',
1948 attrname
], attrval
)):
1950 if (attrname
== 'mode'
1951 or attrname
== 'xmit_hash_policy'
1952 or attrname
== 'lacp_rate' or attrname
== 'min_links'):
1956 if ((attrname
not in ['lacp_rate',
1958 self
._link
_cache
_check
([bondname
, 'linkinfo', 'mode'], '802.3ad',
1960 self
.write_file('/sys/class/net/%s/bonding/%s'
1961 % (bondname
, attrname
), attrval
)
1962 except Exception, e
:
1963 if ifupdownflags
.flags
.FORCE
:
1964 self
.logger
.warn(str(e
))
1969 def bond_set_use_carrier(self
, bondname
, use_carrier
):
1970 if not use_carrier
or (use_carrier
!= '0' and use_carrier
!= '1'):
1972 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'use_carrier'],
1975 self
.write_file('/sys/class/net/%s' % bondname
+
1976 '/bonding/use_carrier', use_carrier
)
1977 self
._cache
_update
([bondname
, 'linkinfo',
1978 'use_carrier'], use_carrier
)
1980 def bond_get_use_carrier(self
, bondname
):
1981 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'use_carrier'])
1983 def bond_get_use_carrier_nl(self
, bondname
):
1984 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_USE_CARRIER
])
1986 def bond_set_xmit_hash_policy(self
, bondname
, hash_policy
, prehook
=None):
1987 valid_values
= ['layer2', 'layer3+4', 'layer2+3']
1990 if hash_policy
not in valid_values
:
1991 raise Exception('invalid hash policy value %s' % hash_policy
)
1992 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'xmit_hash_policy'],
1997 self
.write_file('/sys/class/net/%s' % bondname
+
1998 '/bonding/xmit_hash_policy', hash_policy
)
1999 self
._cache
_update
([bondname
, 'linkinfo', 'xmit_hash_policy'],
2002 def bond_get_xmit_hash_policy(self
, bondname
):
2003 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'xmit_hash_policy'])
2005 def bond_get_xmit_hash_policy_nl(self
, bondname
):
2006 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_XMIT_HASH_POLICY
])
2008 def bond_set_miimon(self
, bondname
, miimon
):
2009 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'miimon'],
2012 self
.write_file('/sys/class/net/%s' % bondname
+
2013 '/bonding/miimon', miimon
)
2014 self
._cache
_update
([bondname
, 'linkinfo', 'miimon'], miimon
)
2016 def bond_get_miimon(self
, bondname
):
2017 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'miimon'])
2019 def bond_get_miimon_nl(self
, bondname
):
2020 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MIIMON
])
2022 def bond_set_mode(self
, bondname
, mode
, prehook
=None):
2023 valid_modes
= ['balance-rr', 'active-backup', 'balance-xor',
2024 'broadcast', '802.3ad', 'balance-tlb', 'balance-alb']
2027 if mode
not in valid_modes
:
2028 raise Exception('invalid mode %s' % mode
)
2029 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'mode'],
2034 self
.write_file('/sys/class/net/%s' % bondname
+ '/bonding/mode', mode
)
2035 self
._cache
_update
([bondname
, 'linkinfo', 'mode'], mode
)
2037 def bond_get_mode(self
, bondname
):
2038 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'mode'])
2040 def bond_get_mode_nl(self
, bondname
):
2041 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MODE
])
2043 def bond_set_lacp_rate(self
, bondname
, lacp_rate
, prehook
=None, posthook
=None):
2044 if not lacp_rate
or (lacp_rate
!= '0' and lacp_rate
!= '1'):
2046 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'lacp_rate'],
2052 self
.write_file('/sys/class/net/%s' % bondname
+
2053 '/bonding/lacp_rate', lacp_rate
)
2059 self
._cache
_update
([bondname
, 'linkinfo',
2060 'lacp_rate'], lacp_rate
)
2062 def bond_get_lacp_rate(self
, bondname
):
2063 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'lacp_rate'])
2065 def bond_get_lacp_rate_nl(self
, bondname
):
2066 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_RATE
])
2068 def bond_set_lacp_bypass_allow(self
, bondname
, allow
, prehook
=None, posthook
=None):
2069 if self
._link
_cache
_check
([bondname
, 'linkinfo', 'lacp_bypass'], allow
):
2074 self
.write_file('/sys/class/net/%s' % bondname
+
2075 '/bonding/lacp_bypass', allow
)
2081 self
._cache
_update
([bondname
, 'linkinfo',
2082 'lacp_bypass'], allow
)
2084 def bond_get_lacp_bypass_allow(self
, bondname
):
2085 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'lacp_bypass'])
2087 def bond_get_lacp_bypass_allow_nl(self
, bondname
):
2088 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_BYPASS
])
2090 def bond_set_min_links(self
, bondname
, min_links
, prehook
=None):
2091 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'min_links'],
2096 self
.write_file('/sys/class/net/%s/bonding/min_links' % bondname
,
2098 self
._cache
_update
([bondname
, 'linkinfo', 'min_links'], min_links
)
2100 def bond_get_min_links(self
, bondname
):
2101 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'min_links'])
2103 def get_min_links_nl(self
, bondname
):
2104 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MIN_LINKS
])
2106 def bond_get_ad_actor_system(self
, bondname
):
2107 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'ad_actor_system'])
2109 def bond_get_ad_actor_system_nl(self
, bondname
):
2110 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYSTEM
])
2112 def bond_get_ad_actor_sys_prio(self
, bondname
):
2113 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'ad_actor_sys_prio'])
2115 def bond_get_ad_actor_sys_prio_nl(self
, bondname
):
2116 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
])
2118 def bond_get_num_unsol_na(self
, bondname
):
2119 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'num_unsol_na'])
2121 def bond_get_num_unsol_na_nl(self
, bondname
):
2122 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
])
2124 def bond_get_num_grat_arp(self
, bondname
):
2125 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'num_grat_arp'])
2127 def bond_get_num_grat_arp_nl(self
, bondname
):
2128 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
])
2130 def bond_get_updelay(self
, bondname
):
2131 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'updelay'])
2133 def bond_get_updelay_nl(self
, bondname
):
2134 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_UPDELAY
])
2136 def bond_get_downdelay(self
, bondname
):
2137 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'downdelay'])
2139 def bond_get_downdelay_nl(self
, bondname
):
2140 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_DOWNDELAY
])
2142 def bond_enslave_slave(self
, bondname
, slave
, prehook
=None, posthook
=None):
2143 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2144 if slaves
and slave
in slaves
:
2148 self
.write_file('/sys/class/net/%s' % bondname
+
2149 '/bonding/slaves', '+' + slave
)
2152 self
._cache
_update
([bondname
, 'linkinfo', 'slaves'], slave
)
2154 def bond_remove_slave(self
, bondname
, slave
):
2155 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2156 if not slaves
or slave
not in slaves
:
2158 sysfs_bond_path
= ('/sys/class/net/%s' % bondname
+
2160 if not os
.path
.exists(sysfs_bond_path
):
2162 self
.write_file(sysfs_bond_path
, '-' + slave
)
2163 self
._cache
_delete
([bondname
, 'linkinfo', 'slaves'], slave
)
2165 def bond_remove_slaves_all(self
, bondname
):
2166 if not self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves']):
2169 sysfs_bond_path
= ('/sys/class/net/%s' % bondname
+
2172 with
open(sysfs_bond_path
, 'r') as f
:
2173 slaves
= f
.readline().strip().split()
2175 raise Exception('error reading slaves of bond %s (%s)' % (bondname
, str(e
)))
2176 for slave
in slaves
:
2177 self
.link_down(slave
)
2179 self
.bond_remove_slave(bondname
, slave
)
2180 except Exception, e
:
2181 if not ifupdownflags
.flags
.FORCE
:
2182 raise Exception('error removing slave %s from bond %s (%s)' % (slave
, bondname
, str(e
)))
2185 self
._cache
_delete
([bondname
, 'linkinfo', 'slaves'])
2188 def bond_load_bonding_module():
2189 return utils
.exec_command('%s -q bonding' % utils
.modprobe_cmd
)
2191 def create_bond(self
, bondname
):
2192 if self
.bond_exists(bondname
):
2194 # load_bonding_module() has already been run
2195 self
.write_file('/sys/class/net/bonding_masters', '+' + bondname
)
2196 self
._cache
_update
([bondname
], {})
2198 def delete_bond(self
, bondname
):
2199 if not os
.path
.exists('/sys/class/net/%s' % bondname
):
2201 self
.write_file('/sys/class/net/bonding_masters', '-' + bondname
)
2202 self
._cache
_delete
([bondname
])
2204 def bond_get_slaves(self
, bondname
):
2205 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2208 slavefile
= '/sys/class/net/%s/bonding/slaves' % bondname
2209 if os
.path
.exists(slavefile
):
2210 buf
= self
.read_file_oneline(slavefile
)
2212 slaves
= buf
.split()
2215 self
._cache
_update
([bondname
, 'linkinfo', 'slaves'], slaves
)
2218 def bond_slave_exists(self
, bond
, slave
):
2219 slaves
= self
.bond_get_slaves(bond
)
2222 return slave
in slaves
2225 def bond_exists(bondname
):
2226 return os
.path
.exists('/sys/class/net/%s/bonding' % bondname
)
2228 #################################################################################
2229 ################################## BRIDGE UTILS #################################
2230 #################################################################################
2232 def create_bridge(self
, bridgename
):
2233 if not LinkUtils
.bridge_utils_is_installed
:
2235 if self
.bridge_exists(bridgename
):
2237 utils
.exec_command('%s addbr %s' % (utils
.brctl_cmd
, bridgename
))
2238 self
._cache
_update
([bridgename
], {})
2240 def delete_bridge(self
, bridgename
):
2241 if not LinkUtils
.bridge_utils_is_installed
:
2243 if not self
.bridge_exists(bridgename
):
2245 utils
.exec_command('%s delbr %s' % (utils
.brctl_cmd
, bridgename
))
2246 self
._cache
_invalidate
()
2248 def add_bridge_port(self
, bridgename
, bridgeportname
):
2249 """ Add port to bridge """
2250 if not LinkUtils
.bridge_utils_is_installed
:
2252 ports
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports'])
2253 if ports
and ports
.get(bridgeportname
):
2255 utils
.exec_command('%s addif %s %s' % (utils
.brctl_cmd
, bridgename
, bridgeportname
))
2256 self
._cache
_update
([bridgename
, 'linkinfo', 'ports', bridgeportname
], {})
2258 def delete_bridge_port(self
, bridgename
, bridgeportname
):
2259 """ Delete port from bridge """
2260 if not LinkUtils
.bridge_utils_is_installed
:
2262 ports
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports'])
2263 if not ports
or not ports
.get(bridgeportname
):
2265 utils
.exec_command('%s delif %s %s' % (utils
.brctl_cmd
, bridgename
, bridgeportname
))
2266 self
._cache
_delete
([bridgename
, 'linkinfo', 'ports', 'bridgeportname'])
2268 def set_bridgeport_attrs(self
, bridgename
, bridgeportname
, attrdict
):
2269 portattrs
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports', bridgeportname
])
2270 if portattrs
== None:
2272 for k
, v
in attrdict
.iteritems():
2273 if ifupdownflags
.flags
.CACHE
:
2274 curval
= portattrs
.get(k
)
2275 if curval
and curval
== v
:
2277 if k
== 'unicast-flood':
2278 self
.write_file('/sys/class/net/%s/brport/unicast_flood' % bridgeportname
, v
)
2279 elif k
== 'multicast-flood':
2280 self
.write_file('/sys/class/net/%s/brport/multicast_flood' % bridgeportname
, v
)
2281 elif k
== 'learning':
2282 self
.write_file('/sys/class/net/%s/brport/learning' % bridgeportname
, v
)
2283 elif k
== 'arp-nd-suppress':
2284 self
.write_file('/sys/class/net/%s/brport/neigh_suppress' % bridgeportname
, v
)
2286 if not LinkUtils
.bridge_utils_is_installed
:
2288 utils
.exec_command('%s set%s %s %s %s' % (utils
.brctl_cmd
, k
, bridgename
, bridgeportname
, v
))
2290 def set_bridgeport_attr(self
, bridgename
, bridgeportname
,
2292 if not LinkUtils
.bridge_utils_is_installed
:
2294 if self
._link
_cache
_check
([bridgename
, 'linkinfo', 'ports', bridgeportname
, attrname
], attrval
):
2296 utils
.exec_command('%s set%s %s %s %s' %
2303 def set_bridge_attrs(self
, bridgename
, attrdict
):
2304 for k
, v
in attrdict
.iteritems():
2307 if self
._link
_cache
_check
([bridgename
, 'linkinfo', k
], v
):
2310 if k
== 'igmp-version':
2311 self
.write_file('/sys/class/net/%s/bridge/'
2312 'multicast_igmp_version' % bridgename
, v
)
2313 elif k
== 'mld-version':
2314 self
.write_file('/sys/class/net/%s/bridge/'
2315 'multicast_mld_version' % bridgename
, v
)
2316 elif k
== 'vlan-protocol':
2317 self
.write_file('/sys/class/net/%s/bridge/'
2318 'vlan_protocol' % bridgename
,
2319 VlanProtocols
.ETHERTYPES_TO_ID
.get(v
.upper(),
2321 elif k
== 'vlan-stats':
2322 self
.write_file('/sys/class/net/%s/bridge/'
2323 'vlan_stats_enabled' % bridgename
, v
)
2324 elif k
== 'mcstats':
2325 self
.write_file('/sys/class/net/%s/bridge/'
2326 'multicast_stats_enabled' % bridgename
, v
)
2328 if not LinkUtils
.bridge_utils_is_installed
:
2330 cmd
= ('%s set%s %s %s' %
2331 (utils
.brctl_cmd
, k
, bridgename
, v
))
2332 utils
.exec_command(cmd
)
2333 except Exception, e
:
2334 self
.logger
.warn('%s: %s' % (bridgename
, str(e
)))
2337 def set_bridge_attr(self
, bridgename
, attrname
, attrval
):
2338 if self
._link
_cache
_check
([bridgename
, 'linkinfo', attrname
], attrval
):
2340 if attrname
== 'igmp-version':
2341 self
.write_file('/sys/class/net/%s/bridge/multicast_igmp_version'
2342 % bridgename
, attrval
)
2343 elif attrname
== 'mld-version':
2344 self
.write_file('/sys/class/net/%s/bridge/multicast_mld_version'
2345 % bridgename
, attrval
)
2346 elif attrname
== 'vlan-protocol':
2347 self
.write_file('/sys/class/net/%s/bridge/vlan_protocol'
2348 % bridgename
, VlanProtocols
.ETHERTYPES_TO_ID
[attrval
.upper()])
2349 elif attrname
== 'vlan-stats':
2350 self
.write_file('/sys/class/net/%s/bridge/vlan_stats_enabled'
2351 % bridgename
, attrval
)
2352 elif attrname
== 'mcstats':
2353 self
.write_file('/sys/class/net/%s/bridge/multicast_stats_enabled'
2354 % bridgename
, attrval
)
2356 if not LinkUtils
.bridge_utils_is_installed
:
2358 cmd
= '%s set%s %s %s' % (utils
.brctl_cmd
,
2359 attrname
, bridgename
, attrval
)
2360 utils
.exec_command(cmd
)
2362 def get_bridge_attrs(self
, bridgename
):
2363 attrs
= self
._link
_cache
_get
([bridgename
, 'linkinfo'])
2365 for key
, value
in attrs
.items():
2366 if type(key
) == str:
2367 no_ints_attrs
[key
] = value
2368 return no_ints_attrs
2370 def get_bridgeport_attrs(self
, bridgename
, bridgeportname
):
2371 return self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports',
2374 def get_bridgeport_attr(self
, bridgename
, bridgeportname
, attrname
):
2375 return self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports',
2376 bridgeportname
, attrname
])
2379 def bridge_set_stp(bridge
, stp_state
):
2380 if not LinkUtils
.bridge_utils_is_installed
:
2382 utils
.exec_command('%s stp %s %s' % (utils
.brctl_cmd
, bridge
, stp_state
))
2384 def bridge_get_stp(self
, bridge
):
2385 sysfs_stpstate
= '/sys/class/net/%s/bridge/stp_state' % bridge
2386 if not os
.path
.exists(sysfs_stpstate
):
2388 stpstate
= self
.read_file_oneline(sysfs_stpstate
)
2392 if int(stpstate
) > 0:
2394 elif int(stpstate
) == 0:
2400 def _conv_value_to_user(s
):
2407 def read_value_from_sysfs(self
, filename
, preprocess_func
):
2408 value
= self
.read_file_oneline(filename
)
2411 return preprocess_func(value
)
2414 def bridge_set_ageing(bridge
, ageing
):
2415 if not LinkUtils
.bridge_utils_is_installed
:
2417 utils
.exec_command('%s setageing %s %s' % (utils
.brctl_cmd
, bridge
, ageing
))
2419 def bridge_get_ageing(self
, bridge
):
2420 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/ageing_time'
2421 % bridge
, self
._conv
_value
_to
_user
)
2424 def set_bridgeprio(bridge
, prio
):
2425 if not LinkUtils
.bridge_utils_is_installed
:
2427 utils
.exec_command('%s setbridgeprio %s %s' % (utils
.brctl_cmd
, bridge
, prio
))
2429 def get_bridgeprio(self
, bridge
):
2430 return self
.read_file_oneline(
2431 '/sys/class/net/%s/bridge/priority' % bridge
)
2434 def bridge_set_fd(bridge
, fd
):
2435 if not LinkUtils
.bridge_utils_is_installed
:
2437 utils
.exec_command('%s setfd %s %s' % (utils
.brctl_cmd
, bridge
, fd
))
2439 def bridge_get_fd(self
, bridge
):
2440 return self
.read_value_from_sysfs(
2441 '/sys/class/net/%s/bridge/forward_delay'
2442 % bridge
, self
._conv
_value
_to
_user
)
2444 def bridge_set_gcint(self
, bridge
, gcint
):
2445 raise Exception('set_gcint not implemented')
2448 def bridge_set_hello(bridge
, hello
):
2449 if not LinkUtils
.bridge_utils_is_installed
:
2451 utils
.exec_command('%s sethello %s %s' % (utils
.brctl_cmd
, bridge
, hello
))
2453 def bridge_get_hello(self
, bridge
):
2454 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/hello_time'
2455 % bridge
, self
._conv
_value
_to
_user
)
2458 def bridge_set_maxage(bridge
, maxage
):
2459 if not LinkUtils
.bridge_utils_is_installed
:
2461 utils
.exec_command('%s setmaxage %s %s' % (utils
.brctl_cmd
, bridge
, maxage
))
2463 def bridge_get_maxage(self
, bridge
):
2464 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/max_age'
2465 % bridge
, self
._conv
_value
_to
_user
)
2468 def bridge_set_pathcost(bridge
, port
, pathcost
):
2469 if not LinkUtils
.bridge_utils_is_installed
:
2471 utils
.exec_command('%s setpathcost %s %s %s' % (utils
.brctl_cmd
, bridge
, port
, pathcost
))
2473 def bridge_get_pathcost(self
, bridge
, port
):
2474 return self
.read_file_oneline('/sys/class/net/%s/brport/path_cost'
2478 def bridge_set_portprio(bridge
, port
, prio
):
2479 if not LinkUtils
.bridge_utils_is_installed
:
2481 utils
.exec_command('%s setportprio %s %s %s' % (utils
.brctl_cmd
, bridge
, port
, prio
))
2483 def bridge_get_portprio(self
, bridge
, port
):
2484 return self
.read_file_oneline('/sys/class/net/%s/brport/priority'
2488 def bridge_set_hashmax(bridge
, hashmax
):
2489 if not LinkUtils
.bridge_utils_is_installed
:
2491 utils
.exec_command('%s sethashmax %s %s' % (utils
.brctl_cmd
, bridge
, hashmax
))
2493 def bridge_get_hashmax(self
, bridge
):
2494 return self
.read_file_oneline('/sys/class/net/%s/bridge/hash_max'
2498 def bridge_set_hashel(bridge
, hashel
):
2499 if not LinkUtils
.bridge_utils_is_installed
:
2501 utils
.exec_command('%s sethashel %s %s' % (utils
.brctl_cmd
, bridge
, hashel
))
2503 def bridge_get_hashel(self
, bridge
):
2504 return self
.read_file_oneline('/sys/class/net/%s/bridge/hash_elasticity'
2508 def bridge_set_mclmc(bridge
, mclmc
):
2509 if not LinkUtils
.bridge_utils_is_installed
:
2511 utils
.exec_command('%s setmclmc %s %s' % (utils
.brctl_cmd
, bridge
, mclmc
))
2513 def bridge_get_mclmc(self
, bridge
):
2514 return self
.read_file_oneline(
2515 '/sys/class/net/%s/bridge/multicast_last_member_count'
2519 def bridge_set_mcrouter(bridge
, mcrouter
):
2520 if not LinkUtils
.bridge_utils_is_installed
:
2522 utils
.exec_command('%s setmcrouter %s %s' % (utils
.brctl_cmd
, bridge
, mcrouter
))
2524 def bridge_get_mcrouter(self
, bridge
):
2525 return self
.read_file_oneline(
2526 '/sys/class/net/%s/bridge/multicast_router' % bridge
)
2529 def bridge_set_mcsnoop(bridge
, mcsnoop
):
2530 if not LinkUtils
.bridge_utils_is_installed
:
2532 utils
.exec_command('%s setmcsnoop %s %s' % (utils
.brctl_cmd
, bridge
, mcsnoop
))
2534 def bridge_get_mcsnoop(self
, bridge
):
2535 return self
.read_file_oneline(
2536 '/sys/class/net/%s/bridge/multicast_snooping' % bridge
)
2539 def bridge_set_mcsqc(bridge
, mcsqc
):
2540 if not LinkUtils
.bridge_utils_is_installed
:
2542 utils
.exec_command('%s setmcsqc %s %s' % (utils
.brctl_cmd
, bridge
, mcsqc
))
2544 def bridge_get_mcsqc(self
, bridge
):
2545 return self
.read_file_oneline(
2546 '/sys/class/net/%s/bridge/multicast_startup_query_count'
2550 def bridge_set_mcqifaddr(bridge
, mcqifaddr
):
2551 if not LinkUtils
.bridge_utils_is_installed
:
2553 utils
.exec_command('%s setmcqifaddr %s %s' % (utils
.brctl_cmd
, bridge
, mcqifaddr
))
2555 def bridge_get_mcqifaddr(self
, bridge
):
2556 return self
.read_file_oneline(
2557 '/sys/class/net/%s/bridge/multicast_startup_query_use_ifaddr'
2561 def bridge_set_mcquerier(bridge
, mcquerier
):
2562 if not LinkUtils
.bridge_utils_is_installed
:
2564 utils
.exec_command('%s setmcquerier %s %s' % (utils
.brctl_cmd
, bridge
, mcquerier
))
2566 def bridge_get_mcquerier(self
, bridge
):
2567 return self
.read_file_oneline(
2568 '/sys/class/net/%s/bridge/multicast_querier' % bridge
)
2570 def bridge_set_mcqv4src(self
, bridge
, vlan
, mcquerier
):
2574 self
.logger
.info('%s: set mcqv4src vlan: invalid parameter %s: %s' %(bridge
, vlan
, str(e
)))
2576 if vlan
== 0 or vlan
> 4095:
2577 self
.logger
.warn('mcqv4src vlan \'%d\' invalid range' % vlan
)
2580 ip
= mcquerier
.split('.')
2582 self
.logger
.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier
)
2585 if not k
.isdigit() or int(k
, 10) < 0 or int(k
, 10) > 255:
2586 self
.logger
.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier
)
2589 if not LinkUtils
.bridge_utils_is_installed
:
2592 utils
.exec_command('%s setmcqv4src %s %d %s' %
2593 (utils
.brctl_cmd
, bridge
, vlan
, mcquerier
))
2595 def bridge_del_mcqv4src(self
, bridge
, vlan
):
2596 if not LinkUtils
.bridge_utils_is_installed
:
2601 self
.logger
.info('%s: del mcqv4src vlan: invalid parameter %s: %s' %(bridge
, vlan
, str(e
)))
2603 utils
.exec_command('%s delmcqv4src %s %d' % (utils
.brctl_cmd
, bridge
, vlan
))
2605 def bridge_get_mcqv4src(self
, bridge
, vlan
=None):
2606 if not LinkUtils
.bridge_utils_is_installed
:
2608 if not self
.supported_command
['showmcqv4src']:
2612 mcqout
= utils
.exec_command('%s showmcqv4src %s' %
2613 (utils
.brctl_cmd
, bridge
))
2614 except Exception as e
:
2616 if 'never heard' in s
:
2617 msg
= ('%s showmcqv4src: skipping unsupported command'
2619 self
.logger
.info(msg
)
2620 self
.supported_command
['showmcqv4src'] = False
2625 mcqlines
= mcqout
.splitlines()
2626 for l
in mcqlines
[1:]:
2628 k
, d
, v
= l
.split('\t')
2633 return mcqv4src
.get(vlan
)
2636 def bridge_get_mcqv4src_sysfs(self
, bridge
, vlan
=None):
2637 if not LinkUtils
.bridge_utils_is_installed
:
2639 if not self
.supported_command
['showmcqv4src']:
2641 if ifupdownflags
.flags
.PERFMODE
:
2645 filename
= '/sys/class/net/%s/bridge/multicast_v4_queriers' % bridge
2646 if os
.path
.exists(filename
):
2647 for line
in self
.read_file(filename
) or []:
2648 vlan_id
, ip
= line
.split('=')
2649 mcqv4src
[vlan_id
] = ip
.strip()
2650 except Exception as e
:
2652 msg
= ('%s showmcqv4src: skipping unsupported command'
2654 self
.logger
.info(msg
)
2655 self
.supported_command
['showmcqv4src'] = False
2658 return mcqv4src
.get(vlan
)
2662 def bridge_set_mclmi(bridge
, mclmi
):
2663 if not LinkUtils
.bridge_utils_is_installed
:
2665 utils
.exec_command('%s setmclmi %s %s' % (utils
.brctl_cmd
, bridge
, mclmi
))
2667 def bridge_get_mclmi(self
, bridge
):
2668 return self
.read_file_oneline(
2669 '/sys/class/net/%s/bridge/multicast_last_member_interval'
2673 def bridge_set_mcmi(bridge
, mcmi
):
2674 if not LinkUtils
.bridge_utils_is_installed
:
2676 utils
.exec_command('%s setmcmi %s %s' % (utils
.brctl_cmd
, bridge
, mcmi
))
2678 def bridge_get_mcmi(self
, bridge
):
2679 return self
.read_file_oneline(
2680 '/sys/class/net/%s/bridge/multicast_membership_interval'
2684 def bridge_exists(bridge
):
2685 return os
.path
.exists('/sys/class/net/%s/bridge' % bridge
)
2688 def is_bridge_port(ifacename
):
2689 return os
.path
.exists('/sys/class/net/%s/brport' % ifacename
)
2692 def bridge_port_exists(bridge
, bridgeportname
):
2694 return os
.path
.exists('/sys/class/net/%s/brif/%s' % (bridge
, bridgeportname
))
2699 def get_bridge_ports(bridgename
):
2701 return os
.listdir('/sys/class/net/%s/brif/' % bridgename
)
2705 def reset_addr_cache(self
, ifname
):
2707 linkCache
.links
[ifname
]['addrs'] = {}
2708 self
.logger
.debug('%s: reset address cache' % ifname
)
2712 def get_ipv6_addrgen_mode(self
, ifname
):
2714 return self
._cache
_get
('link', [ifname
, 'af_spec', socket
.AF_INET6
])[Link
.IFLA_INET6_ADDR_GEN_MODE
]
2716 # default to 0 (eui64)
2719 def ipv6_addrgen(self
, ifname
, addrgen
, link_created
):
2721 # IFLA_INET6_ADDR_GEN_MODE values:
2724 if self
._link
_cache
_get
([ifname
, 'af_spec', socket
.AF_INET6
])[Link
.IFLA_INET6_ADDR_GEN_MODE
] == addrgen
:
2725 self
.logger
.debug('%s: ipv6 addrgen already %s' % (ifname
, 'off' if addrgen
else 'on'))
2728 disabled_ipv6
= self
.read_file_oneline('/proc/sys/net/ipv6/conf/%s/disable_ipv6' % ifname
)
2729 if not disabled_ipv6
or int(disabled_ipv6
) == 1:
2730 self
.logger
.info('%s: cannot set addrgen: ipv6 is disabled on this device' % ifname
)
2733 if int(self
._link
_cache
_get
([ifname
, 'mtu'])) < 1280:
2734 self
.logger
.info('%s: ipv6 addrgen is disabled on device with MTU '
2735 'lower than 1280: cannot set addrgen %s' % (ifname
, 'off' if addrgen
else 'on'))
2737 except (KeyError, TypeError):
2738 self
.logger
.debug('%s: ipv6 addrgen probably not supported or disabled on this device' % ifname
)
2743 if not link_created
:
2744 # When setting addrgenmode it is necessary to flap the macvlan
2745 # device. After flapping the device we also need to re-add all
2746 # the user configuration. The best way to add the user config
2747 # is to flush our internal address cache
2748 self
.reset_addr_cache(ifname
)
2750 cmd
= 'link set dev %s addrgenmode %s' % (ifname
, 'none' if addrgen
else 'eui64')
2752 is_link_up
= self
.is_link_up(ifname
)
2755 self
.link_down(ifname
)
2757 if LinkUtils
.ipbatch
:
2758 self
.add_to_batch(cmd
)
2760 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
2763 self
.link_up(ifname
)