3 # Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
5 # Julien Fortin, julien@cumulusnetworks.com
15 from ipaddr
import IPNetwork
, IPv6Network
18 import ifupdown2
.ifupdown
.statemanager
as statemanager
19 import ifupdown2
.ifupdown
.ifupdownflags
as ifupdownflags
21 from ifupdown2
.nlmanager
.nlmanager
import Link
, Route
23 from ifupdown2
.ifupdown
.iface
import *
24 from ifupdown2
.ifupdown
.utils
import utils
25 from ifupdown2
.ifupdown
.netlink
import netlink
27 from ifupdown2
.ifupdownaddons
.utilsbase
import utilsBase
28 from ifupdown2
.ifupdownaddons
.cache
import linkCache
, MSTPAttrsCache
30 import ifupdown
.ifupdownflags
as ifupdownflags
31 import ifupdown
.statemanager
as statemanager
33 from nlmanager
.nlmanager
import Link
, Route
35 from ifupdown
.iface
import *
36 from ifupdown
.utils
import utils
37 from ifupdown
.netlink
import netlink
39 from ifupdownaddons
.utilsbase
import utilsBase
40 from ifupdownaddons
.cache
import linkCache
, MSTPAttrsCache
43 class LinkUtils(utilsBase
):
45 This class contains helper methods to cache and manipulate interfaces through
46 non-netlink APIs (sysfs, iproute2, brctl...)
48 _CACHE_FILL_DONE
= False
55 bridge_utils_is_installed
= os
.path
.exists(utils
.brctl_cmd
)
56 bridge_utils_missing_warning
= True
58 DEFAULT_IP_METRIC
= 1024
59 ADDR_METRIC_SUPPORT
= None
61 def __init__(self
, *args
, **kargs
):
62 utilsBase
.__init
__(self
, *args
, **kargs
)
64 self
.supported_command
= {
65 '%s -c -json vlan show' % utils
.bridge_cmd
: True,
68 self
.bridge_vlan_cache
= {}
69 self
.bridge_vlan_cache_fill_done
= False
71 if not ifupdownflags
.flags
.PERFMODE
and not LinkUtils
._CACHE
_FILL
_DONE
:
74 if LinkUtils
.ADDR_METRIC_SUPPORT
is None:
76 cmd
= [utils
.ip_cmd
, 'addr', 'help']
77 self
.logger
.info('executing %s addr help' % utils
.ip_cmd
)
79 process
= subprocess
.Popen(cmd
, stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
)
80 stdout
, stderr
= process
.communicate()
81 LinkUtils
.ADDR_METRIC_SUPPORT
= '[ metric METRIC ]' in stderr
or ''
82 self
.logger
.info('address metric support: %s' % ('OK' if LinkUtils
.ADDR_METRIC_SUPPORT
else 'KO'))
84 LinkUtils
.ADDR_METRIC_SUPPORT
= False
85 self
.logger
.info('address metric support: KO')
88 def addr_metric_support(cls
):
89 return cls
.ADDR_METRIC_SUPPORT
92 def get_default_ip_metric(cls
):
93 return cls
.DEFAULT_IP_METRIC
97 LinkUtils
._CACHE
_FILL
_DONE
= False
98 LinkUtils
.ipbatchbuf
= ''
99 LinkUtils
.ipbatch
= False
100 LinkUtils
.ipbatch_pause
= False
102 def _fill_cache(self
):
103 if not LinkUtils
._CACHE
_FILL
_DONE
:
106 LinkUtils
._CACHE
_FILL
_DONE
= True
111 def _get_vland_id(citems
, i
, warn
):
114 index
= sub
.index('id')
116 return sub
[index
+ 1]
119 raise Exception('invalid use of \'vlan\' keyword')
122 def _link_fill(self
, ifacename
=None, refresh
=False):
123 """ fills cache with link information
125 if ifacename argument given, fill cache for ifacename, else
126 fill cache for all interfaces in the system
129 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
132 # if ifacename already present, return
133 if (ifacename
and not refresh
and
134 linkCache
.get_attr([ifacename
, 'ifflag'])):
141 [linkCache
.update_attrdict([ifname
], linkattrs
)
142 for ifname
, linkattrs
in netlink
.link_dump(ifacename
).items()]
143 except Exception as e
:
144 self
.logger
.info('%s' % str(e
))
145 # this netlink call replaces the call to _link_fill_iproute2_cmd()
146 # We shouldn't have netlink calls in the iproute2 module, this will
147 # be removed in the future. We plan to release, a flexible backend
148 # (netlink+iproute2) by default we will use netlink backend but with
149 # a CLI arg we can switch to iproute2 backend.
150 # Until we decide to create this "backend" switch capability,
151 # we have to put the netlink call inside the iproute2 module.
153 self
._link
_fill
_iproute
2_cmd
(ifacename
, refresh
)
155 self
._fill
_bond
_info
(ifacename
)
156 self
._fill
_bridge
_info
(ifacename
)
158 def _fill_bridge_info(self
, ifacename
):
164 cache_dict
= {ifacename
: linkCache
.links
.get(ifacename
, {})}
166 cache_dict
= linkCache
.links
168 for ifname
, obj
in cache_dict
.items():
169 slave_kind
= obj
.get('slave_kind')
170 if not slave_kind
and slave_kind
!= 'bridge':
173 info_slave_data
= obj
.get('info_slave_data')
174 if not info_slave_data
:
177 ifla_master
= obj
.get('master')
179 raise Exception('No master associated with bridge port %s' % ifname
)
182 Link
.IFLA_BRPORT_STATE
,
183 Link
.IFLA_BRPORT_COST
,
184 Link
.IFLA_BRPORT_PRIORITY
,
186 if nl_attr
not in info_slave_data
and LinkUtils
.bridge_utils_is_installed
:
187 self
._fill
_bridge
_info
_brctl
()
191 'pathcost': str(info_slave_data
.get(Link
.IFLA_BRPORT_COST
, 0)),
192 'fdelay': format(float(info_slave_data
.get(Link
.IFLA_BRPORT_FORWARD_DELAY_TIMER
, 0) / 100), '.2f'),
193 'portmcrouter': str(info_slave_data
.get(Link
.IFLA_BRPORT_MULTICAST_ROUTER
, 0)),
194 'portmcfl': str(info_slave_data
.get(Link
.IFLA_BRPORT_FAST_LEAVE
, 0)),
195 'portprio': str(info_slave_data
.get(Link
.IFLA_BRPORT_PRIORITY
, 0)),
196 'unicast-flood': str(info_slave_data
.get(Link
.IFLA_BRPORT_UNICAST_FLOOD
, 0)),
197 'multicast-flood': str(info_slave_data
.get(Link
.IFLA_BRPORT_MCAST_FLOOD
, 0)),
198 'learning': str(info_slave_data
.get(Link
.IFLA_BRPORT_LEARNING
, 0)),
199 'arp-nd-suppress': str(info_slave_data
.get(Link
.IFLA_BRPORT_ARP_SUPPRESS
, 0))
202 if ifla_master
in brports
:
203 brports
[ifla_master
][ifname
] = brport_attrs
205 brports
[ifla_master
] = {ifname
: brport_attrs
}
207 linkCache
.update_attrdict([ifla_master
, 'linkinfo', 'ports'], brports
[ifla_master
])
209 if LinkUtils
.bridge_utils_is_installed
:
210 self
._fill
_bridge
_info
_brctl
()
212 def _fill_bridge_info_brctl(self
):
213 brctlout
= utils
.exec_command('%s show' % utils
.brctl_cmd
)
217 for bline
in brctlout
.splitlines()[1:]:
218 bitems
= bline
.split()
222 linkCache
.update_attrdict([bitems
[0], 'linkinfo'],
225 linkCache
.update_attrdict([bitems
[0]],
226 {'linkinfo': {'stp': bitems
[2]}})
227 self
._bridge
_attrs
_fill
(bitems
[0])
229 def _bridge_attrs_fill(self
, bridgename
):
233 brout
= utils
.exec_command('%s showstp %s' % (utils
.brctl_cmd
, bridgename
))
234 chunks
= re
.split(r
'\n\n', brout
, maxsplit
=0, flags
=re
.MULTILINE
)
237 # Get all bridge attributes
238 broutlines
= chunks
[0].splitlines()
239 # battrs['pathcost'] = broutlines[3].split('path cost')[1].strip()
242 battrs
['maxage'] = broutlines
[4].split('bridge max age')[
243 1].strip().replace('.00', '')
248 battrs
['hello'] = broutlines
[5].split('bridge hello time')[
249 1].strip().replace('.00', '')
254 battrs
['fd'] = broutlines
[6].split('bridge forward delay')[
255 1].strip().replace('.00', '')
260 battrs
['ageing'] = broutlines
[7].split('ageing time')[
261 1].strip().replace('.00', '')
266 battrs
['mcrouter'] = broutlines
[12].split('mc router')[
267 1].strip().split('\t\t\t')[0]
272 battrs
['bridgeprio'] = self
.read_file_oneline(
273 '/sys/class/net/%s/bridge/priority' % bridgename
)
278 battrs
['vlan-protocol'] = VlanProtocols
.ID_TO_ETHERTYPES
[
279 self
.read_file_oneline(
280 '/sys/class/net/%s/bridge/vlan_protocol' % bridgename
)]
285 battrs
.update(self
._bridge
_get
_mcattrs
_from
_sysfs
(bridgename
))
289 # XXX: comment this out until mc attributes become available
291 # battrs['hashel'] = broutlines[10].split('hash elasticity')[1].split()[0].strip()
292 # battrs['hashmax'] = broutlines[10].split('hash max')[1].strip()
293 # battrs['mclmc'] = broutlines[11].split('mc last member count')[1].split()[0].strip()
294 # battrs['mciqc'] = broutlines[11].split('mc init query count')[1].strip()
295 # battrs['mcrouter'] = broutlines[12].split('mc router')[1].split()[0].strip()
296 ##battrs['mcsnoop'] = broutlines[12].split('mc snooping')[1].strip()
297 # battrs['mclmt'] = broutlines[13].split('mc last member timer')[1].split()[0].strip()
299 self
.logger
.warn('%s: error while processing bridge attributes: %s' % (bridgename
, str(e
)))
302 linkCache
.update_attrdict([bridgename
, 'linkinfo'], battrs
)
303 for cidx
in range(1, len(chunks
)):
304 bpout
= chunks
[cidx
].lstrip('\n')
305 if not bpout
or bpout
[0] == ' ':
307 bplines
= bpout
.splitlines()
308 pname
= bplines
[0].split()[0]
311 bportattrs
['pathcost'] = bplines
[2].split(
312 'path cost')[1].strip()
313 bportattrs
['fdelay'] = bplines
[4].split(
314 'forward delay timer')[1].strip()
315 bportattrs
['portmcrouter'] = self
.read_file_oneline(
316 '/sys/class/net/%s/brport/multicast_router' % pname
)
317 bportattrs
['portmcfl'] = self
.read_file_oneline(
318 '/sys/class/net/%s/brport/multicast_fast_leave' % pname
)
319 bportattrs
['portprio'] = self
.read_file_oneline(
320 '/sys/class/net/%s/brport/priority' % pname
)
321 bportattrs
['unicast-flood'] = self
.read_file_oneline(
322 '/sys/class/net/%s/brport/unicast_flood' % pname
)
323 bportattrs
['multicast-flood'] = self
.read_file_oneline(
324 '/sys/class/net/%s/brport/multicast_flood' % pname
)
325 bportattrs
['learning'] = self
.read_file_oneline(
326 '/sys/class/net/%s/brport/learning' % pname
)
327 bportattrs
['arp-nd-suppress'] = self
.read_file_oneline(
328 '/sys/class/net/%s/brport/neigh_suppress' % pname
)
329 # bportattrs['mcrouters'] = bplines[6].split('mc router')[1].split()[0].strip()
330 # bportattrs['mc fast leave'] = bplines[6].split('mc fast leave')[1].strip()
332 self
.logger
.warn('%s: error while processing bridge attributes: %s' % (bridgename
, str(e
)))
333 bports
[pname
] = bportattrs
334 linkCache
.update_attrdict([bridgename
, 'linkinfo', 'ports'], bports
)
336 _bridge_sysfs_mcattrs
= {
337 'mclmc': 'multicast_last_member_count',
338 'mcrouter': 'multicast_router',
339 'mcsnoop': 'multicast_snooping',
340 'mcsqc': 'multicast_startup_query_count',
341 'mcqifaddr': 'multicast_query_use_ifaddr',
342 'mcquerier': 'multicast_querier',
343 'hashel': 'hash_elasticity',
344 'hashmax': 'hash_max',
345 'mclmi': 'multicast_last_member_interval',
346 'mcmi': 'multicast_membership_interval',
347 'mcqpi': 'multicast_querier_interval',
348 'mcqi': 'multicast_query_interval',
349 'mcqri': 'multicast_query_response_interval',
350 'mcsqi': 'multicast_startup_query_interval',
351 'igmp-version': 'multicast_igmp_version',
352 'mld-version': 'multicast_mld_version',
353 'vlan-stats': 'vlan_stats_enabled',
354 'mcstats': 'multicast_stats_enabled',
357 def _bridge_get_mcattrs_from_sysfs(self
, bridgename
):
358 mcattrsdivby100
= ['mclmi', 'mcmi', 'mcqpi', 'mcqi', 'mcqri', 'mcsqi']
361 for m
, s
in self
._bridge
_sysfs
_mcattrs
.items():
362 n
= self
.read_file_oneline('/sys/class/net/%s/bridge/%s' % (bridgename
, s
))
363 if m
in mcattrsdivby100
:
368 self
.logger
.warn('error getting mc attr %s (%s)' % (m
, str(e
)))
374 def _fill_bond_info(self
, ifacename
):
375 bonding_masters
= self
.read_file_oneline('/sys/class/net/bonding_masters')
376 if not bonding_masters
:
379 bond_masters_list
= bonding_masters
.split()
382 if ifacename
in bond_masters_list
:
383 bond_masters_list
= [ifacename
]
385 # we want to refresh this interface only if it's a bond master
388 for bondname
in bond_masters_list
:
390 if bondname
not in linkCache
.links
:
391 linkCache
.set_attr([bondname
], {'linkinfo': {}})
392 linkCache
.set_attr([bondname
, 'linkinfo', 'slaves'],
393 self
.read_file_oneline('/sys/class/net/%s/bonding/slaves'
396 # if some attribute are missing we try to get the bond attributes via sysfs
397 bond_linkinfo
= linkCache
.links
[bondname
]['linkinfo']
398 for attr
in [Link
.IFLA_BOND_MODE
, Link
.IFLA_BOND_XMIT_HASH_POLICY
, Link
.IFLA_BOND_MIN_LINKS
]:
399 if attr
not in bond_linkinfo
:
400 self
._fill
_bond
_info
_sysfs
(bondname
)
401 # after we fill in the cache we can continue to the next bond
404 self
._fill
_bond
_info
_sysfs
(bondname
)
406 except Exception as e
:
407 self
.logger
.debug('LinkUtils: bond cache error: %s' % str(e
))
409 def _fill_bond_info_sysfs(self
, bondname
):
411 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_MIN_LINKS
],
412 self
.read_file_oneline(
413 '/sys/class/net/%s/bonding/min_links'
415 except Exception as e
:
416 self
.logger
.debug(str(e
))
419 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_MODE
],
420 self
.read_file_oneline('/sys/class/net/%s/bonding/mode'
421 % bondname
).split()[0])
422 except Exception as e
:
423 self
.logger
.debug(str(e
))
425 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_XMIT_HASH_POLICY
],
426 self
.read_file_oneline(
427 '/sys/class/net/%s/bonding/xmit_hash_policy'
428 % bondname
).split()[0])
429 except Exception as e
:
430 self
.logger
.debug(str(e
))
432 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_RATE
],
433 self
.read_file_oneline('/sys/class/net/%s/bonding/lacp_rate'
434 % bondname
).split()[1])
435 except Exception as e
:
436 self
.logger
.debug(str(e
))
438 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
],
439 self
.read_file_oneline('/sys/class/net/%s/bonding/ad_actor_sys_prio'
441 except Exception as e
:
442 self
.logger
.debug(str(e
))
444 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYSTEM
],
445 self
.read_file_oneline('/sys/class/net/%s/bonding/ad_actor_system'
447 except Exception as e
:
448 self
.logger
.debug(str(e
))
450 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_BYPASS
],
451 self
.read_file_oneline('/sys/class/net/%s/bonding/lacp_bypass'
452 % bondname
).split()[1])
453 except Exception as e
:
454 self
.logger
.debug(str(e
))
456 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_UPDELAY
],
457 self
.read_file_oneline('/sys/class/net/%s/bonding/updelay'
459 except Exception as e
:
460 self
.logger
.debug(str(e
))
462 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_DOWNDELAY
],
463 self
.read_file_oneline('/sys/class/net/%s/bonding/downdelay'
465 except Exception as e
:
466 self
.logger
.debug(str(e
))
469 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_USE_CARRIER
],
470 self
.read_file_oneline('/sys/class/net/%s/bonding/use_carrier' % bondname
))
471 except Exception as e
:
472 self
.logger
.debug(str(e
))
475 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_MIIMON
],
476 self
.read_file_oneline('/sys/class/net/%s/bonding/miimon' % bondname
))
477 except Exception as e
:
478 self
.logger
.debug(str(e
))
481 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
],
482 self
.read_file_oneline('/sys/class/net/%s/bonding/num_unsol_na' % bondname
))
483 except Exception as e
:
484 self
.logger
.debug(str(e
))
487 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
],
488 self
.read_file_oneline('/sys/class/net/%s/bonding/num_grat_arp' % bondname
))
489 except Exception as e
:
490 self
.logger
.debug(str(e
))
493 def _link_fill_iproute2_cmd(self
, ifacename
=None, refresh
=False):
496 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
499 # if ifacename already present, return
500 if (ifacename
and not refresh
and
501 linkCache
.get_attr([ifacename
, 'ifflag'])):
505 cmdout
= self
.link_show(ifacename
=ifacename
)
508 for c
in cmdout
.splitlines():
510 ifnamenlink
= citems
[1].split('@')
511 if len(ifnamenlink
) > 1:
512 ifname
= ifnamenlink
[0]
513 iflink
= ifnamenlink
[1].strip(':')
515 ifname
= ifnamenlink
[0].strip(':')
518 linkattrs
['link'] = iflink
519 linkattrs
['ifindex'] = citems
[0].strip(':')
520 flags
= citems
[2].strip('<>').split(',')
521 linkattrs
['flags'] = flags
522 linkattrs
['ifflag'] = 'UP' if 'UP' in flags
else 'DOWN'
523 for i
in range(0, len(citems
)):
525 if citems
[i
] == 'mtu':
526 linkattrs
['mtu'] = citems
[i
+ 1]
527 elif citems
[i
] == 'state':
528 linkattrs
['state'] = citems
[i
+ 1]
529 elif citems
[i
] == 'link/ether':
530 linkattrs
['hwaddress'] = citems
[i
+ 1]
531 elif citems
[i
] in ['link/gre', 'link/ipip', 'link/sit', 'link/gre6', 'link/tunnel6', 'gretap']:
532 linkattrs
['kind'] = 'tunnel'
533 tunattrs
= {'mode': citems
[i
].split('/')[-1],
538 for j
in range(i
, len(citems
)):
539 if citems
[j
] == 'local':
540 tunattrs
['local'] = citems
[j
+ 1]
541 elif citems
[j
] == 'remote':
542 tunattrs
['endpoint'] = citems
[j
+ 1]
543 elif citems
[j
] == 'ttl':
544 tunattrs
['ttl'] = citems
[j
+ 1]
545 elif citems
[j
] == 'dev':
546 tunattrs
['physdev'] = citems
[j
+ 1]
547 linkattrs
['linkinfo'] = tunattrs
549 elif citems
[i
] == 'vlan':
550 vlanid
= self
._get
_vland
_id
(citems
, i
, warn
)
552 linkattrs
['linkinfo'] = {'vlanid': vlanid
}
553 linkattrs
['kind'] = 'vlan'
554 elif citems
[i
] == 'dummy':
555 linkattrs
['kind'] = 'dummy'
556 elif citems
[i
] == 'vxlan' and citems
[i
+ 1] == 'id':
557 linkattrs
['kind'] = 'vxlan'
558 vattrs
= {'vxlanid': citems
[i
+ 2],
561 'ageing': citems
[i
+ 2],
563 for j
in range(i
+ 2, len(citems
)):
564 if citems
[j
] == 'local':
565 vattrs
['local'] = citems
[j
+ 1]
566 elif citems
[j
] == 'remote':
567 vattrs
['svcnode'] = citems
[j
+ 1]
568 elif citems
[j
] == 'ageing':
569 vattrs
['ageing'] = citems
[j
+ 1]
570 elif citems
[j
] == 'nolearning':
571 vattrs
['learning'] = 'off'
572 elif citems
[j
] == 'dev':
573 vattrs
['physdev'] = citems
[j
+ 1]
574 linkattrs
['linkinfo'] = vattrs
576 elif citems
[i
] == 'vrf' and citems
[i
+ 1] == 'table':
577 vattrs
= {'table': citems
[i
+ 2]}
578 linkattrs
['linkinfo'] = vattrs
579 linkattrs
['kind'] = 'vrf'
580 linkCache
.vrfs
[ifname
] = vattrs
582 elif citems
[i
] == 'veth':
583 linkattrs
['kind'] = 'veth'
584 elif citems
[i
] == 'vrf_slave':
585 linkattrs
['slave_kind'] = 'vrf_slave'
587 elif citems
[i
] == 'macvlan' and citems
[i
+ 1] == 'mode':
588 linkattrs
['kind'] = 'macvlan'
589 except Exception as e
:
591 self
.logger
.debug('%s: parsing error: id, mtu, state, '
592 'link/ether, vlan, dummy, vxlan, local, '
593 'remote, ageing, nolearning, vrf, table, '
594 'vrf_slave are reserved keywords: %s' %
597 # linkattrs['alias'] = self.read_file_oneline(
598 # '/sys/class/net/%s/ifalias' %ifname)
599 linkout
[ifname
] = linkattrs
600 [linkCache
.update_attrdict([ifname
], linkattrs
)
601 for ifname
, linkattrs
in linkout
.items()]
604 def _addr_filter(ifname
, addr
, scope
=None):
605 default_addrs
= ['127.0.0.1/8', '::1/128', '0.0.0.0']
606 if ifname
== 'lo' and addr
in default_addrs
:
608 if scope
and scope
== 'link':
612 def _addr_fill(self
, ifacename
=None, refresh
=False):
613 """ fills cache with address information
615 if ifacename argument given, fill cache for ifacename, else
616 fill cache for all interfaces in the system
618 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
621 # Check if ifacename is already full, in which case, return
622 if ifacename
and not refresh
:
623 linkCache
.get_attr([ifacename
, 'addrs'])
630 [linkCache
.update_attrdict([ifname
], linkattrs
)
631 for ifname
, linkattrs
in netlink
.addr_dump(ifname
=ifacename
).items()]
632 except Exception as e
:
633 self
.logger
.info(str(e
))
635 # this netlink call replaces the call to _addr_fill_iproute2_cmd()
636 # We shouldn't have netlink calls in the iproute2 module, this will
637 # be removed in the future. We plan to release, a flexible backend
638 # (netlink+iproute2) by default we will use netlink backend but with
639 # a CLI arg we can switch to iproute2 backend.
640 # Until we decide to create this "backend" switch capability,
641 # we have to put the netlink call inside the iproute2 module.
644 self
._addr
_fill
_iproute
2_cmd
(ifacename
, refresh
)
646 def _addr_fill_iproute2_cmd(self
, ifacename
=None, refresh
=False):
647 """ fills cache with address information
649 if ifacename argument given, fill cache for ifacename, else
650 fill cache for all interfaces in the system
653 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
656 # Check if ifacename is already full, in which case, return
657 if ifacename
and not refresh
:
658 linkCache
.get_attr([ifacename
, 'addrs'])
662 cmdout
= self
.addr_show(ifacename
=ifacename
)
665 for c
in cmdout
.splitlines():
667 ifnamenlink
= citems
[1].split('@')
668 if len(ifnamenlink
) > 1:
669 ifname
= ifnamenlink
[0]
671 ifname
= ifnamenlink
[0].strip(':')
672 if not linkout
.get(ifname
):
674 linkattrs
['addrs'] = OrderedDict({})
676 linkout
[ifname
].update(linkattrs
)
678 linkout
[ifname
] = linkattrs
679 if citems
[2] == 'inet':
680 if self
._addr
_filter
(ifname
, citems
[3], scope
=citems
[5]):
683 addrattrs
['scope'] = citems
[5]
684 addrattrs
['type'] = 'inet'
685 linkout
[ifname
]['addrs'][citems
[3]] = addrattrs
686 elif citems
[2] == 'inet6':
687 if self
._addr
_filter
(ifname
, citems
[3], scope
=citems
[5]):
689 if citems
[5] == 'link':
690 continue # skip 'link' addresses
692 addrattrs
['scope'] = citems
[5]
693 addrattrs
['type'] = 'inet6'
694 linkout
[ifname
]['addrs'][citems
[3]] = addrattrs
695 [linkCache
.update_attrdict([ifname
], linkattrs
)
696 for ifname
, linkattrs
in linkout
.items()]
698 def cache_get(self
, t
, attrlist
, refresh
=False):
699 return self
._cache
_get
(t
, attrlist
, refresh
)
701 def _cache_get(self
, t
, attrlist
, refresh
=False):
703 if ifupdownflags
.flags
.DRYRUN
:
705 if ifupdownflags
.flags
.CACHE
:
706 if self
._fill
_cache
():
707 # if we filled the cache, return new data
708 return linkCache
.get_attr(attrlist
)
710 return linkCache
.get_attr(attrlist
)
712 self
._link
_fill
(attrlist
[0], refresh
)
714 self
._addr
_fill
(attrlist
[0], refresh
)
716 self
._link
_fill
(attrlist
[0], refresh
)
717 self
._addr
_fill
(attrlist
[0], refresh
)
718 return linkCache
.get_attr(attrlist
)
720 self
.logger
.debug('_cache_get(%s) : [%s]' % (str(attrlist
), str(e
)))
723 def cache_check(self
, attrlist
, value
, refresh
=False):
724 return self
._cache
_check
('link', attrlist
, value
, refresh
=refresh
)
726 def _cache_check(self
, t
, attrlist
, value
, refresh
=False):
728 return self
._cache
_get
(t
, attrlist
, refresh
) == value
730 self
.logger
.debug('_cache_check(%s) : [%s]'
731 % (str(attrlist
), str(e
)))
734 def cache_update(self
, attrlist
, value
):
735 return self
._cache
_update
(attrlist
, value
)
738 def _cache_update(attrlist
, value
):
739 if ifupdownflags
.flags
.DRYRUN
:
742 if attrlist
[-1] == 'slaves':
743 linkCache
.append_to_attrlist(attrlist
, value
)
745 linkCache
.set_attr(attrlist
, value
)
750 def _cache_delete(attrlist
, value
=None):
751 if ifupdownflags
.flags
.DRYRUN
:
755 linkCache
.remove_from_attrlist(attrlist
, value
)
757 linkCache
.del_attr(attrlist
)
762 def _cache_invalidate():
763 linkCache
.invalidate()
764 LinkUtils
._CACHE
_FILL
_DONE
= False
768 LinkUtils
.ipbatcbuf
= ''
769 LinkUtils
.ipbatch
= True
770 LinkUtils
.ipbatch_pause
= False
773 def add_to_batch(cmd
):
774 LinkUtils
.ipbatchbuf
+= cmd
+ '\n'
778 LinkUtils
.ipbatch_pause
= True
782 LinkUtils
.ipbatch_pause
= False
784 def batch_commit(self
):
785 if not LinkUtils
.ipbatchbuf
:
786 LinkUtils
.ipbatchbuf
= ''
787 LinkUtils
.ipbatch
= False
788 LinkUtils
.ipbatch_pause
= False
791 utils
.exec_command('%s -force -batch -' % utils
.ip_cmd
,
792 stdin
=self
.ipbatchbuf
)
796 LinkUtils
.ipbatchbuf
= ''
797 LinkUtils
.ipbatch
= False
798 LinkUtils
.ipbatch_pause
= False
800 def bridge_batch_commit(self
):
801 if not LinkUtils
.ipbatchbuf
:
802 LinkUtils
.ipbatchbuf
= ''
803 LinkUtils
.ipbatch
= False
804 LinkUtils
.ipbatch_pause
= False
807 utils
.exec_command('%s -force -batch -'
808 % utils
.bridge_cmd
, stdin
=self
.ipbatchbuf
)
812 LinkUtils
.ipbatchbuf
= ''
813 LinkUtils
.ipbatch
= False
814 LinkUtils
.ipbatch_pause
= False
816 def addr_show(self
, ifacename
=None):
818 if not self
.link_exists(ifacename
):
820 return utils
.exec_commandl([utils
.ip_cmd
,
821 '-o', 'addr', 'show', 'dev', ifacename
])
823 return utils
.exec_commandl([utils
.ip_cmd
,
824 '-o', 'addr', 'show'])
827 def link_show(ifacename
=None):
829 return utils
.exec_commandl([utils
.ip_cmd
,
830 '-o', '-d', 'link', 'show', 'dev', ifacename
])
832 return utils
.exec_commandl([utils
.ip_cmd
,
833 '-o', '-d', 'link', 'show'])
835 def addr_add(self
, ifacename
, address
, broadcast
=None,
836 peer
=None, scope
=None, preferred_lifetime
=None, metric
=None):
839 cmd
= 'addr add %s' % address
841 cmd
+= ' broadcast %s' % broadcast
843 cmd
+= ' peer %s' % peer
845 cmd
+= ' scope %s' % scope
846 if preferred_lifetime
:
847 cmd
+= ' preferred_lft %s' % preferred_lifetime
848 cmd
+= ' dev %s' % ifacename
851 cmd
+= ' metric %s' % metric
853 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
854 self
.add_to_batch(cmd
)
856 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
857 self
._cache
_update
([ifacename
, 'addrs', address
], {})
859 def addr_del(self
, ifacename
, address
, broadcast
=None,
860 peer
=None, scope
=None):
861 """ Delete ipv4 address """
864 if not self
._cache
_get
('addr', [ifacename
, 'addrs', address
]):
866 cmd
= 'addr del %s' % address
868 cmd
+= 'broadcast %s' % broadcast
870 cmd
+= 'peer %s' % peer
872 cmd
+= 'scope %s' % scope
873 cmd
+= ' dev %s' % ifacename
874 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
875 self
._cache
_delete
([ifacename
, 'addrs', address
])
877 def addr_flush(self
, ifacename
):
878 cmd
= 'addr flush dev %s' % ifacename
879 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
880 self
.add_to_batch(cmd
)
882 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
883 self
._cache
_delete
([ifacename
, 'addrs'])
885 def del_addr_all(self
, ifacename
, skip_addrs
=[]):
888 runningaddrsdict
= self
.get_running_addrs(ifname
=ifacename
)
890 # XXX: ignore errors. Fix this to delete secondary addresses
892 [self
.addr_del(ifacename
, a
) for a
in
893 set(runningaddrsdict
.keys()).difference(skip_addrs
)]
898 def addr_get(self
, ifacename
, details
=True, refresh
=False):
899 addrs
= self
._cache
_get
('addr', [ifacename
, 'addrs'], refresh
=refresh
)
906 def get_running_addrs(self
, ifaceobj
=None, ifname
=None, details
=True, addr_virtual_ifaceobj
=None):
908 We now support addr with link scope. Since the kernel may add it's
909 own link address to some interfaces we need to filter them out and
910 make sure we only deal with the addresses set by ifupdown2.
912 To do so we look at the previous configuration made by ifupdown2
913 (with the help of the statemanager) together with the addresses
914 specified by the user in /etc/network/interfaces, these addresses
915 are then compared to the running state of the intf (ip addr show)
916 made via a netlink addr dump.
917 For each configured addresses of scope link, we check if it was
918 previously configured by ifupdown2 to create a final set of the
919 addresses watched by ifupdown2
921 if not ifaceobj
and not ifname
:
927 interface_name
= ifaceobj
.name
929 interface_name
= ifname
931 if addr_virtual_ifaceobj
:
932 for virtual
in addr_virtual_ifaceobj
.get_attr_value('address-virtual') or []:
933 for ip
in virtual
.split():
940 saved_ifaceobjs
= statemanager
.statemanager_api
.get_ifaceobjs(addr_virtual_ifaceobj
.name
)
941 for saved_ifaceobj
in saved_ifaceobjs
or []:
942 for virtual
in saved_ifaceobj
.get_attr_value('address-virtual') or []:
943 for ip
in virtual
.split():
951 for addr
in ifaceobj
.get_attr_value('address') or []:
952 config_addrs
.add(addr
)
954 saved_ifaceobjs
= statemanager
.statemanager_api
.get_ifaceobjs(interface_name
)
955 for saved_ifaceobj
in saved_ifaceobjs
or []:
956 for addr
in saved_ifaceobj
.get_attr_value('address') or []:
957 config_addrs
.add(addr
)
959 running_addrs
= OrderedDict()
960 cached_addrs
= self
.addr_get(interface_name
)
962 for addr
, addr_details
in cached_addrs
.items():
964 scope
= int(addr_details
['scope'])
968 addr_obj
= IPNetwork(addr
)
969 if isinstance(addr_obj
, IPv6Network
):
970 d
['family'] = 'inet6'
973 running_addrs
[addr
] = d
975 running_addrs
[addr
] = {}
977 if (scope
& Route
.RT_SCOPE_LINK
and addr
in config_addrs
) or not scope
& Route
.RT_SCOPE_LINK
:
978 running_addrs
[addr
] = addr_details
984 return running_addrs
.keys()
987 def compare_user_config_vs_running_state(running_addrs
, user_addrs
):
991 for ip
in user_addrs
or []:
994 if type(obj
) == IPv6Network
:
1000 for ip
in running_addrs
or []:
1001 running_ipobj
.append(IPNetwork(ip
))
1003 return running_ipobj
== (ip4
+ ip6
)
1005 def addr_add_multiple(self
, ifaceobj
, ifacename
, addrs
, purge_existing
=False, metric
=None):
1008 # if perfmode is not set and also if iface has no sibling
1009 # objects, purge addresses that are not present in the new
1011 runningaddrs
= self
.get_running_addrs(
1014 addr_virtual_ifaceobj
=ifaceobj
1016 addrs
= utils
.get_normalized_ip_addr(ifacename
, addrs
)
1018 if self
.compare_user_config_vs_running_state(runningaddrs
, addrs
):
1021 # if primary address is not same, there is no need to keep any.
1022 # reset all addresses
1023 if (addrs
and runningaddrs
and
1024 (addrs
[0] != runningaddrs
[0])):
1025 self
.del_addr_all(ifacename
)
1027 self
.del_addr_all(ifacename
, addrs
)
1028 except Exception, e
:
1029 self
.logger
.warning('%s: %s' % (ifacename
, str(e
)))
1032 self
.addr_add(ifacename
, a
, metric
=metric
)
1033 except Exception, e
:
1034 self
.logger
.error(str(e
))
1036 def _link_set_ifflag(self
, ifacename
, value
):
1037 # Dont look at the cache, the cache may have stale value
1038 # because link status can be changed by external
1039 # entity (One such entity is ifupdown main program)
1040 cmd
= 'link set dev %s %s' % (ifacename
, value
.lower())
1041 if LinkUtils
.ipbatch
:
1042 self
.add_to_batch(cmd
)
1044 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1046 def link_up(self
, ifacename
):
1047 self
._link
_set
_ifflag
(ifacename
, 'UP')
1049 def link_down(self
, ifacename
):
1050 self
._link
_set
_ifflag
(ifacename
, 'DOWN')
1052 def link_set(self
, ifacename
, key
, value
=None,
1053 force
=False, t
=None, state
=None):
1055 if (key
not in ['master', 'nomaster'] and
1056 self
._cache
_check
('link', [ifacename
, key
], value
)):
1058 cmd
= 'link set dev %s' % ifacename
1060 cmd
+= ' type %s' % t
1063 cmd
+= ' %s' % value
1065 cmd
+= ' %s' % state
1066 if LinkUtils
.ipbatch
:
1067 self
.add_to_batch(cmd
)
1069 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1070 if key
not in ['master', 'nomaster']:
1071 self
._cache
_update
([ifacename
, key
], value
)
1073 def link_set_hwaddress(self
, ifacename
, hwaddress
, force
=False):
1075 if self
._cache
_check
('link', [ifacename
, 'hwaddress'], hwaddress
):
1077 self
.link_down(ifacename
)
1078 cmd
= 'link set dev %s address %s' % (ifacename
, hwaddress
)
1079 if LinkUtils
.ipbatch
:
1080 self
.add_to_batch(cmd
)
1082 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1083 self
.link_up(ifacename
)
1084 self
._cache
_update
([ifacename
, 'hwaddress'], hwaddress
)
1086 def link_set_mtu(self
, ifacename
, mtu
):
1087 if ifupdownflags
.flags
.DRYRUN
:
1089 if not mtu
or not ifacename
: return
1090 self
.write_file('/sys/class/net/%s/mtu' % ifacename
, mtu
)
1091 self
._cache
_update
([ifacename
, 'mtu'], mtu
)
1093 def link_set_alias(self
, ifacename
, alias
):
1094 self
.write_file('/sys/class/net/%s/ifalias' % ifacename
,
1095 '\n' if not alias
else alias
)
1097 def link_get_alias(self
, ifacename
):
1098 return self
.read_file_oneline('/sys/class/net/%s/ifalias'
1101 def link_isloopback(self
, ifacename
):
1102 flags
= self
._cache
_get
('link', [ifacename
, 'flags'])
1105 if 'LOOPBACK' in flags
:
1109 def link_get_status(self
, ifacename
):
1110 return self
._cache
_get
('link', [ifacename
, 'ifflag'], refresh
=True)
1113 def route_add_gateway(ifacename
, gateway
, vrf
=None, metric
=None):
1117 cmd
= '%s route add default via %s proto kernel' % (utils
.ip_cmd
,
1120 cmd
= ('%s route add table %s default via %s proto kernel' %
1121 (utils
.ip_cmd
, vrf
, gateway
))
1124 cmd
+= 'metric %s' % metric
1125 cmd
+= ' dev %s' % ifacename
1126 utils
.exec_command(cmd
)
1129 def route_del_gateway(ifacename
, gateway
, vrf
=None, metric
=None):
1134 cmd
= ('%s route del default via %s proto kernel' %
1135 (utils
.ip_cmd
, gateway
))
1137 cmd
= ('%s route del table %s default via %s proto kernel' %
1138 (utils
.ip_cmd
, vrf
, gateway
))
1140 cmd
+= ' metric %s' % metric
1141 cmd
+= ' dev %s' % ifacename
1142 utils
.exec_command(cmd
)
1145 def _get_vrf_id(ifacename
):
1147 return linkCache
.vrfs
[ifacename
]['table']
1149 dump
= netlink
.link_dump(ifacename
)
1151 [linkCache
.update_attrdict([ifname
], linkattrs
)
1152 for ifname
, linkattrs
in dump
.items()]
1154 if dump
and dump
.get(ifacename
, {}).get('kind') == 'vrf':
1155 vrf_table
= dump
.get(ifacename
, {}).get('linkinfo', {}).get('table')
1156 linkCache
.vrfs
[ifacename
] = {'table': vrf_table
}
1161 def fix_ipv6_route_metric(self
, ifaceobj
, macvlan_ifacename
, ips
):
1164 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
:
1166 for upper_iface
in ifaceobj
.upperifaces
:
1167 vrf_table
= self
._get
_vrf
_id
(upper_iface
)
1175 ip_network_obj
= IPNetwork(ip
)
1177 if type(ip_network_obj
) == IPv6Network
:
1178 route_prefix
= '%s/%d' % (ip_network_obj
.network
, ip_network_obj
.prefixlen
)
1181 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1182 LinkUtils
.add_to_batch('route del %s table %s dev %s' % (route_prefix
, vrf_table
, macvlan_ifacename
))
1184 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'del', route_prefix
, 'table', vrf_table
, 'dev', macvlan_ifacename
])
1186 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1187 LinkUtils
.add_to_batch('route del %s dev %s' % (route_prefix
, macvlan_ifacename
))
1189 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'del', route_prefix
, 'dev', macvlan_ifacename
])
1190 ip_route_del
.append((route_prefix
, vrf_table
))
1192 for ip
, vrf_table
in ip_route_del
:
1194 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1195 LinkUtils
.add_to_batch('route add %s table %s dev %s proto kernel metric 9999' % (ip
, vrf_table
, macvlan_ifacename
))
1197 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'add', ip
, 'table', vrf_table
, 'dev', macvlan_ifacename
, 'proto', 'kernel' 'metric', '9999'])
1199 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1200 LinkUtils
.add_to_batch('route add %s dev %s proto kernel metric 9999' % (ip
, macvlan_ifacename
))
1202 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'add', ip
, 'dev', macvlan_ifacename
, 'proto', 'kernel' 'metric', '9999'])
1204 def link_create_vlan(self
, vlan_device_name
, vlan_raw_device
, vlanid
):
1205 if self
.link_exists(vlan_device_name
):
1207 utils
.exec_command('%s link add link %s name %s type vlan id %d' %
1209 vlan_raw_device
, vlan_device_name
, vlanid
))
1210 self
._cache
_update
([vlan_device_name
], {})
1212 def link_create_vlan_from_name(self
, vlan_device_name
):
1213 v
= vlan_device_name
.split('.')
1215 self
.logger
.warn('invalid vlan device name %s' % vlan_device_name
)
1217 self
.link_create_vlan(vlan_device_name
, v
[0], v
[1])
1219 def link_create_macvlan(self
, name
, linkdev
, mode
='private'):
1220 if self
.link_exists(name
):
1222 cmd
= ('link add link %s' % linkdev
+
1224 ' type macvlan mode %s' % mode
)
1225 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1226 self
.add_to_batch(cmd
)
1228 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1229 self
._cache
_update
([name
], {})
1231 def get_vxlan_peers(self
, dev
, svcnodeip
):
1232 cmd
= '%s fdb show brport %s' % (utils
.bridge_cmd
,
1236 ps
= subprocess
.Popen(shlex
.split(cmd
), stdout
=subprocess
.PIPE
, close_fds
=False)
1237 utils
.enable_subprocess_signal_forwarding(ps
, signal
.SIGINT
)
1238 output
= subprocess
.check_output(('grep', '00:00:00:00:00:00'), stdin
=ps
.stdout
)
1240 utils
.disable_subprocess_signal_forwarding(signal
.SIGINT
)
1242 ppat
= re
.compile('\s+dst\s+(\d+.\d+.\d+.\d+)\s+')
1243 for l
in output
.split('\n'):
1245 if m
and m
.group(1) != svcnodeip
:
1246 cur_peers
.append(m
.group(1))
1248 self
.logger
.warn('error parsing ip link output')
1249 except subprocess
.CalledProcessError
as e
:
1250 if e
.returncode
!= 1:
1251 self
.logger
.error(str(e
))
1253 utils
.disable_subprocess_signal_forwarding(signal
.SIGINT
)
1257 def tunnel_create(self
, tunnelname
, mode
, attrs
={}):
1258 """ generic link_create function """
1259 if self
.link_exists(tunnelname
):
1267 cmd
+= ' %s mode %s' %(tunnelname
, mode
)
1269 for k
, v
in attrs
.iteritems():
1273 if self
.ipbatch
and not self
.ipbatch_pause
:
1274 self
.add_to_batch(cmd
)
1276 utils
.exec_command('ip %s' % cmd
)
1277 self
._cache
_update
([tunnelname
], {})
1279 def tunnel_change(self
, tunnelname
, attrs
={}):
1280 """ tunnel change function """
1281 if not self
.link_exists(tunnelname
):
1283 cmd
= 'tunnel change'
1284 cmd
+= ' %s' %(tunnelname)
1286 for k
, v
in attrs
.iteritems():
1290 if self
.ipbatch
and not self
.ipbatch_pause
:
1291 self
.add_to_batch(cmd
)
1293 utils
.exec_command('ip %s' % cmd
)
1294 self
._cache
_update
([tunnelname
], {})
1296 def link_create_vxlan(self
, name
, vxlanid
,
1303 if svcnodeip
and remoteips
:
1304 raise Exception("svcnodeip and remoteip is mutually exclusive")
1307 args
+= ' remote %s' % svcnodeip
1309 args
+= ' ageing %s' % ageing
1310 if learning
== 'off':
1311 args
+= ' nolearning'
1313 if self
.link_exists(name
):
1314 cmd
= 'link set dev %s type vxlan dstport %d' % (name
, LinkUtils
.VXLAN_UDP_PORT
)
1315 vxlanattrs
= self
.get_vxlandev_attrs(name
)
1316 # on ifreload do not overwrite anycast_ip to individual ip if clagd
1319 running_localtunnelip
= vxlanattrs
.get('local')
1320 if anycastip
and running_localtunnelip
and anycastip
== running_localtunnelip
:
1321 localtunnelip
= running_localtunnelip
1322 running_svcnode
= vxlanattrs
.get('svcnode')
1323 if running_svcnode
and not svcnodeip
:
1326 cmd
= 'link add dev %s type vxlan id %s dstport %d' % (name
, vxlanid
, LinkUtils
.VXLAN_UDP_PORT
)
1329 args
+= ' local %s' % localtunnelip
1332 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1333 self
.add_to_batch(cmd
)
1335 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1337 # XXX: update linkinfo correctly
1338 #self._cache_update([name], {})
1341 def link_exists(ifacename
):
1342 if ifupdownflags
.flags
.DRYRUN
:
1344 return os
.path
.exists('/sys/class/net/%s' % ifacename
)
1346 def link_get_ifindex(self
, ifacename
):
1347 if ifupdownflags
.flags
.DRYRUN
:
1349 return self
.read_file_oneline('/sys/class/net/%s/ifindex' % ifacename
)
1351 def is_vlan_device_by_name(self
, ifacename
):
1352 if re
.search(r
'\.', ifacename
):
1357 def link_add_macvlan(ifname
, macvlan_ifacename
):
1358 utils
.exec_commandl(['ip', 'link', 'add', 'link', ifname
, 'name', macvlan_ifacename
, 'type', 'macvlan', 'mode', 'private'])
1361 def route_add(route
):
1362 utils
.exec_command('%s route add %s' % (utils
.ip_cmd
,
1366 def route6_add(route
):
1367 utils
.exec_command('%s -6 route add %s' % (utils
.ip_cmd
,
1370 def get_vlandev_attrs(self
, ifacename
):
1371 return (self
._cache
_get
('link', [ifacename
, 'link']),
1372 self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlanid']),
1373 self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlan_protocol']))
1375 def get_vlan_protocol(self
, ifacename
):
1376 return self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlan_protocol'])
1378 def get_vxlandev_attrs(self
, ifacename
):
1379 return self
._cache
_get
('link', [ifacename
, 'linkinfo'])
1381 def get_vxlandev_learning(self
, ifacename
):
1382 return self
._cache
_get
('link', [ifacename
, 'linkinfo', Link
.IFLA_VXLAN_LEARNING
])
1384 def set_vxlandev_learning(self
, ifacename
, learn
):
1386 utils
.exec_command('%s link set dev %s type vxlan learning' %
1387 (utils
.ip_cmd
, ifacename
))
1388 self
._cache
_update
([ifacename
, 'linkinfo', 'learning'], 'on')
1390 utils
.exec_command('%s link set dev %s type vxlan nolearning' %
1391 (utils
.ip_cmd
, ifacename
))
1392 self
._cache
_update
([ifacename
, 'linkinfo', 'learning'], 'off')
1394 def link_get_linkinfo_attrs(self
, ifacename
):
1395 return self
._cache
_get
('link', [ifacename
, 'linkinfo'])
1397 def link_get_mtu(self
, ifacename
, refresh
=False):
1398 return self
._cache
_get
('link', [ifacename
, 'mtu'], refresh
=refresh
)
1400 def link_get_mtu_sysfs(self
, ifacename
):
1401 return self
.read_file_oneline('/sys/class/net/%s/mtu'
1404 def link_get_kind(self
, ifacename
):
1405 return self
._cache
_get
('link', [ifacename
, 'kind'])
1407 def link_get_slave_kind(self
, ifacename
):
1408 return self
._cache
_get
('link', [ifacename
, 'slave_kind'])
1410 def link_get_hwaddress(self
, ifacename
):
1411 address
= self
._cache
_get
('link', [ifacename
, 'hwaddress'])
1412 # newly created logical interface addresses dont end up in the cache
1413 # read hwaddress from sysfs file for these interfaces
1415 address
= self
.read_file_oneline('/sys/class/net/%s/address'
1419 def link_create(self
, ifacename
, t
, attrs
={}):
1420 """ generic link_create function """
1421 if self
.link_exists(ifacename
):
1424 cmd
+= ' name %s type %s' % (ifacename
, t
)
1426 for k
, v
in attrs
.iteritems():
1430 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1431 self
.add_to_batch(cmd
)
1433 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1434 self
._cache
_update
([ifacename
], {})
1436 def link_delete(self
, ifacename
):
1437 if not self
.link_exists(ifacename
):
1439 cmd
= 'link del %s' % ifacename
1440 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1441 self
.add_to_batch(cmd
)
1443 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1444 self
._cache
_invalidate
()
1446 def link_get_master(self
, ifacename
):
1447 sysfs_master_path
= '/sys/class/net/%s/master' % ifacename
1448 if os
.path
.exists(sysfs_master_path
):
1449 link_path
= os
.readlink(sysfs_master_path
)
1451 return os
.path
.basename(link_path
)
1455 return self
._cache
_get
('link', [ifacename
, 'master'])
1457 def get_brport_peer_link(self
, bridgename
):
1459 return self
._cache
_get
('link', [bridgename
, 'info_slave_data', Link
.IFLA_BRPORT_PEER_LINK
])
1464 def bridge_port_vids_add(bridgeportname
, vids
):
1465 [utils
.exec_command('%s vlan add vid %s dev %s' %
1467 v
, bridgeportname
)) for v
in vids
]
1470 def bridge_port_vids_del(bridgeportname
, vids
):
1473 [utils
.exec_command('%s vlan del vid %s dev %s' %
1475 v
, bridgeportname
)) for v
in vids
]
1478 def bridge_port_vids_flush(bridgeportname
, vid
):
1479 utils
.exec_command('%s vlan del vid %s dev %s' %
1481 vid
, bridgeportname
))
1484 def bridge_port_vids_get(bridgeportname
):
1485 bridgeout
= utils
.exec_command('%s vlan show dev %s' %
1490 brvlanlines
= bridgeout
.readlines()[2:]
1491 vids
= [l
.strip() for l
in brvlanlines
]
1492 return [v
for v
in vids
if v
]
1495 def bridge_port_vids_get_all():
1497 bridgeout
= utils
.exec_command('%s -c vlan show'
1501 brvlanlines
= bridgeout
.splitlines()
1503 for l
in brvlanlines
[1:]:
1504 if l
and not l
.startswith(' ') and not l
.startswith('\t'):
1506 brportname
= attrs
[0].strip()
1507 brvlaninfo
[brportname
] = {'pvid': None, 'vlan': []}
1508 l
= ' '.join(attrs
[1:])
1509 if not brportname
or not l
:
1513 brvlaninfo
[brportname
]['pvid'] = l
.split()[0]
1514 elif 'Egress Untagged' not in l
:
1515 brvlaninfo
[brportname
]['vlan'].append(l
)
1518 def bridge_port_vids_get_all_json(self
):
1519 if not self
.supported_command
['%s -c -json vlan show'
1520 % utils
.bridge_cmd
]:
1524 bridgeout
= utils
.exec_command('%s -c -json vlan show'
1527 self
.supported_command
['%s -c -json vlan show'
1528 % utils
.bridge_cmd
] = False
1529 self
.logger
.info('%s -c -json vlan show: skipping unsupported command'
1532 return self
.get_bridge_vlan_nojson()
1533 except Exception as e
:
1534 self
.logger
.info('bridge: get_bridge_vlan_nojson: %s' % str(e
))
1537 if not bridgeout
: return brvlaninfo
1539 vlan_json_dict
= json
.loads(bridgeout
, encoding
="utf-8")
1540 except Exception, e
:
1541 self
.logger
.info('json loads failed with (%s)' % str(e
))
1543 return vlan_json_dict
1546 def get_bridge_vlan_nojson():
1548 bridgeout
= utils
.exec_commandl([utils
.bridge_cmd
, '-c', 'vlan', 'show'])
1550 output
= [line
.split('\n') for line
in bridgeout
.split('\n\n')]
1551 output
[0] = output
[0][1:]
1559 prefix
, vlan
= entry
.split('\t')
1561 current_swp
= prefix
1562 vlan_json
[prefix
] = []
1566 v
['vlan'] = int(vlan
)
1570 start
, end
= vlan
.split('-')
1572 end
= end
[0:end
.index(' ')]
1573 v
['vlan'] = int(start
)
1574 v
['vlanEnd'] = int(end
)
1576 v
['vlan'] = int(vlan
[0:vlan
.index(' ')])
1579 flags
.append('PVID')
1580 if 'Egress Untagged' in vlan
:
1581 flags
.append('Egress Untagged')
1585 vlan_json
[current_swp
].append(v
)
1588 def bridge_vlan_cache_get(self
, ifacename
, refresh
=False):
1589 if not self
.bridge_vlan_cache_fill_done
or refresh
:
1590 self
.bridge_vlan_cache
= self
.bridge_port_vids_get_all_json()
1591 self
.bridge_vlan_cache_fill_done
= True
1592 return self
.bridge_vlan_cache
.get(ifacename
, {})
1594 def bridge_vlan_get_pvid(self
, ifacename
, refresh
=False):
1597 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1598 v
= vinfo
.get('vlan')
1599 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1604 def bridge_vlan_get_vids(self
, ifacename
, refresh
=False):
1607 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1608 v
= vinfo
.get('vlan')
1609 ispvid
= True if 'PVID' in vinfo
.get('flags', []) else False
1611 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1614 vEnd
= vinfo
.get('vlanEnd')
1616 vids
.extend(range(v
, vEnd
+ 1))
1621 def bridge_vlan_get_vids_n_pvid(self
, ifacename
, refresh
=False):
1625 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1626 v
= vinfo
.get('vlan')
1627 ispvid
= True if 'PVID' in vinfo
.get('flags', []) else False
1629 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1630 vEnd
= vinfo
.get('vlanEnd')
1632 vids
.extend(range(v
, vEnd
+ 1))
1637 def bridge_port_pvid_add(self
, bridgeportname
, pvid
):
1638 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1639 self
.add_to_batch('vlan add vid %s untagged pvid dev %s' %
1640 (pvid
, bridgeportname
))
1642 utils
.exec_command('%s vlan add vid %s untagged pvid dev %s' %
1644 pvid
, bridgeportname
))
1646 def bridge_port_pvid_del(self
, bridgeportname
, pvid
):
1647 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1648 self
.add_to_batch('vlan del vid %s untagged pvid dev %s' %
1649 (pvid
, bridgeportname
))
1651 utils
.exec_command('%s vlan del vid %s untagged pvid dev %s' %
1653 pvid
, bridgeportname
))
1655 def bridge_port_pvids_get(self
, bridgeportname
):
1656 return self
.read_file_oneline('/sys/class/net/%s/brport/pvid'
1659 def bridge_vids_add(self
, bridgeportname
, vids
, bridge
=True):
1660 target
= 'self' if bridge
else ''
1661 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1662 [self
.add_to_batch('vlan add vid %s dev %s %s' %
1663 (v
, bridgeportname
, target
)) for v
in vids
]
1665 [utils
.exec_command('%s vlan add vid %s dev %s %s' %
1667 v
, bridgeportname
, target
)) for v
in vids
]
1669 def bridge_vids_del(self
, bridgeportname
, vids
, bridge
=True):
1670 target
= 'self' if bridge
else ''
1671 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1672 [self
.add_to_batch('vlan del vid %s dev %s %s' %
1673 (v
, bridgeportname
, target
)) for v
in vids
]
1675 [utils
.exec_command('%s vlan del vid %s dev %s %s' %
1677 v
, bridgeportname
, target
)) for v
in vids
]
1680 def bridge_fdb_add(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1681 target
= 'self' if bridge
else ''
1684 vlan_str
= 'vlan %s ' % vlan
1688 dst_str
= 'dst %s ' % remote
1690 utils
.exec_command('%s fdb replace %s dev %s %s %s %s' %
1692 address
, dev
, vlan_str
, target
, dst_str
))
1695 def bridge_fdb_append(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1696 target
= 'self' if bridge
else ''
1699 vlan_str
= 'vlan %s ' % vlan
1703 dst_str
= 'dst %s ' % remote
1705 utils
.exec_command('%s fdb append %s dev %s %s %s %s' %
1707 address
, dev
, vlan_str
, target
, dst_str
))
1710 def bridge_fdb_del(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1711 target
= 'self' if bridge
else ''
1714 vlan_str
= 'vlan %s ' % vlan
1718 dst_str
= 'dst %s ' % remote
1719 utils
.exec_command('%s fdb del %s dev %s %s %s %s' %
1721 address
, dev
, vlan_str
, target
, dst_str
))
1723 def bridge_is_vlan_aware(self
, bridgename
):
1724 filename
= '/sys/class/net/%s/bridge/vlan_filtering' % bridgename
1725 if os
.path
.exists(filename
) and self
.read_file_oneline(filename
) == '1':
1730 def bridge_port_get_bridge_name(bridgeport
):
1731 filename
= '/sys/class/net/%s/brport/bridge' % bridgeport
1733 return os
.path
.basename(os
.readlink(filename
))
1738 def bridge_port_exists(bridge
, bridgeportname
):
1740 return os
.path
.exists('/sys/class/net/%s/brif/%s'
1741 % (bridge
, bridgeportname
))
1745 def bridge_fdb_show_dev(self
, dev
):
1748 output
= utils
.exec_command('%s fdb show dev %s'
1749 % (utils
.bridge_cmd
, dev
))
1751 for fdb_entry
in output
.splitlines():
1753 entries
= fdb_entry
.split()
1754 fdbs
.setdefault(entries
[2], []).append(entries
[0])
1756 self
.logger
.debug('%s: invalid fdb line \'%s\''
1763 def is_bridge(bridge
):
1764 return os
.path
.exists('/sys/class/net/%s/bridge' % bridge
)
1766 def is_link_up(self
, ifacename
):
1769 flags
= self
.read_file_oneline('/sys/class/net/%s/flags' % ifacename
)
1770 iflags
= int(flags
, 16)
1777 def ip_route_get_dev(self
, prefix
, vrf_master
=None):
1780 cmd
= '%s route get %s vrf %s' % (utils
.ip_cmd
, prefix
, vrf_master
)
1782 cmd
= '%s route get %s' % (utils
.ip_cmd
, prefix
)
1784 output
= utils
.exec_command(cmd
)
1786 rline
= output
.splitlines()[0]
1788 rattrs
= rline
.split()
1789 return rattrs
[rattrs
.index('dev') + 1]
1790 except Exception, e
:
1791 self
.logger
.debug('ip_route_get_dev: failed .. %s' % str(e
))
1795 def link_get_lowers(ifacename
):
1797 lowers
= glob
.glob("/sys/class/net/%s/lower_*" % ifacename
)
1800 return [os
.path
.basename(l
)[6:] for l
in lowers
]
1805 def link_get_uppers(ifacename
):
1807 uppers
= glob
.glob("/sys/class/net/%s/upper_*" % ifacename
)
1810 return [os
.path
.basename(u
)[6:] for u
in uppers
]
1814 def link_get_vrfs(self
):
1815 if not LinkUtils
._CACHE
_FILL
_DONE
:
1817 return linkCache
.vrfs
1820 def cache_get_info_slave(attrlist
):
1822 return linkCache
.get_attr(attrlist
)
1826 def get_brport_learning(self
, ifacename
):
1827 learn
= self
.read_file_oneline('/sys/class/net/%s/brport/learning'
1829 if learn
and learn
== '1':
1834 def get_brport_learning_bool(self
, ifacename
):
1835 return utils
.get_boolean_from_string(self
.read_file_oneline('/sys/class/net/%s/brport/learning' % ifacename
))
1837 def set_brport_learning(self
, ifacename
, learn
):
1839 return self
.write_file('/sys/class/net/%s/brport/learning'
1842 return self
.write_file('/sys/class/net/%s/brport/learning'
1845 #################################################################################
1846 ################################### BOND UTILS ##################################
1847 #################################################################################
1849 def _link_cache_get(self
, attrlist
, refresh
=False):
1850 return self
._cache
_get
('link', attrlist
, refresh
)
1852 def cache_delete(self
, attrlist
, value
=None):
1853 return self
._cache
_delete
(attrlist
, value
)
1855 def link_cache_get(self
, attrlist
, refresh
=False):
1856 return self
._link
_cache
_get
(attrlist
, refresh
)
1858 def link_cache_check(self
, attrlist
, value
, refresh
=False):
1859 return self
._link
_cache
_check
(attrlist
, value
, refresh
)
1861 def _link_cache_check(self
, attrlist
, value
, refresh
=False):
1863 return self
._link
_cache
_get
(attrlist
, refresh
) == value
1864 except Exception, e
:
1865 self
.logger
.debug('_cache_check(%s) : [%s]'
1866 % (str(attrlist
), str(e
)))
1871 Link
.IFLA_BOND_MODE
: 'mode',
1872 Link
.IFLA_BOND_MIIMON
: 'miimon',
1873 Link
.IFLA_BOND_USE_CARRIER
: 'use_carrier',
1874 Link
.IFLA_BOND_AD_LACP_RATE
: 'lacp_rate',
1875 Link
.IFLA_BOND_XMIT_HASH_POLICY
: 'xmit_hash_policy',
1876 Link
.IFLA_BOND_MIN_LINKS
: 'min_links',
1877 Link
.IFLA_BOND_NUM_PEER_NOTIF
: 'num_grat_arp',
1878 Link
.IFLA_BOND_AD_ACTOR_SYSTEM
: 'ad_actor_system',
1879 Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
: 'ad_actor_sys_prio',
1880 Link
.IFLA_BOND_AD_LACP_BYPASS
: 'lacp_bypass',
1881 Link
.IFLA_BOND_UPDELAY
: 'updelay',
1882 Link
.IFLA_BOND_DOWNDELAY
: 'downdelay',
1885 def bond_set_attrs_nl(self
, bondname
, ifla_info_data
):
1886 bond_attr_name
= 'None' # for log purpose (in case an exception raised)
1887 for nl_attr
, value
in ifla_info_data
.items():
1889 bond_attr_name
= self
.bondcmd_attrmap
[nl_attr
]
1890 file_path
= '/sys/class/net/%s/bonding/%s' % (bondname
, bond_attr_name
)
1891 if os
.path
.exists(file_path
):
1892 self
.write_file(file_path
, str(value
))
1893 except Exception as e
:
1894 exception_str
= '%s: %s %s: %s' % (bondname
, bond_attr_name
, value
, str(e
))
1895 if ifupdownflags
.flags
.FORCE
:
1896 self
.logger
.warning(exception_str
)
1898 self
.logger
.debug(exception_str
)
1900 def bond_set_attrs(self
, bondname
, attrdict
, prehook
):
1901 for attrname
, attrval
in attrdict
.items():
1902 if (self
._link
_cache
_check
([bondname
, 'linkinfo',
1903 attrname
], attrval
)):
1905 if (attrname
== 'mode'
1906 or attrname
== 'xmit_hash_policy'
1907 or attrname
== 'lacp_rate' or attrname
== 'min_links'):
1911 if ((attrname
not in ['lacp_rate',
1913 self
._link
_cache
_check
([bondname
, 'linkinfo', 'mode'], '802.3ad',
1915 self
.write_file('/sys/class/net/%s/bonding/%s'
1916 % (bondname
, attrname
), attrval
)
1917 except Exception, e
:
1918 if ifupdownflags
.flags
.FORCE
:
1919 self
.logger
.warn(str(e
))
1924 def bond_set_use_carrier(self
, bondname
, use_carrier
):
1925 if not use_carrier
or (use_carrier
!= '0' and use_carrier
!= '1'):
1927 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'use_carrier'],
1930 self
.write_file('/sys/class/net/%s' % bondname
+
1931 '/bonding/use_carrier', use_carrier
)
1932 self
._cache
_update
([bondname
, 'linkinfo',
1933 'use_carrier'], use_carrier
)
1935 def bond_get_use_carrier(self
, bondname
):
1936 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'use_carrier'])
1938 def bond_get_use_carrier_nl(self
, bondname
):
1939 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_USE_CARRIER
])
1941 def bond_set_xmit_hash_policy(self
, bondname
, hash_policy
, prehook
=None):
1942 valid_values
= ['layer2', 'layer3+4', 'layer2+3']
1945 if hash_policy
not in valid_values
:
1946 raise Exception('invalid hash policy value %s' % hash_policy
)
1947 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'xmit_hash_policy'],
1952 self
.write_file('/sys/class/net/%s' % bondname
+
1953 '/bonding/xmit_hash_policy', hash_policy
)
1954 self
._cache
_update
([bondname
, 'linkinfo', 'xmit_hash_policy'],
1957 def bond_get_xmit_hash_policy(self
, bondname
):
1958 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'xmit_hash_policy'])
1960 def bond_get_xmit_hash_policy_nl(self
, bondname
):
1961 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_XMIT_HASH_POLICY
])
1963 def bond_set_miimon(self
, bondname
, miimon
):
1964 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'miimon'],
1967 self
.write_file('/sys/class/net/%s' % bondname
+
1968 '/bonding/miimon', miimon
)
1969 self
._cache
_update
([bondname
, 'linkinfo', 'miimon'], miimon
)
1971 def bond_get_miimon(self
, bondname
):
1972 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'miimon'])
1974 def bond_get_miimon_nl(self
, bondname
):
1975 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MIIMON
])
1977 def bond_set_mode(self
, bondname
, mode
, prehook
=None):
1978 valid_modes
= ['balance-rr', 'active-backup', 'balance-xor',
1979 'broadcast', '802.3ad', 'balance-tlb', 'balance-alb']
1982 if mode
not in valid_modes
:
1983 raise Exception('invalid mode %s' % mode
)
1984 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'mode'],
1989 self
.write_file('/sys/class/net/%s' % bondname
+ '/bonding/mode', mode
)
1990 self
._cache
_update
([bondname
, 'linkinfo', 'mode'], mode
)
1992 def bond_get_mode(self
, bondname
):
1993 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'mode'])
1995 def bond_get_mode_nl(self
, bondname
):
1996 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MODE
])
1998 def bond_set_lacp_rate(self
, bondname
, lacp_rate
, prehook
=None, posthook
=None):
1999 if not lacp_rate
or (lacp_rate
!= '0' and lacp_rate
!= '1'):
2001 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'lacp_rate'],
2007 self
.write_file('/sys/class/net/%s' % bondname
+
2008 '/bonding/lacp_rate', lacp_rate
)
2014 self
._cache
_update
([bondname
, 'linkinfo',
2015 'lacp_rate'], lacp_rate
)
2017 def bond_get_lacp_rate(self
, bondname
):
2018 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'lacp_rate'])
2020 def bond_get_lacp_rate_nl(self
, bondname
):
2021 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_RATE
])
2023 def bond_set_lacp_bypass_allow(self
, bondname
, allow
, prehook
=None, posthook
=None):
2024 if self
._link
_cache
_check
([bondname
, 'linkinfo', 'lacp_bypass'], allow
):
2029 self
.write_file('/sys/class/net/%s' % bondname
+
2030 '/bonding/lacp_bypass', allow
)
2036 self
._cache
_update
([bondname
, 'linkinfo',
2037 'lacp_bypass'], allow
)
2039 def bond_get_lacp_bypass_allow(self
, bondname
):
2040 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'lacp_bypass'])
2042 def bond_get_lacp_bypass_allow_nl(self
, bondname
):
2043 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_BYPASS
])
2045 def bond_set_min_links(self
, bondname
, min_links
, prehook
=None):
2046 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'min_links'],
2051 self
.write_file('/sys/class/net/%s/bonding/min_links' % bondname
,
2053 self
._cache
_update
([bondname
, 'linkinfo', 'min_links'], min_links
)
2055 def bond_get_min_links(self
, bondname
):
2056 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'min_links'])
2058 def get_min_links_nl(self
, bondname
):
2059 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MIN_LINKS
])
2061 def bond_get_ad_actor_system(self
, bondname
):
2062 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'ad_actor_system'])
2064 def bond_get_ad_actor_system_nl(self
, bondname
):
2065 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYSTEM
])
2067 def bond_get_ad_actor_sys_prio(self
, bondname
):
2068 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'ad_actor_sys_prio'])
2070 def bond_get_ad_actor_sys_prio_nl(self
, bondname
):
2071 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
])
2073 def bond_get_num_unsol_na(self
, bondname
):
2074 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'num_unsol_na'])
2076 def bond_get_num_unsol_na_nl(self
, bondname
):
2077 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
])
2079 def bond_get_num_grat_arp(self
, bondname
):
2080 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'num_grat_arp'])
2082 def bond_get_num_grat_arp_nl(self
, bondname
):
2083 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
])
2085 def bond_get_updelay(self
, bondname
):
2086 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'updelay'])
2088 def bond_get_updelay_nl(self
, bondname
):
2089 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_UPDELAY
])
2091 def bond_get_downdelay(self
, bondname
):
2092 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'downdelay'])
2094 def bond_get_downdelay_nl(self
, bondname
):
2095 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_DOWNDELAY
])
2097 def bond_enslave_slave(self
, bondname
, slave
, prehook
=None, posthook
=None):
2098 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2099 if slaves
and slave
in slaves
:
2103 self
.write_file('/sys/class/net/%s' % bondname
+
2104 '/bonding/slaves', '+' + slave
)
2107 self
._cache
_update
([bondname
, 'linkinfo', 'slaves'], slave
)
2109 def bond_remove_slave(self
, bondname
, slave
):
2110 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2111 if not slaves
or slave
not in slaves
:
2113 sysfs_bond_path
= ('/sys/class/net/%s' % bondname
+
2115 if not os
.path
.exists(sysfs_bond_path
):
2117 self
.write_file(sysfs_bond_path
, '-' + slave
)
2118 self
._cache
_delete
([bondname
, 'linkinfo', 'slaves'], slave
)
2120 def bond_remove_slaves_all(self
, bondname
):
2121 if not self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves']):
2124 sysfs_bond_path
= ('/sys/class/net/%s' % bondname
+
2127 with
open(sysfs_bond_path
, 'r') as f
:
2128 slaves
= f
.readline().strip().split()
2130 raise Exception('error reading slaves of bond %s (%s)' % (bondname
, str(e
)))
2131 for slave
in slaves
:
2132 self
.link_down(slave
)
2134 self
.bond_remove_slave(bondname
, slave
)
2135 except Exception, e
:
2136 if not ifupdownflags
.flags
.FORCE
:
2137 raise Exception('error removing slave %s from bond %s (%s)' % (slave
, bondname
, str(e
)))
2140 self
._cache
_delete
([bondname
, 'linkinfo', 'slaves'])
2143 def bond_load_bonding_module():
2144 return utils
.exec_command('%s -q bonding' % utils
.modprobe_cmd
)
2146 def create_bond(self
, bondname
):
2147 if self
.bond_exists(bondname
):
2149 # load_bonding_module() has already been run
2150 self
.write_file('/sys/class/net/bonding_masters', '+' + bondname
)
2151 self
._cache
_update
([bondname
], {})
2153 def delete_bond(self
, bondname
):
2154 if not os
.path
.exists('/sys/class/net/%s' % bondname
):
2156 self
.write_file('/sys/class/net/bonding_masters', '-' + bondname
)
2157 self
._cache
_delete
([bondname
])
2159 def bond_get_slaves(self
, bondname
):
2160 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2163 slavefile
= '/sys/class/net/%s/bonding/slaves' % bondname
2164 if os
.path
.exists(slavefile
):
2165 buf
= self
.read_file_oneline(slavefile
)
2167 slaves
= buf
.split()
2170 self
._cache
_update
([bondname
, 'linkinfo', 'slaves'], slaves
)
2173 def bond_slave_exists(self
, bond
, slave
):
2174 slaves
= self
.bond_get_slaves(bond
)
2177 return slave
in slaves
2180 def bond_exists(bondname
):
2181 return os
.path
.exists('/sys/class/net/%s/bonding' % bondname
)
2183 #################################################################################
2184 ################################## BRIDGE UTILS #################################
2185 #################################################################################
2187 def create_bridge(self
, bridgename
):
2188 if not LinkUtils
.bridge_utils_is_installed
:
2190 if self
.bridge_exists(bridgename
):
2192 utils
.exec_command('%s addbr %s' % (utils
.brctl_cmd
, bridgename
))
2193 self
._cache
_update
([bridgename
], {})
2195 def delete_bridge(self
, bridgename
):
2196 if not LinkUtils
.bridge_utils_is_installed
:
2198 if not self
.bridge_exists(bridgename
):
2200 utils
.exec_command('%s delbr %s' % (utils
.brctl_cmd
, bridgename
))
2201 self
._cache
_invalidate
()
2203 def add_bridge_port(self
, bridgename
, bridgeportname
):
2204 """ Add port to bridge """
2205 if not LinkUtils
.bridge_utils_is_installed
:
2207 ports
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports'])
2208 if ports
and ports
.get(bridgeportname
):
2210 utils
.exec_command('%s addif %s %s' % (utils
.brctl_cmd
, bridgename
, bridgeportname
))
2211 self
._cache
_update
([bridgename
, 'linkinfo', 'ports', bridgeportname
], {})
2213 def delete_bridge_port(self
, bridgename
, bridgeportname
):
2214 """ Delete port from bridge """
2215 if not LinkUtils
.bridge_utils_is_installed
:
2217 ports
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports'])
2218 if not ports
or not ports
.get(bridgeportname
):
2220 utils
.exec_command('%s delif %s %s' % (utils
.brctl_cmd
, bridgename
, bridgeportname
))
2221 self
._cache
_delete
([bridgename
, 'linkinfo', 'ports', 'bridgeportname'])
2223 def set_bridgeport_attrs(self
, bridgename
, bridgeportname
, attrdict
):
2224 portattrs
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports', bridgeportname
])
2225 if portattrs
== None:
2227 for k
, v
in attrdict
.iteritems():
2228 if ifupdownflags
.flags
.CACHE
:
2229 curval
= portattrs
.get(k
)
2230 if curval
and curval
== v
:
2232 if k
== 'unicast-flood':
2233 self
.write_file('/sys/class/net/%s/brport/unicast_flood' % bridgeportname
, v
)
2234 elif k
== 'multicast-flood':
2235 self
.write_file('/sys/class/net/%s/brport/multicast_flood' % bridgeportname
, v
)
2236 elif k
== 'learning':
2237 self
.write_file('/sys/class/net/%s/brport/learning' % bridgeportname
, v
)
2238 elif k
== 'arp-nd-suppress':
2239 self
.write_file('/sys/class/net/%s/brport/neigh_suppress' % bridgeportname
, v
)
2241 if not LinkUtils
.bridge_utils_is_installed
:
2243 utils
.exec_command('%s set%s %s %s %s' % (utils
.brctl_cmd
, k
, bridgename
, bridgeportname
, v
))
2245 def set_bridgeport_attr(self
, bridgename
, bridgeportname
,
2247 if not LinkUtils
.bridge_utils_is_installed
:
2249 if self
._link
_cache
_check
([bridgename
, 'linkinfo', 'ports', bridgeportname
, attrname
], attrval
):
2251 utils
.exec_command('%s set%s %s %s %s' %
2258 def set_bridge_attrs(self
, bridgename
, attrdict
):
2259 for k
, v
in attrdict
.iteritems():
2262 if self
._link
_cache
_check
([bridgename
, 'linkinfo', k
], v
):
2265 if k
== 'igmp-version':
2266 self
.write_file('/sys/class/net/%s/bridge/'
2267 'multicast_igmp_version' % bridgename
, v
)
2268 elif k
== 'mld-version':
2269 self
.write_file('/sys/class/net/%s/bridge/'
2270 'multicast_mld_version' % bridgename
, v
)
2271 elif k
== 'vlan-protocol':
2272 self
.write_file('/sys/class/net/%s/bridge/'
2273 'vlan_protocol' % bridgename
,
2274 VlanProtocols
.ETHERTYPES_TO_ID
.get(v
.upper(),
2276 elif k
== 'vlan-stats':
2277 self
.write_file('/sys/class/net/%s/bridge/'
2278 'vlan_stats_enabled' % bridgename
, v
)
2279 elif k
== 'mcstats':
2280 self
.write_file('/sys/class/net/%s/bridge/'
2281 'multicast_stats_enabled' % bridgename
, v
)
2283 if not LinkUtils
.bridge_utils_is_installed
:
2285 cmd
= ('%s set%s %s %s' %
2286 (utils
.brctl_cmd
, k
, bridgename
, v
))
2287 utils
.exec_command(cmd
)
2288 except Exception, e
:
2289 self
.logger
.warn('%s: %s' % (bridgename
, str(e
)))
2292 def set_bridge_attr(self
, bridgename
, attrname
, attrval
):
2293 if self
._link
_cache
_check
([bridgename
, 'linkinfo', attrname
], attrval
):
2295 if attrname
== 'igmp-version':
2296 self
.write_file('/sys/class/net/%s/bridge/multicast_igmp_version'
2297 % bridgename
, attrval
)
2298 elif attrname
== 'mld-version':
2299 self
.write_file('/sys/class/net/%s/bridge/multicast_mld_version'
2300 % bridgename
, attrval
)
2301 elif attrname
== 'vlan-protocol':
2302 self
.write_file('/sys/class/net/%s/bridge/vlan_protocol'
2303 % bridgename
, VlanProtocols
.ETHERTYPES_TO_ID
[attrval
.upper()])
2304 elif attrname
== 'vlan-stats':
2305 self
.write_file('/sys/class/net/%s/bridge/vlan_stats_enabled'
2306 % bridgename
, attrval
)
2307 elif attrname
== 'mcstats':
2308 self
.write_file('/sys/class/net/%s/bridge/multicast_stats_enabled'
2309 % bridgename
, attrval
)
2311 if not LinkUtils
.bridge_utils_is_installed
:
2313 cmd
= '%s set%s %s %s' % (utils
.brctl_cmd
,
2314 attrname
, bridgename
, attrval
)
2315 utils
.exec_command(cmd
)
2317 def get_bridge_attrs(self
, bridgename
):
2318 attrs
= self
._link
_cache
_get
([bridgename
, 'linkinfo'])
2320 for key
, value
in attrs
.items():
2321 if type(key
) == str:
2322 no_ints_attrs
[key
] = value
2323 return no_ints_attrs
2325 def get_bridgeport_attrs(self
, bridgename
, bridgeportname
):
2326 return self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports',
2329 def get_bridgeport_attr(self
, bridgename
, bridgeportname
, attrname
):
2330 return self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports',
2331 bridgeportname
, attrname
])
2334 def bridge_set_stp(bridge
, stp_state
):
2335 if not LinkUtils
.bridge_utils_is_installed
:
2337 utils
.exec_command('%s stp %s %s' % (utils
.brctl_cmd
, bridge
, stp_state
))
2339 def bridge_get_stp(self
, bridge
):
2340 sysfs_stpstate
= '/sys/class/net/%s/bridge/stp_state' % bridge
2341 if not os
.path
.exists(sysfs_stpstate
):
2343 stpstate
= self
.read_file_oneline(sysfs_stpstate
)
2347 if int(stpstate
) > 0:
2349 elif int(stpstate
) == 0:
2355 def _conv_value_to_user(s
):
2362 def read_value_from_sysfs(self
, filename
, preprocess_func
):
2363 value
= self
.read_file_oneline(filename
)
2366 return preprocess_func(value
)
2369 def bridge_set_ageing(bridge
, ageing
):
2370 if not LinkUtils
.bridge_utils_is_installed
:
2372 utils
.exec_command('%s setageing %s %s' % (utils
.brctl_cmd
, bridge
, ageing
))
2374 def bridge_get_ageing(self
, bridge
):
2375 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/ageing_time'
2376 % bridge
, self
._conv
_value
_to
_user
)
2379 def set_bridgeprio(bridge
, prio
):
2380 if not LinkUtils
.bridge_utils_is_installed
:
2382 utils
.exec_command('%s setbridgeprio %s %s' % (utils
.brctl_cmd
, bridge
, prio
))
2384 def get_bridgeprio(self
, bridge
):
2385 return self
.read_file_oneline(
2386 '/sys/class/net/%s/bridge/priority' % bridge
)
2389 def bridge_set_fd(bridge
, fd
):
2390 if not LinkUtils
.bridge_utils_is_installed
:
2392 utils
.exec_command('%s setfd %s %s' % (utils
.brctl_cmd
, bridge
, fd
))
2394 def bridge_get_fd(self
, bridge
):
2395 return self
.read_value_from_sysfs(
2396 '/sys/class/net/%s/bridge/forward_delay'
2397 % bridge
, self
._conv
_value
_to
_user
)
2399 def bridge_set_gcint(self
, bridge
, gcint
):
2400 raise Exception('set_gcint not implemented')
2403 def bridge_set_hello(bridge
, hello
):
2404 if not LinkUtils
.bridge_utils_is_installed
:
2406 utils
.exec_command('%s sethello %s %s' % (utils
.brctl_cmd
, bridge
, hello
))
2408 def bridge_get_hello(self
, bridge
):
2409 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/hello_time'
2410 % bridge
, self
._conv
_value
_to
_user
)
2413 def bridge_set_maxage(bridge
, maxage
):
2414 if not LinkUtils
.bridge_utils_is_installed
:
2416 utils
.exec_command('%s setmaxage %s %s' % (utils
.brctl_cmd
, bridge
, maxage
))
2418 def bridge_get_maxage(self
, bridge
):
2419 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/max_age'
2420 % bridge
, self
._conv
_value
_to
_user
)
2423 def bridge_set_pathcost(bridge
, port
, pathcost
):
2424 if not LinkUtils
.bridge_utils_is_installed
:
2426 utils
.exec_command('%s setpathcost %s %s %s' % (utils
.brctl_cmd
, bridge
, port
, pathcost
))
2428 def bridge_get_pathcost(self
, bridge
, port
):
2429 return self
.read_file_oneline('/sys/class/net/%s/brport/path_cost'
2433 def bridge_set_portprio(bridge
, port
, prio
):
2434 if not LinkUtils
.bridge_utils_is_installed
:
2436 utils
.exec_command('%s setportprio %s %s %s' % (utils
.brctl_cmd
, bridge
, port
, prio
))
2438 def bridge_get_portprio(self
, bridge
, port
):
2439 return self
.read_file_oneline('/sys/class/net/%s/brport/priority'
2443 def bridge_set_hashmax(bridge
, hashmax
):
2444 if not LinkUtils
.bridge_utils_is_installed
:
2446 utils
.exec_command('%s sethashmax %s %s' % (utils
.brctl_cmd
, bridge
, hashmax
))
2448 def bridge_get_hashmax(self
, bridge
):
2449 return self
.read_file_oneline('/sys/class/net/%s/bridge/hash_max'
2453 def bridge_set_hashel(bridge
, hashel
):
2454 if not LinkUtils
.bridge_utils_is_installed
:
2456 utils
.exec_command('%s sethashel %s %s' % (utils
.brctl_cmd
, bridge
, hashel
))
2458 def bridge_get_hashel(self
, bridge
):
2459 return self
.read_file_oneline('/sys/class/net/%s/bridge/hash_elasticity'
2463 def bridge_set_mclmc(bridge
, mclmc
):
2464 if not LinkUtils
.bridge_utils_is_installed
:
2466 utils
.exec_command('%s setmclmc %s %s' % (utils
.brctl_cmd
, bridge
, mclmc
))
2468 def bridge_get_mclmc(self
, bridge
):
2469 return self
.read_file_oneline(
2470 '/sys/class/net/%s/bridge/multicast_last_member_count'
2474 def bridge_set_mcrouter(bridge
, mcrouter
):
2475 if not LinkUtils
.bridge_utils_is_installed
:
2477 utils
.exec_command('%s setmcrouter %s %s' % (utils
.brctl_cmd
, bridge
, mcrouter
))
2479 def bridge_get_mcrouter(self
, bridge
):
2480 return self
.read_file_oneline(
2481 '/sys/class/net/%s/bridge/multicast_router' % bridge
)
2484 def bridge_set_mcsnoop(bridge
, mcsnoop
):
2485 if not LinkUtils
.bridge_utils_is_installed
:
2487 utils
.exec_command('%s setmcsnoop %s %s' % (utils
.brctl_cmd
, bridge
, mcsnoop
))
2489 def bridge_get_mcsnoop(self
, bridge
):
2490 return self
.read_file_oneline(
2491 '/sys/class/net/%s/bridge/multicast_snooping' % bridge
)
2494 def bridge_set_mcsqc(bridge
, mcsqc
):
2495 if not LinkUtils
.bridge_utils_is_installed
:
2497 utils
.exec_command('%s setmcsqc %s %s' % (utils
.brctl_cmd
, bridge
, mcsqc
))
2499 def bridge_get_mcsqc(self
, bridge
):
2500 return self
.read_file_oneline(
2501 '/sys/class/net/%s/bridge/multicast_startup_query_count'
2505 def bridge_set_mcqifaddr(bridge
, mcqifaddr
):
2506 if not LinkUtils
.bridge_utils_is_installed
:
2508 utils
.exec_command('%s setmcqifaddr %s %s' % (utils
.brctl_cmd
, bridge
, mcqifaddr
))
2510 def bridge_get_mcqifaddr(self
, bridge
):
2511 return self
.read_file_oneline(
2512 '/sys/class/net/%s/bridge/multicast_startup_query_use_ifaddr'
2516 def bridge_set_mcquerier(bridge
, mcquerier
):
2517 if not LinkUtils
.bridge_utils_is_installed
:
2519 utils
.exec_command('%s setmcquerier %s %s' % (utils
.brctl_cmd
, bridge
, mcquerier
))
2521 def bridge_get_mcquerier(self
, bridge
):
2522 return self
.read_file_oneline(
2523 '/sys/class/net/%s/bridge/multicast_querier' % bridge
)
2525 def bridge_set_mcqv4src(self
, bridge
, vlan
, mcquerier
):
2529 self
.logger
.info('%s: set mcqv4src vlan: invalid parameter %s: %s' %(bridge
, vlan
, str(e
)))
2531 if vlan
== 0 or vlan
> 4095:
2532 self
.logger
.warn('mcqv4src vlan \'%d\' invalid range' % vlan
)
2535 ip
= mcquerier
.split('.')
2537 self
.logger
.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier
)
2540 if not k
.isdigit() or int(k
, 10) < 0 or int(k
, 10) > 255:
2541 self
.logger
.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier
)
2544 if not LinkUtils
.bridge_utils_is_installed
:
2547 utils
.exec_command('%s setmcqv4src %s %d %s' %
2548 (utils
.brctl_cmd
, bridge
, vlan
, mcquerier
))
2550 def bridge_del_mcqv4src(self
, bridge
, vlan
):
2551 if not LinkUtils
.bridge_utils_is_installed
:
2556 self
.logger
.info('%s: del mcqv4src vlan: invalid parameter %s: %s' %(bridge
, vlan
, str(e
)))
2558 utils
.exec_command('%s delmcqv4src %s %d' % (utils
.brctl_cmd
, bridge
, vlan
))
2560 def bridge_get_mcqv4src(self
, bridge
, vlan
=None):
2561 if not LinkUtils
.bridge_utils_is_installed
:
2563 if not self
.supported_command
['showmcqv4src']:
2567 mcqout
= utils
.exec_command('%s showmcqv4src %s' %
2568 (utils
.brctl_cmd
, bridge
))
2569 except Exception as e
:
2571 if 'never heard' in s
:
2572 msg
= ('%s showmcqv4src: skipping unsupported command'
2574 self
.logger
.info(msg
)
2575 self
.supported_command
['showmcqv4src'] = False
2580 mcqlines
= mcqout
.splitlines()
2581 for l
in mcqlines
[1:]:
2583 k
, d
, v
= l
.split('\t')
2588 return mcqv4src
.get(vlan
)
2592 def bridge_set_mclmi(bridge
, mclmi
):
2593 if not LinkUtils
.bridge_utils_is_installed
:
2595 utils
.exec_command('%s setmclmi %s %s' % (utils
.brctl_cmd
, bridge
, mclmi
))
2597 def bridge_get_mclmi(self
, bridge
):
2598 return self
.read_file_oneline(
2599 '/sys/class/net/%s/bridge/multicast_last_member_interval'
2603 def bridge_set_mcmi(bridge
, mcmi
):
2604 if not LinkUtils
.bridge_utils_is_installed
:
2606 utils
.exec_command('%s setmcmi %s %s' % (utils
.brctl_cmd
, bridge
, mcmi
))
2608 def bridge_get_mcmi(self
, bridge
):
2609 return self
.read_file_oneline(
2610 '/sys/class/net/%s/bridge/multicast_membership_interval'
2614 def bridge_exists(bridge
):
2615 return os
.path
.exists('/sys/class/net/%s/bridge' % bridge
)
2618 def is_bridge_port(ifacename
):
2619 return os
.path
.exists('/sys/class/net/%s/brport' % ifacename
)
2622 def bridge_port_exists(bridge
, bridgeportname
):
2624 return os
.path
.exists('/sys/class/net/%s/brif/%s' % (bridge
, bridgeportname
))
2629 def get_bridge_ports(bridgename
):
2631 return os
.listdir('/sys/class/net/%s/brif/' % bridgename
)
2635 def ipv6_addrgen(self
, ifname
, addrgen
):
2636 cmd
= 'link set dev %s addrgenmode %s' % (ifname
, 'eui64' if addrgen
else 'none')
2638 is_link_up
= self
.is_link_up(ifname
)
2641 self
.link_down(ifname
)
2643 if LinkUtils
.ipbatch
:
2644 self
.add_to_batch(cmd
)
2646 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
2649 self
.link_up(ifname
)