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
] == 'vlan':
532 vlanid
= self
._get
_vland
_id
(citems
, i
, warn
)
534 linkattrs
['linkinfo'] = {'vlanid': vlanid
}
535 linkattrs
['kind'] = 'vlan'
536 elif citems
[i
] == 'dummy':
537 linkattrs
['kind'] = 'dummy'
538 elif citems
[i
] == 'vxlan' and citems
[i
+ 1] == 'id':
539 linkattrs
['kind'] = 'vxlan'
540 vattrs
= {'vxlanid': citems
[i
+ 2],
543 'ageing': citems
[i
+ 2],
545 for j
in range(i
+ 2, len(citems
)):
546 if citems
[j
] == 'local':
547 vattrs
['local'] = citems
[j
+ 1]
548 elif citems
[j
] == 'remote':
549 vattrs
['svcnode'] = citems
[j
+ 1]
550 elif citems
[j
] == 'ageing':
551 vattrs
['ageing'] = citems
[j
+ 1]
552 elif citems
[j
] == 'nolearning':
553 vattrs
['learning'] = 'off'
554 elif citems
[j
] == 'dev':
555 vattrs
['physdev'] = citems
[j
+ 1]
556 linkattrs
['linkinfo'] = vattrs
558 elif citems
[i
] == 'vrf' and citems
[i
+ 1] == 'table':
559 vattrs
= {'table': citems
[i
+ 2]}
560 linkattrs
['linkinfo'] = vattrs
561 linkattrs
['kind'] = 'vrf'
562 linkCache
.vrfs
[ifname
] = vattrs
564 elif citems
[i
] == 'veth':
565 linkattrs
['kind'] = 'veth'
566 elif citems
[i
] == 'vrf_slave':
567 linkattrs
['slave_kind'] = 'vrf_slave'
569 elif citems
[i
] == 'macvlan' and citems
[i
+ 1] == 'mode':
570 linkattrs
['kind'] = 'macvlan'
571 except Exception as e
:
573 self
.logger
.debug('%s: parsing error: id, mtu, state, '
574 'link/ether, vlan, dummy, vxlan, local, '
575 'remote, ageing, nolearning, vrf, table, '
576 'vrf_slave are reserved keywords: %s' %
579 # linkattrs['alias'] = self.read_file_oneline(
580 # '/sys/class/net/%s/ifalias' %ifname)
581 linkout
[ifname
] = linkattrs
582 [linkCache
.update_attrdict([ifname
], linkattrs
)
583 for ifname
, linkattrs
in linkout
.items()]
586 def _addr_filter(ifname
, addr
, scope
=None):
587 default_addrs
= ['127.0.0.1/8', '::1/128', '0.0.0.0']
588 if ifname
== 'lo' and addr
in default_addrs
:
590 if scope
and scope
== 'link':
594 def _addr_fill(self
, ifacename
=None, refresh
=False):
595 """ fills cache with address information
597 if ifacename argument given, fill cache for ifacename, else
598 fill cache for all interfaces in the system
600 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
603 # Check if ifacename is already full, in which case, return
604 if ifacename
and not refresh
:
605 linkCache
.get_attr([ifacename
, 'addrs'])
612 [linkCache
.update_attrdict([ifname
], linkattrs
)
613 for ifname
, linkattrs
in netlink
.addr_dump(ifname
=ifacename
).items()]
614 except Exception as e
:
615 self
.logger
.info(str(e
))
617 # this netlink call replaces the call to _addr_fill_iproute2_cmd()
618 # We shouldn't have netlink calls in the iproute2 module, this will
619 # be removed in the future. We plan to release, a flexible backend
620 # (netlink+iproute2) by default we will use netlink backend but with
621 # a CLI arg we can switch to iproute2 backend.
622 # Until we decide to create this "backend" switch capability,
623 # we have to put the netlink call inside the iproute2 module.
626 self
._addr
_fill
_iproute
2_cmd
(ifacename
, refresh
)
628 def _addr_fill_iproute2_cmd(self
, ifacename
=None, refresh
=False):
629 """ fills cache with address information
631 if ifacename argument given, fill cache for ifacename, else
632 fill cache for all interfaces in the system
635 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
638 # Check if ifacename is already full, in which case, return
639 if ifacename
and not refresh
:
640 linkCache
.get_attr([ifacename
, 'addrs'])
644 cmdout
= self
.addr_show(ifacename
=ifacename
)
647 for c
in cmdout
.splitlines():
649 ifnamenlink
= citems
[1].split('@')
650 if len(ifnamenlink
) > 1:
651 ifname
= ifnamenlink
[0]
653 ifname
= ifnamenlink
[0].strip(':')
654 if not linkout
.get(ifname
):
656 linkattrs
['addrs'] = OrderedDict({})
658 linkout
[ifname
].update(linkattrs
)
660 linkout
[ifname
] = linkattrs
661 if citems
[2] == 'inet':
662 if self
._addr
_filter
(ifname
, citems
[3], scope
=citems
[5]):
665 addrattrs
['scope'] = citems
[5]
666 addrattrs
['type'] = 'inet'
667 linkout
[ifname
]['addrs'][citems
[3]] = addrattrs
668 elif citems
[2] == 'inet6':
669 if self
._addr
_filter
(ifname
, citems
[3], scope
=citems
[5]):
671 if citems
[5] == 'link':
672 continue # skip 'link' addresses
674 addrattrs
['scope'] = citems
[5]
675 addrattrs
['type'] = 'inet6'
676 linkout
[ifname
]['addrs'][citems
[3]] = addrattrs
677 [linkCache
.update_attrdict([ifname
], linkattrs
)
678 for ifname
, linkattrs
in linkout
.items()]
680 def cache_get(self
, t
, attrlist
, refresh
=False):
681 return self
._cache
_get
(t
, attrlist
, refresh
)
683 def _cache_get(self
, t
, attrlist
, refresh
=False):
685 if ifupdownflags
.flags
.DRYRUN
:
687 if ifupdownflags
.flags
.CACHE
:
688 if self
._fill
_cache
():
689 # if we filled the cache, return new data
690 return linkCache
.get_attr(attrlist
)
692 return linkCache
.get_attr(attrlist
)
694 self
._link
_fill
(attrlist
[0], refresh
)
696 self
._addr
_fill
(attrlist
[0], refresh
)
698 self
._link
_fill
(attrlist
[0], refresh
)
699 self
._addr
_fill
(attrlist
[0], refresh
)
700 return linkCache
.get_attr(attrlist
)
702 self
.logger
.debug('_cache_get(%s) : [%s]' % (str(attrlist
), str(e
)))
705 def cache_check(self
, attrlist
, value
, refresh
=False):
706 return self
._cache
_check
('link', attrlist
, value
, refresh
=refresh
)
708 def _cache_check(self
, t
, attrlist
, value
, refresh
=False):
710 return self
._cache
_get
(t
, attrlist
, refresh
) == value
712 self
.logger
.debug('_cache_check(%s) : [%s]'
713 % (str(attrlist
), str(e
)))
716 def cache_update(self
, attrlist
, value
):
717 return self
._cache
_update
(attrlist
, value
)
720 def _cache_update(attrlist
, value
):
721 if ifupdownflags
.flags
.DRYRUN
:
724 if attrlist
[-1] == 'slaves':
725 linkCache
.append_to_attrlist(attrlist
, value
)
727 linkCache
.set_attr(attrlist
, value
)
732 def _cache_delete(attrlist
, value
=None):
733 if ifupdownflags
.flags
.DRYRUN
:
737 linkCache
.remove_from_attrlist(attrlist
, value
)
739 linkCache
.del_attr(attrlist
)
744 def _cache_invalidate():
745 linkCache
.invalidate()
746 LinkUtils
._CACHE
_FILL
_DONE
= False
750 LinkUtils
.ipbatcbuf
= ''
751 LinkUtils
.ipbatch
= True
752 LinkUtils
.ipbatch_pause
= False
755 def add_to_batch(cmd
):
756 LinkUtils
.ipbatchbuf
+= cmd
+ '\n'
760 LinkUtils
.ipbatch_pause
= True
764 LinkUtils
.ipbatch_pause
= False
766 def batch_commit(self
):
767 if not LinkUtils
.ipbatchbuf
:
768 LinkUtils
.ipbatchbuf
= ''
769 LinkUtils
.ipbatch
= False
770 LinkUtils
.ipbatch_pause
= False
773 utils
.exec_command('%s -force -batch -' % utils
.ip_cmd
,
774 stdin
=self
.ipbatchbuf
)
778 LinkUtils
.ipbatchbuf
= ''
779 LinkUtils
.ipbatch
= False
780 LinkUtils
.ipbatch_pause
= False
782 def bridge_batch_commit(self
):
783 if not LinkUtils
.ipbatchbuf
:
784 LinkUtils
.ipbatchbuf
= ''
785 LinkUtils
.ipbatch
= False
786 LinkUtils
.ipbatch_pause
= False
789 utils
.exec_command('%s -force -batch -'
790 % utils
.bridge_cmd
, stdin
=self
.ipbatchbuf
)
794 LinkUtils
.ipbatchbuf
= ''
795 LinkUtils
.ipbatch
= False
796 LinkUtils
.ipbatch_pause
= False
798 def addr_show(self
, ifacename
=None):
800 if not self
.link_exists(ifacename
):
802 return utils
.exec_commandl([utils
.ip_cmd
,
803 '-o', 'addr', 'show', 'dev', ifacename
])
805 return utils
.exec_commandl([utils
.ip_cmd
,
806 '-o', 'addr', 'show'])
809 def link_show(ifacename
=None):
811 return utils
.exec_commandl([utils
.ip_cmd
,
812 '-o', '-d', 'link', 'show', 'dev', ifacename
])
814 return utils
.exec_commandl([utils
.ip_cmd
,
815 '-o', '-d', 'link', 'show'])
817 def addr_add(self
, ifacename
, address
, broadcast
=None,
818 peer
=None, scope
=None, preferred_lifetime
=None, metric
=None):
821 cmd
= 'addr add %s' % address
823 cmd
+= ' broadcast %s' % broadcast
825 cmd
+= ' peer %s' % peer
827 cmd
+= ' scope %s' % scope
828 if preferred_lifetime
:
829 cmd
+= ' preferred_lft %s' % preferred_lifetime
830 cmd
+= ' dev %s' % ifacename
833 cmd
+= ' metric %s' % metric
835 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
836 self
.add_to_batch(cmd
)
838 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
839 self
._cache
_update
([ifacename
, 'addrs', address
], {})
841 def addr_del(self
, ifacename
, address
, broadcast
=None,
842 peer
=None, scope
=None):
843 """ Delete ipv4 address """
846 if not self
._cache
_get
('addr', [ifacename
, 'addrs', address
]):
848 cmd
= 'addr del %s' % address
850 cmd
+= 'broadcast %s' % broadcast
852 cmd
+= 'peer %s' % peer
854 cmd
+= 'scope %s' % scope
855 cmd
+= ' dev %s' % ifacename
856 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
857 self
._cache
_delete
([ifacename
, 'addrs', address
])
859 def addr_flush(self
, ifacename
):
860 cmd
= 'addr flush dev %s' % ifacename
861 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
862 self
.add_to_batch(cmd
)
864 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
865 self
._cache
_delete
([ifacename
, 'addrs'])
867 def del_addr_all(self
, ifacename
, skip_addrs
=[]):
870 runningaddrsdict
= self
.get_running_addrs(ifname
=ifacename
)
872 # XXX: ignore errors. Fix this to delete secondary addresses
874 [self
.addr_del(ifacename
, a
) for a
in
875 set(runningaddrsdict
.keys()).difference(skip_addrs
)]
880 def addr_get(self
, ifacename
, details
=True, refresh
=False):
881 addrs
= self
._cache
_get
('addr', [ifacename
, 'addrs'], refresh
=refresh
)
888 def get_running_addrs(self
, ifaceobj
=None, ifname
=None, details
=True, addr_virtual_ifaceobj
=None):
890 We now support addr with link scope. Since the kernel may add it's
891 own link address to some interfaces we need to filter them out and
892 make sure we only deal with the addresses set by ifupdown2.
894 To do so we look at the previous configuration made by ifupdown2
895 (with the help of the statemanager) together with the addresses
896 specified by the user in /etc/network/interfaces, these addresses
897 are then compared to the running state of the intf (ip addr show)
898 made via a netlink addr dump.
899 For each configured addresses of scope link, we check if it was
900 previously configured by ifupdown2 to create a final set of the
901 addresses watched by ifupdown2
903 if not ifaceobj
and not ifname
:
909 interface_name
= ifaceobj
.name
911 interface_name
= ifname
913 if addr_virtual_ifaceobj
:
914 for virtual
in addr_virtual_ifaceobj
.get_attr_value('address-virtual') or []:
915 for ip
in virtual
.split():
922 saved_ifaceobjs
= statemanager
.statemanager_api
.get_ifaceobjs(addr_virtual_ifaceobj
.name
)
923 for saved_ifaceobj
in saved_ifaceobjs
or []:
924 for virtual
in saved_ifaceobj
.get_attr_value('address-virtual') or []:
925 for ip
in virtual
.split():
933 for addr
in ifaceobj
.get_attr_value('address') or []:
934 config_addrs
.add(addr
)
936 saved_ifaceobjs
= statemanager
.statemanager_api
.get_ifaceobjs(interface_name
)
937 for saved_ifaceobj
in saved_ifaceobjs
or []:
938 for addr
in saved_ifaceobj
.get_attr_value('address') or []:
939 config_addrs
.add(addr
)
941 running_addrs
= OrderedDict()
942 cached_addrs
= self
.addr_get(interface_name
)
944 for addr
, addr_details
in cached_addrs
.items():
946 scope
= int(addr_details
['scope'])
950 addr_obj
= IPNetwork(addr
)
951 if isinstance(addr_obj
, IPv6Network
):
952 d
['family'] = 'inet6'
955 running_addrs
[addr
] = d
957 running_addrs
[addr
] = {}
959 if (scope
& Route
.RT_SCOPE_LINK
and addr
in config_addrs
) or not scope
& Route
.RT_SCOPE_LINK
:
960 running_addrs
[addr
] = addr_details
966 return running_addrs
.keys()
969 def compare_user_config_vs_running_state(running_addrs
, user_addrs
):
973 for ip
in user_addrs
or []:
976 if type(obj
) == IPv6Network
:
982 for ip
in running_addrs
or []:
983 running_ipobj
.append(IPNetwork(ip
))
985 return running_ipobj
== (ip4
+ ip6
)
987 def addr_add_multiple(self
, ifaceobj
, ifacename
, addrs
, purge_existing
=False, metric
=None):
990 # if perfmode is not set and also if iface has no sibling
991 # objects, purge addresses that are not present in the new
993 runningaddrs
= self
.get_running_addrs(
996 addr_virtual_ifaceobj
=ifaceobj
998 addrs
= utils
.get_normalized_ip_addr(ifacename
, addrs
)
1000 if self
.compare_user_config_vs_running_state(runningaddrs
, addrs
):
1003 # if primary address is not same, there is no need to keep any.
1004 # reset all addresses
1005 if (addrs
and runningaddrs
and
1006 (addrs
[0] != runningaddrs
[0])):
1007 self
.del_addr_all(ifacename
)
1009 self
.del_addr_all(ifacename
, addrs
)
1010 except Exception, e
:
1011 self
.logger
.warning('%s: %s' % (ifacename
, str(e
)))
1014 self
.addr_add(ifacename
, a
, metric
=metric
)
1015 except Exception, e
:
1016 self
.logger
.error(str(e
))
1018 def _link_set_ifflag(self
, ifacename
, value
):
1019 # Dont look at the cache, the cache may have stale value
1020 # because link status can be changed by external
1021 # entity (One such entity is ifupdown main program)
1022 cmd
= 'link set dev %s %s' % (ifacename
, value
.lower())
1023 if LinkUtils
.ipbatch
:
1024 self
.add_to_batch(cmd
)
1026 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1028 def link_up(self
, ifacename
):
1029 self
._link
_set
_ifflag
(ifacename
, 'UP')
1031 def link_down(self
, ifacename
):
1032 self
._link
_set
_ifflag
(ifacename
, 'DOWN')
1034 def link_set(self
, ifacename
, key
, value
=None,
1035 force
=False, t
=None, state
=None):
1037 if (key
not in ['master', 'nomaster'] and
1038 self
._cache
_check
('link', [ifacename
, key
], value
)):
1040 cmd
= 'link set dev %s' % ifacename
1042 cmd
+= ' type %s' % t
1045 cmd
+= ' %s' % value
1047 cmd
+= ' %s' % state
1048 if LinkUtils
.ipbatch
:
1049 self
.add_to_batch(cmd
)
1051 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1052 if key
not in ['master', 'nomaster']:
1053 self
._cache
_update
([ifacename
, key
], value
)
1055 def link_set_hwaddress(self
, ifacename
, hwaddress
, force
=False):
1057 if self
._cache
_check
('link', [ifacename
, 'hwaddress'], hwaddress
):
1059 self
.link_down(ifacename
)
1060 cmd
= 'link set dev %s address %s' % (ifacename
, hwaddress
)
1061 if LinkUtils
.ipbatch
:
1062 self
.add_to_batch(cmd
)
1064 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1065 self
.link_up(ifacename
)
1066 self
._cache
_update
([ifacename
, 'hwaddress'], hwaddress
)
1068 def link_set_mtu(self
, ifacename
, mtu
):
1069 if ifupdownflags
.flags
.DRYRUN
:
1071 if not mtu
or not ifacename
: return
1072 self
.write_file('/sys/class/net/%s/mtu' % ifacename
, mtu
)
1073 self
._cache
_update
([ifacename
, 'mtu'], mtu
)
1075 def link_set_alias(self
, ifacename
, alias
):
1076 self
.write_file('/sys/class/net/%s/ifalias' % ifacename
,
1077 '\n' if not alias
else alias
)
1079 def link_get_alias(self
, ifacename
):
1080 return self
.read_file_oneline('/sys/class/net/%s/ifalias'
1083 def link_isloopback(self
, ifacename
):
1084 flags
= self
._cache
_get
('link', [ifacename
, 'flags'])
1087 if 'LOOPBACK' in flags
:
1091 def link_get_status(self
, ifacename
):
1092 return self
._cache
_get
('link', [ifacename
, 'ifflag'], refresh
=True)
1095 def route_add_gateway(ifacename
, gateway
, vrf
=None, metric
=None):
1099 cmd
= '%s route add default via %s proto kernel' % (utils
.ip_cmd
,
1102 cmd
= ('%s route add table %s default via %s proto kernel' %
1103 (utils
.ip_cmd
, vrf
, gateway
))
1106 cmd
+= 'metric %s' % metric
1107 cmd
+= ' dev %s' % ifacename
1108 utils
.exec_command(cmd
)
1111 def route_del_gateway(ifacename
, gateway
, vrf
=None, metric
=None):
1116 cmd
= ('%s route del default via %s proto kernel' %
1117 (utils
.ip_cmd
, gateway
))
1119 cmd
= ('%s route del table %s default via %s proto kernel' %
1120 (utils
.ip_cmd
, vrf
, gateway
))
1122 cmd
+= ' metric %s' % metric
1123 cmd
+= ' dev %s' % ifacename
1124 utils
.exec_command(cmd
)
1127 def _get_vrf_id(ifacename
):
1129 return linkCache
.vrfs
[ifacename
]['table']
1131 dump
= netlink
.link_dump(ifacename
)
1133 [linkCache
.update_attrdict([ifname
], linkattrs
)
1134 for ifname
, linkattrs
in dump
.items()]
1136 if dump
and dump
.get(ifacename
, {}).get('kind') == 'vrf':
1137 vrf_table
= dump
.get(ifacename
, {}).get('linkinfo', {}).get('table')
1138 linkCache
.vrfs
[ifacename
] = {'table': vrf_table
}
1143 def fix_ipv6_route_metric(self
, ifaceobj
, macvlan_ifacename
, ips
):
1146 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
:
1148 for upper_iface
in ifaceobj
.upperifaces
:
1149 vrf_table
= self
._get
_vrf
_id
(upper_iface
)
1157 ip_network_obj
= IPNetwork(ip
)
1159 if type(ip_network_obj
) == IPv6Network
:
1160 route_prefix
= '%s/%d' % (ip_network_obj
.network
, ip_network_obj
.prefixlen
)
1163 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1164 LinkUtils
.add_to_batch('route del %s table %s dev %s' % (route_prefix
, vrf_table
, macvlan_ifacename
))
1166 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'del', route_prefix
, 'table', vrf_table
, 'dev', macvlan_ifacename
])
1168 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1169 LinkUtils
.add_to_batch('route del %s dev %s' % (route_prefix
, macvlan_ifacename
))
1171 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'del', route_prefix
, 'dev', macvlan_ifacename
])
1172 ip_route_del
.append((route_prefix
, vrf_table
))
1174 for ip
, vrf_table
in ip_route_del
:
1176 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1177 LinkUtils
.add_to_batch('route add %s table %s dev %s proto kernel metric 9999' % (ip
, vrf_table
, macvlan_ifacename
))
1179 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'add', ip
, 'table', vrf_table
, 'dev', macvlan_ifacename
, 'proto', 'kernel' 'metric', '9999'])
1181 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1182 LinkUtils
.add_to_batch('route add %s dev %s proto kernel metric 9999' % (ip
, macvlan_ifacename
))
1184 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'add', ip
, 'dev', macvlan_ifacename
, 'proto', 'kernel' 'metric', '9999'])
1186 def link_create_vlan(self
, vlan_device_name
, vlan_raw_device
, vlanid
):
1187 if self
.link_exists(vlan_device_name
):
1189 utils
.exec_command('%s link add link %s name %s type vlan id %d' %
1191 vlan_raw_device
, vlan_device_name
, vlanid
))
1192 self
._cache
_update
([vlan_device_name
], {})
1194 def link_create_vlan_from_name(self
, vlan_device_name
):
1195 v
= vlan_device_name
.split('.')
1197 self
.logger
.warn('invalid vlan device name %s' % vlan_device_name
)
1199 self
.link_create_vlan(vlan_device_name
, v
[0], v
[1])
1201 def link_create_macvlan(self
, name
, linkdev
, mode
='private'):
1202 if self
.link_exists(name
):
1204 cmd
= ('link add link %s' % linkdev
+
1206 ' type macvlan mode %s' % mode
)
1207 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1208 self
.add_to_batch(cmd
)
1210 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1211 self
._cache
_update
([name
], {})
1213 def get_vxlan_peers(self
, dev
, svcnodeip
):
1214 cmd
= '%s fdb show brport %s' % (utils
.bridge_cmd
,
1218 ps
= subprocess
.Popen(shlex
.split(cmd
), stdout
=subprocess
.PIPE
, close_fds
=False)
1219 utils
.enable_subprocess_signal_forwarding(ps
, signal
.SIGINT
)
1220 output
= subprocess
.check_output(('grep', '00:00:00:00:00:00'), stdin
=ps
.stdout
)
1222 utils
.disable_subprocess_signal_forwarding(signal
.SIGINT
)
1224 ppat
= re
.compile('\s+dst\s+(\d+.\d+.\d+.\d+)\s+')
1225 for l
in output
.split('\n'):
1227 if m
and m
.group(1) != svcnodeip
:
1228 cur_peers
.append(m
.group(1))
1230 self
.logger
.warn('error parsing ip link output')
1231 except subprocess
.CalledProcessError
as e
:
1232 if e
.returncode
!= 1:
1233 self
.logger
.error(str(e
))
1235 utils
.disable_subprocess_signal_forwarding(signal
.SIGINT
)
1239 def link_create_vxlan(self
, name
, vxlanid
,
1246 if svcnodeip
and remoteips
:
1247 raise Exception("svcnodeip and remoteip is mutually exclusive")
1250 args
+= ' remote %s' % svcnodeip
1252 args
+= ' ageing %s' % ageing
1253 if learning
== 'off':
1254 args
+= ' nolearning'
1256 if self
.link_exists(name
):
1257 cmd
= 'link set dev %s type vxlan dstport %d' % (name
, LinkUtils
.VXLAN_UDP_PORT
)
1258 vxlanattrs
= self
.get_vxlandev_attrs(name
)
1259 # on ifreload do not overwrite anycast_ip to individual ip if clagd
1262 running_localtunnelip
= vxlanattrs
.get('local')
1263 if anycastip
and running_localtunnelip
and anycastip
== running_localtunnelip
:
1264 localtunnelip
= running_localtunnelip
1265 running_svcnode
= vxlanattrs
.get('svcnode')
1266 if running_svcnode
and not svcnodeip
:
1269 cmd
= 'link add dev %s type vxlan id %s dstport %d' % (name
, vxlanid
, LinkUtils
.VXLAN_UDP_PORT
)
1272 args
+= ' local %s' % localtunnelip
1275 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1276 self
.add_to_batch(cmd
)
1278 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1280 # XXX: update linkinfo correctly
1281 #self._cache_update([name], {})
1284 def link_exists(ifacename
):
1285 if ifupdownflags
.flags
.DRYRUN
:
1287 return os
.path
.exists('/sys/class/net/%s' % ifacename
)
1289 def link_get_ifindex(self
, ifacename
):
1290 if ifupdownflags
.flags
.DRYRUN
:
1292 return self
.read_file_oneline('/sys/class/net/%s/ifindex' % ifacename
)
1294 def is_vlan_device_by_name(self
, ifacename
):
1295 if re
.search(r
'\.', ifacename
):
1300 def link_add_macvlan(ifname
, macvlan_ifacename
):
1301 utils
.exec_commandl(['ip', 'link', 'add', 'link', ifname
, 'name', macvlan_ifacename
, 'type', 'macvlan', 'mode', 'private'])
1304 def route_add(route
):
1305 utils
.exec_command('%s route add %s' % (utils
.ip_cmd
,
1309 def route6_add(route
):
1310 utils
.exec_command('%s -6 route add %s' % (utils
.ip_cmd
,
1313 def get_vlandev_attrs(self
, ifacename
):
1314 return (self
._cache
_get
('link', [ifacename
, 'link']),
1315 self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlanid']),
1316 self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlan_protocol']))
1318 def get_vlan_protocol(self
, ifacename
):
1319 return self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlan_protocol'])
1321 def get_vxlandev_attrs(self
, ifacename
):
1322 return self
._cache
_get
('link', [ifacename
, 'linkinfo'])
1324 def get_vxlandev_learning(self
, ifacename
):
1325 return self
._cache
_get
('link', [ifacename
, 'linkinfo', Link
.IFLA_VXLAN_LEARNING
])
1327 def set_vxlandev_learning(self
, ifacename
, learn
):
1329 utils
.exec_command('%s link set dev %s type vxlan learning' %
1330 (utils
.ip_cmd
, ifacename
))
1331 self
._cache
_update
([ifacename
, 'linkinfo', 'learning'], 'on')
1333 utils
.exec_command('%s link set dev %s type vxlan nolearning' %
1334 (utils
.ip_cmd
, ifacename
))
1335 self
._cache
_update
([ifacename
, 'linkinfo', 'learning'], 'off')
1337 def link_get_linkinfo_attrs(self
, ifacename
):
1338 return self
._cache
_get
('link', [ifacename
, 'linkinfo'])
1340 def link_get_mtu(self
, ifacename
, refresh
=False):
1341 return self
._cache
_get
('link', [ifacename
, 'mtu'], refresh
=refresh
)
1343 def link_get_mtu_sysfs(self
, ifacename
):
1344 return self
.read_file_oneline('/sys/class/net/%s/mtu'
1347 def link_get_kind(self
, ifacename
):
1348 return self
._cache
_get
('link', [ifacename
, 'kind'])
1350 def link_get_slave_kind(self
, ifacename
):
1351 return self
._cache
_get
('link', [ifacename
, 'slave_kind'])
1353 def link_get_hwaddress(self
, ifacename
):
1354 address
= self
._cache
_get
('link', [ifacename
, 'hwaddress'])
1355 # newly created logical interface addresses dont end up in the cache
1356 # read hwaddress from sysfs file for these interfaces
1358 address
= self
.read_file_oneline('/sys/class/net/%s/address'
1362 def link_create(self
, ifacename
, t
, attrs
={}):
1363 """ generic link_create function """
1364 if self
.link_exists(ifacename
):
1367 cmd
+= ' name %s type %s' % (ifacename
, t
)
1369 for k
, v
in attrs
.iteritems():
1373 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1374 self
.add_to_batch(cmd
)
1376 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1377 self
._cache
_update
([ifacename
], {})
1379 def link_delete(self
, ifacename
):
1380 if not self
.link_exists(ifacename
):
1382 cmd
= 'link del %s' % ifacename
1383 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1384 self
.add_to_batch(cmd
)
1386 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1387 self
._cache
_invalidate
()
1389 def link_get_master(self
, ifacename
):
1390 sysfs_master_path
= '/sys/class/net/%s/master' % ifacename
1391 if os
.path
.exists(sysfs_master_path
):
1392 link_path
= os
.readlink(sysfs_master_path
)
1394 return os
.path
.basename(link_path
)
1398 return self
._cache
_get
('link', [ifacename
, 'master'])
1400 def get_brport_peer_link(self
, bridgename
):
1402 return self
._cache
_get
('link', [bridgename
, 'info_slave_data', Link
.IFLA_BRPORT_PEER_LINK
])
1407 def bridge_port_vids_add(bridgeportname
, vids
):
1408 [utils
.exec_command('%s vlan add vid %s dev %s' %
1410 v
, bridgeportname
)) for v
in vids
]
1413 def bridge_port_vids_del(bridgeportname
, vids
):
1416 [utils
.exec_command('%s vlan del vid %s dev %s' %
1418 v
, bridgeportname
)) for v
in vids
]
1421 def bridge_port_vids_flush(bridgeportname
, vid
):
1422 utils
.exec_command('%s vlan del vid %s dev %s' %
1424 vid
, bridgeportname
))
1427 def bridge_port_vids_get(bridgeportname
):
1428 bridgeout
= utils
.exec_command('%s vlan show dev %s' %
1433 brvlanlines
= bridgeout
.readlines()[2:]
1434 vids
= [l
.strip() for l
in brvlanlines
]
1435 return [v
for v
in vids
if v
]
1438 def bridge_port_vids_get_all():
1440 bridgeout
= utils
.exec_command('%s -c vlan show'
1444 brvlanlines
= bridgeout
.splitlines()
1446 for l
in brvlanlines
[1:]:
1447 if l
and not l
.startswith(' ') and not l
.startswith('\t'):
1449 brportname
= attrs
[0].strip()
1450 brvlaninfo
[brportname
] = {'pvid': None, 'vlan': []}
1451 l
= ' '.join(attrs
[1:])
1452 if not brportname
or not l
:
1456 brvlaninfo
[brportname
]['pvid'] = l
.split()[0]
1457 elif 'Egress Untagged' not in l
:
1458 brvlaninfo
[brportname
]['vlan'].append(l
)
1461 def bridge_port_vids_get_all_json(self
):
1462 if not self
.supported_command
['%s -c -json vlan show'
1463 % utils
.bridge_cmd
]:
1467 bridgeout
= utils
.exec_command('%s -c -json vlan show'
1470 self
.supported_command
['%s -c -json vlan show'
1471 % utils
.bridge_cmd
] = False
1472 self
.logger
.info('%s -c -json vlan show: skipping unsupported command'
1475 return self
.get_bridge_vlan_nojson()
1476 except Exception as e
:
1477 self
.logger
.info('bridge: get_bridge_vlan_nojson: %s' % str(e
))
1480 if not bridgeout
: return brvlaninfo
1482 vlan_json_dict
= json
.loads(bridgeout
, encoding
="utf-8")
1483 except Exception, e
:
1484 self
.logger
.info('json loads failed with (%s)' % str(e
))
1486 return vlan_json_dict
1489 def get_bridge_vlan_nojson():
1491 bridgeout
= utils
.exec_commandl([utils
.bridge_cmd
, '-c', 'vlan', 'show'])
1493 output
= [line
.split('\n') for line
in bridgeout
.split('\n\n')]
1494 output
[0] = output
[0][1:]
1502 prefix
, vlan
= entry
.split('\t')
1504 current_swp
= prefix
1505 vlan_json
[prefix
] = []
1509 v
['vlan'] = int(vlan
)
1513 start
, end
= vlan
.split('-')
1515 end
= end
[0:end
.index(' ')]
1516 v
['vlan'] = int(start
)
1517 v
['vlanEnd'] = int(end
)
1519 v
['vlan'] = int(vlan
[0:vlan
.index(' ')])
1522 flags
.append('PVID')
1523 if 'Egress Untagged' in vlan
:
1524 flags
.append('Egress Untagged')
1528 vlan_json
[current_swp
].append(v
)
1531 def bridge_vlan_cache_get(self
, ifacename
, refresh
=False):
1532 if not self
.bridge_vlan_cache_fill_done
or refresh
:
1533 self
.bridge_vlan_cache
= self
.bridge_port_vids_get_all_json()
1534 self
.bridge_vlan_cache_fill_done
= True
1535 return self
.bridge_vlan_cache
.get(ifacename
, {})
1537 def bridge_vlan_get_pvid(self
, ifacename
, refresh
=False):
1540 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1541 v
= vinfo
.get('vlan')
1542 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1547 def bridge_vlan_get_vids(self
, ifacename
, refresh
=False):
1550 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1551 v
= vinfo
.get('vlan')
1552 ispvid
= True if 'PVID' in vinfo
.get('flags', []) else False
1554 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1557 vEnd
= vinfo
.get('vlanEnd')
1559 vids
.extend(range(v
, vEnd
+ 1))
1564 def bridge_vlan_get_vids_n_pvid(self
, ifacename
, refresh
=False):
1568 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1569 v
= vinfo
.get('vlan')
1570 ispvid
= True if 'PVID' in vinfo
.get('flags', []) else False
1572 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1573 vEnd
= vinfo
.get('vlanEnd')
1575 vids
.extend(range(v
, vEnd
+ 1))
1580 def bridge_port_pvid_add(self
, bridgeportname
, pvid
):
1581 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1582 self
.add_to_batch('vlan add vid %s untagged pvid dev %s' %
1583 (pvid
, bridgeportname
))
1585 utils
.exec_command('%s vlan add vid %s untagged pvid dev %s' %
1587 pvid
, bridgeportname
))
1589 def bridge_port_pvid_del(self
, bridgeportname
, pvid
):
1590 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1591 self
.add_to_batch('vlan del vid %s untagged pvid dev %s' %
1592 (pvid
, bridgeportname
))
1594 utils
.exec_command('%s vlan del vid %s untagged pvid dev %s' %
1596 pvid
, bridgeportname
))
1598 def bridge_port_pvids_get(self
, bridgeportname
):
1599 return self
.read_file_oneline('/sys/class/net/%s/brport/pvid'
1602 def bridge_vids_add(self
, bridgeportname
, vids
, bridge
=True):
1603 target
= 'self' if bridge
else ''
1604 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1605 [self
.add_to_batch('vlan add vid %s dev %s %s' %
1606 (v
, bridgeportname
, target
)) for v
in vids
]
1608 [utils
.exec_command('%s vlan add vid %s dev %s %s' %
1610 v
, bridgeportname
, target
)) for v
in vids
]
1612 def bridge_vids_del(self
, bridgeportname
, vids
, bridge
=True):
1613 target
= 'self' if bridge
else ''
1614 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1615 [self
.add_to_batch('vlan del vid %s dev %s %s' %
1616 (v
, bridgeportname
, target
)) for v
in vids
]
1618 [utils
.exec_command('%s vlan del vid %s dev %s %s' %
1620 v
, bridgeportname
, target
)) for v
in vids
]
1623 def bridge_fdb_add(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1624 target
= 'self' if bridge
else ''
1627 vlan_str
= 'vlan %s ' % vlan
1631 dst_str
= 'dst %s ' % remote
1633 utils
.exec_command('%s fdb replace %s dev %s %s %s %s' %
1635 address
, dev
, vlan_str
, target
, dst_str
))
1638 def bridge_fdb_append(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1639 target
= 'self' if bridge
else ''
1642 vlan_str
= 'vlan %s ' % vlan
1646 dst_str
= 'dst %s ' % remote
1648 utils
.exec_command('%s fdb append %s dev %s %s %s %s' %
1650 address
, dev
, vlan_str
, target
, dst_str
))
1653 def bridge_fdb_del(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1654 target
= 'self' if bridge
else ''
1657 vlan_str
= 'vlan %s ' % vlan
1661 dst_str
= 'dst %s ' % remote
1662 utils
.exec_command('%s fdb del %s dev %s %s %s %s' %
1664 address
, dev
, vlan_str
, target
, dst_str
))
1666 def bridge_is_vlan_aware(self
, bridgename
):
1667 filename
= '/sys/class/net/%s/bridge/vlan_filtering' % bridgename
1668 if os
.path
.exists(filename
) and self
.read_file_oneline(filename
) == '1':
1673 def bridge_port_get_bridge_name(bridgeport
):
1674 filename
= '/sys/class/net/%s/brport/bridge' % bridgeport
1676 return os
.path
.basename(os
.readlink(filename
))
1681 def bridge_port_exists(bridge
, bridgeportname
):
1683 return os
.path
.exists('/sys/class/net/%s/brif/%s'
1684 % (bridge
, bridgeportname
))
1688 def bridge_fdb_show_dev(self
, dev
):
1691 output
= utils
.exec_command('%s fdb show dev %s'
1692 % (utils
.bridge_cmd
, dev
))
1694 for fdb_entry
in output
.splitlines():
1696 entries
= fdb_entry
.split()
1697 fdbs
.setdefault(entries
[2], []).append(entries
[0])
1699 self
.logger
.debug('%s: invalid fdb line \'%s\''
1706 def is_bridge(bridge
):
1707 return os
.path
.exists('/sys/class/net/%s/bridge' % bridge
)
1709 def is_link_up(self
, ifacename
):
1712 flags
= self
.read_file_oneline('/sys/class/net/%s/flags' % ifacename
)
1713 iflags
= int(flags
, 16)
1720 def ip_route_get_dev(self
, prefix
, vrf_master
=None):
1723 cmd
= '%s route get %s vrf %s' % (utils
.ip_cmd
, prefix
, vrf_master
)
1725 cmd
= '%s route get %s' % (utils
.ip_cmd
, prefix
)
1727 output
= utils
.exec_command(cmd
)
1729 rline
= output
.splitlines()[0]
1731 rattrs
= rline
.split()
1732 return rattrs
[rattrs
.index('dev') + 1]
1733 except Exception, e
:
1734 self
.logger
.debug('ip_route_get_dev: failed .. %s' % str(e
))
1738 def link_get_lowers(ifacename
):
1740 lowers
= glob
.glob("/sys/class/net/%s/lower_*" % ifacename
)
1743 return [os
.path
.basename(l
)[6:] for l
in lowers
]
1748 def link_get_uppers(ifacename
):
1750 uppers
= glob
.glob("/sys/class/net/%s/upper_*" % ifacename
)
1753 return [os
.path
.basename(u
)[6:] for u
in uppers
]
1757 def link_get_vrfs(self
):
1758 if not LinkUtils
._CACHE
_FILL
_DONE
:
1760 return linkCache
.vrfs
1763 def cache_get_info_slave(attrlist
):
1765 return linkCache
.get_attr(attrlist
)
1769 def get_brport_learning(self
, ifacename
):
1770 learn
= self
.read_file_oneline('/sys/class/net/%s/brport/learning'
1772 if learn
and learn
== '1':
1777 def get_brport_learning_bool(self
, ifacename
):
1778 return utils
.get_boolean_from_string(self
.read_file_oneline('/sys/class/net/%s/brport/learning' % ifacename
))
1780 def set_brport_learning(self
, ifacename
, learn
):
1782 return self
.write_file('/sys/class/net/%s/brport/learning'
1785 return self
.write_file('/sys/class/net/%s/brport/learning'
1788 #################################################################################
1789 ################################### BOND UTILS ##################################
1790 #################################################################################
1792 def _link_cache_get(self
, attrlist
, refresh
=False):
1793 return self
._cache
_get
('link', attrlist
, refresh
)
1795 def cache_delete(self
, attrlist
, value
=None):
1796 return self
._cache
_delete
(attrlist
, value
)
1798 def link_cache_get(self
, attrlist
, refresh
=False):
1799 return self
._link
_cache
_get
(attrlist
, refresh
)
1801 def link_cache_check(self
, attrlist
, value
, refresh
=False):
1802 return self
._link
_cache
_check
(attrlist
, value
, refresh
)
1804 def _link_cache_check(self
, attrlist
, value
, refresh
=False):
1806 return self
._link
_cache
_get
(attrlist
, refresh
) == value
1807 except Exception, e
:
1808 self
.logger
.debug('_cache_check(%s) : [%s]'
1809 % (str(attrlist
), str(e
)))
1814 Link
.IFLA_BOND_MODE
: 'mode',
1815 Link
.IFLA_BOND_MIIMON
: 'miimon',
1816 Link
.IFLA_BOND_USE_CARRIER
: 'use_carrier',
1817 Link
.IFLA_BOND_AD_LACP_RATE
: 'lacp_rate',
1818 Link
.IFLA_BOND_XMIT_HASH_POLICY
: 'xmit_hash_policy',
1819 Link
.IFLA_BOND_MIN_LINKS
: 'min_links',
1820 Link
.IFLA_BOND_NUM_PEER_NOTIF
: 'num_grat_arp',
1821 Link
.IFLA_BOND_AD_ACTOR_SYSTEM
: 'ad_actor_system',
1822 Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
: 'ad_actor_sys_prio',
1823 Link
.IFLA_BOND_AD_LACP_BYPASS
: 'lacp_bypass',
1824 Link
.IFLA_BOND_UPDELAY
: 'updelay',
1825 Link
.IFLA_BOND_DOWNDELAY
: 'downdelay',
1828 def bond_set_attrs_nl(self
, bondname
, ifla_info_data
):
1829 bond_attr_name
= 'None' # for log purpose (in case an exception raised)
1830 for nl_attr
, value
in ifla_info_data
.items():
1832 bond_attr_name
= self
.bondcmd_attrmap
[nl_attr
]
1833 file_path
= '/sys/class/net/%s/bonding/%s' % (bondname
, bond_attr_name
)
1834 if os
.path
.exists(file_path
):
1835 self
.write_file(file_path
, str(value
))
1836 except Exception as e
:
1837 exception_str
= '%s: %s %s: %s' % (bondname
, bond_attr_name
, value
, str(e
))
1838 if ifupdownflags
.flags
.FORCE
:
1839 self
.logger
.warning(exception_str
)
1841 self
.logger
.debug(exception_str
)
1843 def bond_set_attrs(self
, bondname
, attrdict
, prehook
):
1844 for attrname
, attrval
in attrdict
.items():
1845 if (self
._link
_cache
_check
([bondname
, 'linkinfo',
1846 attrname
], attrval
)):
1848 if (attrname
== 'mode'
1849 or attrname
== 'xmit_hash_policy'
1850 or attrname
== 'lacp_rate' or attrname
== 'min_links'):
1854 if ((attrname
not in ['lacp_rate',
1856 self
._link
_cache
_check
([bondname
, 'linkinfo', 'mode'], '802.3ad',
1858 self
.write_file('/sys/class/net/%s/bonding/%s'
1859 % (bondname
, attrname
), attrval
)
1860 except Exception, e
:
1861 if ifupdownflags
.flags
.FORCE
:
1862 self
.logger
.warn(str(e
))
1867 def bond_set_use_carrier(self
, bondname
, use_carrier
):
1868 if not use_carrier
or (use_carrier
!= '0' and use_carrier
!= '1'):
1870 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'use_carrier'],
1873 self
.write_file('/sys/class/net/%s' % bondname
+
1874 '/bonding/use_carrier', use_carrier
)
1875 self
._cache
_update
([bondname
, 'linkinfo',
1876 'use_carrier'], use_carrier
)
1878 def bond_get_use_carrier(self
, bondname
):
1879 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'use_carrier'])
1881 def bond_get_use_carrier_nl(self
, bondname
):
1882 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_USE_CARRIER
])
1884 def bond_set_xmit_hash_policy(self
, bondname
, hash_policy
, prehook
=None):
1885 valid_values
= ['layer2', 'layer3+4', 'layer2+3']
1888 if hash_policy
not in valid_values
:
1889 raise Exception('invalid hash policy value %s' % hash_policy
)
1890 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'xmit_hash_policy'],
1895 self
.write_file('/sys/class/net/%s' % bondname
+
1896 '/bonding/xmit_hash_policy', hash_policy
)
1897 self
._cache
_update
([bondname
, 'linkinfo', 'xmit_hash_policy'],
1900 def bond_get_xmit_hash_policy(self
, bondname
):
1901 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'xmit_hash_policy'])
1903 def bond_get_xmit_hash_policy_nl(self
, bondname
):
1904 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_XMIT_HASH_POLICY
])
1906 def bond_set_miimon(self
, bondname
, miimon
):
1907 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'miimon'],
1910 self
.write_file('/sys/class/net/%s' % bondname
+
1911 '/bonding/miimon', miimon
)
1912 self
._cache
_update
([bondname
, 'linkinfo', 'miimon'], miimon
)
1914 def bond_get_miimon(self
, bondname
):
1915 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'miimon'])
1917 def bond_get_miimon_nl(self
, bondname
):
1918 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MIIMON
])
1920 def bond_set_mode(self
, bondname
, mode
, prehook
=None):
1921 valid_modes
= ['balance-rr', 'active-backup', 'balance-xor',
1922 'broadcast', '802.3ad', 'balance-tlb', 'balance-alb']
1925 if mode
not in valid_modes
:
1926 raise Exception('invalid mode %s' % mode
)
1927 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'mode'],
1932 self
.write_file('/sys/class/net/%s' % bondname
+ '/bonding/mode', mode
)
1933 self
._cache
_update
([bondname
, 'linkinfo', 'mode'], mode
)
1935 def bond_get_mode(self
, bondname
):
1936 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'mode'])
1938 def bond_get_mode_nl(self
, bondname
):
1939 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MODE
])
1941 def bond_set_lacp_rate(self
, bondname
, lacp_rate
, prehook
=None, posthook
=None):
1942 if not lacp_rate
or (lacp_rate
!= '0' and lacp_rate
!= '1'):
1944 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'lacp_rate'],
1950 self
.write_file('/sys/class/net/%s' % bondname
+
1951 '/bonding/lacp_rate', lacp_rate
)
1957 self
._cache
_update
([bondname
, 'linkinfo',
1958 'lacp_rate'], lacp_rate
)
1960 def bond_get_lacp_rate(self
, bondname
):
1961 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'lacp_rate'])
1963 def bond_get_lacp_rate_nl(self
, bondname
):
1964 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_RATE
])
1966 def bond_set_lacp_bypass_allow(self
, bondname
, allow
, prehook
=None, posthook
=None):
1967 if self
._link
_cache
_check
([bondname
, 'linkinfo', 'lacp_bypass'], allow
):
1972 self
.write_file('/sys/class/net/%s' % bondname
+
1973 '/bonding/lacp_bypass', allow
)
1979 self
._cache
_update
([bondname
, 'linkinfo',
1980 'lacp_bypass'], allow
)
1982 def bond_get_lacp_bypass_allow(self
, bondname
):
1983 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'lacp_bypass'])
1985 def bond_get_lacp_bypass_allow_nl(self
, bondname
):
1986 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_BYPASS
])
1988 def bond_set_min_links(self
, bondname
, min_links
, prehook
=None):
1989 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'min_links'],
1994 self
.write_file('/sys/class/net/%s/bonding/min_links' % bondname
,
1996 self
._cache
_update
([bondname
, 'linkinfo', 'min_links'], min_links
)
1998 def bond_get_min_links(self
, bondname
):
1999 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'min_links'])
2001 def get_min_links_nl(self
, bondname
):
2002 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MIN_LINKS
])
2004 def bond_get_ad_actor_system(self
, bondname
):
2005 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'ad_actor_system'])
2007 def bond_get_ad_actor_system_nl(self
, bondname
):
2008 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYSTEM
])
2010 def bond_get_ad_actor_sys_prio(self
, bondname
):
2011 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'ad_actor_sys_prio'])
2013 def bond_get_ad_actor_sys_prio_nl(self
, bondname
):
2014 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
])
2016 def bond_get_num_unsol_na(self
, bondname
):
2017 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'num_unsol_na'])
2019 def bond_get_num_unsol_na_nl(self
, bondname
):
2020 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
])
2022 def bond_get_num_grat_arp(self
, bondname
):
2023 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'num_grat_arp'])
2025 def bond_get_num_grat_arp_nl(self
, bondname
):
2026 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
])
2028 def bond_get_updelay(self
, bondname
):
2029 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'updelay'])
2031 def bond_get_updelay_nl(self
, bondname
):
2032 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_UPDELAY
])
2034 def bond_get_downdelay(self
, bondname
):
2035 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'downdelay'])
2037 def bond_get_downdelay_nl(self
, bondname
):
2038 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_DOWNDELAY
])
2040 def bond_enslave_slave(self
, bondname
, slave
, prehook
=None, posthook
=None):
2041 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2042 if slaves
and slave
in slaves
:
2046 self
.write_file('/sys/class/net/%s' % bondname
+
2047 '/bonding/slaves', '+' + slave
)
2050 self
._cache
_update
([bondname
, 'linkinfo', 'slaves'], slave
)
2052 def bond_remove_slave(self
, bondname
, slave
):
2053 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2054 if not slaves
or slave
not in slaves
:
2056 sysfs_bond_path
= ('/sys/class/net/%s' % bondname
+
2058 if not os
.path
.exists(sysfs_bond_path
):
2060 self
.write_file(sysfs_bond_path
, '-' + slave
)
2061 self
._cache
_delete
([bondname
, 'linkinfo', 'slaves'], slave
)
2063 def bond_remove_slaves_all(self
, bondname
):
2064 if not self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves']):
2067 sysfs_bond_path
= ('/sys/class/net/%s' % bondname
+
2070 with
open(sysfs_bond_path
, 'r') as f
:
2071 slaves
= f
.readline().strip().split()
2073 raise Exception('error reading slaves of bond %s (%s)' % (bondname
, str(e
)))
2074 for slave
in slaves
:
2075 self
.link_down(slave
)
2077 self
.bond_remove_slave(bondname
, slave
)
2078 except Exception, e
:
2079 if not ifupdownflags
.flags
.FORCE
:
2080 raise Exception('error removing slave %s from bond %s (%s)' % (slave
, bondname
, str(e
)))
2083 self
._cache
_delete
([bondname
, 'linkinfo', 'slaves'])
2086 def bond_load_bonding_module():
2087 return utils
.exec_command('%s -q bonding' % utils
.modprobe_cmd
)
2089 def create_bond(self
, bondname
):
2090 if self
.bond_exists(bondname
):
2092 # load_bonding_module() has already been run
2093 self
.write_file('/sys/class/net/bonding_masters', '+' + bondname
)
2094 self
._cache
_update
([bondname
], {})
2096 def delete_bond(self
, bondname
):
2097 if not os
.path
.exists('/sys/class/net/%s' % bondname
):
2099 self
.write_file('/sys/class/net/bonding_masters', '-' + bondname
)
2100 self
._cache
_delete
([bondname
])
2102 def bond_get_slaves(self
, bondname
):
2103 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2106 slavefile
= '/sys/class/net/%s/bonding/slaves' % bondname
2107 if os
.path
.exists(slavefile
):
2108 buf
= self
.read_file_oneline(slavefile
)
2110 slaves
= buf
.split()
2113 self
._cache
_update
([bondname
, 'linkinfo', 'slaves'], slaves
)
2116 def bond_slave_exists(self
, bond
, slave
):
2117 slaves
= self
.bond_get_slaves(bond
)
2120 return slave
in slaves
2123 def bond_exists(bondname
):
2124 return os
.path
.exists('/sys/class/net/%s/bonding' % bondname
)
2126 #################################################################################
2127 ################################## BRIDGE UTILS #################################
2128 #################################################################################
2130 def create_bridge(self
, bridgename
):
2131 if not LinkUtils
.bridge_utils_is_installed
:
2133 if self
.bridge_exists(bridgename
):
2135 utils
.exec_command('%s addbr %s' % (utils
.brctl_cmd
, bridgename
))
2136 self
._cache
_update
([bridgename
], {})
2138 def delete_bridge(self
, bridgename
):
2139 if not LinkUtils
.bridge_utils_is_installed
:
2141 if not self
.bridge_exists(bridgename
):
2143 utils
.exec_command('%s delbr %s' % (utils
.brctl_cmd
, bridgename
))
2144 self
._cache
_invalidate
()
2146 def add_bridge_port(self
, bridgename
, bridgeportname
):
2147 """ Add port to bridge """
2148 if not LinkUtils
.bridge_utils_is_installed
:
2150 ports
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports'])
2151 if ports
and ports
.get(bridgeportname
):
2153 utils
.exec_command('%s addif %s %s' % (utils
.brctl_cmd
, bridgename
, bridgeportname
))
2154 self
._cache
_update
([bridgename
, 'linkinfo', 'ports', bridgeportname
], {})
2156 def delete_bridge_port(self
, bridgename
, bridgeportname
):
2157 """ Delete port from bridge """
2158 if not LinkUtils
.bridge_utils_is_installed
:
2160 ports
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports'])
2161 if not ports
or not ports
.get(bridgeportname
):
2163 utils
.exec_command('%s delif %s %s' % (utils
.brctl_cmd
, bridgename
, bridgeportname
))
2164 self
._cache
_delete
([bridgename
, 'linkinfo', 'ports', 'bridgeportname'])
2166 def set_bridgeport_attrs(self
, bridgename
, bridgeportname
, attrdict
):
2167 portattrs
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports', bridgeportname
])
2168 if portattrs
== None:
2170 for k
, v
in attrdict
.iteritems():
2171 if ifupdownflags
.flags
.CACHE
:
2172 curval
= portattrs
.get(k
)
2173 if curval
and curval
== v
:
2175 if k
== 'unicast-flood':
2176 self
.write_file('/sys/class/net/%s/brport/unicast_flood' % bridgeportname
, v
)
2177 elif k
== 'multicast-flood':
2178 self
.write_file('/sys/class/net/%s/brport/multicast_flood' % bridgeportname
, v
)
2179 elif k
== 'learning':
2180 self
.write_file('/sys/class/net/%s/brport/learning' % bridgeportname
, v
)
2181 elif k
== 'arp-nd-suppress':
2182 self
.write_file('/sys/class/net/%s/brport/neigh_suppress' % bridgeportname
, v
)
2184 if not LinkUtils
.bridge_utils_is_installed
:
2186 utils
.exec_command('%s set%s %s %s %s' % (utils
.brctl_cmd
, k
, bridgename
, bridgeportname
, v
))
2188 def set_bridgeport_attr(self
, bridgename
, bridgeportname
,
2190 if not LinkUtils
.bridge_utils_is_installed
:
2192 if self
._link
_cache
_check
([bridgename
, 'linkinfo', 'ports', bridgeportname
, attrname
], attrval
):
2194 utils
.exec_command('%s set%s %s %s %s' %
2201 def set_bridge_attrs(self
, bridgename
, attrdict
):
2202 for k
, v
in attrdict
.iteritems():
2205 if self
._link
_cache
_check
([bridgename
, 'linkinfo', k
], v
):
2208 if k
== 'igmp-version':
2209 self
.write_file('/sys/class/net/%s/bridge/'
2210 'multicast_igmp_version' % bridgename
, v
)
2211 elif k
== 'mld-version':
2212 self
.write_file('/sys/class/net/%s/bridge/'
2213 'multicast_mld_version' % bridgename
, v
)
2214 elif k
== 'vlan-protocol':
2215 self
.write_file('/sys/class/net/%s/bridge/'
2216 'vlan_protocol' % bridgename
,
2217 VlanProtocols
.ETHERTYPES_TO_ID
.get(v
.upper(),
2219 elif k
== 'vlan-stats':
2220 self
.write_file('/sys/class/net/%s/bridge/'
2221 'vlan_stats_enabled' % bridgename
, v
)
2222 elif k
== 'mcstats':
2223 self
.write_file('/sys/class/net/%s/bridge/'
2224 'multicast_stats_enabled' % bridgename
, v
)
2226 if not LinkUtils
.bridge_utils_is_installed
:
2228 cmd
= ('%s set%s %s %s' %
2229 (utils
.brctl_cmd
, k
, bridgename
, v
))
2230 utils
.exec_command(cmd
)
2231 except Exception, e
:
2232 self
.logger
.warn('%s: %s' % (bridgename
, str(e
)))
2235 def set_bridge_attr(self
, bridgename
, attrname
, attrval
):
2236 if self
._link
_cache
_check
([bridgename
, 'linkinfo', attrname
], attrval
):
2238 if attrname
== 'igmp-version':
2239 self
.write_file('/sys/class/net/%s/bridge/multicast_igmp_version'
2240 % bridgename
, attrval
)
2241 elif attrname
== 'mld-version':
2242 self
.write_file('/sys/class/net/%s/bridge/multicast_mld_version'
2243 % bridgename
, attrval
)
2244 elif attrname
== 'vlan-protocol':
2245 self
.write_file('/sys/class/net/%s/bridge/vlan_protocol'
2246 % bridgename
, VlanProtocols
.ETHERTYPES_TO_ID
[attrval
.upper()])
2247 elif attrname
== 'vlan-stats':
2248 self
.write_file('/sys/class/net/%s/bridge/vlan_stats_enabled'
2249 % bridgename
, attrval
)
2250 elif attrname
== 'mcstats':
2251 self
.write_file('/sys/class/net/%s/bridge/multicast_stats_enabled'
2252 % bridgename
, attrval
)
2254 if not LinkUtils
.bridge_utils_is_installed
:
2256 cmd
= '%s set%s %s %s' % (utils
.brctl_cmd
,
2257 attrname
, bridgename
, attrval
)
2258 utils
.exec_command(cmd
)
2260 def get_bridge_attrs(self
, bridgename
):
2261 attrs
= self
._link
_cache
_get
([bridgename
, 'linkinfo'])
2263 for key
, value
in attrs
.items():
2264 if type(key
) == str:
2265 no_ints_attrs
[key
] = value
2266 return no_ints_attrs
2268 def get_bridgeport_attrs(self
, bridgename
, bridgeportname
):
2269 return self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports',
2272 def get_bridgeport_attr(self
, bridgename
, bridgeportname
, attrname
):
2273 return self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports',
2274 bridgeportname
, attrname
])
2277 def bridge_set_stp(bridge
, stp_state
):
2278 if not LinkUtils
.bridge_utils_is_installed
:
2280 utils
.exec_command('%s stp %s %s' % (utils
.brctl_cmd
, bridge
, stp_state
))
2282 def bridge_get_stp(self
, bridge
):
2283 sysfs_stpstate
= '/sys/class/net/%s/bridge/stp_state' % bridge
2284 if not os
.path
.exists(sysfs_stpstate
):
2286 stpstate
= self
.read_file_oneline(sysfs_stpstate
)
2290 if int(stpstate
) > 0:
2292 elif int(stpstate
) == 0:
2298 def _conv_value_to_user(s
):
2305 def read_value_from_sysfs(self
, filename
, preprocess_func
):
2306 value
= self
.read_file_oneline(filename
)
2309 return preprocess_func(value
)
2312 def bridge_set_ageing(bridge
, ageing
):
2313 if not LinkUtils
.bridge_utils_is_installed
:
2315 utils
.exec_command('%s setageing %s %s' % (utils
.brctl_cmd
, bridge
, ageing
))
2317 def bridge_get_ageing(self
, bridge
):
2318 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/ageing_time'
2319 % bridge
, self
._conv
_value
_to
_user
)
2322 def set_bridgeprio(bridge
, prio
):
2323 if not LinkUtils
.bridge_utils_is_installed
:
2325 utils
.exec_command('%s setbridgeprio %s %s' % (utils
.brctl_cmd
, bridge
, prio
))
2327 def get_bridgeprio(self
, bridge
):
2328 return self
.read_file_oneline(
2329 '/sys/class/net/%s/bridge/priority' % bridge
)
2332 def bridge_set_fd(bridge
, fd
):
2333 if not LinkUtils
.bridge_utils_is_installed
:
2335 utils
.exec_command('%s setfd %s %s' % (utils
.brctl_cmd
, bridge
, fd
))
2337 def bridge_get_fd(self
, bridge
):
2338 return self
.read_value_from_sysfs(
2339 '/sys/class/net/%s/bridge/forward_delay'
2340 % bridge
, self
._conv
_value
_to
_user
)
2342 def bridge_set_gcint(self
, bridge
, gcint
):
2343 raise Exception('set_gcint not implemented')
2346 def bridge_set_hello(bridge
, hello
):
2347 if not LinkUtils
.bridge_utils_is_installed
:
2349 utils
.exec_command('%s sethello %s %s' % (utils
.brctl_cmd
, bridge
, hello
))
2351 def bridge_get_hello(self
, bridge
):
2352 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/hello_time'
2353 % bridge
, self
._conv
_value
_to
_user
)
2356 def bridge_set_maxage(bridge
, maxage
):
2357 if not LinkUtils
.bridge_utils_is_installed
:
2359 utils
.exec_command('%s setmaxage %s %s' % (utils
.brctl_cmd
, bridge
, maxage
))
2361 def bridge_get_maxage(self
, bridge
):
2362 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/max_age'
2363 % bridge
, self
._conv
_value
_to
_user
)
2366 def bridge_set_pathcost(bridge
, port
, pathcost
):
2367 if not LinkUtils
.bridge_utils_is_installed
:
2369 utils
.exec_command('%s setpathcost %s %s %s' % (utils
.brctl_cmd
, bridge
, port
, pathcost
))
2371 def bridge_get_pathcost(self
, bridge
, port
):
2372 return self
.read_file_oneline('/sys/class/net/%s/brport/path_cost'
2376 def bridge_set_portprio(bridge
, port
, prio
):
2377 if not LinkUtils
.bridge_utils_is_installed
:
2379 utils
.exec_command('%s setportprio %s %s %s' % (utils
.brctl_cmd
, bridge
, port
, prio
))
2381 def bridge_get_portprio(self
, bridge
, port
):
2382 return self
.read_file_oneline('/sys/class/net/%s/brport/priority'
2386 def bridge_set_hashmax(bridge
, hashmax
):
2387 if not LinkUtils
.bridge_utils_is_installed
:
2389 utils
.exec_command('%s sethashmax %s %s' % (utils
.brctl_cmd
, bridge
, hashmax
))
2391 def bridge_get_hashmax(self
, bridge
):
2392 return self
.read_file_oneline('/sys/class/net/%s/bridge/hash_max'
2396 def bridge_set_hashel(bridge
, hashel
):
2397 if not LinkUtils
.bridge_utils_is_installed
:
2399 utils
.exec_command('%s sethashel %s %s' % (utils
.brctl_cmd
, bridge
, hashel
))
2401 def bridge_get_hashel(self
, bridge
):
2402 return self
.read_file_oneline('/sys/class/net/%s/bridge/hash_elasticity'
2406 def bridge_set_mclmc(bridge
, mclmc
):
2407 if not LinkUtils
.bridge_utils_is_installed
:
2409 utils
.exec_command('%s setmclmc %s %s' % (utils
.brctl_cmd
, bridge
, mclmc
))
2411 def bridge_get_mclmc(self
, bridge
):
2412 return self
.read_file_oneline(
2413 '/sys/class/net/%s/bridge/multicast_last_member_count'
2417 def bridge_set_mcrouter(bridge
, mcrouter
):
2418 if not LinkUtils
.bridge_utils_is_installed
:
2420 utils
.exec_command('%s setmcrouter %s %s' % (utils
.brctl_cmd
, bridge
, mcrouter
))
2422 def bridge_get_mcrouter(self
, bridge
):
2423 return self
.read_file_oneline(
2424 '/sys/class/net/%s/bridge/multicast_router' % bridge
)
2427 def bridge_set_mcsnoop(bridge
, mcsnoop
):
2428 if not LinkUtils
.bridge_utils_is_installed
:
2430 utils
.exec_command('%s setmcsnoop %s %s' % (utils
.brctl_cmd
, bridge
, mcsnoop
))
2432 def bridge_get_mcsnoop(self
, bridge
):
2433 return self
.read_file_oneline(
2434 '/sys/class/net/%s/bridge/multicast_snooping' % bridge
)
2437 def bridge_set_mcsqc(bridge
, mcsqc
):
2438 if not LinkUtils
.bridge_utils_is_installed
:
2440 utils
.exec_command('%s setmcsqc %s %s' % (utils
.brctl_cmd
, bridge
, mcsqc
))
2442 def bridge_get_mcsqc(self
, bridge
):
2443 return self
.read_file_oneline(
2444 '/sys/class/net/%s/bridge/multicast_startup_query_count'
2448 def bridge_set_mcqifaddr(bridge
, mcqifaddr
):
2449 if not LinkUtils
.bridge_utils_is_installed
:
2451 utils
.exec_command('%s setmcqifaddr %s %s' % (utils
.brctl_cmd
, bridge
, mcqifaddr
))
2453 def bridge_get_mcqifaddr(self
, bridge
):
2454 return self
.read_file_oneline(
2455 '/sys/class/net/%s/bridge/multicast_startup_query_use_ifaddr'
2459 def bridge_set_mcquerier(bridge
, mcquerier
):
2460 if not LinkUtils
.bridge_utils_is_installed
:
2462 utils
.exec_command('%s setmcquerier %s %s' % (utils
.brctl_cmd
, bridge
, mcquerier
))
2464 def bridge_get_mcquerier(self
, bridge
):
2465 return self
.read_file_oneline(
2466 '/sys/class/net/%s/bridge/multicast_querier' % bridge
)
2468 def bridge_set_mcqv4src(self
, bridge
, vlan
, mcquerier
):
2472 self
.logger
.info('%s: set mcqv4src vlan: invalid parameter %s: %s' %(bridge
, vlan
, str(e
)))
2474 if vlan
== 0 or vlan
> 4095:
2475 self
.logger
.warn('mcqv4src vlan \'%d\' invalid range' % vlan
)
2478 ip
= mcquerier
.split('.')
2480 self
.logger
.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier
)
2483 if not k
.isdigit() or int(k
, 10) < 0 or int(k
, 10) > 255:
2484 self
.logger
.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier
)
2487 if not LinkUtils
.bridge_utils_is_installed
:
2490 utils
.exec_command('%s setmcqv4src %s %d %s' %
2491 (utils
.brctl_cmd
, bridge
, vlan
, mcquerier
))
2493 def bridge_del_mcqv4src(self
, bridge
, vlan
):
2494 if not LinkUtils
.bridge_utils_is_installed
:
2499 self
.logger
.info('%s: del mcqv4src vlan: invalid parameter %s: %s' %(bridge
, vlan
, str(e
)))
2501 utils
.exec_command('%s delmcqv4src %s %d' % (utils
.brctl_cmd
, bridge
, vlan
))
2503 def bridge_get_mcqv4src(self
, bridge
, vlan
=None):
2504 if not LinkUtils
.bridge_utils_is_installed
:
2506 if not self
.supported_command
['showmcqv4src']:
2510 mcqout
= utils
.exec_command('%s showmcqv4src %s' %
2511 (utils
.brctl_cmd
, bridge
))
2512 except Exception as e
:
2514 if 'never heard' in s
:
2515 msg
= ('%s showmcqv4src: skipping unsupported command'
2517 self
.logger
.info(msg
)
2518 self
.supported_command
['showmcqv4src'] = False
2523 mcqlines
= mcqout
.splitlines()
2524 for l
in mcqlines
[1:]:
2526 k
, d
, v
= l
.split('\t')
2531 return mcqv4src
.get(vlan
)
2535 def bridge_set_mclmi(bridge
, mclmi
):
2536 if not LinkUtils
.bridge_utils_is_installed
:
2538 utils
.exec_command('%s setmclmi %s %s' % (utils
.brctl_cmd
, bridge
, mclmi
))
2540 def bridge_get_mclmi(self
, bridge
):
2541 return self
.read_file_oneline(
2542 '/sys/class/net/%s/bridge/multicast_last_member_interval'
2546 def bridge_set_mcmi(bridge
, mcmi
):
2547 if not LinkUtils
.bridge_utils_is_installed
:
2549 utils
.exec_command('%s setmcmi %s %s' % (utils
.brctl_cmd
, bridge
, mcmi
))
2551 def bridge_get_mcmi(self
, bridge
):
2552 return self
.read_file_oneline(
2553 '/sys/class/net/%s/bridge/multicast_membership_interval'
2557 def bridge_exists(bridge
):
2558 return os
.path
.exists('/sys/class/net/%s/bridge' % bridge
)
2561 def is_bridge_port(ifacename
):
2562 return os
.path
.exists('/sys/class/net/%s/brport' % ifacename
)
2565 def bridge_port_exists(bridge
, bridgeportname
):
2567 return os
.path
.exists('/sys/class/net/%s/brif/%s' % (bridge
, bridgeportname
))
2572 def get_bridge_ports(bridgename
):
2574 return os
.listdir('/sys/class/net/%s/brif/' % bridgename
)
2578 def ipv6_addrgen(self
, ifname
, addrgen
):
2579 cmd
= 'link set dev %s addrgenmode %s' % (ifname
, 'eui64' if addrgen
else 'none')
2581 is_link_up
= self
.is_link_up(ifname
)
2584 self
.link_down(ifname
)
2586 if LinkUtils
.ipbatch
:
2587 self
.add_to_batch(cmd
)
2589 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
2592 self
.link_up(ifname
)