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 string
import maketrans
17 from ipaddr
import IPNetwork
, IPv6Network
20 import ifupdown2
.ifupdown
.statemanager
as statemanager
21 import ifupdown2
.ifupdown
.ifupdownflags
as ifupdownflags
23 from ifupdown2
.nlmanager
.nlmanager
import Link
, Route
25 from ifupdown2
.ifupdown
.iface
import *
26 from ifupdown2
.ifupdown
.utils
import utils
27 from ifupdown2
.ifupdown
.netlink
import netlink
29 from ifupdown2
.ifupdownaddons
.utilsbase
import utilsBase
30 from ifupdown2
.ifupdownaddons
.cache
import linkCache
, MSTPAttrsCache
32 import ifupdown
.ifupdownflags
as ifupdownflags
33 import ifupdown
.statemanager
as statemanager
35 from nlmanager
.nlmanager
import Link
, Route
37 from ifupdown
.iface
import *
38 from ifupdown
.utils
import utils
39 from ifupdown
.netlink
import netlink
41 from ifupdownaddons
.utilsbase
import utilsBase
42 from ifupdownaddons
.cache
import linkCache
, MSTPAttrsCache
45 class LinkUtils(utilsBase
):
47 This class contains helper methods to cache and manipulate interfaces through
48 non-netlink APIs (sysfs, iproute2, brctl...)
50 _CACHE_FILL_DONE
= False
57 bridge_utils_is_installed
= os
.path
.exists(utils
.brctl_cmd
)
58 bridge_utils_missing_warning
= True
60 DEFAULT_IP_METRIC
= 1024
61 ADDR_METRIC_SUPPORT
= None
63 mac_translate_tab
= maketrans(":.-,", " ")
65 def __init__(self
, *args
, **kargs
):
66 utilsBase
.__init
__(self
, *args
, **kargs
)
68 self
.supported_command
= {
69 '%s -c -json vlan show' % utils
.bridge_cmd
: True,
72 self
.bridge_vlan_cache
= {}
73 self
.bridge_vlan_cache_fill_done
= False
75 if not ifupdownflags
.flags
.PERFMODE
and not LinkUtils
._CACHE
_FILL
_DONE
:
78 if LinkUtils
.ADDR_METRIC_SUPPORT
is None:
80 cmd
= [utils
.ip_cmd
, 'addr', 'help']
81 self
.logger
.info('executing %s addr help' % utils
.ip_cmd
)
83 process
= subprocess
.Popen(cmd
, stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
)
84 stdout
, stderr
= process
.communicate()
85 LinkUtils
.ADDR_METRIC_SUPPORT
= '[ metric METRIC ]' in stderr
or ''
86 self
.logger
.info('address metric support: %s' % ('OK' if LinkUtils
.ADDR_METRIC_SUPPORT
else 'KO'))
88 LinkUtils
.ADDR_METRIC_SUPPORT
= False
89 self
.logger
.info('address metric support: KO')
92 def mac_str_to_int(cls
, hw_address
):
95 for i
in hw_address
.translate(cls
.mac_translate_tab
).split():
101 def addr_metric_support(cls
):
102 return cls
.ADDR_METRIC_SUPPORT
105 def get_default_ip_metric(cls
):
106 return cls
.DEFAULT_IP_METRIC
110 LinkUtils
._CACHE
_FILL
_DONE
= False
111 LinkUtils
.ipbatchbuf
= ''
112 LinkUtils
.ipbatch
= False
113 LinkUtils
.ipbatch_pause
= False
115 def _fill_cache(self
):
116 if not LinkUtils
._CACHE
_FILL
_DONE
:
119 LinkUtils
._CACHE
_FILL
_DONE
= True
124 def _get_vland_id(citems
, i
, warn
):
127 index
= sub
.index('id')
129 return sub
[index
+ 1]
132 raise Exception('invalid use of \'vlan\' keyword')
135 def _link_fill(self
, ifacename
=None, refresh
=False):
136 """ fills cache with link information
138 if ifacename argument given, fill cache for ifacename, else
139 fill cache for all interfaces in the system
142 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
145 # if ifacename already present, return
146 if (ifacename
and not refresh
and
147 linkCache
.get_attr([ifacename
, 'ifflag'])):
154 [linkCache
.update_attrdict([ifname
], linkattrs
)
155 for ifname
, linkattrs
in netlink
.link_dump(ifacename
).items()]
156 except Exception as e
:
157 self
.logger
.info('%s' % str(e
))
158 # this netlink call replaces the call to _link_fill_iproute2_cmd()
159 # We shouldn't have netlink calls in the iproute2 module, this will
160 # be removed in the future. We plan to release, a flexible backend
161 # (netlink+iproute2) by default we will use netlink backend but with
162 # a CLI arg we can switch to iproute2 backend.
163 # Until we decide to create this "backend" switch capability,
164 # we have to put the netlink call inside the iproute2 module.
166 self
._link
_fill
_iproute
2_cmd
(ifacename
, refresh
)
168 self
._fill
_bond
_info
(ifacename
)
169 self
._fill
_bridge
_info
(ifacename
)
171 def _fill_bridge_info(self
, ifacename
):
177 cache_dict
= {ifacename
: linkCache
.links
.get(ifacename
, {})}
179 cache_dict
= linkCache
.links
181 for ifname
, obj
in cache_dict
.items():
182 slave_kind
= obj
.get('slave_kind')
183 if not slave_kind
and slave_kind
!= 'bridge':
186 info_slave_data
= obj
.get('info_slave_data')
187 if not info_slave_data
:
190 ifla_master
= obj
.get('master')
192 raise Exception('No master associated with bridge port %s' % ifname
)
195 Link
.IFLA_BRPORT_STATE
,
196 Link
.IFLA_BRPORT_COST
,
197 Link
.IFLA_BRPORT_PRIORITY
,
199 if nl_attr
not in info_slave_data
and LinkUtils
.bridge_utils_is_installed
:
200 self
._fill
_bridge
_info
_brctl
()
204 'pathcost': str(info_slave_data
.get(Link
.IFLA_BRPORT_COST
, 0)),
205 'fdelay': format(float(info_slave_data
.get(Link
.IFLA_BRPORT_FORWARD_DELAY_TIMER
, 0) / 100), '.2f'),
206 'portmcrouter': str(info_slave_data
.get(Link
.IFLA_BRPORT_MULTICAST_ROUTER
, 0)),
207 'portmcfl': str(info_slave_data
.get(Link
.IFLA_BRPORT_FAST_LEAVE
, 0)),
208 'portprio': str(info_slave_data
.get(Link
.IFLA_BRPORT_PRIORITY
, 0)),
209 'unicast-flood': str(info_slave_data
.get(Link
.IFLA_BRPORT_UNICAST_FLOOD
, 0)),
210 'multicast-flood': str(info_slave_data
.get(Link
.IFLA_BRPORT_MCAST_FLOOD
, 0)),
211 'learning': str(info_slave_data
.get(Link
.IFLA_BRPORT_LEARNING
, 0)),
212 'arp-nd-suppress': str(info_slave_data
.get(Link
.IFLA_BRPORT_ARP_SUPPRESS
, 0))
215 if ifla_master
in brports
:
216 brports
[ifla_master
][ifname
] = brport_attrs
218 brports
[ifla_master
] = {ifname
: brport_attrs
}
220 linkCache
.update_attrdict([ifla_master
, 'linkinfo', 'ports'], brports
[ifla_master
])
222 if LinkUtils
.bridge_utils_is_installed
:
223 self
._fill
_bridge
_info
_brctl
()
225 def _fill_bridge_info_brctl(self
):
226 brctlout
= utils
.exec_command('%s show' % utils
.brctl_cmd
)
230 for bline
in brctlout
.splitlines()[1:]:
231 bitems
= bline
.split()
235 linkCache
.update_attrdict([bitems
[0], 'linkinfo'],
238 linkCache
.update_attrdict([bitems
[0]],
239 {'linkinfo': {'stp': bitems
[2]}})
240 self
._bridge
_attrs
_fill
(bitems
[0])
242 def _bridge_attrs_fill(self
, bridgename
):
247 # Get all bridge attributes
248 # battrs['pathcost'] = broutlines[3].split('path cost')[1].strip()
251 battrs
['maxage'] = self
.read_file_oneline(
252 '/sys/class/net/%s/bridge/max_age' % bridgename
)
258 battrs
['hello'] = self
.read_file_oneline(
259 '/sys/class/net/%s/bridge/hello_time' % bridgename
)
264 battrs
['fd'] = self
.read_file_oneline(
265 '/sys/class/net/%s/bridge/forward_delay' % bridgename
)
270 battrs
['ageing'] = self
.read_file_oneline(
271 '/sys/class/net/%s/bridge/ageing_time' % bridgename
)
276 battrs
['mcrouter'] = self
.read_file_oneline(
277 '/sys/class/net/%s/bridge/multicast_router' % bridgename
)
282 battrs
['bridgeprio'] = self
.read_file_oneline(
283 '/sys/class/net/%s/bridge/priority' % bridgename
)
288 battrs
['vlan-protocol'] = VlanProtocols
.ID_TO_ETHERTYPES
[
289 self
.read_file_oneline(
290 '/sys/class/net/%s/bridge/vlan_protocol' % bridgename
)]
295 battrs
.update(self
._bridge
_get
_mcattrs
_from
_sysfs
(bridgename
))
299 # XXX: comment this out until mc attributes become available
302 # battrs['mciqc'] = broutlines[11].split('mc init query count')[1].strip()
303 # battrs['mclmt'] = broutlines[13].split('mc last member timer')[1].split()[0].strip()
305 self
.logger
.warn('%s: error while processing bridge attributes: %s' % (bridgename
, str(e
)))
308 linkCache
.update_attrdict([bridgename
, 'linkinfo'], battrs
)
310 names
= [os
.path
.basename(x
) for x
in glob
.glob("/sys/class/net/%s/brif/*" % bridgename
)]
315 bportattrs
['pathcost'] = self
.read_file_oneline(
316 '/sys/class/net/%s/brport/path_cost' % pname
)
317 bportattrs
['fdelay'] = self
.read_file_oneline(
318 '/sys/class/net/%s/brport/forward_delay_timer' % pname
)
319 bportattrs
['portmcrouter'] = self
.read_file_oneline(
320 '/sys/class/net/%s/brport/multicast_router' % pname
)
321 bportattrs
['portmcfl'] = self
.read_file_oneline(
322 '/sys/class/net/%s/brport/multicast_fast_leave' % pname
)
323 bportattrs
['portprio'] = self
.read_file_oneline(
324 '/sys/class/net/%s/brport/priority' % pname
)
325 bportattrs
['unicast-flood'] = self
.read_file_oneline(
326 '/sys/class/net/%s/brport/unicast_flood' % pname
)
327 bportattrs
['multicast-flood'] = self
.read_file_oneline(
328 '/sys/class/net/%s/brport/multicast_flood' % pname
)
329 bportattrs
['learning'] = self
.read_file_oneline(
330 '/sys/class/net/%s/brport/learning' % pname
)
331 bportattrs
['arp-nd-suppress'] = self
.read_file_oneline(
332 '/sys/class/net/%s/brport/neigh_suppress' % pname
)
334 #bportattrs['mcrouters'] = self.read_file_oneline(
335 # '/sys/class/net/%s/brport/multicast_router' % pname)
336 #bportattrs['mc fast leave'] = self.read_file_oneline(
337 # '/sys/class/net/%s/brport/multicast_fast_leave' % pname)
340 self
.logger
.warn('%s: error while processing bridge attributes: %s' % (bridgename
, str(e
)))
341 bports
[pname
] = bportattrs
342 linkCache
.update_attrdict([bridgename
, 'linkinfo', 'ports'], bports
)
344 _bridge_sysfs_mcattrs
= {
345 'mclmc': 'multicast_last_member_count',
346 'mcrouter': 'multicast_router',
347 'mcsnoop': 'multicast_snooping',
348 'mcsqc': 'multicast_startup_query_count',
349 'mcqifaddr': 'multicast_query_use_ifaddr',
350 'mcquerier': 'multicast_querier',
351 'hashel': 'hash_elasticity',
352 'hashmax': 'hash_max',
353 'mclmi': 'multicast_last_member_interval',
354 'mcmi': 'multicast_membership_interval',
355 'mcqpi': 'multicast_querier_interval',
356 'mcqi': 'multicast_query_interval',
357 'mcqri': 'multicast_query_response_interval',
358 'mcsqi': 'multicast_startup_query_interval',
359 'igmp-version': 'multicast_igmp_version',
360 'mld-version': 'multicast_mld_version',
361 'vlan-stats': 'vlan_stats_enabled',
362 'mcstats': 'multicast_stats_enabled',
365 def _bridge_get_mcattrs_from_sysfs(self
, bridgename
):
366 mcattrsdivby100
= ['mclmi', 'mcmi', 'mcqpi', 'mcqi', 'mcqri', 'mcsqi']
369 for m
, s
in self
._bridge
_sysfs
_mcattrs
.items():
370 n
= self
.read_file_oneline('/sys/class/net/%s/bridge/%s' % (bridgename
, s
))
371 if m
in mcattrsdivby100
:
376 self
.logger
.warn('error getting mc attr %s (%s)' % (m
, str(e
)))
382 def _fill_bond_info(self
, ifacename
):
383 bonding_masters
= self
.read_file_oneline('/sys/class/net/bonding_masters')
384 if not bonding_masters
:
387 bond_masters_list
= bonding_masters
.split()
390 if ifacename
in bond_masters_list
:
391 bond_masters_list
= [ifacename
]
393 # we want to refresh this interface only if it's a bond master
396 for bondname
in bond_masters_list
:
398 if bondname
not in linkCache
.links
:
399 linkCache
.set_attr([bondname
], {'linkinfo': {}})
400 linkCache
.set_attr([bondname
, 'linkinfo', 'slaves'],
401 self
.read_file_oneline('/sys/class/net/%s/bonding/slaves'
404 # if some attribute are missing we try to get the bond attributes via sysfs
405 bond_linkinfo
= linkCache
.links
[bondname
]['linkinfo']
406 for attr
in [Link
.IFLA_BOND_MODE
, Link
.IFLA_BOND_XMIT_HASH_POLICY
, Link
.IFLA_BOND_MIN_LINKS
]:
407 if attr
not in bond_linkinfo
:
408 self
._fill
_bond
_info
_sysfs
(bondname
)
409 # after we fill in the cache we can continue to the next bond
412 self
._fill
_bond
_info
_sysfs
(bondname
)
414 except Exception as e
:
415 self
.logger
.debug('LinkUtils: bond cache error: %s' % str(e
))
417 def _fill_bond_info_sysfs(self
, bondname
):
419 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_MIN_LINKS
],
420 self
.read_file_oneline(
421 '/sys/class/net/%s/bonding/min_links'
423 except Exception as e
:
424 self
.logger
.debug(str(e
))
427 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_MODE
],
428 self
.read_file_oneline('/sys/class/net/%s/bonding/mode'
429 % bondname
).split()[0])
430 except Exception as e
:
431 self
.logger
.debug(str(e
))
433 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_XMIT_HASH_POLICY
],
434 self
.read_file_oneline(
435 '/sys/class/net/%s/bonding/xmit_hash_policy'
436 % bondname
).split()[0])
437 except Exception as e
:
438 self
.logger
.debug(str(e
))
440 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_RATE
],
441 self
.read_file_oneline('/sys/class/net/%s/bonding/lacp_rate'
442 % bondname
).split()[1])
443 except Exception as e
:
444 self
.logger
.debug(str(e
))
446 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
],
447 self
.read_file_oneline('/sys/class/net/%s/bonding/ad_actor_sys_prio'
449 except Exception as e
:
450 self
.logger
.debug(str(e
))
452 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYSTEM
],
453 self
.read_file_oneline('/sys/class/net/%s/bonding/ad_actor_system'
455 except Exception as e
:
456 self
.logger
.debug(str(e
))
458 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_BYPASS
],
459 self
.read_file_oneline('/sys/class/net/%s/bonding/lacp_bypass'
460 % bondname
).split()[1])
461 except Exception as e
:
462 self
.logger
.debug(str(e
))
464 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_UPDELAY
],
465 self
.read_file_oneline('/sys/class/net/%s/bonding/updelay'
467 except Exception as e
:
468 self
.logger
.debug(str(e
))
470 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_DOWNDELAY
],
471 self
.read_file_oneline('/sys/class/net/%s/bonding/downdelay'
473 except Exception as e
:
474 self
.logger
.debug(str(e
))
477 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_USE_CARRIER
],
478 self
.read_file_oneline('/sys/class/net/%s/bonding/use_carrier' % bondname
))
479 except Exception as e
:
480 self
.logger
.debug(str(e
))
483 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_MIIMON
],
484 self
.read_file_oneline('/sys/class/net/%s/bonding/miimon' % bondname
))
485 except Exception as e
:
486 self
.logger
.debug(str(e
))
489 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
],
490 self
.read_file_oneline('/sys/class/net/%s/bonding/num_unsol_na' % bondname
))
491 except Exception as e
:
492 self
.logger
.debug(str(e
))
495 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
],
496 self
.read_file_oneline('/sys/class/net/%s/bonding/num_grat_arp' % bondname
))
497 except Exception as e
:
498 self
.logger
.debug(str(e
))
501 def _link_fill_iproute2_cmd(self
, ifacename
=None, refresh
=False):
504 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
507 # if ifacename already present, return
508 if (ifacename
and not refresh
and
509 linkCache
.get_attr([ifacename
, 'ifflag'])):
513 cmdout
= self
.link_show(ifacename
=ifacename
)
516 for c
in cmdout
.splitlines():
518 ifnamenlink
= citems
[1].split('@')
519 if len(ifnamenlink
) > 1:
520 ifname
= ifnamenlink
[0]
521 iflink
= ifnamenlink
[1].strip(':')
523 ifname
= ifnamenlink
[0].strip(':')
526 linkattrs
['link'] = iflink
527 linkattrs
['ifindex'] = citems
[0].strip(':')
528 flags
= citems
[2].strip('<>').split(',')
529 linkattrs
['flags'] = flags
530 linkattrs
['ifflag'] = 'UP' if 'UP' in flags
else 'DOWN'
531 for i
in range(0, len(citems
)):
533 if citems
[i
] == 'mtu':
534 linkattrs
['mtu'] = citems
[i
+ 1]
535 elif citems
[i
] == 'state':
536 linkattrs
['state'] = citems
[i
+ 1]
537 elif citems
[i
] == 'link/ether':
538 linkattrs
['hwaddress'] = citems
[i
+ 1]
539 elif citems
[i
] in ['link/gre', 'link/ipip', 'link/sit', 'link/gre6', 'link/tunnel6', 'gretap']:
540 linkattrs
['kind'] = 'tunnel'
541 tunattrs
= {'mode': citems
[i
].split('/')[-1],
546 for j
in range(i
, len(citems
)):
547 if citems
[j
] == 'local':
548 tunattrs
['local'] = citems
[j
+ 1]
549 elif citems
[j
] == 'remote':
550 tunattrs
['endpoint'] = citems
[j
+ 1]
551 elif citems
[j
] == 'ttl':
552 tunattrs
['ttl'] = citems
[j
+ 1]
553 elif citems
[j
] == 'dev':
554 tunattrs
['physdev'] = citems
[j
+ 1]
555 elif citems
[j
] in ['vti', 'vti6', 'ip6gre', 'ipip6', 'ip6ip6']:
556 tunattrs
['mode'] = citems
[j
]
557 linkattrs
['linkinfo'] = tunattrs
559 elif citems
[i
] == 'link/ppp':
560 linkattrs
['kind'] = 'ppp'
561 elif citems
[i
] == 'vlan':
562 vlanid
= self
._get
_vland
_id
(citems
, i
, warn
)
564 linkattrs
['linkinfo'] = {'vlanid': vlanid
}
565 linkattrs
['kind'] = 'vlan'
566 elif citems
[i
] == 'dummy':
567 linkattrs
['kind'] = 'dummy'
568 elif citems
[i
] == 'vxlan' and citems
[i
+ 1] == 'id':
569 linkattrs
['kind'] = 'vxlan'
570 vattrs
= {'vxlanid': citems
[i
+ 2],
573 'ageing': citems
[i
+ 2],
575 for j
in range(i
+ 2, len(citems
)):
576 if citems
[j
] == 'local':
577 vattrs
['local'] = citems
[j
+ 1]
578 elif citems
[j
] == 'remote':
579 vattrs
['svcnode'] = citems
[j
+ 1]
580 elif citems
[j
] == 'ageing':
581 vattrs
['ageing'] = citems
[j
+ 1]
582 elif citems
[j
] == 'nolearning':
583 vattrs
['learning'] = 'off'
584 elif citems
[j
] == 'dev':
585 vattrs
['physdev'] = citems
[j
+ 1]
586 linkattrs
['linkinfo'] = vattrs
588 elif citems
[i
] == 'vrf' and citems
[i
+ 1] == 'table':
589 vattrs
= {'table': citems
[i
+ 2]}
590 linkattrs
['linkinfo'] = vattrs
591 linkattrs
['kind'] = 'vrf'
592 linkCache
.vrfs
[ifname
] = vattrs
594 elif citems
[i
] == 'veth':
595 linkattrs
['kind'] = 'veth'
596 elif citems
[i
] == 'vrf_slave':
597 linkattrs
['slave_kind'] = 'vrf_slave'
599 elif citems
[i
] == 'macvlan' and citems
[i
+ 1] == 'mode':
600 linkattrs
['kind'] = 'macvlan'
601 elif citems
[i
] == 'xfrm':
602 linkattrs
['kind'] = 'xfrm'
603 except Exception as e
:
605 self
.logger
.debug('%s: parsing error: id, mtu, state, '
606 'link/ether, vlan, dummy, vxlan, local, '
607 'remote, ageing, nolearning, vrf, table, '
608 'vrf_slave are reserved keywords: %s' %
611 # linkattrs['alias'] = self.read_file_oneline(
612 # '/sys/class/net/%s/ifalias' %ifname)
613 linkout
[ifname
] = linkattrs
614 [linkCache
.update_attrdict([ifname
], linkattrs
)
615 for ifname
, linkattrs
in linkout
.items()]
618 def _addr_filter(ifname
, addr
, scope
=None):
619 default_addrs
= ['127.0.0.1/8', '::1/128', '0.0.0.0']
620 if ifname
== 'lo' and addr
in default_addrs
:
622 if scope
and scope
== 'link':
626 def _addr_fill(self
, ifacename
=None, refresh
=False):
627 """ fills cache with address information
629 if ifacename argument given, fill cache for ifacename, else
630 fill cache for all interfaces in the system
632 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
635 # Check if ifacename is already full, in which case, return
636 if ifacename
and not refresh
:
637 linkCache
.get_attr([ifacename
, 'addrs'])
644 [linkCache
.update_attrdict([ifname
], linkattrs
)
645 for ifname
, linkattrs
in netlink
.addr_dump(ifname
=ifacename
).items()]
646 except Exception as e
:
647 self
.logger
.info(str(e
))
649 # this netlink call replaces the call to _addr_fill_iproute2_cmd()
650 # We shouldn't have netlink calls in the iproute2 module, this will
651 # be removed in the future. We plan to release, a flexible backend
652 # (netlink+iproute2) by default we will use netlink backend but with
653 # a CLI arg we can switch to iproute2 backend.
654 # Until we decide to create this "backend" switch capability,
655 # we have to put the netlink call inside the iproute2 module.
658 self
._addr
_fill
_iproute
2_cmd
(ifacename
, refresh
)
660 def _addr_fill_iproute2_cmd(self
, ifacename
=None, refresh
=False):
661 """ fills cache with address information
663 if ifacename argument given, fill cache for ifacename, else
664 fill cache for all interfaces in the system
667 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
670 # Check if ifacename is already full, in which case, return
671 if ifacename
and not refresh
:
672 linkCache
.get_attr([ifacename
, 'addrs'])
676 cmdout
= self
.addr_show(ifacename
=ifacename
)
679 for c
in cmdout
.splitlines():
681 ifnamenlink
= citems
[1].split('@')
682 if len(ifnamenlink
) > 1:
683 ifname
= ifnamenlink
[0]
685 ifname
= ifnamenlink
[0].strip(':')
686 if not linkout
.get(ifname
):
688 linkattrs
['addrs'] = OrderedDict({})
690 linkout
[ifname
].update(linkattrs
)
692 linkout
[ifname
] = linkattrs
693 if citems
[2] == 'inet':
694 if self
._addr
_filter
(ifname
, citems
[3], scope
=citems
[5]):
697 addrattrs
['scope'] = citems
[5]
698 addrattrs
['type'] = 'inet'
699 linkout
[ifname
]['addrs'][citems
[3]] = addrattrs
700 elif citems
[2] == 'inet6':
701 if self
._addr
_filter
(ifname
, citems
[3], scope
=citems
[5]):
703 if citems
[5] == 'link':
704 continue # skip 'link' addresses
706 addrattrs
['scope'] = citems
[5]
707 addrattrs
['type'] = 'inet6'
708 linkout
[ifname
]['addrs'][citems
[3]] = addrattrs
709 [linkCache
.update_attrdict([ifname
], linkattrs
)
710 for ifname
, linkattrs
in linkout
.items()]
712 def del_cache_entry(self
, ifname
):
714 del linkCache
.links
[ifname
]
718 def cache_get(self
, t
, attrlist
, refresh
=False):
719 return self
._cache
_get
(t
, attrlist
, refresh
)
721 def _cache_get(self
, t
, attrlist
, refresh
=False):
723 if ifupdownflags
.flags
.DRYRUN
:
725 if ifupdownflags
.flags
.CACHE
:
726 if self
._fill
_cache
():
727 # if we filled the cache, return new data
728 return linkCache
.get_attr(attrlist
)
730 return linkCache
.get_attr(attrlist
)
732 self
._link
_fill
(attrlist
[0], refresh
)
734 self
._addr
_fill
(attrlist
[0], refresh
)
736 self
._link
_fill
(attrlist
[0], refresh
)
737 self
._addr
_fill
(attrlist
[0], refresh
)
738 return linkCache
.get_attr(attrlist
)
740 self
.logger
.debug('_cache_get(%s) : [%s]' % (str(attrlist
), str(e
)))
743 def cache_check(self
, attrlist
, value
, refresh
=False):
744 return self
._cache
_check
('link', attrlist
, value
, refresh
=refresh
)
746 def _cache_check(self
, t
, attrlist
, value
, refresh
=False):
748 return self
._cache
_get
(t
, attrlist
, refresh
) == value
750 self
.logger
.debug('_cache_check(%s) : [%s]'
751 % (str(attrlist
), str(e
)))
754 def cache_update(self
, attrlist
, value
):
755 return self
._cache
_update
(attrlist
, value
)
758 def _cache_update(attrlist
, value
):
759 if ifupdownflags
.flags
.DRYRUN
:
762 if attrlist
[-1] == 'slaves':
763 linkCache
.append_to_attrlist(attrlist
, value
)
765 linkCache
.set_attr(attrlist
, value
)
770 def _cache_delete(attrlist
, value
=None):
771 if ifupdownflags
.flags
.DRYRUN
:
775 linkCache
.remove_from_attrlist(attrlist
, value
)
777 linkCache
.del_attr(attrlist
)
782 def _cache_invalidate():
783 linkCache
.invalidate()
784 LinkUtils
._CACHE
_FILL
_DONE
= False
788 LinkUtils
.ipbatcbuf
= ''
789 LinkUtils
.ipbatch
= True
790 LinkUtils
.ipbatch_pause
= False
793 def add_to_batch(cmd
):
794 LinkUtils
.ipbatchbuf
+= cmd
+ '\n'
798 LinkUtils
.ipbatch_pause
= True
802 LinkUtils
.ipbatch_pause
= False
804 def batch_commit(self
):
805 if not LinkUtils
.ipbatchbuf
:
806 LinkUtils
.ipbatchbuf
= ''
807 LinkUtils
.ipbatch
= False
808 LinkUtils
.ipbatch_pause
= False
811 utils
.exec_command('%s -force -batch -' % utils
.ip_cmd
,
812 stdin
=self
.ipbatchbuf
)
816 LinkUtils
.ipbatchbuf
= ''
817 LinkUtils
.ipbatch
= False
818 LinkUtils
.ipbatch_pause
= False
820 def bridge_batch_commit(self
):
821 if not LinkUtils
.ipbatchbuf
:
822 LinkUtils
.ipbatchbuf
= ''
823 LinkUtils
.ipbatch
= False
824 LinkUtils
.ipbatch_pause
= False
827 utils
.exec_command('%s -force -batch -'
828 % utils
.bridge_cmd
, stdin
=self
.ipbatchbuf
)
832 LinkUtils
.ipbatchbuf
= ''
833 LinkUtils
.ipbatch
= False
834 LinkUtils
.ipbatch_pause
= False
836 def addr_show(self
, ifacename
=None):
838 if not self
.link_exists(ifacename
):
840 return utils
.exec_commandl([utils
.ip_cmd
,
841 '-o', 'addr', 'show', 'dev', ifacename
])
843 return utils
.exec_commandl([utils
.ip_cmd
,
844 '-o', 'addr', 'show'])
847 def link_show(ifacename
=None):
849 return utils
.exec_commandl([utils
.ip_cmd
,
850 '-o', '-d', 'link', 'show', 'dev', ifacename
])
852 return utils
.exec_commandl([utils
.ip_cmd
,
853 '-o', '-d', 'link', 'show'])
855 def addr_add(self
, ifacename
, address
, broadcast
=None,
856 peer
=None, scope
=None, preferred_lifetime
=None, metric
=None):
859 cmd
= 'addr add %s' % address
861 cmd
+= ' broadcast %s' % broadcast
863 cmd
+= ' peer %s' % peer
865 cmd
+= ' scope %s' % scope
866 if preferred_lifetime
:
867 cmd
+= ' preferred_lft %s' % preferred_lifetime
868 cmd
+= ' dev %s' % ifacename
871 cmd
+= ' metric %s' % metric
873 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
874 self
.add_to_batch(cmd
)
876 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
877 self
._cache
_update
([ifacename
, 'addrs', address
], {})
879 def addr_del(self
, ifacename
, address
, broadcast
=None,
880 peer
=None, scope
=None):
881 """ Delete ipv4 address """
884 if not self
._cache
_get
('addr', [ifacename
, 'addrs', address
]):
886 cmd
= 'addr del %s' % address
888 cmd
+= ' broadcast %s' % broadcast
890 cmd
+= ' peer %s' % peer
892 cmd
+= ' scope %s' % scope
893 cmd
+= ' dev %s' % ifacename
894 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
895 self
._cache
_delete
([ifacename
, 'addrs', address
])
897 def addr_flush(self
, ifacename
):
898 cmd
= 'addr flush dev %s' % ifacename
899 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
900 self
.add_to_batch(cmd
)
902 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
903 self
._cache
_delete
([ifacename
, 'addrs'])
905 def del_addr_all(self
, ifacename
, skip_addrs
=[]):
908 runningaddrsdict
= self
.get_running_addrs(ifname
=ifacename
)
910 # XXX: ignore errors. Fix this to delete secondary addresses
912 [self
.addr_del(ifacename
, a
) for a
in
913 set(runningaddrsdict
.keys()).difference(skip_addrs
)]
918 def addr_get(self
, ifacename
, details
=True, refresh
=False):
919 addrs
= self
._cache
_get
('addr', [ifacename
, 'addrs'], refresh
=refresh
)
926 def get_running_addrs(self
, ifaceobj
=None, ifname
=None, details
=True, addr_virtual_ifaceobj
=None):
928 We now support addr with link scope. Since the kernel may add it's
929 own link address to some interfaces we need to filter them out and
930 make sure we only deal with the addresses set by ifupdown2.
932 To do so we look at the previous configuration made by ifupdown2
933 (with the help of the statemanager) together with the addresses
934 specified by the user in /etc/network/interfaces, these addresses
935 are then compared to the running state of the intf (ip addr show)
936 made via a netlink addr dump.
937 For each configured addresses of scope link, we check if it was
938 previously configured by ifupdown2 to create a final set of the
939 addresses watched by ifupdown2
941 if not ifaceobj
and not ifname
:
947 interface_name
= ifaceobj
.name
949 interface_name
= ifname
951 if addr_virtual_ifaceobj
:
952 for attr_name
in ["address-virtual", "vrrp"]:
953 for virtual
in addr_virtual_ifaceobj
.get_attr_value(attr_name
) or []:
954 for ip
in virtual
.split():
961 saved_ifaceobjs
= statemanager
.statemanager_api
.get_ifaceobjs(addr_virtual_ifaceobj
.name
)
962 for saved_ifaceobj
in saved_ifaceobjs
or []:
963 for virtual
in saved_ifaceobj
.get_attr_value(attr_name
) or []:
964 for ip
in virtual
.split():
972 for addr
in ifaceobj
.get_attr_value('address') or []:
973 config_addrs
.add(addr
)
975 saved_ifaceobjs
= statemanager
.statemanager_api
.get_ifaceobjs(interface_name
)
976 for saved_ifaceobj
in saved_ifaceobjs
or []:
977 for addr
in saved_ifaceobj
.get_attr_value('address') or []:
978 config_addrs
.add(addr
)
980 running_addrs
= OrderedDict()
981 cached_addrs
= self
.addr_get(interface_name
)
983 for addr
, addr_details
in cached_addrs
.items():
985 scope
= int(addr_details
['scope'])
989 addr_obj
= IPNetwork(addr
)
990 if isinstance(addr_obj
, IPv6Network
):
991 d
['family'] = 'inet6'
994 running_addrs
[addr
] = d
996 running_addrs
[addr
] = {}
998 if (scope
& Route
.RT_SCOPE_LINK
and addr
in config_addrs
) or not scope
& Route
.RT_SCOPE_LINK
:
999 running_addrs
[addr
] = addr_details
1004 return running_addrs
1005 return running_addrs
.keys()
1008 def compare_user_config_vs_running_state(running_addrs
, user_addrs
):
1012 for ip
in user_addrs
or []:
1015 if type(obj
) == IPv6Network
:
1016 ip6
.append(str(obj
))
1018 ip4
.append(str(obj
))
1021 for ip
in running_addrs
or []:
1022 running_ipobj
.append(str(IPNetwork(ip
)))
1024 return running_ipobj
== (ip4
+ ip6
)
1026 def addr_add_multiple(self
, ifaceobj
, ifacename
, addrs
, purge_existing
=False, metric
=None):
1029 # if perfmode is not set and also if iface has no sibling
1030 # objects, purge addresses that are not present in the new
1032 runningaddrs
= self
.get_running_addrs(
1035 addr_virtual_ifaceobj
=ifaceobj
1037 addrs
= utils
.get_normalized_ip_addr(ifacename
, addrs
)
1039 if self
.compare_user_config_vs_running_state(runningaddrs
, addrs
):
1042 # if primary address is not same, there is no need to keep any.
1043 # reset all addresses
1044 if (addrs
and runningaddrs
and
1045 (addrs
[0] != runningaddrs
[0])):
1046 self
.del_addr_all(ifacename
)
1048 self
.del_addr_all(ifacename
, addrs
)
1049 except Exception, e
:
1050 self
.logger
.warning('%s: %s' % (ifacename
, str(e
)))
1053 self
.addr_add(ifacename
, a
, metric
=metric
)
1054 except Exception, e
:
1055 self
.logger
.error(str(e
))
1057 def _link_set_ifflag(self
, ifacename
, value
):
1058 # Dont look at the cache, the cache may have stale value
1059 # because link status can be changed by external
1060 # entity (One such entity is ifupdown main program)
1061 cmd
= 'link set dev %s %s' % (ifacename
, value
.lower())
1062 if LinkUtils
.ipbatch
:
1063 self
.add_to_batch(cmd
)
1065 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1067 def link_up(self
, ifacename
):
1068 self
._link
_set
_ifflag
(ifacename
, 'UP')
1070 def link_down(self
, ifacename
):
1071 self
._link
_set
_ifflag
(ifacename
, 'DOWN')
1073 def link_set(self
, ifacename
, key
, value
=None,
1074 force
=False, t
=None, state
=None):
1076 if (key
not in ['master', 'nomaster'] and
1077 self
._cache
_check
('link', [ifacename
, key
], value
)):
1079 cmd
= 'link set dev %s' % ifacename
1081 cmd
+= ' type %s' % t
1084 cmd
+= ' %s' % value
1086 cmd
+= ' %s' % state
1087 if LinkUtils
.ipbatch
:
1088 self
.add_to_batch(cmd
)
1090 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1091 if key
not in ['master', 'nomaster']:
1092 self
._cache
_update
([ifacename
, key
], value
)
1094 def link_set_hwaddress(self
, ifacename
, hwaddress
, force
=False, keep_down
=False):
1096 link_hwaddress
= self
.link_get_hwaddress(ifacename
)
1098 if self
.mac_str_to_int(link_hwaddress
) == self
.mac_str_to_int(hwaddress
):
1101 self
.link_down(ifacename
)
1102 cmd
= 'link set dev %s address %s' % (ifacename
, hwaddress
)
1103 if LinkUtils
.ipbatch
:
1104 self
.add_to_batch(cmd
)
1106 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1109 self
.link_up(ifacename
)
1110 self
._cache
_update
([ifacename
, 'hwaddress'], hwaddress
)
1113 def link_set_mtu(self
, ifacename
, mtu
):
1114 if ifupdownflags
.flags
.DRYRUN
:
1116 if not mtu
or not ifacename
: return
1117 self
.write_file('/sys/class/net/%s/mtu' % ifacename
, mtu
)
1118 self
._cache
_update
([ifacename
, 'mtu'], mtu
)
1120 def link_set_alias(self
, ifacename
, alias
):
1121 self
.write_file('/sys/class/net/%s/ifalias' % ifacename
,
1122 '\n' if not alias
else alias
)
1124 def link_get_alias(self
, ifacename
):
1125 return self
.read_file_oneline('/sys/class/net/%s/ifalias'
1128 def link_isloopback(self
, ifacename
):
1129 flags
= self
._cache
_get
('link', [ifacename
, 'flags'])
1132 if 'LOOPBACK' in flags
:
1136 def link_get_status(self
, ifacename
):
1137 return self
._cache
_get
('link', [ifacename
, 'ifflag'], refresh
=True)
1140 def route_add_gateway(ifacename
, gateway
, vrf
=None, metric
=None, onlink
=True):
1144 cmd
= '%s route add default via %s proto kernel' % (utils
.ip_cmd
,
1147 cmd
= ('%s route add table %s default via %s proto kernel' %
1148 (utils
.ip_cmd
, vrf
, gateway
))
1151 cmd
+= ' metric %s' % metric
1152 cmd
+= ' dev %s' % ifacename
1157 utils
.exec_command(cmd
)
1160 def route_del_gateway(ifacename
, gateway
, vrf
=None, metric
=None):
1165 cmd
= ('%s route del default via %s proto kernel' %
1166 (utils
.ip_cmd
, gateway
))
1168 cmd
= ('%s route del table %s default via %s proto kernel' %
1169 (utils
.ip_cmd
, vrf
, gateway
))
1171 cmd
+= ' metric %s' % metric
1172 cmd
+= ' dev %s' % ifacename
1173 utils
.exec_command(cmd
)
1176 def _get_vrf_id(ifacename
):
1178 return linkCache
.vrfs
[ifacename
]['table']
1180 dump
= netlink
.link_dump(ifacename
)
1182 [linkCache
.update_attrdict([ifname
], linkattrs
)
1183 for ifname
, linkattrs
in dump
.items()]
1185 if dump
and dump
.get(ifacename
, {}).get('kind') == 'vrf':
1186 vrf_table
= dump
.get(ifacename
, {}).get('linkinfo', {}).get('table')
1187 linkCache
.vrfs
[ifacename
] = {'table': vrf_table
}
1192 def fix_ipv6_route_metric(self
, ifaceobj
, macvlan_ifacename
, ips
):
1195 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
:
1197 for upper_iface
in ifaceobj
.upperifaces
:
1198 vrf_table
= self
._get
_vrf
_id
(upper_iface
)
1206 ip_network_obj
= IPNetwork(ip
)
1208 if type(ip_network_obj
) == IPv6Network
:
1209 route_prefix
= '%s/%d' % (ip_network_obj
.network
, ip_network_obj
.prefixlen
)
1212 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1213 LinkUtils
.add_to_batch('route del %s table %s dev %s' % (route_prefix
, vrf_table
, macvlan_ifacename
))
1215 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'del', route_prefix
, 'table', vrf_table
, 'dev', macvlan_ifacename
])
1217 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1218 LinkUtils
.add_to_batch('route del %s dev %s' % (route_prefix
, macvlan_ifacename
))
1220 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'del', route_prefix
, 'dev', macvlan_ifacename
])
1221 ip_route_del
.append((route_prefix
, vrf_table
))
1223 for ip
, vrf_table
in ip_route_del
:
1225 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1226 LinkUtils
.add_to_batch('route add %s table %s dev %s proto kernel metric 9999' % (ip
, vrf_table
, macvlan_ifacename
))
1228 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'add', ip
, 'table', vrf_table
, 'dev', macvlan_ifacename
, 'proto', 'kernel' 'metric', '9999'])
1230 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1231 LinkUtils
.add_to_batch('route add %s dev %s proto kernel metric 9999' % (ip
, macvlan_ifacename
))
1233 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'add', ip
, 'dev', macvlan_ifacename
, 'proto', 'kernel' 'metric', '9999'])
1235 def link_create_vlan(self
, vlan_device_name
, vlan_raw_device
, vlanid
):
1236 if self
.link_exists(vlan_device_name
):
1238 utils
.exec_command('%s link add link %s name %s type vlan id %d' %
1240 vlan_raw_device
, vlan_device_name
, vlanid
))
1241 self
._cache
_update
([vlan_device_name
], {})
1243 def link_create_vlan_from_name(self
, vlan_device_name
):
1244 v
= vlan_device_name
.split('.')
1246 self
.logger
.warn('invalid vlan device name %s' % vlan_device_name
)
1248 self
.link_create_vlan(vlan_device_name
, v
[0], v
[1])
1250 def link_create_macvlan(self
, name
, linkdev
, mode
='private'):
1251 if self
.link_exists(name
):
1253 cmd
= ('link add link %s' % linkdev
+
1255 ' type macvlan mode %s' % mode
)
1256 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1257 self
.add_to_batch(cmd
)
1259 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1260 self
._cache
_update
([name
], {})
1262 def get_vxlan_peers(self
, dev
, svcnodeip
):
1263 cmd
= '%s fdb show brport %s' % (utils
.bridge_cmd
,
1267 ps
= subprocess
.Popen(shlex
.split(cmd
), stdout
=subprocess
.PIPE
, close_fds
=False)
1268 utils
.enable_subprocess_signal_forwarding(ps
, signal
.SIGINT
)
1269 output
= subprocess
.check_output(('grep', '00:00:00:00:00:00'), stdin
=ps
.stdout
)
1271 utils
.disable_subprocess_signal_forwarding(signal
.SIGINT
)
1273 ppat
= re
.compile('\s+dst\s+(\d+.\d+.\d+.\d+)\s+')
1274 for l
in output
.split('\n'):
1276 if m
and m
.group(1) != svcnodeip
:
1277 cur_peers
.append(m
.group(1))
1279 self
.logger
.warn('error parsing ip link output')
1280 except subprocess
.CalledProcessError
as e
:
1281 if e
.returncode
!= 1:
1282 self
.logger
.error(str(e
))
1284 utils
.disable_subprocess_signal_forwarding(signal
.SIGINT
)
1288 def tunnel_create(self
, tunnelname
, mode
, attrs
={}):
1289 """ generic link_create function """
1290 if self
.link_exists(tunnelname
):
1297 if mode
in ['gretap']:
1298 cmd
+= ' link add %s type %s' % (tunnelname
, mode
)
1300 cmd
+= ' tunnel add %s mode %s' % (tunnelname
, mode
)
1303 for k
, v
in attrs
.iteritems():
1307 if self
.ipbatch
and not self
.ipbatch_pause
:
1308 self
.add_to_batch(cmd
)
1310 utils
.exec_command('ip %s' % cmd
)
1311 self
._cache
_update
([tunnelname
], {})
1313 def tunnel_change(self
, tunnelname
, attrs
={}):
1314 """ tunnel change function """
1315 if not self
.link_exists(tunnelname
):
1317 cmd
= 'tunnel change'
1318 cmd
+= ' %s' %(tunnelname)
1320 for k
, v
in attrs
.iteritems():
1324 if self
.ipbatch
and not self
.ipbatch_pause
:
1325 self
.add_to_batch(cmd
)
1327 utils
.exec_command('ip %s' % cmd
)
1329 def link_create_vxlan(self
, name
, vxlanid
,
1337 if svcnodeip
and remoteips
:
1338 raise Exception("svcnodeip and remoteip is mutually exclusive")
1341 args
+= ' remote %s' % svcnodeip
1343 args
+= ' ageing %s' % ageing
1344 if learning
== 'off':
1345 args
+= ' nolearning'
1347 args
+= ' ttl %s' % ttl
1349 if self
.link_exists(name
):
1350 cmd
= 'link set dev %s type vxlan dstport %d' % (name
, LinkUtils
.VXLAN_UDP_PORT
)
1351 vxlanattrs
= self
.get_vxlandev_attrs(name
)
1352 # on ifreload do not overwrite anycast_ip to individual ip if clagd
1355 running_localtunnelip
= vxlanattrs
.get('local')
1356 if anycastip
and running_localtunnelip
and anycastip
== running_localtunnelip
:
1357 localtunnelip
= running_localtunnelip
1358 running_svcnode
= vxlanattrs
.get('svcnode')
1359 if running_svcnode
and not svcnodeip
:
1362 cmd
= 'link add dev %s type vxlan id %s dstport %d' % (name
, vxlanid
, LinkUtils
.VXLAN_UDP_PORT
)
1365 args
+= ' local %s' % localtunnelip
1368 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1369 self
.add_to_batch(cmd
)
1371 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1373 # XXX: update linkinfo correctly
1374 #self._cache_update([name], {})
1377 def link_exists(ifacename
):
1378 if ifupdownflags
.flags
.DRYRUN
:
1380 return os
.path
.exists('/sys/class/net/%s' % ifacename
)
1383 def link_exists_nodryrun(ifname
):
1384 return os
.path
.exists('/sys/class/net/%s' % ifname
)
1386 def link_get_ifindex(self
, ifacename
):
1387 if ifupdownflags
.flags
.DRYRUN
:
1389 return self
.read_file_oneline('/sys/class/net/%s/ifindex' % ifacename
)
1391 def is_vlan_device_by_name(self
, ifacename
):
1392 if re
.search(r
'\.', ifacename
):
1397 def link_add_macvlan(ifname
, macvlan_ifacename
, mode
):
1398 utils
.exec_commandl(['ip', 'link', 'add', 'link', ifname
, 'name', macvlan_ifacename
, 'type', 'macvlan', 'mode', mode
])
1401 def link_add_xfrm(ifname
, xfrm_name
, xfrm_id
):
1402 utils
.exec_commandl(['ip', 'link', 'add', xfrm_name
, 'type', 'xfrm', 'dev', ifname
, 'if_id', xfrm_id
])
1405 def route_add(route
):
1406 utils
.exec_command('%s route add %s' % (utils
.ip_cmd
,
1410 def route6_add(route
):
1411 utils
.exec_command('%s -6 route add %s' % (utils
.ip_cmd
,
1414 def get_vlandev_attrs(self
, ifacename
):
1415 return (self
._cache
_get
('link', [ifacename
, 'link']),
1416 self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlanid']),
1417 self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlan_protocol']))
1419 def get_vlan_protocol(self
, ifacename
):
1420 return self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlan_protocol'])
1422 def get_vxlandev_attrs(self
, ifacename
):
1423 return self
._cache
_get
('link', [ifacename
, 'linkinfo'])
1425 def get_vxlandev_learning(self
, ifacename
):
1426 return self
._cache
_get
('link', [ifacename
, 'linkinfo', Link
.IFLA_VXLAN_LEARNING
])
1428 def set_vxlandev_learning(self
, ifacename
, learn
):
1430 utils
.exec_command('%s link set dev %s type vxlan learning' %
1431 (utils
.ip_cmd
, ifacename
))
1432 self
._cache
_update
([ifacename
, 'linkinfo', 'learning'], 'on')
1434 utils
.exec_command('%s link set dev %s type vxlan nolearning' %
1435 (utils
.ip_cmd
, ifacename
))
1436 self
._cache
_update
([ifacename
, 'linkinfo', 'learning'], 'off')
1438 def link_get_linkinfo_attrs(self
, ifacename
):
1439 return self
._cache
_get
('link', [ifacename
, 'linkinfo'])
1441 def link_get_mtu(self
, ifacename
, refresh
=False):
1442 return self
._cache
_get
('link', [ifacename
, 'mtu'], refresh
=refresh
)
1444 def link_get_mtu_sysfs(self
, ifacename
):
1445 return self
.read_file_oneline('/sys/class/net/%s/mtu'
1448 def link_get_kind(self
, ifacename
):
1449 return self
._cache
_get
('link', [ifacename
, 'kind'])
1451 def link_get_slave_kind(self
, ifacename
):
1452 return self
._cache
_get
('link', [ifacename
, 'slave_kind'])
1454 def link_get_hwaddress(self
, ifacename
):
1455 address
= self
._cache
_get
('link', [ifacename
, 'hwaddress'])
1456 # newly created logical interface addresses dont end up in the cache
1457 # read hwaddress from sysfs file for these interfaces
1459 address
= self
.read_file_oneline('/sys/class/net/%s/address'
1463 def link_create(self
, ifacename
, t
, attrs
={}):
1464 """ generic link_create function """
1465 if self
.link_exists(ifacename
):
1468 cmd
+= ' name %s type %s' % (ifacename
, t
)
1470 for k
, v
in attrs
.iteritems():
1474 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1475 self
.add_to_batch(cmd
)
1477 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1478 self
._cache
_update
([ifacename
], {})
1480 def link_delete(self
, ifacename
):
1481 if not self
.link_exists(ifacename
):
1483 cmd
= 'link del %s' % ifacename
1484 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1485 self
.add_to_batch(cmd
)
1487 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1488 self
._cache
_invalidate
()
1490 def link_get_master(self
, ifacename
):
1491 sysfs_master_path
= '/sys/class/net/%s/master' % ifacename
1492 if os
.path
.exists(sysfs_master_path
):
1493 link_path
= os
.readlink(sysfs_master_path
)
1495 return os
.path
.basename(link_path
)
1499 return self
._cache
_get
('link', [ifacename
, 'master'])
1501 def get_brport_peer_link(self
, bridgename
):
1503 return self
._cache
_get
('link', [bridgename
, 'info_slave_data', Link
.IFLA_BRPORT_PEER_LINK
])
1508 def bridge_port_vids_add(bridgeportname
, vids
):
1509 [utils
.exec_command('%s vlan add vid %s dev %s' %
1511 v
, bridgeportname
)) for v
in vids
]
1514 def bridge_port_vids_del(bridgeportname
, vids
):
1517 [utils
.exec_command('%s vlan del vid %s dev %s' %
1519 v
, bridgeportname
)) for v
in vids
]
1522 def bridge_port_vids_flush(bridgeportname
, vid
):
1523 utils
.exec_command('%s vlan del vid %s dev %s' %
1525 vid
, bridgeportname
))
1528 def bridge_port_vids_get(bridgeportname
):
1529 bridgeout
= utils
.exec_command('%s vlan show dev %s' %
1534 brvlanlines
= bridgeout
.readlines()[2:]
1535 vids
= [l
.strip() for l
in brvlanlines
]
1536 return [v
for v
in vids
if v
]
1539 def bridge_port_vids_get_all():
1541 bridgeout
= utils
.exec_command('%s -c vlan show'
1545 brvlanlines
= bridgeout
.splitlines()
1547 for l
in brvlanlines
[1:]:
1548 if l
and not l
.startswith(' ') and not l
.startswith('\t'):
1550 brportname
= attrs
[0].strip()
1551 brvlaninfo
[brportname
] = {'pvid': None, 'vlan': []}
1552 l
= ' '.join(attrs
[1:])
1553 if not brportname
or not l
:
1557 brvlaninfo
[brportname
]['pvid'] = l
.split()[0]
1558 elif 'Egress Untagged' not in l
:
1559 brvlaninfo
[brportname
]['vlan'].append(l
)
1562 def bridge_port_vids_get_all_json(self
):
1563 if not self
.supported_command
['%s -c -json vlan show'
1564 % utils
.bridge_cmd
]:
1568 bridgeout
= utils
.exec_command('%s -c -json vlan show'
1571 self
.supported_command
['%s -c -json vlan show'
1572 % utils
.bridge_cmd
] = False
1573 self
.logger
.info('%s -c -json vlan show: skipping unsupported command'
1576 return self
.get_bridge_vlan_nojson()
1577 except Exception as e
:
1578 self
.logger
.info('bridge: get_bridge_vlan_nojson: %s' % str(e
))
1581 if not bridgeout
: return brvlaninfo
1583 vlan_json
= json
.loads(bridgeout
, encoding
="utf-8")
1584 except Exception, e
:
1585 self
.logger
.info('json loads failed with (%s)' % str(e
))
1589 if isinstance(vlan_json
, list):
1590 # newer iproute2 version changed the bridge vlan show output
1591 # ifupdown2 relies on the previous format, we have the convert
1592 # data into old format
1593 bridge_port_vids
= dict()
1595 for intf
in vlan_json
:
1596 bridge_port_vids
[intf
["ifname"]] = intf
["vlans"]
1598 return bridge_port_vids
1600 # older iproute2 version have different ways to dump vlans
1601 # ifupdown2 prefers the following syntax:
1605 # "flags": ["PVID", "Egress Untagged"]
1610 # "flags": ["PVID", "Egress Untagged"]
1614 except Exception as e
:
1615 self
.logger
.debug("bridge vlan show: Unknown json output: %s" % str(e
))
1619 def get_bridge_vlan_nojson():
1621 bridgeout
= utils
.exec_commandl([utils
.bridge_cmd
, '-c', 'vlan', 'show'])
1623 output
= [line
.split('\n') for line
in bridgeout
.split('\n\n')]
1624 output
[0] = output
[0][1:]
1632 prefix
, vlan
= entry
.split('\t')
1634 current_swp
= prefix
1635 vlan_json
[prefix
] = []
1639 v
['vlan'] = int(vlan
)
1643 start
, end
= vlan
.split('-')
1645 end
= end
[0:end
.index(' ')]
1646 v
['vlan'] = int(start
)
1647 v
['vlanEnd'] = int(end
)
1649 v
['vlan'] = int(vlan
[0:vlan
.index(' ')])
1652 flags
.append('PVID')
1653 if 'Egress Untagged' in vlan
:
1654 flags
.append('Egress Untagged')
1658 vlan_json
[current_swp
].append(v
)
1661 def bridge_vlan_cache_get(self
, ifacename
, refresh
=False):
1662 if not self
.bridge_vlan_cache_fill_done
or refresh
:
1663 self
.bridge_vlan_cache
= self
.bridge_port_vids_get_all_json()
1664 self
.bridge_vlan_cache_fill_done
= True
1665 return self
.bridge_vlan_cache
.get(ifacename
, {})
1667 def bridge_vlan_get_pvid(self
, ifacename
, refresh
=False):
1670 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1671 v
= vinfo
.get('vlan')
1672 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1677 def bridge_vlan_get_vids(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
1687 vEnd
= vinfo
.get('vlanEnd')
1689 vids
.extend(range(v
, vEnd
+ 1))
1694 def bridge_vlan_get_vids_n_pvid(self
, ifacename
, refresh
=False):
1698 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1699 v
= vinfo
.get('vlan')
1700 ispvid
= True if 'PVID' in vinfo
.get('flags', []) else False
1702 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1703 vEnd
= vinfo
.get('vlanEnd')
1705 vids
.extend(range(v
, vEnd
+ 1))
1710 def bridge_port_pvid_add(self
, bridgeportname
, pvid
):
1711 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1712 self
.add_to_batch('vlan add vid %s untagged pvid dev %s' %
1713 (pvid
, bridgeportname
))
1715 utils
.exec_command('%s vlan add vid %s untagged pvid dev %s' %
1717 pvid
, bridgeportname
))
1719 def bridge_port_pvid_del(self
, bridgeportname
, pvid
):
1720 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1721 self
.add_to_batch('vlan del vid %s untagged pvid dev %s' %
1722 (pvid
, bridgeportname
))
1724 utils
.exec_command('%s vlan del vid %s untagged pvid dev %s' %
1726 pvid
, bridgeportname
))
1728 def bridge_port_pvids_get(self
, bridgeportname
):
1729 return self
.read_file_oneline('/sys/class/net/%s/brport/pvid'
1732 def bridge_vids_add(self
, bridgeportname
, vids
, bridge
=True):
1733 target
= 'self' if bridge
else ''
1734 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1735 [self
.add_to_batch('vlan add vid %s dev %s %s' %
1736 (v
, bridgeportname
, target
)) for v
in vids
]
1738 [utils
.exec_command('%s vlan add vid %s dev %s %s' %
1740 v
, bridgeportname
, target
)) for v
in vids
]
1742 def bridge_vids_del(self
, bridgeportname
, vids
, bridge
=True):
1743 target
= 'self' if bridge
else ''
1744 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1745 [self
.add_to_batch('vlan del vid %s dev %s %s' %
1746 (v
, bridgeportname
, target
)) for v
in vids
]
1748 [utils
.exec_command('%s vlan del vid %s dev %s %s' %
1750 v
, bridgeportname
, target
)) for v
in vids
]
1753 def bridge_fdb_add(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1754 target
= 'self' if bridge
else ''
1757 vlan_str
= 'vlan %s ' % vlan
1761 dst_str
= 'dst %s ' % remote
1763 utils
.exec_command('%s fdb replace %s dev %s %s %s %s' %
1765 address
, dev
, vlan_str
, target
, dst_str
))
1768 def bridge_fdb_append(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1769 target
= 'self' if bridge
else ''
1772 vlan_str
= 'vlan %s ' % vlan
1776 dst_str
= 'dst %s ' % remote
1778 utils
.exec_command('%s fdb append %s dev %s %s %s %s' %
1780 address
, dev
, vlan_str
, target
, dst_str
))
1783 def bridge_fdb_del(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1784 target
= 'self' if bridge
else ''
1787 vlan_str
= 'vlan %s ' % vlan
1791 dst_str
= 'dst %s ' % remote
1792 utils
.exec_command('%s fdb del %s dev %s %s %s %s' %
1794 address
, dev
, vlan_str
, target
, dst_str
))
1796 def bridge_is_vlan_aware(self
, bridgename
):
1797 filename
= '/sys/class/net/%s/bridge/vlan_filtering' % bridgename
1798 if os
.path
.exists(filename
) and self
.read_file_oneline(filename
) == '1':
1803 def bridge_port_get_bridge_name(bridgeport
):
1804 filename
= '/sys/class/net/%s/brport/bridge' % bridgeport
1806 return os
.path
.basename(os
.readlink(filename
))
1811 def bridge_port_exists(bridge
, bridgeportname
):
1813 return os
.path
.exists('/sys/class/net/%s/brif/%s'
1814 % (bridge
, bridgeportname
))
1818 def bridge_fdb_show_dev(self
, dev
):
1821 output
= utils
.exec_command('%s fdb show dev %s'
1822 % (utils
.bridge_cmd
, dev
))
1824 for fdb_entry
in output
.splitlines():
1826 entries
= fdb_entry
.split()
1827 fdbs
.setdefault(entries
[2], []).append(entries
[0])
1829 self
.logger
.debug('%s: invalid fdb line \'%s\''
1836 def is_bridge(bridge
):
1837 return os
.path
.exists('/sys/class/net/%s/bridge' % bridge
)
1839 def is_link_up(self
, ifacename
):
1842 flags
= self
.read_file_oneline('/sys/class/net/%s/flags' % ifacename
)
1843 iflags
= int(flags
, 16)
1850 def ip_route_get_dev(self
, prefix
, vrf_master
=None):
1853 cmd
= '%s route get %s vrf %s' % (utils
.ip_cmd
, prefix
, vrf_master
)
1855 cmd
= '%s route get %s' % (utils
.ip_cmd
, prefix
)
1857 output
= utils
.exec_command(cmd
)
1859 rline
= output
.splitlines()[0]
1861 rattrs
= rline
.split()
1862 return rattrs
[rattrs
.index('dev') + 1]
1863 except Exception, e
:
1864 self
.logger
.debug('ip_route_get_dev: failed .. %s' % str(e
))
1868 def link_get_lowers(ifacename
):
1870 lowers
= glob
.glob("/sys/class/net/%s/lower_*" % ifacename
)
1873 return [os
.path
.basename(l
)[6:] for l
in lowers
]
1878 def link_get_uppers(ifacename
):
1880 uppers
= glob
.glob("/sys/class/net/%s/upper_*" % ifacename
)
1883 return [os
.path
.basename(u
)[6:] for u
in uppers
]
1887 def link_get_vrfs(self
):
1888 if not LinkUtils
._CACHE
_FILL
_DONE
:
1890 return linkCache
.vrfs
1893 def cache_get_info_slave(attrlist
):
1895 return linkCache
.get_attr(attrlist
)
1899 def get_brport_learning(self
, ifacename
):
1900 learn
= self
.read_file_oneline('/sys/class/net/%s/brport/learning'
1902 if learn
and learn
== '1':
1907 def get_brport_learning_bool(self
, ifacename
):
1908 return utils
.get_boolean_from_string(self
.read_file_oneline('/sys/class/net/%s/brport/learning' % ifacename
))
1910 def set_brport_learning(self
, ifacename
, learn
):
1912 return self
.write_file('/sys/class/net/%s/brport/learning'
1915 return self
.write_file('/sys/class/net/%s/brport/learning'
1918 #################################################################################
1919 ################################### BOND UTILS ##################################
1920 #################################################################################
1922 def _link_cache_get(self
, attrlist
, refresh
=False):
1923 return self
._cache
_get
('link', attrlist
, refresh
)
1925 def cache_delete(self
, attrlist
, value
=None):
1926 return self
._cache
_delete
(attrlist
, value
)
1928 def link_cache_get(self
, attrlist
, refresh
=False):
1929 return self
._link
_cache
_get
(attrlist
, refresh
)
1931 def link_cache_check(self
, attrlist
, value
, refresh
=False):
1932 return self
._link
_cache
_check
(attrlist
, value
, refresh
)
1934 def _link_cache_check(self
, attrlist
, value
, refresh
=False):
1936 return self
._link
_cache
_get
(attrlist
, refresh
) == value
1937 except Exception, e
:
1938 self
.logger
.debug('_cache_check(%s) : [%s]'
1939 % (str(attrlist
), str(e
)))
1944 Link
.IFLA_BOND_MODE
: 'mode',
1945 Link
.IFLA_BOND_MIIMON
: 'miimon',
1946 Link
.IFLA_BOND_USE_CARRIER
: 'use_carrier',
1947 Link
.IFLA_BOND_AD_LACP_RATE
: 'lacp_rate',
1948 Link
.IFLA_BOND_XMIT_HASH_POLICY
: 'xmit_hash_policy',
1949 Link
.IFLA_BOND_MIN_LINKS
: 'min_links',
1950 Link
.IFLA_BOND_NUM_PEER_NOTIF
: 'num_grat_arp',
1951 Link
.IFLA_BOND_AD_ACTOR_SYSTEM
: 'ad_actor_system',
1952 Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
: 'ad_actor_sys_prio',
1953 Link
.IFLA_BOND_AD_LACP_BYPASS
: 'lacp_bypass',
1954 Link
.IFLA_BOND_UPDELAY
: 'updelay',
1955 Link
.IFLA_BOND_DOWNDELAY
: 'downdelay',
1958 def bond_set_attrs_nl(self
, bondname
, ifla_info_data
):
1959 bond_attr_name
= 'None' # for log purpose (in case an exception raised)
1960 for nl_attr
, value
in ifla_info_data
.items():
1962 bond_attr_name
= self
.bondcmd_attrmap
[nl_attr
]
1963 file_path
= '/sys/class/net/%s/bonding/%s' % (bondname
, bond_attr_name
)
1964 if os
.path
.exists(file_path
):
1965 self
.write_file(file_path
, str(value
))
1966 except Exception as e
:
1967 exception_str
= '%s: %s %s: %s' % (bondname
, bond_attr_name
, value
, str(e
))
1968 if ifupdownflags
.flags
.FORCE
:
1969 self
.logger
.warning(exception_str
)
1971 self
.logger
.debug(exception_str
)
1973 def bond_set_attrs(self
, bondname
, attrdict
, prehook
):
1974 for attrname
, attrval
in attrdict
.items():
1975 if (self
._link
_cache
_check
([bondname
, 'linkinfo',
1976 attrname
], attrval
)):
1978 if (attrname
== 'mode'
1979 or attrname
== 'xmit_hash_policy'
1980 or attrname
== 'lacp_rate' or attrname
== 'min_links'):
1984 if ((attrname
not in ['lacp_rate',
1986 self
._link
_cache
_check
([bondname
, 'linkinfo', 'mode'], '802.3ad',
1988 self
.write_file('/sys/class/net/%s/bonding/%s'
1989 % (bondname
, attrname
), attrval
)
1990 except Exception, e
:
1991 if ifupdownflags
.flags
.FORCE
:
1992 self
.logger
.warn(str(e
))
1997 def bond_set_use_carrier(self
, bondname
, use_carrier
):
1998 if not use_carrier
or (use_carrier
!= '0' and use_carrier
!= '1'):
2000 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'use_carrier'],
2003 self
.write_file('/sys/class/net/%s' % bondname
+
2004 '/bonding/use_carrier', use_carrier
)
2005 self
._cache
_update
([bondname
, 'linkinfo',
2006 'use_carrier'], use_carrier
)
2008 def bond_get_use_carrier(self
, bondname
):
2009 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'use_carrier'])
2011 def bond_get_use_carrier_nl(self
, bondname
):
2012 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_USE_CARRIER
])
2014 def bond_set_xmit_hash_policy(self
, bondname
, hash_policy
, prehook
=None):
2015 valid_values
= ['layer2', 'layer3+4', 'layer2+3']
2018 if hash_policy
not in valid_values
:
2019 raise Exception('invalid hash policy value %s' % hash_policy
)
2020 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'xmit_hash_policy'],
2025 self
.write_file('/sys/class/net/%s' % bondname
+
2026 '/bonding/xmit_hash_policy', hash_policy
)
2027 self
._cache
_update
([bondname
, 'linkinfo', 'xmit_hash_policy'],
2030 def bond_get_xmit_hash_policy(self
, bondname
):
2031 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'xmit_hash_policy'])
2033 def bond_get_xmit_hash_policy_nl(self
, bondname
):
2034 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_XMIT_HASH_POLICY
])
2036 def bond_set_miimon(self
, bondname
, miimon
):
2037 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'miimon'],
2040 self
.write_file('/sys/class/net/%s' % bondname
+
2041 '/bonding/miimon', miimon
)
2042 self
._cache
_update
([bondname
, 'linkinfo', 'miimon'], miimon
)
2044 def bond_get_miimon(self
, bondname
):
2045 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'miimon'])
2047 def bond_get_miimon_nl(self
, bondname
):
2048 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MIIMON
])
2050 def bond_set_mode(self
, bondname
, mode
, prehook
=None):
2051 valid_modes
= ['balance-rr', 'active-backup', 'balance-xor',
2052 'broadcast', '802.3ad', 'balance-tlb', 'balance-alb']
2055 if mode
not in valid_modes
:
2056 raise Exception('invalid mode %s' % mode
)
2057 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'mode'],
2062 self
.write_file('/sys/class/net/%s' % bondname
+ '/bonding/mode', mode
)
2063 self
._cache
_update
([bondname
, 'linkinfo', 'mode'], mode
)
2065 def bond_get_mode(self
, bondname
):
2066 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'mode'])
2068 def bond_get_mode_nl(self
, bondname
):
2069 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MODE
])
2071 def bond_set_lacp_rate(self
, bondname
, lacp_rate
, prehook
=None, posthook
=None):
2072 if not lacp_rate
or (lacp_rate
!= '0' and lacp_rate
!= '1'):
2074 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'lacp_rate'],
2080 self
.write_file('/sys/class/net/%s' % bondname
+
2081 '/bonding/lacp_rate', lacp_rate
)
2087 self
._cache
_update
([bondname
, 'linkinfo',
2088 'lacp_rate'], lacp_rate
)
2090 def bond_get_lacp_rate(self
, bondname
):
2091 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'lacp_rate'])
2093 def bond_get_lacp_rate_nl(self
, bondname
):
2094 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_RATE
])
2096 def bond_set_lacp_bypass_allow(self
, bondname
, allow
, prehook
=None, posthook
=None):
2097 if self
._link
_cache
_check
([bondname
, 'linkinfo', 'lacp_bypass'], allow
):
2102 self
.write_file('/sys/class/net/%s' % bondname
+
2103 '/bonding/lacp_bypass', allow
)
2109 self
._cache
_update
([bondname
, 'linkinfo',
2110 'lacp_bypass'], allow
)
2112 def bond_get_lacp_bypass_allow(self
, bondname
):
2113 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'lacp_bypass'])
2115 def bond_get_lacp_bypass_allow_nl(self
, bondname
):
2116 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_BYPASS
])
2118 def bond_set_min_links(self
, bondname
, min_links
, prehook
=None):
2119 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'min_links'],
2124 self
.write_file('/sys/class/net/%s/bonding/min_links' % bondname
,
2126 self
._cache
_update
([bondname
, 'linkinfo', 'min_links'], min_links
)
2128 def bond_get_min_links(self
, bondname
):
2129 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'min_links'])
2131 def get_min_links_nl(self
, bondname
):
2132 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MIN_LINKS
])
2134 def bond_get_ad_actor_system(self
, bondname
):
2135 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'ad_actor_system'])
2137 def bond_get_ad_actor_system_nl(self
, bondname
):
2138 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYSTEM
])
2140 def bond_get_ad_actor_sys_prio(self
, bondname
):
2141 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'ad_actor_sys_prio'])
2143 def bond_get_ad_actor_sys_prio_nl(self
, bondname
):
2144 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
])
2146 def bond_get_num_unsol_na(self
, bondname
):
2147 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'num_unsol_na'])
2149 def bond_get_num_unsol_na_nl(self
, bondname
):
2150 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
])
2152 def bond_get_num_grat_arp(self
, bondname
):
2153 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'num_grat_arp'])
2155 def bond_get_num_grat_arp_nl(self
, bondname
):
2156 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
])
2158 def bond_get_updelay(self
, bondname
):
2159 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'updelay'])
2161 def bond_get_updelay_nl(self
, bondname
):
2162 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_UPDELAY
])
2164 def bond_get_downdelay(self
, bondname
):
2165 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'downdelay'])
2167 def bond_get_downdelay_nl(self
, bondname
):
2168 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_DOWNDELAY
])
2170 def bond_enslave_slave(self
, bondname
, slave
, prehook
=None, posthook
=None):
2171 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2172 if slaves
and slave
in slaves
:
2176 self
.write_file('/sys/class/net/%s' % bondname
+
2177 '/bonding/slaves', '+' + slave
)
2180 self
._cache
_update
([bondname
, 'linkinfo', 'slaves'], slave
)
2182 def bond_remove_slave(self
, bondname
, slave
):
2183 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2184 if not slaves
or slave
not in slaves
:
2186 sysfs_bond_path
= ('/sys/class/net/%s' % bondname
+
2188 if not os
.path
.exists(sysfs_bond_path
):
2190 self
.write_file(sysfs_bond_path
, '-' + slave
)
2191 self
._cache
_delete
([bondname
, 'linkinfo', 'slaves'], slave
)
2193 def bond_remove_slaves_all(self
, bondname
):
2194 if not self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves']):
2197 sysfs_bond_path
= ('/sys/class/net/%s' % bondname
+
2200 with
open(sysfs_bond_path
, 'r') as f
:
2201 slaves
= f
.readline().strip().split()
2203 raise Exception('error reading slaves of bond %s (%s)' % (bondname
, str(e
)))
2204 for slave
in slaves
:
2205 self
.link_down(slave
)
2207 self
.bond_remove_slave(bondname
, slave
)
2208 except Exception, e
:
2209 if not ifupdownflags
.flags
.FORCE
:
2210 raise Exception('error removing slave %s from bond %s (%s)' % (slave
, bondname
, str(e
)))
2213 self
._cache
_delete
([bondname
, 'linkinfo', 'slaves'])
2216 def bond_load_bonding_module():
2217 return utils
.exec_command('%s -q bonding' % utils
.modprobe_cmd
)
2219 def create_bond(self
, bondname
):
2220 if self
.bond_exists(bondname
):
2222 # load_bonding_module() has already been run
2223 self
.write_file('/sys/class/net/bonding_masters', '+' + bondname
)
2224 self
._cache
_update
([bondname
], {})
2226 def delete_bond(self
, bondname
):
2227 if not os
.path
.exists('/sys/class/net/%s' % bondname
):
2229 self
.write_file('/sys/class/net/bonding_masters', '-' + bondname
)
2230 self
._cache
_delete
([bondname
])
2232 def bond_get_slaves(self
, bondname
):
2233 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2236 slavefile
= '/sys/class/net/%s/bonding/slaves' % bondname
2237 if os
.path
.exists(slavefile
):
2238 buf
= self
.read_file_oneline(slavefile
)
2240 slaves
= buf
.split()
2243 self
._cache
_update
([bondname
, 'linkinfo', 'slaves'], slaves
)
2246 def bond_slave_exists(self
, bond
, slave
):
2247 slaves
= self
.bond_get_slaves(bond
)
2250 return slave
in slaves
2253 def bond_exists(bondname
):
2254 return os
.path
.exists('/sys/class/net/%s/bonding' % bondname
)
2256 #################################################################################
2257 ################################## BRIDGE UTILS #################################
2258 #################################################################################
2260 def create_bridge(self
, bridgename
):
2261 if not LinkUtils
.bridge_utils_is_installed
:
2263 if self
.bridge_exists(bridgename
):
2265 utils
.exec_command('%s addbr %s' % (utils
.brctl_cmd
, bridgename
))
2266 self
._cache
_update
([bridgename
], {})
2268 def delete_bridge(self
, bridgename
):
2269 if not LinkUtils
.bridge_utils_is_installed
:
2271 if not self
.bridge_exists(bridgename
):
2273 utils
.exec_command('%s delbr %s' % (utils
.brctl_cmd
, bridgename
))
2274 self
._cache
_invalidate
()
2276 def add_bridge_port(self
, bridgename
, bridgeportname
):
2277 """ Add port to bridge """
2278 if not LinkUtils
.bridge_utils_is_installed
:
2280 ports
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports'])
2281 if ports
and ports
.get(bridgeportname
):
2283 utils
.exec_command('%s addif %s %s' % (utils
.brctl_cmd
, bridgename
, bridgeportname
))
2284 self
._cache
_update
([bridgename
, 'linkinfo', 'ports', bridgeportname
], {})
2286 def delete_bridge_port(self
, bridgename
, bridgeportname
):
2287 """ Delete port from bridge """
2288 if not LinkUtils
.bridge_utils_is_installed
:
2290 ports
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports'])
2291 if not ports
or not ports
.get(bridgeportname
):
2293 utils
.exec_command('%s delif %s %s' % (utils
.brctl_cmd
, bridgename
, bridgeportname
))
2294 self
._cache
_delete
([bridgename
, 'linkinfo', 'ports', 'bridgeportname'])
2296 def set_bridgeport_attrs(self
, bridgename
, bridgeportname
, attrdict
):
2297 portattrs
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports', bridgeportname
])
2298 if portattrs
== None:
2300 for k
, v
in attrdict
.iteritems():
2301 if ifupdownflags
.flags
.CACHE
:
2302 curval
= portattrs
.get(k
)
2303 if curval
and curval
== v
:
2305 if k
== 'unicast-flood':
2306 self
.write_file('/sys/class/net/%s/brport/unicast_flood' % bridgeportname
, v
)
2307 elif k
== 'multicast-flood':
2308 self
.write_file('/sys/class/net/%s/brport/multicast_flood' % bridgeportname
, v
)
2309 elif k
== 'learning':
2310 self
.write_file('/sys/class/net/%s/brport/learning' % bridgeportname
, v
)
2311 elif k
== 'arp-nd-suppress':
2312 self
.write_file('/sys/class/net/%s/brport/neigh_suppress' % bridgeportname
, v
)
2314 if not LinkUtils
.bridge_utils_is_installed
:
2316 utils
.exec_command('%s set%s %s %s %s' % (utils
.brctl_cmd
, k
, bridgename
, bridgeportname
, v
))
2318 def set_bridgeport_attr(self
, bridgename
, bridgeportname
,
2320 if not LinkUtils
.bridge_utils_is_installed
:
2322 if self
._link
_cache
_check
([bridgename
, 'linkinfo', 'ports', bridgeportname
, attrname
], attrval
):
2324 utils
.exec_command('%s set%s %s %s %s' %
2331 def set_bridge_attrs(self
, bridgename
, attrdict
):
2332 for k
, v
in attrdict
.iteritems():
2335 if self
._link
_cache
_check
([bridgename
, 'linkinfo', k
], v
):
2338 if k
== 'igmp-version':
2339 self
.write_file('/sys/class/net/%s/bridge/'
2340 'multicast_igmp_version' % bridgename
, v
)
2341 elif k
== 'mld-version':
2342 self
.write_file('/sys/class/net/%s/bridge/'
2343 'multicast_mld_version' % bridgename
, v
)
2344 elif k
== 'vlan-protocol':
2345 self
.write_file('/sys/class/net/%s/bridge/'
2346 'vlan_protocol' % bridgename
,
2347 VlanProtocols
.ETHERTYPES_TO_ID
.get(v
.upper(),
2349 elif k
== 'vlan-stats':
2350 self
.write_file('/sys/class/net/%s/bridge/'
2351 'vlan_stats_enabled' % bridgename
, v
)
2352 elif k
== 'mcstats':
2353 self
.write_file('/sys/class/net/%s/bridge/'
2354 'multicast_stats_enabled' % bridgename
, v
)
2356 if not LinkUtils
.bridge_utils_is_installed
:
2358 cmd
= ('%s set%s %s %s' %
2359 (utils
.brctl_cmd
, k
, bridgename
, v
))
2360 utils
.exec_command(cmd
)
2361 except Exception, e
:
2362 self
.logger
.warn('%s: %s' % (bridgename
, str(e
)))
2365 def set_bridge_attr(self
, bridgename
, attrname
, attrval
):
2366 if self
._link
_cache
_check
([bridgename
, 'linkinfo', attrname
], attrval
):
2368 if attrname
== 'igmp-version':
2369 self
.write_file('/sys/class/net/%s/bridge/multicast_igmp_version'
2370 % bridgename
, attrval
)
2371 elif attrname
== 'mld-version':
2372 self
.write_file('/sys/class/net/%s/bridge/multicast_mld_version'
2373 % bridgename
, attrval
)
2374 elif attrname
== 'vlan-protocol':
2375 self
.write_file('/sys/class/net/%s/bridge/vlan_protocol'
2376 % bridgename
, VlanProtocols
.ETHERTYPES_TO_ID
[attrval
.upper()])
2377 elif attrname
== 'vlan-stats':
2378 self
.write_file('/sys/class/net/%s/bridge/vlan_stats_enabled'
2379 % bridgename
, attrval
)
2380 elif attrname
== 'mcstats':
2381 self
.write_file('/sys/class/net/%s/bridge/multicast_stats_enabled'
2382 % bridgename
, attrval
)
2384 if not LinkUtils
.bridge_utils_is_installed
:
2386 cmd
= '%s set%s %s %s' % (utils
.brctl_cmd
,
2387 attrname
, bridgename
, attrval
)
2388 utils
.exec_command(cmd
)
2390 def get_bridge_attrs(self
, bridgename
):
2391 attrs
= self
._link
_cache
_get
([bridgename
, 'linkinfo'])
2393 for key
, value
in attrs
.items():
2394 if type(key
) == str:
2395 no_ints_attrs
[key
] = value
2396 return no_ints_attrs
2398 def get_bridgeport_attrs(self
, bridgename
, bridgeportname
):
2399 return self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports',
2402 def get_bridgeport_attr(self
, bridgename
, bridgeportname
, attrname
):
2403 return self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports',
2404 bridgeportname
, attrname
])
2407 def bridge_set_stp(bridge
, stp_state
):
2408 if not LinkUtils
.bridge_utils_is_installed
:
2410 utils
.exec_command('%s stp %s %s' % (utils
.brctl_cmd
, bridge
, stp_state
))
2412 def bridge_get_stp(self
, bridge
):
2413 sysfs_stpstate
= '/sys/class/net/%s/bridge/stp_state' % bridge
2414 if not os
.path
.exists(sysfs_stpstate
):
2416 stpstate
= self
.read_file_oneline(sysfs_stpstate
)
2420 if int(stpstate
) > 0:
2422 elif int(stpstate
) == 0:
2428 def _conv_value_to_user(s
):
2435 def read_value_from_sysfs(self
, filename
, preprocess_func
):
2436 value
= self
.read_file_oneline(filename
)
2439 return preprocess_func(value
)
2442 def bridge_set_ageing(bridge
, ageing
):
2443 if not LinkUtils
.bridge_utils_is_installed
:
2445 utils
.exec_command('%s setageing %s %s' % (utils
.brctl_cmd
, bridge
, ageing
))
2447 def bridge_get_ageing(self
, bridge
):
2448 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/ageing_time'
2449 % bridge
, self
._conv
_value
_to
_user
)
2452 def set_bridgeprio(bridge
, prio
):
2453 if not LinkUtils
.bridge_utils_is_installed
:
2455 utils
.exec_command('%s setbridgeprio %s %s' % (utils
.brctl_cmd
, bridge
, prio
))
2457 def get_bridgeprio(self
, bridge
):
2458 return self
.read_file_oneline(
2459 '/sys/class/net/%s/bridge/priority' % bridge
)
2462 def bridge_set_fd(bridge
, fd
):
2463 if not LinkUtils
.bridge_utils_is_installed
:
2465 utils
.exec_command('%s setfd %s %s' % (utils
.brctl_cmd
, bridge
, fd
))
2467 def bridge_get_fd(self
, bridge
):
2468 return self
.read_value_from_sysfs(
2469 '/sys/class/net/%s/bridge/forward_delay'
2470 % bridge
, self
._conv
_value
_to
_user
)
2472 def bridge_set_gcint(self
, bridge
, gcint
):
2473 raise Exception('set_gcint not implemented')
2476 def bridge_set_hello(bridge
, hello
):
2477 if not LinkUtils
.bridge_utils_is_installed
:
2479 utils
.exec_command('%s sethello %s %s' % (utils
.brctl_cmd
, bridge
, hello
))
2481 def bridge_get_hello(self
, bridge
):
2482 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/hello_time'
2483 % bridge
, self
._conv
_value
_to
_user
)
2486 def bridge_set_maxage(bridge
, maxage
):
2487 if not LinkUtils
.bridge_utils_is_installed
:
2489 utils
.exec_command('%s setmaxage %s %s' % (utils
.brctl_cmd
, bridge
, maxage
))
2491 def bridge_get_maxage(self
, bridge
):
2492 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/max_age'
2493 % bridge
, self
._conv
_value
_to
_user
)
2496 def bridge_set_pathcost(bridge
, port
, pathcost
):
2497 if not LinkUtils
.bridge_utils_is_installed
:
2499 utils
.exec_command('%s setpathcost %s %s %s' % (utils
.brctl_cmd
, bridge
, port
, pathcost
))
2501 def bridge_get_pathcost(self
, bridge
, port
):
2502 return self
.read_file_oneline('/sys/class/net/%s/brport/path_cost'
2506 def bridge_set_portprio(bridge
, port
, prio
):
2507 if not LinkUtils
.bridge_utils_is_installed
:
2509 utils
.exec_command('%s setportprio %s %s %s' % (utils
.brctl_cmd
, bridge
, port
, prio
))
2511 def bridge_get_portprio(self
, bridge
, port
):
2512 return self
.read_file_oneline('/sys/class/net/%s/brport/priority'
2516 def bridge_set_hashmax(bridge
, hashmax
):
2517 if not LinkUtils
.bridge_utils_is_installed
:
2519 utils
.exec_command('%s sethashmax %s %s' % (utils
.brctl_cmd
, bridge
, hashmax
))
2521 def bridge_get_hashmax(self
, bridge
):
2522 return self
.read_file_oneline('/sys/class/net/%s/bridge/hash_max'
2526 def bridge_set_hashel(bridge
, hashel
):
2527 if not LinkUtils
.bridge_utils_is_installed
:
2529 utils
.exec_command('%s sethashel %s %s' % (utils
.brctl_cmd
, bridge
, hashel
))
2531 def bridge_get_hashel(self
, bridge
):
2532 return self
.read_file_oneline('/sys/class/net/%s/bridge/hash_elasticity'
2536 def bridge_set_mclmc(bridge
, mclmc
):
2537 if not LinkUtils
.bridge_utils_is_installed
:
2539 utils
.exec_command('%s setmclmc %s %s' % (utils
.brctl_cmd
, bridge
, mclmc
))
2541 def bridge_get_mclmc(self
, bridge
):
2542 return self
.read_file_oneline(
2543 '/sys/class/net/%s/bridge/multicast_last_member_count'
2547 def bridge_set_mcrouter(bridge
, mcrouter
):
2548 if not LinkUtils
.bridge_utils_is_installed
:
2550 utils
.exec_command('%s setmcrouter %s %s' % (utils
.brctl_cmd
, bridge
, mcrouter
))
2552 def bridge_get_mcrouter(self
, bridge
):
2553 return self
.read_file_oneline(
2554 '/sys/class/net/%s/bridge/multicast_router' % bridge
)
2557 def bridge_set_mcsnoop(bridge
, mcsnoop
):
2558 if not LinkUtils
.bridge_utils_is_installed
:
2560 utils
.exec_command('%s setmcsnoop %s %s' % (utils
.brctl_cmd
, bridge
, mcsnoop
))
2562 def bridge_get_mcsnoop(self
, bridge
):
2563 return self
.read_file_oneline(
2564 '/sys/class/net/%s/bridge/multicast_snooping' % bridge
)
2567 def bridge_set_mcsqc(bridge
, mcsqc
):
2568 if not LinkUtils
.bridge_utils_is_installed
:
2570 utils
.exec_command('%s setmcsqc %s %s' % (utils
.brctl_cmd
, bridge
, mcsqc
))
2572 def bridge_get_mcsqc(self
, bridge
):
2573 return self
.read_file_oneline(
2574 '/sys/class/net/%s/bridge/multicast_startup_query_count'
2578 def bridge_set_mcqifaddr(bridge
, mcqifaddr
):
2579 if not LinkUtils
.bridge_utils_is_installed
:
2581 utils
.exec_command('%s setmcqifaddr %s %s' % (utils
.brctl_cmd
, bridge
, mcqifaddr
))
2583 def bridge_get_mcqifaddr(self
, bridge
):
2584 return self
.read_file_oneline(
2585 '/sys/class/net/%s/bridge/multicast_startup_query_use_ifaddr'
2589 def bridge_set_mcquerier(bridge
, mcquerier
):
2590 if not LinkUtils
.bridge_utils_is_installed
:
2592 utils
.exec_command('%s setmcquerier %s %s' % (utils
.brctl_cmd
, bridge
, mcquerier
))
2594 def bridge_get_mcquerier(self
, bridge
):
2595 return self
.read_file_oneline(
2596 '/sys/class/net/%s/bridge/multicast_querier' % bridge
)
2598 def bridge_set_mcqv4src(self
, bridge
, vlan
, mcquerier
):
2602 self
.logger
.info('%s: set mcqv4src vlan: invalid parameter %s: %s' %(bridge
, vlan
, str(e
)))
2604 if vlan
== 0 or vlan
> 4095:
2605 self
.logger
.warn('mcqv4src vlan \'%d\' invalid range' % vlan
)
2608 ip
= mcquerier
.split('.')
2610 self
.logger
.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier
)
2613 if not k
.isdigit() or int(k
, 10) < 0 or int(k
, 10) > 255:
2614 self
.logger
.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier
)
2617 if not LinkUtils
.bridge_utils_is_installed
:
2620 utils
.exec_command('%s setmcqv4src %s %d %s' %
2621 (utils
.brctl_cmd
, bridge
, vlan
, mcquerier
))
2623 def bridge_del_mcqv4src(self
, bridge
, vlan
):
2624 if not LinkUtils
.bridge_utils_is_installed
:
2629 self
.logger
.info('%s: del mcqv4src vlan: invalid parameter %s: %s' %(bridge
, vlan
, str(e
)))
2631 utils
.exec_command('%s delmcqv4src %s %d' % (utils
.brctl_cmd
, bridge
, vlan
))
2633 def bridge_get_mcqv4src(self
, bridge
, vlan
=None):
2634 if not LinkUtils
.bridge_utils_is_installed
:
2636 if not self
.supported_command
['showmcqv4src']:
2640 mcqout
= utils
.exec_command('%s showmcqv4src %s' %
2641 (utils
.brctl_cmd
, bridge
))
2642 except Exception as e
:
2644 if 'never heard' in s
:
2645 msg
= ('%s showmcqv4src: skipping unsupported command'
2647 self
.logger
.info(msg
)
2648 self
.supported_command
['showmcqv4src'] = False
2653 mcqlines
= mcqout
.splitlines()
2654 for l
in mcqlines
[1:]:
2656 k
, d
, v
= l
.split('\t')
2661 return mcqv4src
.get(vlan
)
2664 def bridge_get_mcqv4src_sysfs(self
, bridge
, vlan
=None):
2665 if not LinkUtils
.bridge_utils_is_installed
:
2667 if not self
.supported_command
['showmcqv4src']:
2669 if ifupdownflags
.flags
.PERFMODE
:
2673 filename
= '/sys/class/net/%s/bridge/multicast_v4_queriers' % bridge
2674 if os
.path
.exists(filename
):
2675 for line
in self
.read_file(filename
) or []:
2676 vlan_id
, ip
= line
.split('=')
2677 mcqv4src
[vlan_id
] = ip
.strip()
2678 except Exception as e
:
2680 msg
= ('%s showmcqv4src: skipping unsupported command'
2682 self
.logger
.info(msg
)
2683 self
.supported_command
['showmcqv4src'] = False
2686 return mcqv4src
.get(vlan
)
2690 def bridge_set_mclmi(bridge
, mclmi
):
2691 if not LinkUtils
.bridge_utils_is_installed
:
2693 utils
.exec_command('%s setmclmi %s %s' % (utils
.brctl_cmd
, bridge
, mclmi
))
2695 def bridge_get_mclmi(self
, bridge
):
2696 return self
.read_file_oneline(
2697 '/sys/class/net/%s/bridge/multicast_last_member_interval'
2701 def bridge_set_mcmi(bridge
, mcmi
):
2702 if not LinkUtils
.bridge_utils_is_installed
:
2704 utils
.exec_command('%s setmcmi %s %s' % (utils
.brctl_cmd
, bridge
, mcmi
))
2706 def bridge_get_mcmi(self
, bridge
):
2707 return self
.read_file_oneline(
2708 '/sys/class/net/%s/bridge/multicast_membership_interval'
2712 def bridge_exists(bridge
):
2713 return os
.path
.exists('/sys/class/net/%s/bridge' % bridge
)
2716 def is_bridge_port(ifacename
):
2717 return os
.path
.exists('/sys/class/net/%s/brport' % ifacename
)
2720 def bridge_port_exists(bridge
, bridgeportname
):
2722 return os
.path
.exists('/sys/class/net/%s/brif/%s' % (bridge
, bridgeportname
))
2727 def get_bridge_ports(bridgename
):
2729 return os
.listdir('/sys/class/net/%s/brif/' % bridgename
)
2733 def reset_addr_cache(self
, ifname
):
2735 linkCache
.links
[ifname
]['addrs'] = {}
2736 self
.logger
.debug('%s: reset address cache' % ifname
)
2740 def get_ipv6_addrgen_mode(self
, ifname
):
2742 return self
._cache
_get
('link', [ifname
, 'af_spec', socket
.AF_INET6
])[Link
.IFLA_INET6_ADDR_GEN_MODE
]
2744 # default to 0 (eui64)
2747 def ipv6_addrgen(self
, ifname
, addrgen
, link_created
):
2749 # IFLA_INET6_ADDR_GEN_MODE values:
2752 if self
._link
_cache
_get
([ifname
, 'af_spec', socket
.AF_INET6
])[Link
.IFLA_INET6_ADDR_GEN_MODE
] == addrgen
:
2753 self
.logger
.debug('%s: ipv6 addrgen already %s' % (ifname
, 'off' if addrgen
else 'on'))
2756 disabled_ipv6
= self
.read_file_oneline('/proc/sys/net/ipv6/conf/%s/disable_ipv6' % ifname
)
2757 if not disabled_ipv6
or int(disabled_ipv6
) == 1:
2758 self
.logger
.info('%s: cannot set addrgen: ipv6 is disabled on this device' % ifname
)
2761 if int(self
._link
_cache
_get
([ifname
, 'mtu'])) < 1280:
2762 self
.logger
.info('%s: ipv6 addrgen is disabled on device with MTU '
2763 'lower than 1280: cannot set addrgen %s' % (ifname
, 'off' if addrgen
else 'on'))
2765 except (KeyError, TypeError):
2766 self
.logger
.debug('%s: ipv6 addrgen probably not supported or disabled on this device' % ifname
)
2771 if not link_created
:
2772 # When setting addrgenmode it is necessary to flap the macvlan
2773 # device. After flapping the device we also need to re-add all
2774 # the user configuration. The best way to add the user config
2775 # is to flush our internal address cache
2776 self
.reset_addr_cache(ifname
)
2778 cmd
= 'link set dev %s addrgenmode %s' % (ifname
, Link
.ifla_inet6_addr_gen_mode_dict
.get(addrgen
))
2780 is_link_up
= self
.is_link_up(ifname
)
2783 self
.link_down(ifname
)
2785 #if LinkUtils.ipbatch:
2786 # self.add_to_batch(cmd)
2788 # because this command might fail on older kernel its better to not batch it
2789 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
2792 self
.link_up(ifname
)