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 linkattrs
['linkinfo'] = vattrs
556 elif citems
[i
] == 'vrf' and citems
[i
+ 1] == 'table':
557 vattrs
= {'table': citems
[i
+ 2]}
558 linkattrs
['linkinfo'] = vattrs
559 linkattrs
['kind'] = 'vrf'
560 linkCache
.vrfs
[ifname
] = vattrs
562 elif citems
[i
] == 'veth':
563 linkattrs
['kind'] = 'veth'
564 elif citems
[i
] == 'vrf_slave':
565 linkattrs
['slave_kind'] = 'vrf_slave'
567 elif citems
[i
] == 'macvlan' and citems
[i
+ 1] == 'mode':
568 linkattrs
['kind'] = 'macvlan'
569 except Exception as e
:
571 self
.logger
.debug('%s: parsing error: id, mtu, state, '
572 'link/ether, vlan, dummy, vxlan, local, '
573 'remote, ageing, nolearning, vrf, table, '
574 'vrf_slave are reserved keywords: %s' %
577 # linkattrs['alias'] = self.read_file_oneline(
578 # '/sys/class/net/%s/ifalias' %ifname)
579 linkout
[ifname
] = linkattrs
580 [linkCache
.update_attrdict([ifname
], linkattrs
)
581 for ifname
, linkattrs
in linkout
.items()]
584 def _addr_filter(ifname
, addr
, scope
=None):
585 default_addrs
= ['127.0.0.1/8', '::1/128', '0.0.0.0']
586 if ifname
== 'lo' and addr
in default_addrs
:
588 if scope
and scope
== 'link':
592 def _addr_fill(self
, ifacename
=None, refresh
=False):
593 """ fills cache with address information
595 if ifacename argument given, fill cache for ifacename, else
596 fill cache for all interfaces in the system
598 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
601 # Check if ifacename is already full, in which case, return
602 if ifacename
and not refresh
:
603 linkCache
.get_attr([ifacename
, 'addrs'])
610 [linkCache
.update_attrdict([ifname
], linkattrs
)
611 for ifname
, linkattrs
in netlink
.addr_dump(ifname
=ifacename
).items()]
612 except Exception as e
:
613 self
.logger
.info(str(e
))
615 # this netlink call replaces the call to _addr_fill_iproute2_cmd()
616 # We shouldn't have netlink calls in the iproute2 module, this will
617 # be removed in the future. We plan to release, a flexible backend
618 # (netlink+iproute2) by default we will use netlink backend but with
619 # a CLI arg we can switch to iproute2 backend.
620 # Until we decide to create this "backend" switch capability,
621 # we have to put the netlink call inside the iproute2 module.
624 self
._addr
_fill
_iproute
2_cmd
(ifacename
, refresh
)
626 def _addr_fill_iproute2_cmd(self
, ifacename
=None, refresh
=False):
627 """ fills cache with address information
629 if ifacename argument given, fill cache for ifacename, else
630 fill cache for all interfaces in the system
633 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
636 # Check if ifacename is already full, in which case, return
637 if ifacename
and not refresh
:
638 linkCache
.get_attr([ifacename
, 'addrs'])
642 cmdout
= self
.addr_show(ifacename
=ifacename
)
645 for c
in cmdout
.splitlines():
647 ifnamenlink
= citems
[1].split('@')
648 if len(ifnamenlink
) > 1:
649 ifname
= ifnamenlink
[0]
651 ifname
= ifnamenlink
[0].strip(':')
652 if not linkout
.get(ifname
):
654 linkattrs
['addrs'] = OrderedDict({})
656 linkout
[ifname
].update(linkattrs
)
658 linkout
[ifname
] = linkattrs
659 if citems
[2] == 'inet':
660 if self
._addr
_filter
(ifname
, citems
[3], scope
=citems
[5]):
663 addrattrs
['scope'] = citems
[5]
664 addrattrs
['type'] = 'inet'
665 linkout
[ifname
]['addrs'][citems
[3]] = addrattrs
666 elif citems
[2] == 'inet6':
667 if self
._addr
_filter
(ifname
, citems
[3], scope
=citems
[5]):
669 if citems
[5] == 'link':
670 continue # skip 'link' addresses
672 addrattrs
['scope'] = citems
[5]
673 addrattrs
['type'] = 'inet6'
674 linkout
[ifname
]['addrs'][citems
[3]] = addrattrs
675 [linkCache
.update_attrdict([ifname
], linkattrs
)
676 for ifname
, linkattrs
in linkout
.items()]
678 def cache_get(self
, t
, attrlist
, refresh
=False):
679 return self
._cache
_get
(t
, attrlist
, refresh
)
681 def _cache_get(self
, t
, attrlist
, refresh
=False):
683 if ifupdownflags
.flags
.DRYRUN
:
685 if ifupdownflags
.flags
.CACHE
:
686 if self
._fill
_cache
():
687 # if we filled the cache, return new data
688 return linkCache
.get_attr(attrlist
)
690 return linkCache
.get_attr(attrlist
)
692 self
._link
_fill
(attrlist
[0], refresh
)
694 self
._addr
_fill
(attrlist
[0], refresh
)
696 self
._link
_fill
(attrlist
[0], refresh
)
697 self
._addr
_fill
(attrlist
[0], refresh
)
698 return linkCache
.get_attr(attrlist
)
700 self
.logger
.debug('_cache_get(%s) : [%s]' % (str(attrlist
), str(e
)))
703 def cache_check(self
, attrlist
, value
, refresh
=False):
704 return self
._cache
_check
('link', attrlist
, value
, refresh
=refresh
)
706 def _cache_check(self
, t
, attrlist
, value
, refresh
=False):
708 return self
._cache
_get
(t
, attrlist
, refresh
) == value
710 self
.logger
.debug('_cache_check(%s) : [%s]'
711 % (str(attrlist
), str(e
)))
714 def cache_update(self
, attrlist
, value
):
715 return self
._cache
_update
(attrlist
, value
)
718 def _cache_update(attrlist
, value
):
719 if ifupdownflags
.flags
.DRYRUN
:
722 if attrlist
[-1] == 'slaves':
723 linkCache
.append_to_attrlist(attrlist
, value
)
725 linkCache
.set_attr(attrlist
, value
)
730 def _cache_delete(attrlist
, value
=None):
731 if ifupdownflags
.flags
.DRYRUN
:
735 linkCache
.remove_from_attrlist(attrlist
, value
)
737 linkCache
.del_attr(attrlist
)
742 def _cache_invalidate():
743 linkCache
.invalidate()
744 LinkUtils
._CACHE
_FILL
_DONE
= False
748 LinkUtils
.ipbatcbuf
= ''
749 LinkUtils
.ipbatch
= True
750 LinkUtils
.ipbatch_pause
= False
753 def add_to_batch(cmd
):
754 LinkUtils
.ipbatchbuf
+= cmd
+ '\n'
758 LinkUtils
.ipbatch_pause
= True
762 LinkUtils
.ipbatch_pause
= False
764 def batch_commit(self
):
765 if not LinkUtils
.ipbatchbuf
:
766 LinkUtils
.ipbatchbuf
= ''
767 LinkUtils
.ipbatch
= False
768 LinkUtils
.ipbatch_pause
= False
771 utils
.exec_command('%s -force -batch -' % utils
.ip_cmd
,
772 stdin
=self
.ipbatchbuf
)
776 LinkUtils
.ipbatchbuf
= ''
777 LinkUtils
.ipbatch
= False
778 LinkUtils
.ipbatch_pause
= False
780 def bridge_batch_commit(self
):
781 if not LinkUtils
.ipbatchbuf
:
782 LinkUtils
.ipbatchbuf
= ''
783 LinkUtils
.ipbatch
= False
784 LinkUtils
.ipbatch_pause
= False
787 utils
.exec_command('%s -force -batch -'
788 % utils
.bridge_cmd
, stdin
=self
.ipbatchbuf
)
792 LinkUtils
.ipbatchbuf
= ''
793 LinkUtils
.ipbatch
= False
794 LinkUtils
.ipbatch_pause
= False
796 def addr_show(self
, ifacename
=None):
798 if not self
.link_exists(ifacename
):
800 return utils
.exec_commandl([utils
.ip_cmd
,
801 '-o', 'addr', 'show', 'dev', ifacename
])
803 return utils
.exec_commandl([utils
.ip_cmd
,
804 '-o', 'addr', 'show'])
807 def link_show(ifacename
=None):
809 return utils
.exec_commandl([utils
.ip_cmd
,
810 '-o', '-d', 'link', 'show', 'dev', ifacename
])
812 return utils
.exec_commandl([utils
.ip_cmd
,
813 '-o', '-d', 'link', 'show'])
815 def addr_add(self
, ifacename
, address
, broadcast
=None,
816 peer
=None, scope
=None, preferred_lifetime
=None, metric
=None):
819 cmd
= 'addr add %s' % address
821 cmd
+= ' broadcast %s' % broadcast
823 cmd
+= ' peer %s' % peer
825 cmd
+= ' scope %s' % scope
826 if preferred_lifetime
:
827 cmd
+= ' preferred_lft %s' % preferred_lifetime
828 cmd
+= ' dev %s' % ifacename
831 cmd
+= ' metric %s' % metric
833 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
834 self
.add_to_batch(cmd
)
836 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
837 self
._cache
_update
([ifacename
, 'addrs', address
], {})
839 def addr_del(self
, ifacename
, address
, broadcast
=None,
840 peer
=None, scope
=None):
841 """ Delete ipv4 address """
844 if not self
._cache
_get
('addr', [ifacename
, 'addrs', address
]):
846 cmd
= 'addr del %s' % address
848 cmd
+= 'broadcast %s' % broadcast
850 cmd
+= 'peer %s' % peer
852 cmd
+= 'scope %s' % scope
853 cmd
+= ' dev %s' % ifacename
854 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
855 self
._cache
_delete
([ifacename
, 'addrs', address
])
857 def addr_flush(self
, ifacename
):
858 cmd
= 'addr flush dev %s' % ifacename
859 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
860 self
.add_to_batch(cmd
)
862 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
863 self
._cache
_delete
([ifacename
, 'addrs'])
865 def del_addr_all(self
, ifacename
, skip_addrs
=[]):
868 runningaddrsdict
= self
.get_running_addrs(ifname
=ifacename
)
870 # XXX: ignore errors. Fix this to delete secondary addresses
872 [self
.addr_del(ifacename
, a
) for a
in
873 set(runningaddrsdict
.keys()).difference(skip_addrs
)]
878 def addr_get(self
, ifacename
, details
=True, refresh
=False):
879 addrs
= self
._cache
_get
('addr', [ifacename
, 'addrs'], refresh
=refresh
)
886 def get_running_addrs(self
, ifaceobj
=None, ifname
=None, details
=True, addr_virtual_ifaceobj
=None):
888 We now support addr with link scope. Since the kernel may add it's
889 own link address to some interfaces we need to filter them out and
890 make sure we only deal with the addresses set by ifupdown2.
892 To do so we look at the previous configuration made by ifupdown2
893 (with the help of the statemanager) together with the addresses
894 specified by the user in /etc/network/interfaces, these addresses
895 are then compared to the running state of the intf (ip addr show)
896 made via a netlink addr dump.
897 For each configured addresses of scope link, we check if it was
898 previously configured by ifupdown2 to create a final set of the
899 addresses watched by ifupdown2
901 if not ifaceobj
and not ifname
:
907 interface_name
= ifaceobj
.name
909 interface_name
= ifname
911 if addr_virtual_ifaceobj
:
912 for virtual
in addr_virtual_ifaceobj
.get_attr_value('address-virtual') or []:
913 for ip
in virtual
.split():
920 saved_ifaceobjs
= statemanager
.statemanager_api
.get_ifaceobjs(addr_virtual_ifaceobj
.name
)
921 for saved_ifaceobj
in saved_ifaceobjs
or []:
922 for virtual
in saved_ifaceobj
.get_attr_value('address-virtual') or []:
923 for ip
in virtual
.split():
931 for addr
in ifaceobj
.get_attr_value('address') or []:
932 config_addrs
.add(addr
)
934 saved_ifaceobjs
= statemanager
.statemanager_api
.get_ifaceobjs(interface_name
)
935 for saved_ifaceobj
in saved_ifaceobjs
or []:
936 for addr
in saved_ifaceobj
.get_attr_value('address') or []:
937 config_addrs
.add(addr
)
939 running_addrs
= OrderedDict()
940 cached_addrs
= self
.addr_get(interface_name
)
942 for addr
, addr_details
in cached_addrs
.items():
944 scope
= int(addr_details
['scope'])
948 addr_obj
= IPNetwork(addr
)
949 if isinstance(addr_obj
, IPv6Network
):
950 d
['family'] = 'inet6'
953 running_addrs
[addr
] = d
955 running_addrs
[addr
] = {}
957 if (scope
& Route
.RT_SCOPE_LINK
and addr
in config_addrs
) or not scope
& Route
.RT_SCOPE_LINK
:
958 running_addrs
[addr
] = addr_details
964 return running_addrs
.keys()
967 def compare_user_config_vs_running_state(running_addrs
, user_addrs
):
971 for ip
in user_addrs
or []:
974 if type(obj
) == IPv6Network
:
980 for ip
in running_addrs
or []:
981 running_ipobj
.append(IPNetwork(ip
))
983 return running_ipobj
== (ip4
+ ip6
)
985 def addr_add_multiple(self
, ifaceobj
, ifacename
, addrs
, purge_existing
=False, metric
=None):
988 # if perfmode is not set and also if iface has no sibling
989 # objects, purge addresses that are not present in the new
991 runningaddrs
= self
.get_running_addrs(
994 addr_virtual_ifaceobj
=ifaceobj
996 addrs
= utils
.get_normalized_ip_addr(ifacename
, addrs
)
998 if self
.compare_user_config_vs_running_state(runningaddrs
, addrs
):
1001 # if primary address is not same, there is no need to keep any.
1002 # reset all addresses
1003 if (addrs
and runningaddrs
and
1004 (addrs
[0] != runningaddrs
[0])):
1005 self
.del_addr_all(ifacename
)
1007 self
.del_addr_all(ifacename
, addrs
)
1008 except Exception, e
:
1009 self
.logger
.warning('%s: %s' % (ifacename
, str(e
)))
1012 self
.addr_add(ifacename
, a
, metric
=metric
)
1013 except Exception, e
:
1014 self
.logger
.error(str(e
))
1016 def _link_set_ifflag(self
, ifacename
, value
):
1017 # Dont look at the cache, the cache may have stale value
1018 # because link status can be changed by external
1019 # entity (One such entity is ifupdown main program)
1020 cmd
= 'link set dev %s %s' % (ifacename
, value
.lower())
1021 if LinkUtils
.ipbatch
:
1022 self
.add_to_batch(cmd
)
1024 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1026 def link_up(self
, ifacename
):
1027 self
._link
_set
_ifflag
(ifacename
, 'UP')
1029 def link_down(self
, ifacename
):
1030 self
._link
_set
_ifflag
(ifacename
, 'DOWN')
1032 def link_set(self
, ifacename
, key
, value
=None,
1033 force
=False, t
=None, state
=None):
1035 if (key
not in ['master', 'nomaster'] and
1036 self
._cache
_check
('link', [ifacename
, key
], value
)):
1038 cmd
= 'link set dev %s' % ifacename
1040 cmd
+= ' type %s' % t
1043 cmd
+= ' %s' % value
1045 cmd
+= ' %s' % state
1046 if LinkUtils
.ipbatch
:
1047 self
.add_to_batch(cmd
)
1049 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1050 if key
not in ['master', 'nomaster']:
1051 self
._cache
_update
([ifacename
, key
], value
)
1053 def link_set_hwaddress(self
, ifacename
, hwaddress
, force
=False):
1055 if self
._cache
_check
('link', [ifacename
, 'hwaddress'], hwaddress
):
1057 self
.link_down(ifacename
)
1058 cmd
= 'link set dev %s address %s' % (ifacename
, hwaddress
)
1059 if LinkUtils
.ipbatch
:
1060 self
.add_to_batch(cmd
)
1062 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1063 self
.link_up(ifacename
)
1064 self
._cache
_update
([ifacename
, 'hwaddress'], hwaddress
)
1066 def link_set_mtu(self
, ifacename
, mtu
):
1067 if ifupdownflags
.flags
.DRYRUN
:
1069 if not mtu
or not ifacename
: return
1070 self
.write_file('/sys/class/net/%s/mtu' % ifacename
, mtu
)
1071 self
._cache
_update
([ifacename
, 'mtu'], mtu
)
1073 def link_set_alias(self
, ifacename
, alias
):
1074 self
.write_file('/sys/class/net/%s/ifalias' % ifacename
,
1075 '\n' if not alias
else alias
)
1077 def link_get_alias(self
, ifacename
):
1078 return self
.read_file_oneline('/sys/class/net/%s/ifalias'
1081 def link_isloopback(self
, ifacename
):
1082 flags
= self
._cache
_get
('link', [ifacename
, 'flags'])
1085 if 'LOOPBACK' in flags
:
1089 def link_get_status(self
, ifacename
):
1090 return self
._cache
_get
('link', [ifacename
, 'ifflag'], refresh
=True)
1093 def route_add_gateway(ifacename
, gateway
, vrf
=None, metric
=None):
1097 cmd
= '%s route add default via %s proto kernel' % (utils
.ip_cmd
,
1100 cmd
= ('%s route add table %s default via %s proto kernel' %
1101 (utils
.ip_cmd
, vrf
, gateway
))
1104 cmd
+= 'metric %s' % metric
1105 cmd
+= ' dev %s' % ifacename
1106 utils
.exec_command(cmd
)
1109 def route_del_gateway(ifacename
, gateway
, vrf
=None, metric
=None):
1114 cmd
= ('%s route del default via %s proto kernel' %
1115 (utils
.ip_cmd
, gateway
))
1117 cmd
= ('%s route del table %s default via %s proto kernel' %
1118 (utils
.ip_cmd
, vrf
, gateway
))
1120 cmd
+= ' metric %s' % metric
1121 cmd
+= ' dev %s' % ifacename
1122 utils
.exec_command(cmd
)
1125 def _get_vrf_id(ifacename
):
1127 return linkCache
.vrfs
[ifacename
]['table']
1129 dump
= netlink
.link_dump(ifacename
)
1131 [linkCache
.update_attrdict([ifname
], linkattrs
)
1132 for ifname
, linkattrs
in dump
.items()]
1134 if dump
and dump
.get(ifacename
, {}).get('kind') == 'vrf':
1135 vrf_table
= dump
.get(ifacename
, {}).get('linkinfo', {}).get('table')
1136 linkCache
.vrfs
[ifacename
] = {'table': vrf_table
}
1141 def fix_ipv6_route_metric(self
, ifaceobj
, macvlan_ifacename
, ips
):
1144 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
:
1146 for upper_iface
in ifaceobj
.upperifaces
:
1147 vrf_table
= self
._get
_vrf
_id
(upper_iface
)
1155 ip_network_obj
= IPNetwork(ip
)
1157 if type(ip_network_obj
) == IPv6Network
:
1158 route_prefix
= '%s/%d' % (ip_network_obj
.network
, ip_network_obj
.prefixlen
)
1161 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1162 LinkUtils
.add_to_batch('route del %s table %s dev %s' % (route_prefix
, vrf_table
, macvlan_ifacename
))
1164 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'del', route_prefix
, 'table', vrf_table
, 'dev', macvlan_ifacename
])
1166 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1167 LinkUtils
.add_to_batch('route del %s dev %s' % (route_prefix
, macvlan_ifacename
))
1169 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'del', route_prefix
, 'dev', macvlan_ifacename
])
1170 ip_route_del
.append((route_prefix
, vrf_table
))
1172 for ip
, vrf_table
in ip_route_del
:
1174 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1175 LinkUtils
.add_to_batch('route add %s table %s dev %s proto kernel metric 9999' % (ip
, vrf_table
, macvlan_ifacename
))
1177 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'add', ip
, 'table', vrf_table
, 'dev', macvlan_ifacename
, 'proto', 'kernel' 'metric', '9999'])
1179 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1180 LinkUtils
.add_to_batch('route add %s dev %s proto kernel metric 9999' % (ip
, macvlan_ifacename
))
1182 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'add', ip
, 'dev', macvlan_ifacename
, 'proto', 'kernel' 'metric', '9999'])
1184 def link_create_vlan(self
, vlan_device_name
, vlan_raw_device
, vlanid
):
1185 if self
.link_exists(vlan_device_name
):
1187 utils
.exec_command('%s link add link %s name %s type vlan id %d' %
1189 vlan_raw_device
, vlan_device_name
, vlanid
))
1190 self
._cache
_update
([vlan_device_name
], {})
1192 def link_create_vlan_from_name(self
, vlan_device_name
):
1193 v
= vlan_device_name
.split('.')
1195 self
.logger
.warn('invalid vlan device name %s' % vlan_device_name
)
1197 self
.link_create_vlan(vlan_device_name
, v
[0], v
[1])
1199 def link_create_macvlan(self
, name
, linkdev
, mode
='private'):
1200 if self
.link_exists(name
):
1202 cmd
= ('link add link %s' % linkdev
+
1204 ' type macvlan mode %s' % mode
)
1205 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1206 self
.add_to_batch(cmd
)
1208 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1209 self
._cache
_update
([name
], {})
1211 def get_vxlan_peers(self
, dev
, svcnodeip
):
1212 cmd
= '%s fdb show brport %s' % (utils
.bridge_cmd
,
1216 ps
= subprocess
.Popen(shlex
.split(cmd
), stdout
=subprocess
.PIPE
, close_fds
=False)
1217 utils
.enable_subprocess_signal_forwarding(ps
, signal
.SIGINT
)
1218 output
= subprocess
.check_output(('grep', '00:00:00:00:00:00'), stdin
=ps
.stdout
)
1220 utils
.disable_subprocess_signal_forwarding(signal
.SIGINT
)
1222 ppat
= re
.compile('\s+dst\s+(\d+.\d+.\d+.\d+)\s+')
1223 for l
in output
.split('\n'):
1225 if m
and m
.group(1) != svcnodeip
:
1226 cur_peers
.append(m
.group(1))
1228 self
.logger
.warn('error parsing ip link output')
1229 except subprocess
.CalledProcessError
as e
:
1230 if e
.returncode
!= 1:
1231 self
.logger
.error(str(e
))
1233 utils
.disable_subprocess_signal_forwarding(signal
.SIGINT
)
1237 def link_create_vxlan(self
, name
, vxlanid
,
1244 if svcnodeip
and remoteips
:
1245 raise Exception("svcnodeip and remoteip is mutually exclusive")
1248 args
+= ' remote %s' % svcnodeip
1250 args
+= ' ageing %s' % ageing
1251 if learning
== 'off':
1252 args
+= ' nolearning'
1254 if self
.link_exists(name
):
1255 cmd
= 'link set dev %s type vxlan dstport %d' % (name
, LinkUtils
.VXLAN_UDP_PORT
)
1256 vxlanattrs
= self
.get_vxlandev_attrs(name
)
1257 # on ifreload do not overwrite anycast_ip to individual ip if clagd
1260 running_localtunnelip
= vxlanattrs
.get('local')
1261 if anycastip
and running_localtunnelip
and anycastip
== running_localtunnelip
:
1262 localtunnelip
= running_localtunnelip
1263 running_svcnode
= vxlanattrs
.get('svcnode')
1264 if running_svcnode
and not svcnodeip
:
1267 cmd
= 'link add dev %s type vxlan id %s dstport %d' % (name
, vxlanid
, LinkUtils
.VXLAN_UDP_PORT
)
1270 args
+= ' local %s' % localtunnelip
1273 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1274 self
.add_to_batch(cmd
)
1276 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1278 # XXX: update linkinfo correctly
1279 #self._cache_update([name], {})
1282 def link_exists(ifacename
):
1283 if ifupdownflags
.flags
.DRYRUN
:
1285 return os
.path
.exists('/sys/class/net/%s' % ifacename
)
1287 def link_get_ifindex(self
, ifacename
):
1288 if ifupdownflags
.flags
.DRYRUN
:
1290 return self
.read_file_oneline('/sys/class/net/%s/ifindex' % ifacename
)
1292 def is_vlan_device_by_name(self
, ifacename
):
1293 if re
.search(r
'\.', ifacename
):
1298 def link_add_macvlan(ifname
, macvlan_ifacename
):
1299 utils
.exec_commandl(['ip', 'link', 'add', 'link', ifname
, 'name', macvlan_ifacename
, 'type', 'macvlan', 'mode', 'private'])
1302 def route_add(route
):
1303 utils
.exec_command('%s route add %s' % (utils
.ip_cmd
,
1307 def route6_add(route
):
1308 utils
.exec_command('%s -6 route add %s' % (utils
.ip_cmd
,
1311 def get_vlandev_attrs(self
, ifacename
):
1312 return (self
._cache
_get
('link', [ifacename
, 'link']),
1313 self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlanid']),
1314 self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlan_protocol']))
1316 def get_vlan_protocol(self
, ifacename
):
1317 return self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlan_protocol'])
1319 def get_vxlandev_attrs(self
, ifacename
):
1320 return self
._cache
_get
('link', [ifacename
, 'linkinfo'])
1322 def get_vxlandev_learning(self
, ifacename
):
1323 return self
._cache
_get
('link', [ifacename
, 'linkinfo', Link
.IFLA_VXLAN_LEARNING
])
1325 def set_vxlandev_learning(self
, ifacename
, learn
):
1327 utils
.exec_command('%s link set dev %s type vxlan learning' %
1328 (utils
.ip_cmd
, ifacename
))
1329 self
._cache
_update
([ifacename
, 'linkinfo', 'learning'], 'on')
1331 utils
.exec_command('%s link set dev %s type vxlan nolearning' %
1332 (utils
.ip_cmd
, ifacename
))
1333 self
._cache
_update
([ifacename
, 'linkinfo', 'learning'], 'off')
1335 def link_get_linkinfo_attrs(self
, ifacename
):
1336 return self
._cache
_get
('link', [ifacename
, 'linkinfo'])
1338 def link_get_mtu(self
, ifacename
, refresh
=False):
1339 return self
._cache
_get
('link', [ifacename
, 'mtu'], refresh
=refresh
)
1341 def link_get_mtu_sysfs(self
, ifacename
):
1342 return self
.read_file_oneline('/sys/class/net/%s/mtu'
1345 def link_get_kind(self
, ifacename
):
1346 return self
._cache
_get
('link', [ifacename
, 'kind'])
1348 def link_get_slave_kind(self
, ifacename
):
1349 return self
._cache
_get
('link', [ifacename
, 'slave_kind'])
1351 def link_get_hwaddress(self
, ifacename
):
1352 address
= self
._cache
_get
('link', [ifacename
, 'hwaddress'])
1353 # newly created logical interface addresses dont end up in the cache
1354 # read hwaddress from sysfs file for these interfaces
1356 address
= self
.read_file_oneline('/sys/class/net/%s/address'
1360 def link_create(self
, ifacename
, t
, attrs
={}):
1361 """ generic link_create function """
1362 if self
.link_exists(ifacename
):
1365 cmd
+= ' name %s type %s' % (ifacename
, t
)
1367 for k
, v
in attrs
.iteritems():
1371 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1372 self
.add_to_batch(cmd
)
1374 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1375 self
._cache
_update
([ifacename
], {})
1377 def link_delete(self
, ifacename
):
1378 if not self
.link_exists(ifacename
):
1380 cmd
= 'link del %s' % ifacename
1381 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1382 self
.add_to_batch(cmd
)
1384 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1385 self
._cache
_invalidate
()
1387 def link_get_master(self
, ifacename
):
1388 sysfs_master_path
= '/sys/class/net/%s/master' % ifacename
1389 if os
.path
.exists(sysfs_master_path
):
1390 link_path
= os
.readlink(sysfs_master_path
)
1392 return os
.path
.basename(link_path
)
1396 return self
._cache
_get
('link', [ifacename
, 'master'])
1398 def get_brport_peer_link(self
, bridgename
):
1400 return self
._cache
_get
('link', [bridgename
, 'info_slave_data', Link
.IFLA_BRPORT_PEER_LINK
])
1405 def bridge_port_vids_add(bridgeportname
, vids
):
1406 [utils
.exec_command('%s vlan add vid %s dev %s' %
1408 v
, bridgeportname
)) for v
in vids
]
1411 def bridge_port_vids_del(bridgeportname
, vids
):
1414 [utils
.exec_command('%s vlan del vid %s dev %s' %
1416 v
, bridgeportname
)) for v
in vids
]
1419 def bridge_port_vids_flush(bridgeportname
, vid
):
1420 utils
.exec_command('%s vlan del vid %s dev %s' %
1422 vid
, bridgeportname
))
1425 def bridge_port_vids_get(bridgeportname
):
1426 bridgeout
= utils
.exec_command('%s vlan show dev %s' %
1431 brvlanlines
= bridgeout
.readlines()[2:]
1432 vids
= [l
.strip() for l
in brvlanlines
]
1433 return [v
for v
in vids
if v
]
1436 def bridge_port_vids_get_all():
1438 bridgeout
= utils
.exec_command('%s -c vlan show'
1442 brvlanlines
= bridgeout
.splitlines()
1444 for l
in brvlanlines
[1:]:
1445 if l
and not l
.startswith(' ') and not l
.startswith('\t'):
1447 brportname
= attrs
[0].strip()
1448 brvlaninfo
[brportname
] = {'pvid': None, 'vlan': []}
1449 l
= ' '.join(attrs
[1:])
1450 if not brportname
or not l
:
1454 brvlaninfo
[brportname
]['pvid'] = l
.split()[0]
1455 elif 'Egress Untagged' not in l
:
1456 brvlaninfo
[brportname
]['vlan'].append(l
)
1459 def bridge_port_vids_get_all_json(self
):
1460 if not self
.supported_command
['%s -c -json vlan show'
1461 % utils
.bridge_cmd
]:
1465 bridgeout
= utils
.exec_command('%s -c -json vlan show'
1468 self
.supported_command
['%s -c -json vlan show'
1469 % utils
.bridge_cmd
] = False
1470 self
.logger
.info('%s -c -json vlan show: skipping unsupported command'
1473 return self
.get_bridge_vlan_nojson()
1474 except Exception as e
:
1475 self
.logger
.info('bridge: get_bridge_vlan_nojson: %s' % str(e
))
1478 if not bridgeout
: return brvlaninfo
1480 vlan_json_dict
= json
.loads(bridgeout
, encoding
="utf-8")
1481 except Exception, e
:
1482 self
.logger
.info('json loads failed with (%s)' % str(e
))
1484 return vlan_json_dict
1487 def get_bridge_vlan_nojson():
1489 bridgeout
= utils
.exec_commandl([utils
.bridge_cmd
, '-c', 'vlan', 'show'])
1491 output
= [line
.split('\n') for line
in bridgeout
.split('\n\n')]
1492 output
[0] = output
[0][1:]
1500 prefix
, vlan
= entry
.split('\t')
1502 current_swp
= prefix
1503 vlan_json
[prefix
] = []
1507 v
['vlan'] = int(vlan
)
1511 start
, end
= vlan
.split('-')
1513 end
= end
[0:end
.index(' ')]
1514 v
['vlan'] = int(start
)
1515 v
['vlanEnd'] = int(end
)
1517 v
['vlan'] = int(vlan
[0:vlan
.index(' ')])
1520 flags
.append('PVID')
1521 if 'Egress Untagged' in vlan
:
1522 flags
.append('Egress Untagged')
1526 vlan_json
[current_swp
].append(v
)
1529 def bridge_vlan_cache_get(self
, ifacename
, refresh
=False):
1530 if not self
.bridge_vlan_cache_fill_done
or refresh
:
1531 self
.bridge_vlan_cache
= self
.bridge_port_vids_get_all_json()
1532 self
.bridge_vlan_cache_fill_done
= True
1533 return self
.bridge_vlan_cache
.get(ifacename
, {})
1535 def bridge_vlan_get_pvid(self
, ifacename
, refresh
=False):
1538 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1539 v
= vinfo
.get('vlan')
1540 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1545 def bridge_vlan_get_vids(self
, ifacename
, refresh
=False):
1548 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1549 v
= vinfo
.get('vlan')
1550 ispvid
= True if 'PVID' in vinfo
.get('flags', []) else False
1552 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1555 vEnd
= vinfo
.get('vlanEnd')
1557 vids
.extend(range(v
, vEnd
+ 1))
1562 def bridge_vlan_get_vids_n_pvid(self
, ifacename
, refresh
=False):
1566 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1567 v
= vinfo
.get('vlan')
1568 ispvid
= True if 'PVID' in vinfo
.get('flags', []) else False
1570 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1571 vEnd
= vinfo
.get('vlanEnd')
1573 vids
.extend(range(v
, vEnd
+ 1))
1578 def bridge_port_pvid_add(self
, bridgeportname
, pvid
):
1579 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1580 self
.add_to_batch('vlan add vid %s untagged pvid dev %s' %
1581 (pvid
, bridgeportname
))
1583 utils
.exec_command('%s vlan add vid %s untagged pvid dev %s' %
1585 pvid
, bridgeportname
))
1587 def bridge_port_pvid_del(self
, bridgeportname
, pvid
):
1588 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1589 self
.add_to_batch('vlan del vid %s untagged pvid dev %s' %
1590 (pvid
, bridgeportname
))
1592 utils
.exec_command('%s vlan del vid %s untagged pvid dev %s' %
1594 pvid
, bridgeportname
))
1596 def bridge_port_pvids_get(self
, bridgeportname
):
1597 return self
.read_file_oneline('/sys/class/net/%s/brport/pvid'
1600 def bridge_vids_add(self
, bridgeportname
, vids
, bridge
=True):
1601 target
= 'self' if bridge
else ''
1602 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1603 [self
.add_to_batch('vlan add vid %s dev %s %s' %
1604 (v
, bridgeportname
, target
)) for v
in vids
]
1606 [utils
.exec_command('%s vlan add vid %s dev %s %s' %
1608 v
, bridgeportname
, target
)) for v
in vids
]
1610 def bridge_vids_del(self
, bridgeportname
, vids
, bridge
=True):
1611 target
= 'self' if bridge
else ''
1612 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1613 [self
.add_to_batch('vlan del vid %s dev %s %s' %
1614 (v
, bridgeportname
, target
)) for v
in vids
]
1616 [utils
.exec_command('%s vlan del vid %s dev %s %s' %
1618 v
, bridgeportname
, target
)) for v
in vids
]
1621 def bridge_fdb_add(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1622 target
= 'self' if bridge
else ''
1625 vlan_str
= 'vlan %s ' % vlan
1629 dst_str
= 'dst %s ' % remote
1631 utils
.exec_command('%s fdb replace %s dev %s %s %s %s' %
1633 address
, dev
, vlan_str
, target
, dst_str
))
1636 def bridge_fdb_append(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1637 target
= 'self' if bridge
else ''
1640 vlan_str
= 'vlan %s ' % vlan
1644 dst_str
= 'dst %s ' % remote
1646 utils
.exec_command('%s fdb append %s dev %s %s %s %s' %
1648 address
, dev
, vlan_str
, target
, dst_str
))
1651 def bridge_fdb_del(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1652 target
= 'self' if bridge
else ''
1655 vlan_str
= 'vlan %s ' % vlan
1659 dst_str
= 'dst %s ' % remote
1660 utils
.exec_command('%s fdb del %s dev %s %s %s %s' %
1662 address
, dev
, vlan_str
, target
, dst_str
))
1664 def bridge_is_vlan_aware(self
, bridgename
):
1665 filename
= '/sys/class/net/%s/bridge/vlan_filtering' % bridgename
1666 if os
.path
.exists(filename
) and self
.read_file_oneline(filename
) == '1':
1671 def bridge_port_get_bridge_name(bridgeport
):
1672 filename
= '/sys/class/net/%s/brport/bridge' % bridgeport
1674 return os
.path
.basename(os
.readlink(filename
))
1679 def bridge_port_exists(bridge
, bridgeportname
):
1681 return os
.path
.exists('/sys/class/net/%s/brif/%s'
1682 % (bridge
, bridgeportname
))
1686 def bridge_fdb_show_dev(self
, dev
):
1689 output
= utils
.exec_command('%s fdb show dev %s'
1690 % (utils
.bridge_cmd
, dev
))
1692 for fdb_entry
in output
.splitlines():
1694 entries
= fdb_entry
.split()
1695 fdbs
.setdefault(entries
[2], []).append(entries
[0])
1697 self
.logger
.debug('%s: invalid fdb line \'%s\''
1704 def is_bridge(bridge
):
1705 return os
.path
.exists('/sys/class/net/%s/bridge' % bridge
)
1707 def is_link_up(self
, ifacename
):
1710 flags
= self
.read_file_oneline('/sys/class/net/%s/flags' % ifacename
)
1711 iflags
= int(flags
, 16)
1718 def ip_route_get_dev(self
, prefix
, vrf_master
=None):
1721 cmd
= '%s route get %s vrf %s' % (utils
.ip_cmd
, prefix
, vrf_master
)
1723 cmd
= '%s route get %s' % (utils
.ip_cmd
, prefix
)
1725 output
= utils
.exec_command(cmd
)
1727 rline
= output
.splitlines()[0]
1729 rattrs
= rline
.split()
1730 return rattrs
[rattrs
.index('dev') + 1]
1731 except Exception, e
:
1732 self
.logger
.debug('ip_route_get_dev: failed .. %s' % str(e
))
1736 def link_get_lowers(ifacename
):
1738 lowers
= glob
.glob("/sys/class/net/%s/lower_*" % ifacename
)
1741 return [os
.path
.basename(l
)[6:] for l
in lowers
]
1746 def link_get_uppers(ifacename
):
1748 uppers
= glob
.glob("/sys/class/net/%s/upper_*" % ifacename
)
1751 return [os
.path
.basename(u
)[6:] for u
in uppers
]
1755 def link_get_vrfs(self
):
1756 if not LinkUtils
._CACHE
_FILL
_DONE
:
1758 return linkCache
.vrfs
1761 def cache_get_info_slave(attrlist
):
1763 return linkCache
.get_attr(attrlist
)
1767 def get_brport_learning(self
, ifacename
):
1768 learn
= self
.read_file_oneline('/sys/class/net/%s/brport/learning'
1770 if learn
and learn
== '1':
1775 def get_brport_learning_bool(self
, ifacename
):
1776 return utils
.get_boolean_from_string(self
.read_file_oneline('/sys/class/net/%s/brport/learning' % ifacename
))
1778 def set_brport_learning(self
, ifacename
, learn
):
1780 return self
.write_file('/sys/class/net/%s/brport/learning'
1783 return self
.write_file('/sys/class/net/%s/brport/learning'
1786 #################################################################################
1787 ################################### BOND UTILS ##################################
1788 #################################################################################
1790 def _link_cache_get(self
, attrlist
, refresh
=False):
1791 return self
._cache
_get
('link', attrlist
, refresh
)
1793 def cache_delete(self
, attrlist
, value
=None):
1794 return self
._cache
_delete
(attrlist
, value
)
1796 def link_cache_get(self
, attrlist
, refresh
=False):
1797 return self
._link
_cache
_get
(attrlist
, refresh
)
1799 def link_cache_check(self
, attrlist
, value
, refresh
=False):
1800 return self
._link
_cache
_check
(attrlist
, value
, refresh
)
1802 def _link_cache_check(self
, attrlist
, value
, refresh
=False):
1804 return self
._link
_cache
_get
(attrlist
, refresh
) == value
1805 except Exception, e
:
1806 self
.logger
.debug('_cache_check(%s) : [%s]'
1807 % (str(attrlist
), str(e
)))
1812 Link
.IFLA_BOND_MODE
: 'mode',
1813 Link
.IFLA_BOND_MIIMON
: 'miimon',
1814 Link
.IFLA_BOND_USE_CARRIER
: 'use_carrier',
1815 Link
.IFLA_BOND_AD_LACP_RATE
: 'lacp_rate',
1816 Link
.IFLA_BOND_XMIT_HASH_POLICY
: 'xmit_hash_policy',
1817 Link
.IFLA_BOND_MIN_LINKS
: 'min_links',
1818 Link
.IFLA_BOND_NUM_PEER_NOTIF
: 'num_grat_arp',
1819 Link
.IFLA_BOND_AD_ACTOR_SYSTEM
: 'ad_actor_system',
1820 Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
: 'ad_actor_sys_prio',
1821 Link
.IFLA_BOND_AD_LACP_BYPASS
: 'lacp_bypass',
1822 Link
.IFLA_BOND_UPDELAY
: 'updelay',
1823 Link
.IFLA_BOND_DOWNDELAY
: 'downdelay',
1826 def bond_set_attrs_nl(self
, bondname
, ifla_info_data
):
1827 bond_attr_name
= 'None' # for log purpose (in case an exception raised)
1828 for nl_attr
, value
in ifla_info_data
.items():
1830 bond_attr_name
= self
.bondcmd_attrmap
[nl_attr
]
1831 file_path
= '/sys/class/net/%s/bonding/%s' % (bondname
, bond_attr_name
)
1832 if os
.path
.exists(file_path
):
1833 self
.write_file(file_path
, str(value
))
1834 except Exception as e
:
1835 exception_str
= '%s: %s %s: %s' % (bondname
, bond_attr_name
, value
, str(e
))
1836 if ifupdownflags
.flags
.FORCE
:
1837 self
.logger
.warning(exception_str
)
1839 self
.logger
.debug(exception_str
)
1841 def bond_set_attrs(self
, bondname
, attrdict
, prehook
):
1842 for attrname
, attrval
in attrdict
.items():
1843 if (self
._link
_cache
_check
([bondname
, 'linkinfo',
1844 attrname
], attrval
)):
1846 if (attrname
== 'mode'
1847 or attrname
== 'xmit_hash_policy'
1848 or attrname
== 'lacp_rate' or attrname
== 'min_links'):
1852 if ((attrname
not in ['lacp_rate',
1854 self
._link
_cache
_check
([bondname
, 'linkinfo', 'mode'], '802.3ad',
1856 self
.write_file('/sys/class/net/%s/bonding/%s'
1857 % (bondname
, attrname
), attrval
)
1858 except Exception, e
:
1859 if ifupdownflags
.flags
.FORCE
:
1860 self
.logger
.warn(str(e
))
1865 def bond_set_use_carrier(self
, bondname
, use_carrier
):
1866 if not use_carrier
or (use_carrier
!= '0' and use_carrier
!= '1'):
1868 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'use_carrier'],
1871 self
.write_file('/sys/class/net/%s' % bondname
+
1872 '/bonding/use_carrier', use_carrier
)
1873 self
._cache
_update
([bondname
, 'linkinfo',
1874 'use_carrier'], use_carrier
)
1876 def bond_get_use_carrier(self
, bondname
):
1877 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'use_carrier'])
1879 def bond_get_use_carrier_nl(self
, bondname
):
1880 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_USE_CARRIER
])
1882 def bond_set_xmit_hash_policy(self
, bondname
, hash_policy
, prehook
=None):
1883 valid_values
= ['layer2', 'layer3+4', 'layer2+3']
1886 if hash_policy
not in valid_values
:
1887 raise Exception('invalid hash policy value %s' % hash_policy
)
1888 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'xmit_hash_policy'],
1893 self
.write_file('/sys/class/net/%s' % bondname
+
1894 '/bonding/xmit_hash_policy', hash_policy
)
1895 self
._cache
_update
([bondname
, 'linkinfo', 'xmit_hash_policy'],
1898 def bond_get_xmit_hash_policy(self
, bondname
):
1899 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'xmit_hash_policy'])
1901 def bond_get_xmit_hash_policy_nl(self
, bondname
):
1902 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_XMIT_HASH_POLICY
])
1904 def bond_set_miimon(self
, bondname
, miimon
):
1905 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'miimon'],
1908 self
.write_file('/sys/class/net/%s' % bondname
+
1909 '/bonding/miimon', miimon
)
1910 self
._cache
_update
([bondname
, 'linkinfo', 'miimon'], miimon
)
1912 def bond_get_miimon(self
, bondname
):
1913 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'miimon'])
1915 def bond_get_miimon_nl(self
, bondname
):
1916 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MIIMON
])
1918 def bond_set_mode(self
, bondname
, mode
, prehook
=None):
1919 valid_modes
= ['balance-rr', 'active-backup', 'balance-xor',
1920 'broadcast', '802.3ad', 'balance-tlb', 'balance-alb']
1923 if mode
not in valid_modes
:
1924 raise Exception('invalid mode %s' % mode
)
1925 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'mode'],
1930 self
.write_file('/sys/class/net/%s' % bondname
+ '/bonding/mode', mode
)
1931 self
._cache
_update
([bondname
, 'linkinfo', 'mode'], mode
)
1933 def bond_get_mode(self
, bondname
):
1934 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'mode'])
1936 def bond_get_mode_nl(self
, bondname
):
1937 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MODE
])
1939 def bond_set_lacp_rate(self
, bondname
, lacp_rate
, prehook
=None, posthook
=None):
1940 if not lacp_rate
or (lacp_rate
!= '0' and lacp_rate
!= '1'):
1942 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'lacp_rate'],
1948 self
.write_file('/sys/class/net/%s' % bondname
+
1949 '/bonding/lacp_rate', lacp_rate
)
1955 self
._cache
_update
([bondname
, 'linkinfo',
1956 'lacp_rate'], lacp_rate
)
1958 def bond_get_lacp_rate(self
, bondname
):
1959 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'lacp_rate'])
1961 def bond_get_lacp_rate_nl(self
, bondname
):
1962 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_RATE
])
1964 def bond_set_lacp_bypass_allow(self
, bondname
, allow
, prehook
=None, posthook
=None):
1965 if self
._link
_cache
_check
([bondname
, 'linkinfo', 'lacp_bypass'], allow
):
1970 self
.write_file('/sys/class/net/%s' % bondname
+
1971 '/bonding/lacp_bypass', allow
)
1977 self
._cache
_update
([bondname
, 'linkinfo',
1978 'lacp_bypass'], allow
)
1980 def bond_get_lacp_bypass_allow(self
, bondname
):
1981 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'lacp_bypass'])
1983 def bond_get_lacp_bypass_allow_nl(self
, bondname
):
1984 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_BYPASS
])
1986 def bond_set_min_links(self
, bondname
, min_links
, prehook
=None):
1987 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'min_links'],
1992 self
.write_file('/sys/class/net/%s/bonding/min_links' % bondname
,
1994 self
._cache
_update
([bondname
, 'linkinfo', 'min_links'], min_links
)
1996 def bond_get_min_links(self
, bondname
):
1997 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'min_links'])
1999 def get_min_links_nl(self
, bondname
):
2000 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MIN_LINKS
])
2002 def bond_get_ad_actor_system(self
, bondname
):
2003 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'ad_actor_system'])
2005 def bond_get_ad_actor_system_nl(self
, bondname
):
2006 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYSTEM
])
2008 def bond_get_ad_actor_sys_prio(self
, bondname
):
2009 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'ad_actor_sys_prio'])
2011 def bond_get_ad_actor_sys_prio_nl(self
, bondname
):
2012 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
])
2014 def bond_get_num_unsol_na(self
, bondname
):
2015 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'num_unsol_na'])
2017 def bond_get_num_unsol_na_nl(self
, bondname
):
2018 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
])
2020 def bond_get_num_grat_arp(self
, bondname
):
2021 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'num_grat_arp'])
2023 def bond_get_num_grat_arp_nl(self
, bondname
):
2024 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
])
2026 def bond_get_updelay(self
, bondname
):
2027 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'updelay'])
2029 def bond_get_updelay_nl(self
, bondname
):
2030 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_UPDELAY
])
2032 def bond_get_downdelay(self
, bondname
):
2033 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'downdelay'])
2035 def bond_get_downdelay_nl(self
, bondname
):
2036 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_DOWNDELAY
])
2038 def bond_enslave_slave(self
, bondname
, slave
, prehook
=None, posthook
=None):
2039 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2040 if slaves
and slave
in slaves
:
2044 self
.write_file('/sys/class/net/%s' % bondname
+
2045 '/bonding/slaves', '+' + slave
)
2048 self
._cache
_update
([bondname
, 'linkinfo', 'slaves'], slave
)
2050 def bond_remove_slave(self
, bondname
, slave
):
2051 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2052 if not slaves
or slave
not in slaves
:
2054 sysfs_bond_path
= ('/sys/class/net/%s' % bondname
+
2056 if not os
.path
.exists(sysfs_bond_path
):
2058 self
.write_file(sysfs_bond_path
, '-' + slave
)
2059 self
._cache
_delete
([bondname
, 'linkinfo', 'slaves'], slave
)
2061 def bond_remove_slaves_all(self
, bondname
):
2062 if not self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves']):
2065 sysfs_bond_path
= ('/sys/class/net/%s' % bondname
+
2068 with
open(sysfs_bond_path
, 'r') as f
:
2069 slaves
= f
.readline().strip().split()
2071 raise Exception('error reading slaves of bond %s (%s)' % (bondname
, str(e
)))
2072 for slave
in slaves
:
2073 self
.link_down(slave
)
2075 self
.bond_remove_slave(bondname
, slave
)
2076 except Exception, e
:
2077 if not ifupdownflags
.flags
.FORCE
:
2078 raise Exception('error removing slave %s from bond %s (%s)' % (slave
, bondname
, str(e
)))
2081 self
._cache
_delete
([bondname
, 'linkinfo', 'slaves'])
2084 def bond_load_bonding_module():
2085 return utils
.exec_command('%s -q bonding' % utils
.modprobe_cmd
)
2087 def create_bond(self
, bondname
):
2088 if self
.bond_exists(bondname
):
2090 # load_bonding_module() has already been run
2091 self
.write_file('/sys/class/net/bonding_masters', '+' + bondname
)
2092 self
._cache
_update
([bondname
], {})
2094 def delete_bond(self
, bondname
):
2095 if not os
.path
.exists('/sys/class/net/%s' % bondname
):
2097 self
.write_file('/sys/class/net/bonding_masters', '-' + bondname
)
2098 self
._cache
_delete
([bondname
])
2100 def bond_get_slaves(self
, bondname
):
2101 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2104 slavefile
= '/sys/class/net/%s/bonding/slaves' % bondname
2105 if os
.path
.exists(slavefile
):
2106 buf
= self
.read_file_oneline(slavefile
)
2108 slaves
= buf
.split()
2111 self
._cache
_update
([bondname
, 'linkinfo', 'slaves'], slaves
)
2114 def bond_slave_exists(self
, bond
, slave
):
2115 slaves
= self
.bond_get_slaves(bond
)
2118 return slave
in slaves
2121 def bond_exists(bondname
):
2122 return os
.path
.exists('/sys/class/net/%s/bonding' % bondname
)
2124 #################################################################################
2125 ################################## BRIDGE UTILS #################################
2126 #################################################################################
2128 def create_bridge(self
, bridgename
):
2129 if not LinkUtils
.bridge_utils_is_installed
:
2131 if self
.bridge_exists(bridgename
):
2133 utils
.exec_command('%s addbr %s' % (utils
.brctl_cmd
, bridgename
))
2134 self
._cache
_update
([bridgename
], {})
2136 def delete_bridge(self
, bridgename
):
2137 if not LinkUtils
.bridge_utils_is_installed
:
2139 if not self
.bridge_exists(bridgename
):
2141 utils
.exec_command('%s delbr %s' % (utils
.brctl_cmd
, bridgename
))
2142 self
._cache
_invalidate
()
2144 def add_bridge_port(self
, bridgename
, bridgeportname
):
2145 """ Add port to bridge """
2146 if not LinkUtils
.bridge_utils_is_installed
:
2148 ports
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports'])
2149 if ports
and ports
.get(bridgeportname
):
2151 utils
.exec_command('%s addif %s %s' % (utils
.brctl_cmd
, bridgename
, bridgeportname
))
2152 self
._cache
_update
([bridgename
, 'linkinfo', 'ports', bridgeportname
], {})
2154 def delete_bridge_port(self
, bridgename
, bridgeportname
):
2155 """ Delete port from bridge """
2156 if not LinkUtils
.bridge_utils_is_installed
:
2158 ports
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports'])
2159 if not ports
or not ports
.get(bridgeportname
):
2161 utils
.exec_command('%s delif %s %s' % (utils
.brctl_cmd
, bridgename
, bridgeportname
))
2162 self
._cache
_delete
([bridgename
, 'linkinfo', 'ports', 'bridgeportname'])
2164 def set_bridgeport_attrs(self
, bridgename
, bridgeportname
, attrdict
):
2165 portattrs
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports', bridgeportname
])
2166 if portattrs
== None:
2168 for k
, v
in attrdict
.iteritems():
2169 if ifupdownflags
.flags
.CACHE
:
2170 curval
= portattrs
.get(k
)
2171 if curval
and curval
== v
:
2173 if k
== 'unicast-flood':
2174 self
.write_file('/sys/class/net/%s/brport/unicast_flood' % bridgeportname
, v
)
2175 elif k
== 'multicast-flood':
2176 self
.write_file('/sys/class/net/%s/brport/multicast_flood' % bridgeportname
, v
)
2177 elif k
== 'learning':
2178 self
.write_file('/sys/class/net/%s/brport/learning' % bridgeportname
, v
)
2179 elif k
== 'arp-nd-suppress':
2180 self
.write_file('/sys/class/net/%s/brport/neigh_suppress' % bridgeportname
, v
)
2182 if not LinkUtils
.bridge_utils_is_installed
:
2184 utils
.exec_command('%s set%s %s %s %s' % (utils
.brctl_cmd
, k
, bridgename
, bridgeportname
, v
))
2186 def set_bridgeport_attr(self
, bridgename
, bridgeportname
,
2188 if not LinkUtils
.bridge_utils_is_installed
:
2190 if self
._link
_cache
_check
([bridgename
, 'linkinfo', 'ports', bridgeportname
, attrname
], attrval
):
2192 utils
.exec_command('%s set%s %s %s %s' %
2199 def set_bridge_attrs(self
, bridgename
, attrdict
):
2200 for k
, v
in attrdict
.iteritems():
2203 if self
._link
_cache
_check
([bridgename
, 'linkinfo', k
], v
):
2206 if k
== 'igmp-version':
2207 self
.write_file('/sys/class/net/%s/bridge/'
2208 'multicast_igmp_version' % bridgename
, v
)
2209 elif k
== 'mld-version':
2210 self
.write_file('/sys/class/net/%s/bridge/'
2211 'multicast_mld_version' % bridgename
, v
)
2212 elif k
== 'vlan-protocol':
2213 self
.write_file('/sys/class/net/%s/bridge/'
2214 'vlan_protocol' % bridgename
,
2215 VlanProtocols
.ETHERTYPES_TO_ID
.get(v
.upper(),
2217 elif k
== 'vlan-stats':
2218 self
.write_file('/sys/class/net/%s/bridge/'
2219 'vlan_stats_enabled' % bridgename
, v
)
2220 elif k
== 'mcstats':
2221 self
.write_file('/sys/class/net/%s/bridge/'
2222 'multicast_stats_enabled' % bridgename
, v
)
2224 if not LinkUtils
.bridge_utils_is_installed
:
2226 cmd
= ('%s set%s %s %s' %
2227 (utils
.brctl_cmd
, k
, bridgename
, v
))
2228 utils
.exec_command(cmd
)
2229 except Exception, e
:
2230 self
.logger
.warn('%s: %s' % (bridgename
, str(e
)))
2233 def set_bridge_attr(self
, bridgename
, attrname
, attrval
):
2234 if self
._link
_cache
_check
([bridgename
, 'linkinfo', attrname
], attrval
):
2236 if attrname
== 'igmp-version':
2237 self
.write_file('/sys/class/net/%s/bridge/multicast_igmp_version'
2238 % bridgename
, attrval
)
2239 elif attrname
== 'mld-version':
2240 self
.write_file('/sys/class/net/%s/bridge/multicast_mld_version'
2241 % bridgename
, attrval
)
2242 elif attrname
== 'vlan-protocol':
2243 self
.write_file('/sys/class/net/%s/bridge/vlan_protocol'
2244 % bridgename
, VlanProtocols
.ETHERTYPES_TO_ID
[attrval
.upper()])
2245 elif attrname
== 'vlan-stats':
2246 self
.write_file('/sys/class/net/%s/bridge/vlan_stats_enabled'
2247 % bridgename
, attrval
)
2248 elif attrname
== 'mcstats':
2249 self
.write_file('/sys/class/net/%s/bridge/multicast_stats_enabled'
2250 % bridgename
, attrval
)
2252 if not LinkUtils
.bridge_utils_is_installed
:
2254 cmd
= '%s set%s %s %s' % (utils
.brctl_cmd
,
2255 attrname
, bridgename
, attrval
)
2256 utils
.exec_command(cmd
)
2258 def get_bridge_attrs(self
, bridgename
):
2259 attrs
= self
._link
_cache
_get
([bridgename
, 'linkinfo'])
2261 for key
, value
in attrs
.items():
2262 if type(key
) == str:
2263 no_ints_attrs
[key
] = value
2264 return no_ints_attrs
2266 def get_bridgeport_attrs(self
, bridgename
, bridgeportname
):
2267 return self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports',
2270 def get_bridgeport_attr(self
, bridgename
, bridgeportname
, attrname
):
2271 return self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports',
2272 bridgeportname
, attrname
])
2275 def bridge_set_stp(bridge
, stp_state
):
2276 if not LinkUtils
.bridge_utils_is_installed
:
2278 utils
.exec_command('%s stp %s %s' % (utils
.brctl_cmd
, bridge
, stp_state
))
2280 def bridge_get_stp(self
, bridge
):
2281 sysfs_stpstate
= '/sys/class/net/%s/bridge/stp_state' % bridge
2282 if not os
.path
.exists(sysfs_stpstate
):
2284 stpstate
= self
.read_file_oneline(sysfs_stpstate
)
2288 if int(stpstate
) > 0:
2290 elif int(stpstate
) == 0:
2296 def _conv_value_to_user(s
):
2303 def read_value_from_sysfs(self
, filename
, preprocess_func
):
2304 value
= self
.read_file_oneline(filename
)
2307 return preprocess_func(value
)
2310 def bridge_set_ageing(bridge
, ageing
):
2311 if not LinkUtils
.bridge_utils_is_installed
:
2313 utils
.exec_command('%s setageing %s %s' % (utils
.brctl_cmd
, bridge
, ageing
))
2315 def bridge_get_ageing(self
, bridge
):
2316 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/ageing_time'
2317 % bridge
, self
._conv
_value
_to
_user
)
2320 def set_bridgeprio(bridge
, prio
):
2321 if not LinkUtils
.bridge_utils_is_installed
:
2323 utils
.exec_command('%s setbridgeprio %s %s' % (utils
.brctl_cmd
, bridge
, prio
))
2325 def get_bridgeprio(self
, bridge
):
2326 return self
.read_file_oneline(
2327 '/sys/class/net/%s/bridge/priority' % bridge
)
2330 def bridge_set_fd(bridge
, fd
):
2331 if not LinkUtils
.bridge_utils_is_installed
:
2333 utils
.exec_command('%s setfd %s %s' % (utils
.brctl_cmd
, bridge
, fd
))
2335 def bridge_get_fd(self
, bridge
):
2336 return self
.read_value_from_sysfs(
2337 '/sys/class/net/%s/bridge/forward_delay'
2338 % bridge
, self
._conv
_value
_to
_user
)
2340 def bridge_set_gcint(self
, bridge
, gcint
):
2341 raise Exception('set_gcint not implemented')
2344 def bridge_set_hello(bridge
, hello
):
2345 if not LinkUtils
.bridge_utils_is_installed
:
2347 utils
.exec_command('%s sethello %s %s' % (utils
.brctl_cmd
, bridge
, hello
))
2349 def bridge_get_hello(self
, bridge
):
2350 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/hello_time'
2351 % bridge
, self
._conv
_value
_to
_user
)
2354 def bridge_set_maxage(bridge
, maxage
):
2355 if not LinkUtils
.bridge_utils_is_installed
:
2357 utils
.exec_command('%s setmaxage %s %s' % (utils
.brctl_cmd
, bridge
, maxage
))
2359 def bridge_get_maxage(self
, bridge
):
2360 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/max_age'
2361 % bridge
, self
._conv
_value
_to
_user
)
2364 def bridge_set_pathcost(bridge
, port
, pathcost
):
2365 if not LinkUtils
.bridge_utils_is_installed
:
2367 utils
.exec_command('%s setpathcost %s %s %s' % (utils
.brctl_cmd
, bridge
, port
, pathcost
))
2369 def bridge_get_pathcost(self
, bridge
, port
):
2370 return self
.read_file_oneline('/sys/class/net/%s/brport/path_cost'
2374 def bridge_set_portprio(bridge
, port
, prio
):
2375 if not LinkUtils
.bridge_utils_is_installed
:
2377 utils
.exec_command('%s setportprio %s %s %s' % (utils
.brctl_cmd
, bridge
, port
, prio
))
2379 def bridge_get_portprio(self
, bridge
, port
):
2380 return self
.read_file_oneline('/sys/class/net/%s/brport/priority'
2384 def bridge_set_hashmax(bridge
, hashmax
):
2385 if not LinkUtils
.bridge_utils_is_installed
:
2387 utils
.exec_command('%s sethashmax %s %s' % (utils
.brctl_cmd
, bridge
, hashmax
))
2389 def bridge_get_hashmax(self
, bridge
):
2390 return self
.read_file_oneline('/sys/class/net/%s/bridge/hash_max'
2394 def bridge_set_hashel(bridge
, hashel
):
2395 if not LinkUtils
.bridge_utils_is_installed
:
2397 utils
.exec_command('%s sethashel %s %s' % (utils
.brctl_cmd
, bridge
, hashel
))
2399 def bridge_get_hashel(self
, bridge
):
2400 return self
.read_file_oneline('/sys/class/net/%s/bridge/hash_elasticity'
2404 def bridge_set_mclmc(bridge
, mclmc
):
2405 if not LinkUtils
.bridge_utils_is_installed
:
2407 utils
.exec_command('%s setmclmc %s %s' % (utils
.brctl_cmd
, bridge
, mclmc
))
2409 def bridge_get_mclmc(self
, bridge
):
2410 return self
.read_file_oneline(
2411 '/sys/class/net/%s/bridge/multicast_last_member_count'
2415 def bridge_set_mcrouter(bridge
, mcrouter
):
2416 if not LinkUtils
.bridge_utils_is_installed
:
2418 utils
.exec_command('%s setmcrouter %s %s' % (utils
.brctl_cmd
, bridge
, mcrouter
))
2420 def bridge_get_mcrouter(self
, bridge
):
2421 return self
.read_file_oneline(
2422 '/sys/class/net/%s/bridge/multicast_router' % bridge
)
2425 def bridge_set_mcsnoop(bridge
, mcsnoop
):
2426 if not LinkUtils
.bridge_utils_is_installed
:
2428 utils
.exec_command('%s setmcsnoop %s %s' % (utils
.brctl_cmd
, bridge
, mcsnoop
))
2430 def bridge_get_mcsnoop(self
, bridge
):
2431 return self
.read_file_oneline(
2432 '/sys/class/net/%s/bridge/multicast_snooping' % bridge
)
2435 def bridge_set_mcsqc(bridge
, mcsqc
):
2436 if not LinkUtils
.bridge_utils_is_installed
:
2438 utils
.exec_command('%s setmcsqc %s %s' % (utils
.brctl_cmd
, bridge
, mcsqc
))
2440 def bridge_get_mcsqc(self
, bridge
):
2441 return self
.read_file_oneline(
2442 '/sys/class/net/%s/bridge/multicast_startup_query_count'
2446 def bridge_set_mcqifaddr(bridge
, mcqifaddr
):
2447 if not LinkUtils
.bridge_utils_is_installed
:
2449 utils
.exec_command('%s setmcqifaddr %s %s' % (utils
.brctl_cmd
, bridge
, mcqifaddr
))
2451 def bridge_get_mcqifaddr(self
, bridge
):
2452 return self
.read_file_oneline(
2453 '/sys/class/net/%s/bridge/multicast_startup_query_use_ifaddr'
2457 def bridge_set_mcquerier(bridge
, mcquerier
):
2458 if not LinkUtils
.bridge_utils_is_installed
:
2460 utils
.exec_command('%s setmcquerier %s %s' % (utils
.brctl_cmd
, bridge
, mcquerier
))
2462 def bridge_get_mcquerier(self
, bridge
):
2463 return self
.read_file_oneline(
2464 '/sys/class/net/%s/bridge/multicast_querier' % bridge
)
2466 def bridge_set_mcqv4src(self
, bridge
, vlan
, mcquerier
):
2470 self
.logger
.info('%s: set mcqv4src vlan: invalid parameter %s: %s' %(bridge
, vlan
, str(e
)))
2472 if vlan
== 0 or vlan
> 4095:
2473 self
.logger
.warn('mcqv4src vlan \'%d\' invalid range' % vlan
)
2476 ip
= mcquerier
.split('.')
2478 self
.logger
.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier
)
2481 if not k
.isdigit() or int(k
, 10) < 0 or int(k
, 10) > 255:
2482 self
.logger
.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier
)
2485 if not LinkUtils
.bridge_utils_is_installed
:
2488 utils
.exec_command('%s setmcqv4src %s %d %s' %
2489 (utils
.brctl_cmd
, bridge
, vlan
, mcquerier
))
2491 def bridge_del_mcqv4src(self
, bridge
, vlan
):
2492 if not LinkUtils
.bridge_utils_is_installed
:
2497 self
.logger
.info('%s: del mcqv4src vlan: invalid parameter %s: %s' %(bridge
, vlan
, str(e
)))
2499 utils
.exec_command('%s delmcqv4src %s %d' % (utils
.brctl_cmd
, bridge
, vlan
))
2501 def bridge_get_mcqv4src(self
, bridge
, vlan
=None):
2502 if not LinkUtils
.bridge_utils_is_installed
:
2504 if not self
.supported_command
['showmcqv4src']:
2508 mcqout
= utils
.exec_command('%s showmcqv4src %s' %
2509 (utils
.brctl_cmd
, bridge
))
2510 except Exception as e
:
2512 if 'never heard' in s
:
2513 msg
= ('%s showmcqv4src: skipping unsupported command'
2515 self
.logger
.info(msg
)
2516 self
.supported_command
['showmcqv4src'] = False
2521 mcqlines
= mcqout
.splitlines()
2522 for l
in mcqlines
[1:]:
2524 k
, d
, v
= l
.split('\t')
2529 return mcqv4src
.get(vlan
)
2533 def bridge_set_mclmi(bridge
, mclmi
):
2534 if not LinkUtils
.bridge_utils_is_installed
:
2536 utils
.exec_command('%s setmclmi %s %s' % (utils
.brctl_cmd
, bridge
, mclmi
))
2538 def bridge_get_mclmi(self
, bridge
):
2539 return self
.read_file_oneline(
2540 '/sys/class/net/%s/bridge/multicast_last_member_interval'
2544 def bridge_set_mcmi(bridge
, mcmi
):
2545 if not LinkUtils
.bridge_utils_is_installed
:
2547 utils
.exec_command('%s setmcmi %s %s' % (utils
.brctl_cmd
, bridge
, mcmi
))
2549 def bridge_get_mcmi(self
, bridge
):
2550 return self
.read_file_oneline(
2551 '/sys/class/net/%s/bridge/multicast_membership_interval'
2555 def bridge_exists(bridge
):
2556 return os
.path
.exists('/sys/class/net/%s/bridge' % bridge
)
2559 def is_bridge_port(ifacename
):
2560 return os
.path
.exists('/sys/class/net/%s/brport' % ifacename
)
2563 def bridge_port_exists(bridge
, bridgeportname
):
2565 return os
.path
.exists('/sys/class/net/%s/brif/%s' % (bridge
, bridgeportname
))
2570 def get_bridge_ports(bridgename
):
2572 return os
.listdir('/sys/class/net/%s/brif/' % bridgename
)