3 # Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
5 # Julien Fortin, julien@cumulusnetworks.com
15 from ipaddr
import IPNetwork
, IPv6Network
18 import ifupdown2
.ifupdown
.statemanager
as statemanager
19 import ifupdown2
.ifupdown
.ifupdownflags
as ifupdownflags
21 from ifupdown2
.nlmanager
.nlmanager
import Link
, Route
23 from ifupdown2
.ifupdown
.iface
import *
24 from ifupdown2
.ifupdown
.utils
import utils
25 from ifupdown2
.ifupdown
.netlink
import netlink
27 from ifupdown2
.ifupdownaddons
.utilsbase
import utilsBase
28 from ifupdown2
.ifupdownaddons
.cache
import linkCache
, MSTPAttrsCache
30 import ifupdown
.ifupdownflags
as ifupdownflags
31 import ifupdown
.statemanager
as statemanager
33 from nlmanager
.nlmanager
import Link
, Route
35 from ifupdown
.iface
import *
36 from ifupdown
.utils
import utils
37 from ifupdown
.netlink
import netlink
39 from ifupdownaddons
.utilsbase
import utilsBase
40 from ifupdownaddons
.cache
import linkCache
, MSTPAttrsCache
43 class LinkUtils(utilsBase
):
45 This class contains helper methods to cache and manipulate interfaces through
46 non-netlink APIs (sysfs, iproute2, brctl...)
48 _CACHE_FILL_DONE
= False
55 bridge_utils_is_installed
= os
.path
.exists(utils
.brctl_cmd
)
56 bridge_utils_missing_warning
= True
58 DEFAULT_IP_METRIC
= 1024
59 ADDR_METRIC_SUPPORT
= None
61 def __init__(self
, *args
, **kargs
):
62 utilsBase
.__init
__(self
, *args
, **kargs
)
64 self
.supported_command
= {
65 '%s -c -json vlan show' % utils
.bridge_cmd
: True,
68 self
.bridge_vlan_cache
= {}
69 self
.bridge_vlan_cache_fill_done
= False
71 if not ifupdownflags
.flags
.PERFMODE
and not LinkUtils
._CACHE
_FILL
_DONE
:
74 if LinkUtils
.ADDR_METRIC_SUPPORT
is None:
76 cmd
= [utils
.ip_cmd
, 'addr', 'help']
77 self
.logger
.info('executing %s addr help' % utils
.ip_cmd
)
79 process
= subprocess
.Popen(cmd
, stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
)
80 stdout
, stderr
= process
.communicate()
81 LinkUtils
.ADDR_METRIC_SUPPORT
= '[ metric METRIC ]' in stderr
or ''
82 self
.logger
.info('address metric support: %s' % ('OK' if LinkUtils
.ADDR_METRIC_SUPPORT
else 'KO'))
84 LinkUtils
.ADDR_METRIC_SUPPORT
= False
85 self
.logger
.info('address metric support: KO')
88 def addr_metric_support(cls
):
89 return cls
.ADDR_METRIC_SUPPORT
92 def get_default_ip_metric(cls
):
93 return cls
.DEFAULT_IP_METRIC
97 LinkUtils
._CACHE
_FILL
_DONE
= False
98 LinkUtils
.ipbatchbuf
= ''
99 LinkUtils
.ipbatch
= False
100 LinkUtils
.ipbatch_pause
= False
102 def _fill_cache(self
):
103 if not LinkUtils
._CACHE
_FILL
_DONE
:
106 LinkUtils
._CACHE
_FILL
_DONE
= True
111 def _get_vland_id(citems
, i
, warn
):
114 index
= sub
.index('id')
116 return sub
[index
+ 1]
119 raise Exception('invalid use of \'vlan\' keyword')
122 def _link_fill(self
, ifacename
=None, refresh
=False):
123 """ fills cache with link information
125 if ifacename argument given, fill cache for ifacename, else
126 fill cache for all interfaces in the system
129 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
132 # if ifacename already present, return
133 if (ifacename
and not refresh
and
134 linkCache
.get_attr([ifacename
, 'ifflag'])):
141 [linkCache
.update_attrdict([ifname
], linkattrs
)
142 for ifname
, linkattrs
in netlink
.link_dump(ifacename
).items()]
143 except Exception as e
:
144 self
.logger
.info('%s' % str(e
))
145 # this netlink call replaces the call to _link_fill_iproute2_cmd()
146 # We shouldn't have netlink calls in the iproute2 module, this will
147 # be removed in the future. We plan to release, a flexible backend
148 # (netlink+iproute2) by default we will use netlink backend but with
149 # a CLI arg we can switch to iproute2 backend.
150 # Until we decide to create this "backend" switch capability,
151 # we have to put the netlink call inside the iproute2 module.
153 self
._link
_fill
_iproute
2_cmd
(ifacename
, refresh
)
155 self
._fill
_bond
_info
(ifacename
)
156 self
._fill
_bridge
_info
(ifacename
)
158 def _fill_bridge_info(self
, ifacename
):
164 cache_dict
= {ifacename
: linkCache
.links
.get(ifacename
, {})}
166 cache_dict
= linkCache
.links
168 for ifname
, obj
in cache_dict
.items():
169 slave_kind
= obj
.get('slave_kind')
170 if not slave_kind
and slave_kind
!= 'bridge':
173 info_slave_data
= obj
.get('info_slave_data')
174 if not info_slave_data
:
177 ifla_master
= obj
.get('master')
179 raise Exception('No master associated with bridge port %s' % ifname
)
182 Link
.IFLA_BRPORT_STATE
,
183 Link
.IFLA_BRPORT_COST
,
184 Link
.IFLA_BRPORT_PRIORITY
,
186 if nl_attr
not in info_slave_data
and LinkUtils
.bridge_utils_is_installed
:
187 self
._fill
_bridge
_info
_brctl
()
191 'pathcost': str(info_slave_data
.get(Link
.IFLA_BRPORT_COST
, 0)),
192 'fdelay': format(float(info_slave_data
.get(Link
.IFLA_BRPORT_FORWARD_DELAY_TIMER
, 0) / 100), '.2f'),
193 'portmcrouter': str(info_slave_data
.get(Link
.IFLA_BRPORT_MULTICAST_ROUTER
, 0)),
194 'portmcfl': str(info_slave_data
.get(Link
.IFLA_BRPORT_FAST_LEAVE
, 0)),
195 'portprio': str(info_slave_data
.get(Link
.IFLA_BRPORT_PRIORITY
, 0)),
196 'unicast-flood': str(info_slave_data
.get(Link
.IFLA_BRPORT_UNICAST_FLOOD
, 0)),
197 'multicast-flood': str(info_slave_data
.get(Link
.IFLA_BRPORT_MCAST_FLOOD
, 0)),
198 'learning': str(info_slave_data
.get(Link
.IFLA_BRPORT_LEARNING
, 0)),
199 'arp-nd-suppress': str(info_slave_data
.get(Link
.IFLA_BRPORT_ARP_SUPPRESS
, 0))
202 if ifla_master
in brports
:
203 brports
[ifla_master
][ifname
] = brport_attrs
205 brports
[ifla_master
] = {ifname
: brport_attrs
}
207 linkCache
.update_attrdict([ifla_master
, 'linkinfo', 'ports'], brports
[ifla_master
])
209 if LinkUtils
.bridge_utils_is_installed
:
210 self
._fill
_bridge
_info
_brctl
()
212 def _fill_bridge_info_brctl(self
):
213 brctlout
= utils
.exec_command('%s show' % utils
.brctl_cmd
)
217 for bline
in brctlout
.splitlines()[1:]:
218 bitems
= bline
.split()
222 linkCache
.update_attrdict([bitems
[0], 'linkinfo'],
225 linkCache
.update_attrdict([bitems
[0]],
226 {'linkinfo': {'stp': bitems
[2]}})
227 self
._bridge
_attrs
_fill
(bitems
[0])
229 def _bridge_attrs_fill(self
, bridgename
):
233 brout
= utils
.exec_command('%s showstp %s' % (utils
.brctl_cmd
, bridgename
))
234 chunks
= re
.split(r
'\n\n', brout
, maxsplit
=0, flags
=re
.MULTILINE
)
237 # Get all bridge attributes
238 broutlines
= chunks
[0].splitlines()
239 # battrs['pathcost'] = broutlines[3].split('path cost')[1].strip()
242 battrs
['maxage'] = broutlines
[4].split('bridge max age')[
243 1].strip().replace('.00', '')
248 battrs
['hello'] = broutlines
[5].split('bridge hello time')[
249 1].strip().replace('.00', '')
254 battrs
['fd'] = broutlines
[6].split('bridge forward delay')[
255 1].strip().replace('.00', '')
260 battrs
['ageing'] = broutlines
[7].split('ageing time')[
261 1].strip().replace('.00', '')
266 battrs
['mcrouter'] = broutlines
[12].split('mc router')[
267 1].strip().split('\t\t\t')[0]
272 battrs
['bridgeprio'] = self
.read_file_oneline(
273 '/sys/class/net/%s/bridge/priority' % bridgename
)
278 battrs
['vlan-protocol'] = VlanProtocols
.ID_TO_ETHERTYPES
[
279 self
.read_file_oneline(
280 '/sys/class/net/%s/bridge/vlan_protocol' % bridgename
)]
285 battrs
.update(self
._bridge
_get
_mcattrs
_from
_sysfs
(bridgename
))
289 # XXX: comment this out until mc attributes become available
291 # battrs['hashel'] = broutlines[10].split('hash elasticity')[1].split()[0].strip()
292 # battrs['hashmax'] = broutlines[10].split('hash max')[1].strip()
293 # battrs['mclmc'] = broutlines[11].split('mc last member count')[1].split()[0].strip()
294 # battrs['mciqc'] = broutlines[11].split('mc init query count')[1].strip()
295 # battrs['mcrouter'] = broutlines[12].split('mc router')[1].split()[0].strip()
296 ##battrs['mcsnoop'] = broutlines[12].split('mc snooping')[1].strip()
297 # battrs['mclmt'] = broutlines[13].split('mc last member timer')[1].split()[0].strip()
299 self
.logger
.warn('%s: error while processing bridge attributes: %s' % (bridgename
, str(e
)))
302 linkCache
.update_attrdict([bridgename
, 'linkinfo'], battrs
)
303 for cidx
in range(1, len(chunks
)):
304 bpout
= chunks
[cidx
].lstrip('\n')
305 if not bpout
or bpout
[0] == ' ':
307 bplines
= bpout
.splitlines()
308 pname
= bplines
[0].split()[0]
311 bportattrs
['pathcost'] = bplines
[2].split(
312 'path cost')[1].strip()
313 bportattrs
['fdelay'] = bplines
[4].split(
314 'forward delay timer')[1].strip()
315 bportattrs
['portmcrouter'] = self
.read_file_oneline(
316 '/sys/class/net/%s/brport/multicast_router' % pname
)
317 bportattrs
['portmcfl'] = self
.read_file_oneline(
318 '/sys/class/net/%s/brport/multicast_fast_leave' % pname
)
319 bportattrs
['portprio'] = self
.read_file_oneline(
320 '/sys/class/net/%s/brport/priority' % pname
)
321 bportattrs
['unicast-flood'] = self
.read_file_oneline(
322 '/sys/class/net/%s/brport/unicast_flood' % pname
)
323 bportattrs
['multicast-flood'] = self
.read_file_oneline(
324 '/sys/class/net/%s/brport/multicast_flood' % pname
)
325 bportattrs
['learning'] = self
.read_file_oneline(
326 '/sys/class/net/%s/brport/learning' % pname
)
327 bportattrs
['arp-nd-suppress'] = self
.read_file_oneline(
328 '/sys/class/net/%s/brport/neigh_suppress' % pname
)
329 # bportattrs['mcrouters'] = bplines[6].split('mc router')[1].split()[0].strip()
330 # bportattrs['mc fast leave'] = bplines[6].split('mc fast leave')[1].strip()
332 self
.logger
.warn('%s: error while processing bridge attributes: %s' % (bridgename
, str(e
)))
333 bports
[pname
] = bportattrs
334 linkCache
.update_attrdict([bridgename
, 'linkinfo', 'ports'], bports
)
336 _bridge_sysfs_mcattrs
= {
337 'mclmc': 'multicast_last_member_count',
338 'mcrouter': 'multicast_router',
339 'mcsnoop': 'multicast_snooping',
340 'mcsqc': 'multicast_startup_query_count',
341 'mcqifaddr': 'multicast_query_use_ifaddr',
342 'mcquerier': 'multicast_querier',
343 'hashel': 'hash_elasticity',
344 'hashmax': 'hash_max',
345 'mclmi': 'multicast_last_member_interval',
346 'mcmi': 'multicast_membership_interval',
347 'mcqpi': 'multicast_querier_interval',
348 'mcqi': 'multicast_query_interval',
349 'mcqri': 'multicast_query_response_interval',
350 'mcsqi': 'multicast_startup_query_interval',
351 'igmp-version': 'multicast_igmp_version',
352 'mld-version': 'multicast_mld_version',
353 'vlan-stats': 'vlan_stats_enabled',
354 'mcstats': 'multicast_stats_enabled',
357 def _bridge_get_mcattrs_from_sysfs(self
, bridgename
):
358 mcattrsdivby100
= ['mclmi', 'mcmi', 'mcqpi', 'mcqi', 'mcqri', 'mcsqi']
361 for m
, s
in self
._bridge
_sysfs
_mcattrs
.items():
362 n
= self
.read_file_oneline('/sys/class/net/%s/bridge/%s' % (bridgename
, s
))
363 if m
in mcattrsdivby100
:
368 self
.logger
.warn('error getting mc attr %s (%s)' % (m
, str(e
)))
374 def _fill_bond_info(self
, ifacename
):
375 bonding_masters
= self
.read_file_oneline('/sys/class/net/bonding_masters')
376 if not bonding_masters
:
379 bond_masters_list
= bonding_masters
.split()
382 if ifacename
in bond_masters_list
:
383 bond_masters_list
= [ifacename
]
385 # we want to refresh this interface only if it's a bond master
388 for bondname
in bond_masters_list
:
390 if bondname
not in linkCache
.links
:
391 linkCache
.set_attr([bondname
], {'linkinfo': {}})
392 linkCache
.set_attr([bondname
, 'linkinfo', 'slaves'],
393 self
.read_file_oneline('/sys/class/net/%s/bonding/slaves'
396 # if some attribute are missing we try to get the bond attributes via sysfs
397 bond_linkinfo
= linkCache
.links
[bondname
]['linkinfo']
398 for attr
in [Link
.IFLA_BOND_MODE
, Link
.IFLA_BOND_XMIT_HASH_POLICY
, Link
.IFLA_BOND_MIN_LINKS
]:
399 if attr
not in bond_linkinfo
:
400 self
._fill
_bond
_info
_sysfs
(bondname
)
401 # after we fill in the cache we can continue to the next bond
404 self
._fill
_bond
_info
_sysfs
(bondname
)
406 except Exception as e
:
407 self
.logger
.debug('LinkUtils: bond cache error: %s' % str(e
))
409 def _fill_bond_info_sysfs(self
, bondname
):
411 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_MIN_LINKS
],
412 self
.read_file_oneline(
413 '/sys/class/net/%s/bonding/min_links'
415 except Exception as e
:
416 self
.logger
.debug(str(e
))
419 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_MODE
],
420 self
.read_file_oneline('/sys/class/net/%s/bonding/mode'
421 % bondname
).split()[0])
422 except Exception as e
:
423 self
.logger
.debug(str(e
))
425 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_XMIT_HASH_POLICY
],
426 self
.read_file_oneline(
427 '/sys/class/net/%s/bonding/xmit_hash_policy'
428 % bondname
).split()[0])
429 except Exception as e
:
430 self
.logger
.debug(str(e
))
432 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_RATE
],
433 self
.read_file_oneline('/sys/class/net/%s/bonding/lacp_rate'
434 % bondname
).split()[1])
435 except Exception as e
:
436 self
.logger
.debug(str(e
))
438 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
],
439 self
.read_file_oneline('/sys/class/net/%s/bonding/ad_actor_sys_prio'
441 except Exception as e
:
442 self
.logger
.debug(str(e
))
444 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYSTEM
],
445 self
.read_file_oneline('/sys/class/net/%s/bonding/ad_actor_system'
447 except Exception as e
:
448 self
.logger
.debug(str(e
))
450 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_BYPASS
],
451 self
.read_file_oneline('/sys/class/net/%s/bonding/lacp_bypass'
452 % bondname
).split()[1])
453 except Exception as e
:
454 self
.logger
.debug(str(e
))
456 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_UPDELAY
],
457 self
.read_file_oneline('/sys/class/net/%s/bonding/updelay'
459 except Exception as e
:
460 self
.logger
.debug(str(e
))
462 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_DOWNDELAY
],
463 self
.read_file_oneline('/sys/class/net/%s/bonding/downdelay'
465 except Exception as e
:
466 self
.logger
.debug(str(e
))
469 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_USE_CARRIER
],
470 self
.read_file_oneline('/sys/class/net/%s/bonding/use_carrier' % bondname
))
471 except Exception as e
:
472 self
.logger
.debug(str(e
))
475 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_MIIMON
],
476 self
.read_file_oneline('/sys/class/net/%s/bonding/miimon' % bondname
))
477 except Exception as e
:
478 self
.logger
.debug(str(e
))
481 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
],
482 self
.read_file_oneline('/sys/class/net/%s/bonding/num_unsol_na' % bondname
))
483 except Exception as e
:
484 self
.logger
.debug(str(e
))
487 linkCache
.set_attr([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
],
488 self
.read_file_oneline('/sys/class/net/%s/bonding/num_grat_arp' % bondname
))
489 except Exception as e
:
490 self
.logger
.debug(str(e
))
493 def _link_fill_iproute2_cmd(self
, ifacename
=None, refresh
=False):
496 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
499 # if ifacename already present, return
500 if (ifacename
and not refresh
and
501 linkCache
.get_attr([ifacename
, 'ifflag'])):
505 cmdout
= self
.link_show(ifacename
=ifacename
)
508 for c
in cmdout
.splitlines():
510 ifnamenlink
= citems
[1].split('@')
511 if len(ifnamenlink
) > 1:
512 ifname
= ifnamenlink
[0]
513 iflink
= ifnamenlink
[1].strip(':')
515 ifname
= ifnamenlink
[0].strip(':')
518 linkattrs
['link'] = iflink
519 linkattrs
['ifindex'] = citems
[0].strip(':')
520 flags
= citems
[2].strip('<>').split(',')
521 linkattrs
['flags'] = flags
522 linkattrs
['ifflag'] = 'UP' if 'UP' in flags
else 'DOWN'
523 for i
in range(0, len(citems
)):
525 if citems
[i
] == 'mtu':
526 linkattrs
['mtu'] = citems
[i
+ 1]
527 elif citems
[i
] == 'state':
528 linkattrs
['state'] = citems
[i
+ 1]
529 elif citems
[i
] == 'link/ether':
530 linkattrs
['hwaddress'] = citems
[i
+ 1]
531 elif citems
[i
] in ['link/gre', 'link/ipip', 'link/sit', 'link/gre6', 'link/tunnel6', 'gretap']:
532 linkattrs
['kind'] = 'tunnel'
533 tunattrs
= {'mode': citems
[i
].split('/')[-1],
538 for j
in range(i
, len(citems
)):
539 if citems
[j
] == 'local':
540 tunattrs
['local'] = citems
[j
+ 1]
541 elif citems
[j
] == 'remote':
542 tunattrs
['endpoint'] = citems
[j
+ 1]
543 elif citems
[j
] == 'ttl':
544 tunattrs
['ttl'] = citems
[j
+ 1]
545 elif citems
[j
] == 'dev':
546 tunattrs
['physdev'] = citems
[j
+ 1]
547 linkattrs
['linkinfo'] = tunattrs
549 elif citems
[i
] == 'link/ppp':
550 linkattrs
['kind'] = 'ppp'
551 elif citems
[i
] == 'vlan':
552 vlanid
= self
._get
_vland
_id
(citems
, i
, warn
)
554 linkattrs
['linkinfo'] = {'vlanid': vlanid
}
555 linkattrs
['kind'] = 'vlan'
556 elif citems
[i
] == 'dummy':
557 linkattrs
['kind'] = 'dummy'
558 elif citems
[i
] == 'vxlan' and citems
[i
+ 1] == 'id':
559 linkattrs
['kind'] = 'vxlan'
560 vattrs
= {'vxlanid': citems
[i
+ 2],
563 'ageing': citems
[i
+ 2],
565 for j
in range(i
+ 2, len(citems
)):
566 if citems
[j
] == 'local':
567 vattrs
['local'] = citems
[j
+ 1]
568 elif citems
[j
] == 'remote':
569 vattrs
['svcnode'] = citems
[j
+ 1]
570 elif citems
[j
] == 'ageing':
571 vattrs
['ageing'] = citems
[j
+ 1]
572 elif citems
[j
] == 'nolearning':
573 vattrs
['learning'] = 'off'
574 elif citems
[j
] == 'dev':
575 vattrs
['physdev'] = citems
[j
+ 1]
576 linkattrs
['linkinfo'] = vattrs
578 elif citems
[i
] == 'vrf' and citems
[i
+ 1] == 'table':
579 vattrs
= {'table': citems
[i
+ 2]}
580 linkattrs
['linkinfo'] = vattrs
581 linkattrs
['kind'] = 'vrf'
582 linkCache
.vrfs
[ifname
] = vattrs
584 elif citems
[i
] == 'veth':
585 linkattrs
['kind'] = 'veth'
586 elif citems
[i
] == 'vrf_slave':
587 linkattrs
['slave_kind'] = 'vrf_slave'
589 elif citems
[i
] == 'macvlan' and citems
[i
+ 1] == 'mode':
590 linkattrs
['kind'] = 'macvlan'
591 except Exception as e
:
593 self
.logger
.debug('%s: parsing error: id, mtu, state, '
594 'link/ether, vlan, dummy, vxlan, local, '
595 'remote, ageing, nolearning, vrf, table, '
596 'vrf_slave are reserved keywords: %s' %
599 # linkattrs['alias'] = self.read_file_oneline(
600 # '/sys/class/net/%s/ifalias' %ifname)
601 linkout
[ifname
] = linkattrs
602 [linkCache
.update_attrdict([ifname
], linkattrs
)
603 for ifname
, linkattrs
in linkout
.items()]
606 def _addr_filter(ifname
, addr
, scope
=None):
607 default_addrs
= ['127.0.0.1/8', '::1/128', '0.0.0.0']
608 if ifname
== 'lo' and addr
in default_addrs
:
610 if scope
and scope
== 'link':
614 def _addr_fill(self
, ifacename
=None, refresh
=False):
615 """ fills cache with address information
617 if ifacename argument given, fill cache for ifacename, else
618 fill cache for all interfaces in the system
620 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
623 # Check if ifacename is already full, in which case, return
624 if ifacename
and not refresh
:
625 linkCache
.get_attr([ifacename
, 'addrs'])
632 [linkCache
.update_attrdict([ifname
], linkattrs
)
633 for ifname
, linkattrs
in netlink
.addr_dump(ifname
=ifacename
).items()]
634 except Exception as e
:
635 self
.logger
.info(str(e
))
637 # this netlink call replaces the call to _addr_fill_iproute2_cmd()
638 # We shouldn't have netlink calls in the iproute2 module, this will
639 # be removed in the future. We plan to release, a flexible backend
640 # (netlink+iproute2) by default we will use netlink backend but with
641 # a CLI arg we can switch to iproute2 backend.
642 # Until we decide to create this "backend" switch capability,
643 # we have to put the netlink call inside the iproute2 module.
646 self
._addr
_fill
_iproute
2_cmd
(ifacename
, refresh
)
648 def _addr_fill_iproute2_cmd(self
, ifacename
=None, refresh
=False):
649 """ fills cache with address information
651 if ifacename argument given, fill cache for ifacename, else
652 fill cache for all interfaces in the system
655 if LinkUtils
._CACHE
_FILL
_DONE
and not refresh
:
658 # Check if ifacename is already full, in which case, return
659 if ifacename
and not refresh
:
660 linkCache
.get_attr([ifacename
, 'addrs'])
664 cmdout
= self
.addr_show(ifacename
=ifacename
)
667 for c
in cmdout
.splitlines():
669 ifnamenlink
= citems
[1].split('@')
670 if len(ifnamenlink
) > 1:
671 ifname
= ifnamenlink
[0]
673 ifname
= ifnamenlink
[0].strip(':')
674 if not linkout
.get(ifname
):
676 linkattrs
['addrs'] = OrderedDict({})
678 linkout
[ifname
].update(linkattrs
)
680 linkout
[ifname
] = linkattrs
681 if citems
[2] == 'inet':
682 if self
._addr
_filter
(ifname
, citems
[3], scope
=citems
[5]):
685 addrattrs
['scope'] = citems
[5]
686 addrattrs
['type'] = 'inet'
687 linkout
[ifname
]['addrs'][citems
[3]] = addrattrs
688 elif citems
[2] == 'inet6':
689 if self
._addr
_filter
(ifname
, citems
[3], scope
=citems
[5]):
691 if citems
[5] == 'link':
692 continue # skip 'link' addresses
694 addrattrs
['scope'] = citems
[5]
695 addrattrs
['type'] = 'inet6'
696 linkout
[ifname
]['addrs'][citems
[3]] = addrattrs
697 [linkCache
.update_attrdict([ifname
], linkattrs
)
698 for ifname
, linkattrs
in linkout
.items()]
700 def cache_get(self
, t
, attrlist
, refresh
=False):
701 return self
._cache
_get
(t
, attrlist
, refresh
)
703 def _cache_get(self
, t
, attrlist
, refresh
=False):
705 if ifupdownflags
.flags
.DRYRUN
:
707 if ifupdownflags
.flags
.CACHE
:
708 if self
._fill
_cache
():
709 # if we filled the cache, return new data
710 return linkCache
.get_attr(attrlist
)
712 return linkCache
.get_attr(attrlist
)
714 self
._link
_fill
(attrlist
[0], refresh
)
716 self
._addr
_fill
(attrlist
[0], refresh
)
718 self
._link
_fill
(attrlist
[0], refresh
)
719 self
._addr
_fill
(attrlist
[0], refresh
)
720 return linkCache
.get_attr(attrlist
)
722 self
.logger
.debug('_cache_get(%s) : [%s]' % (str(attrlist
), str(e
)))
725 def cache_check(self
, attrlist
, value
, refresh
=False):
726 return self
._cache
_check
('link', attrlist
, value
, refresh
=refresh
)
728 def _cache_check(self
, t
, attrlist
, value
, refresh
=False):
730 return self
._cache
_get
(t
, attrlist
, refresh
) == value
732 self
.logger
.debug('_cache_check(%s) : [%s]'
733 % (str(attrlist
), str(e
)))
736 def cache_update(self
, attrlist
, value
):
737 return self
._cache
_update
(attrlist
, value
)
740 def _cache_update(attrlist
, value
):
741 if ifupdownflags
.flags
.DRYRUN
:
744 if attrlist
[-1] == 'slaves':
745 linkCache
.append_to_attrlist(attrlist
, value
)
747 linkCache
.set_attr(attrlist
, value
)
752 def _cache_delete(attrlist
, value
=None):
753 if ifupdownflags
.flags
.DRYRUN
:
757 linkCache
.remove_from_attrlist(attrlist
, value
)
759 linkCache
.del_attr(attrlist
)
764 def _cache_invalidate():
765 linkCache
.invalidate()
766 LinkUtils
._CACHE
_FILL
_DONE
= False
770 LinkUtils
.ipbatcbuf
= ''
771 LinkUtils
.ipbatch
= True
772 LinkUtils
.ipbatch_pause
= False
775 def add_to_batch(cmd
):
776 LinkUtils
.ipbatchbuf
+= cmd
+ '\n'
780 LinkUtils
.ipbatch_pause
= True
784 LinkUtils
.ipbatch_pause
= False
786 def batch_commit(self
):
787 if not LinkUtils
.ipbatchbuf
:
788 LinkUtils
.ipbatchbuf
= ''
789 LinkUtils
.ipbatch
= False
790 LinkUtils
.ipbatch_pause
= False
793 utils
.exec_command('%s -force -batch -' % utils
.ip_cmd
,
794 stdin
=self
.ipbatchbuf
)
798 LinkUtils
.ipbatchbuf
= ''
799 LinkUtils
.ipbatch
= False
800 LinkUtils
.ipbatch_pause
= False
802 def bridge_batch_commit(self
):
803 if not LinkUtils
.ipbatchbuf
:
804 LinkUtils
.ipbatchbuf
= ''
805 LinkUtils
.ipbatch
= False
806 LinkUtils
.ipbatch_pause
= False
809 utils
.exec_command('%s -force -batch -'
810 % utils
.bridge_cmd
, stdin
=self
.ipbatchbuf
)
814 LinkUtils
.ipbatchbuf
= ''
815 LinkUtils
.ipbatch
= False
816 LinkUtils
.ipbatch_pause
= False
818 def addr_show(self
, ifacename
=None):
820 if not self
.link_exists(ifacename
):
822 return utils
.exec_commandl([utils
.ip_cmd
,
823 '-o', 'addr', 'show', 'dev', ifacename
])
825 return utils
.exec_commandl([utils
.ip_cmd
,
826 '-o', 'addr', 'show'])
829 def link_show(ifacename
=None):
831 return utils
.exec_commandl([utils
.ip_cmd
,
832 '-o', '-d', 'link', 'show', 'dev', ifacename
])
834 return utils
.exec_commandl([utils
.ip_cmd
,
835 '-o', '-d', 'link', 'show'])
837 def addr_add(self
, ifacename
, address
, broadcast
=None,
838 peer
=None, scope
=None, preferred_lifetime
=None, metric
=None):
841 cmd
= 'addr add %s' % address
843 cmd
+= ' broadcast %s' % broadcast
845 cmd
+= ' peer %s' % peer
847 cmd
+= ' scope %s' % scope
848 if preferred_lifetime
:
849 cmd
+= ' preferred_lft %s' % preferred_lifetime
850 cmd
+= ' dev %s' % ifacename
853 cmd
+= ' metric %s' % metric
855 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
856 self
.add_to_batch(cmd
)
858 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
859 self
._cache
_update
([ifacename
, 'addrs', address
], {})
861 def addr_del(self
, ifacename
, address
, broadcast
=None,
862 peer
=None, scope
=None):
863 """ Delete ipv4 address """
866 if not self
._cache
_get
('addr', [ifacename
, 'addrs', address
]):
868 cmd
= 'addr del %s' % address
870 cmd
+= 'broadcast %s' % broadcast
872 cmd
+= 'peer %s' % peer
874 cmd
+= 'scope %s' % scope
875 cmd
+= ' dev %s' % ifacename
876 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
877 self
._cache
_delete
([ifacename
, 'addrs', address
])
879 def addr_flush(self
, ifacename
):
880 cmd
= 'addr flush dev %s' % ifacename
881 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
882 self
.add_to_batch(cmd
)
884 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
885 self
._cache
_delete
([ifacename
, 'addrs'])
887 def del_addr_all(self
, ifacename
, skip_addrs
=[]):
890 runningaddrsdict
= self
.get_running_addrs(ifname
=ifacename
)
892 # XXX: ignore errors. Fix this to delete secondary addresses
894 [self
.addr_del(ifacename
, a
) for a
in
895 set(runningaddrsdict
.keys()).difference(skip_addrs
)]
900 def addr_get(self
, ifacename
, details
=True, refresh
=False):
901 addrs
= self
._cache
_get
('addr', [ifacename
, 'addrs'], refresh
=refresh
)
908 def get_running_addrs(self
, ifaceobj
=None, ifname
=None, details
=True, addr_virtual_ifaceobj
=None):
910 We now support addr with link scope. Since the kernel may add it's
911 own link address to some interfaces we need to filter them out and
912 make sure we only deal with the addresses set by ifupdown2.
914 To do so we look at the previous configuration made by ifupdown2
915 (with the help of the statemanager) together with the addresses
916 specified by the user in /etc/network/interfaces, these addresses
917 are then compared to the running state of the intf (ip addr show)
918 made via a netlink addr dump.
919 For each configured addresses of scope link, we check if it was
920 previously configured by ifupdown2 to create a final set of the
921 addresses watched by ifupdown2
923 if not ifaceobj
and not ifname
:
929 interface_name
= ifaceobj
.name
931 interface_name
= ifname
933 if addr_virtual_ifaceobj
:
934 for virtual
in addr_virtual_ifaceobj
.get_attr_value('address-virtual') or []:
935 for ip
in virtual
.split():
942 saved_ifaceobjs
= statemanager
.statemanager_api
.get_ifaceobjs(addr_virtual_ifaceobj
.name
)
943 for saved_ifaceobj
in saved_ifaceobjs
or []:
944 for virtual
in saved_ifaceobj
.get_attr_value('address-virtual') or []:
945 for ip
in virtual
.split():
953 for addr
in ifaceobj
.get_attr_value('address') or []:
954 config_addrs
.add(addr
)
956 saved_ifaceobjs
= statemanager
.statemanager_api
.get_ifaceobjs(interface_name
)
957 for saved_ifaceobj
in saved_ifaceobjs
or []:
958 for addr
in saved_ifaceobj
.get_attr_value('address') or []:
959 config_addrs
.add(addr
)
961 running_addrs
= OrderedDict()
962 cached_addrs
= self
.addr_get(interface_name
)
964 for addr
, addr_details
in cached_addrs
.items():
966 scope
= int(addr_details
['scope'])
970 addr_obj
= IPNetwork(addr
)
971 if isinstance(addr_obj
, IPv6Network
):
972 d
['family'] = 'inet6'
975 running_addrs
[addr
] = d
977 running_addrs
[addr
] = {}
979 if (scope
& Route
.RT_SCOPE_LINK
and addr
in config_addrs
) or not scope
& Route
.RT_SCOPE_LINK
:
980 running_addrs
[addr
] = addr_details
986 return running_addrs
.keys()
989 def compare_user_config_vs_running_state(running_addrs
, user_addrs
):
993 for ip
in user_addrs
or []:
996 if type(obj
) == IPv6Network
:
1002 for ip
in running_addrs
or []:
1003 running_ipobj
.append(IPNetwork(ip
))
1005 return running_ipobj
== (ip4
+ ip6
)
1007 def addr_add_multiple(self
, ifaceobj
, ifacename
, addrs
, purge_existing
=False, metric
=None):
1010 # if perfmode is not set and also if iface has no sibling
1011 # objects, purge addresses that are not present in the new
1013 runningaddrs
= self
.get_running_addrs(
1016 addr_virtual_ifaceobj
=ifaceobj
1018 addrs
= utils
.get_normalized_ip_addr(ifacename
, addrs
)
1020 if self
.compare_user_config_vs_running_state(runningaddrs
, addrs
):
1023 # if primary address is not same, there is no need to keep any.
1024 # reset all addresses
1025 if (addrs
and runningaddrs
and
1026 (addrs
[0] != runningaddrs
[0])):
1027 self
.del_addr_all(ifacename
)
1029 self
.del_addr_all(ifacename
, addrs
)
1030 except Exception, e
:
1031 self
.logger
.warning('%s: %s' % (ifacename
, str(e
)))
1034 self
.addr_add(ifacename
, a
, metric
=metric
)
1035 except Exception, e
:
1036 self
.logger
.error(str(e
))
1038 def _link_set_ifflag(self
, ifacename
, value
):
1039 # Dont look at the cache, the cache may have stale value
1040 # because link status can be changed by external
1041 # entity (One such entity is ifupdown main program)
1042 cmd
= 'link set dev %s %s' % (ifacename
, value
.lower())
1043 if LinkUtils
.ipbatch
:
1044 self
.add_to_batch(cmd
)
1046 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1048 def link_up(self
, ifacename
):
1049 self
._link
_set
_ifflag
(ifacename
, 'UP')
1051 def link_down(self
, ifacename
):
1052 self
._link
_set
_ifflag
(ifacename
, 'DOWN')
1054 def link_set(self
, ifacename
, key
, value
=None,
1055 force
=False, t
=None, state
=None):
1057 if (key
not in ['master', 'nomaster'] and
1058 self
._cache
_check
('link', [ifacename
, key
], value
)):
1060 cmd
= 'link set dev %s' % ifacename
1062 cmd
+= ' type %s' % t
1065 cmd
+= ' %s' % value
1067 cmd
+= ' %s' % state
1068 if LinkUtils
.ipbatch
:
1069 self
.add_to_batch(cmd
)
1071 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1072 if key
not in ['master', 'nomaster']:
1073 self
._cache
_update
([ifacename
, key
], value
)
1075 def link_set_hwaddress(self
, ifacename
, hwaddress
, force
=False):
1077 if self
._cache
_check
('link', [ifacename
, 'hwaddress'], hwaddress
):
1079 self
.link_down(ifacename
)
1080 cmd
= 'link set dev %s address %s' % (ifacename
, hwaddress
)
1081 if LinkUtils
.ipbatch
:
1082 self
.add_to_batch(cmd
)
1084 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1085 self
.link_up(ifacename
)
1086 self
._cache
_update
([ifacename
, 'hwaddress'], hwaddress
)
1088 def link_set_mtu(self
, ifacename
, mtu
):
1089 if ifupdownflags
.flags
.DRYRUN
:
1091 if not mtu
or not ifacename
: return
1092 self
.write_file('/sys/class/net/%s/mtu' % ifacename
, mtu
)
1093 self
._cache
_update
([ifacename
, 'mtu'], mtu
)
1095 def link_set_alias(self
, ifacename
, alias
):
1096 self
.write_file('/sys/class/net/%s/ifalias' % ifacename
,
1097 '\n' if not alias
else alias
)
1099 def link_get_alias(self
, ifacename
):
1100 return self
.read_file_oneline('/sys/class/net/%s/ifalias'
1103 def link_isloopback(self
, ifacename
):
1104 flags
= self
._cache
_get
('link', [ifacename
, 'flags'])
1107 if 'LOOPBACK' in flags
:
1111 def link_get_status(self
, ifacename
):
1112 return self
._cache
_get
('link', [ifacename
, 'ifflag'], refresh
=True)
1115 def route_add_gateway(ifacename
, gateway
, vrf
=None, metric
=None):
1119 cmd
= '%s route add default via %s proto kernel' % (utils
.ip_cmd
,
1122 cmd
= ('%s route add table %s default via %s proto kernel' %
1123 (utils
.ip_cmd
, vrf
, gateway
))
1126 cmd
+= 'metric %s' % metric
1127 cmd
+= ' dev %s' % ifacename
1128 utils
.exec_command(cmd
)
1131 def route_del_gateway(ifacename
, gateway
, vrf
=None, metric
=None):
1136 cmd
= ('%s route del default via %s proto kernel' %
1137 (utils
.ip_cmd
, gateway
))
1139 cmd
= ('%s route del table %s default via %s proto kernel' %
1140 (utils
.ip_cmd
, vrf
, gateway
))
1142 cmd
+= ' metric %s' % metric
1143 cmd
+= ' dev %s' % ifacename
1144 utils
.exec_command(cmd
)
1147 def _get_vrf_id(ifacename
):
1149 return linkCache
.vrfs
[ifacename
]['table']
1151 dump
= netlink
.link_dump(ifacename
)
1153 [linkCache
.update_attrdict([ifname
], linkattrs
)
1154 for ifname
, linkattrs
in dump
.items()]
1156 if dump
and dump
.get(ifacename
, {}).get('kind') == 'vrf':
1157 vrf_table
= dump
.get(ifacename
, {}).get('linkinfo', {}).get('table')
1158 linkCache
.vrfs
[ifacename
] = {'table': vrf_table
}
1163 def fix_ipv6_route_metric(self
, ifaceobj
, macvlan_ifacename
, ips
):
1166 if ifaceobj
.link_privflags
& ifaceLinkPrivFlags
.VRF_SLAVE
:
1168 for upper_iface
in ifaceobj
.upperifaces
:
1169 vrf_table
= self
._get
_vrf
_id
(upper_iface
)
1177 ip_network_obj
= IPNetwork(ip
)
1179 if type(ip_network_obj
) == IPv6Network
:
1180 route_prefix
= '%s/%d' % (ip_network_obj
.network
, ip_network_obj
.prefixlen
)
1183 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1184 LinkUtils
.add_to_batch('route del %s table %s dev %s' % (route_prefix
, vrf_table
, macvlan_ifacename
))
1186 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'del', route_prefix
, 'table', vrf_table
, 'dev', macvlan_ifacename
])
1188 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1189 LinkUtils
.add_to_batch('route del %s dev %s' % (route_prefix
, macvlan_ifacename
))
1191 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'del', route_prefix
, 'dev', macvlan_ifacename
])
1192 ip_route_del
.append((route_prefix
, vrf_table
))
1194 for ip
, vrf_table
in ip_route_del
:
1196 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1197 LinkUtils
.add_to_batch('route add %s table %s dev %s proto kernel metric 9999' % (ip
, vrf_table
, macvlan_ifacename
))
1199 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'add', ip
, 'table', vrf_table
, 'dev', macvlan_ifacename
, 'proto', 'kernel' 'metric', '9999'])
1201 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1202 LinkUtils
.add_to_batch('route add %s dev %s proto kernel metric 9999' % (ip
, macvlan_ifacename
))
1204 utils
.exec_commandl([utils
.ip_cmd
, 'route', 'add', ip
, 'dev', macvlan_ifacename
, 'proto', 'kernel' 'metric', '9999'])
1206 def link_create_vlan(self
, vlan_device_name
, vlan_raw_device
, vlanid
):
1207 if self
.link_exists(vlan_device_name
):
1209 utils
.exec_command('%s link add link %s name %s type vlan id %d' %
1211 vlan_raw_device
, vlan_device_name
, vlanid
))
1212 self
._cache
_update
([vlan_device_name
], {})
1214 def link_create_vlan_from_name(self
, vlan_device_name
):
1215 v
= vlan_device_name
.split('.')
1217 self
.logger
.warn('invalid vlan device name %s' % vlan_device_name
)
1219 self
.link_create_vlan(vlan_device_name
, v
[0], v
[1])
1221 def link_create_macvlan(self
, name
, linkdev
, mode
='private'):
1222 if self
.link_exists(name
):
1224 cmd
= ('link add link %s' % linkdev
+
1226 ' type macvlan mode %s' % mode
)
1227 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1228 self
.add_to_batch(cmd
)
1230 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1231 self
._cache
_update
([name
], {})
1233 def get_vxlan_peers(self
, dev
, svcnodeip
):
1234 cmd
= '%s fdb show brport %s' % (utils
.bridge_cmd
,
1238 ps
= subprocess
.Popen(shlex
.split(cmd
), stdout
=subprocess
.PIPE
, close_fds
=False)
1239 utils
.enable_subprocess_signal_forwarding(ps
, signal
.SIGINT
)
1240 output
= subprocess
.check_output(('grep', '00:00:00:00:00:00'), stdin
=ps
.stdout
)
1242 utils
.disable_subprocess_signal_forwarding(signal
.SIGINT
)
1244 ppat
= re
.compile('\s+dst\s+(\d+.\d+.\d+.\d+)\s+')
1245 for l
in output
.split('\n'):
1247 if m
and m
.group(1) != svcnodeip
:
1248 cur_peers
.append(m
.group(1))
1250 self
.logger
.warn('error parsing ip link output')
1251 except subprocess
.CalledProcessError
as e
:
1252 if e
.returncode
!= 1:
1253 self
.logger
.error(str(e
))
1255 utils
.disable_subprocess_signal_forwarding(signal
.SIGINT
)
1259 def tunnel_create(self
, tunnelname
, mode
, attrs
={}):
1260 """ generic link_create function """
1261 if self
.link_exists(tunnelname
):
1269 cmd
+= ' %s mode %s' %(tunnelname
, mode
)
1271 for k
, v
in attrs
.iteritems():
1275 if self
.ipbatch
and not self
.ipbatch_pause
:
1276 self
.add_to_batch(cmd
)
1278 utils
.exec_command('ip %s' % cmd
)
1279 self
._cache
_update
([tunnelname
], {})
1281 def tunnel_change(self
, tunnelname
, attrs
={}):
1282 """ tunnel change function """
1283 if not self
.link_exists(tunnelname
):
1285 cmd
= 'tunnel change'
1286 cmd
+= ' %s' %(tunnelname)
1288 for k
, v
in attrs
.iteritems():
1292 if self
.ipbatch
and not self
.ipbatch_pause
:
1293 self
.add_to_batch(cmd
)
1295 utils
.exec_command('ip %s' % cmd
)
1296 self
._cache
_update
([tunnelname
], {})
1298 def link_create_vxlan(self
, name
, vxlanid
,
1305 if svcnodeip
and remoteips
:
1306 raise Exception("svcnodeip and remoteip is mutually exclusive")
1309 args
+= ' remote %s' % svcnodeip
1311 args
+= ' ageing %s' % ageing
1312 if learning
== 'off':
1313 args
+= ' nolearning'
1315 if self
.link_exists(name
):
1316 cmd
= 'link set dev %s type vxlan dstport %d' % (name
, LinkUtils
.VXLAN_UDP_PORT
)
1317 vxlanattrs
= self
.get_vxlandev_attrs(name
)
1318 # on ifreload do not overwrite anycast_ip to individual ip if clagd
1321 running_localtunnelip
= vxlanattrs
.get('local')
1322 if anycastip
and running_localtunnelip
and anycastip
== running_localtunnelip
:
1323 localtunnelip
= running_localtunnelip
1324 running_svcnode
= vxlanattrs
.get('svcnode')
1325 if running_svcnode
and not svcnodeip
:
1328 cmd
= 'link add dev %s type vxlan id %s dstport %d' % (name
, vxlanid
, LinkUtils
.VXLAN_UDP_PORT
)
1331 args
+= ' local %s' % localtunnelip
1334 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1335 self
.add_to_batch(cmd
)
1337 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1339 # XXX: update linkinfo correctly
1340 #self._cache_update([name], {})
1343 def link_exists(ifacename
):
1344 if ifupdownflags
.flags
.DRYRUN
:
1346 return os
.path
.exists('/sys/class/net/%s' % ifacename
)
1348 def link_get_ifindex(self
, ifacename
):
1349 if ifupdownflags
.flags
.DRYRUN
:
1351 return self
.read_file_oneline('/sys/class/net/%s/ifindex' % ifacename
)
1353 def is_vlan_device_by_name(self
, ifacename
):
1354 if re
.search(r
'\.', ifacename
):
1359 def link_add_macvlan(ifname
, macvlan_ifacename
):
1360 utils
.exec_commandl(['ip', 'link', 'add', 'link', ifname
, 'name', macvlan_ifacename
, 'type', 'macvlan', 'mode', 'private'])
1363 def route_add(route
):
1364 utils
.exec_command('%s route add %s' % (utils
.ip_cmd
,
1368 def route6_add(route
):
1369 utils
.exec_command('%s -6 route add %s' % (utils
.ip_cmd
,
1372 def get_vlandev_attrs(self
, ifacename
):
1373 return (self
._cache
_get
('link', [ifacename
, 'link']),
1374 self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlanid']),
1375 self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlan_protocol']))
1377 def get_vlan_protocol(self
, ifacename
):
1378 return self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlan_protocol'])
1380 def get_vxlandev_attrs(self
, ifacename
):
1381 return self
._cache
_get
('link', [ifacename
, 'linkinfo'])
1383 def get_vxlandev_learning(self
, ifacename
):
1384 return self
._cache
_get
('link', [ifacename
, 'linkinfo', Link
.IFLA_VXLAN_LEARNING
])
1386 def set_vxlandev_learning(self
, ifacename
, learn
):
1388 utils
.exec_command('%s link set dev %s type vxlan learning' %
1389 (utils
.ip_cmd
, ifacename
))
1390 self
._cache
_update
([ifacename
, 'linkinfo', 'learning'], 'on')
1392 utils
.exec_command('%s link set dev %s type vxlan nolearning' %
1393 (utils
.ip_cmd
, ifacename
))
1394 self
._cache
_update
([ifacename
, 'linkinfo', 'learning'], 'off')
1396 def link_get_linkinfo_attrs(self
, ifacename
):
1397 return self
._cache
_get
('link', [ifacename
, 'linkinfo'])
1399 def link_get_mtu(self
, ifacename
, refresh
=False):
1400 return self
._cache
_get
('link', [ifacename
, 'mtu'], refresh
=refresh
)
1402 def link_get_mtu_sysfs(self
, ifacename
):
1403 return self
.read_file_oneline('/sys/class/net/%s/mtu'
1406 def link_get_kind(self
, ifacename
):
1407 return self
._cache
_get
('link', [ifacename
, 'kind'])
1409 def link_get_slave_kind(self
, ifacename
):
1410 return self
._cache
_get
('link', [ifacename
, 'slave_kind'])
1412 def link_get_hwaddress(self
, ifacename
):
1413 address
= self
._cache
_get
('link', [ifacename
, 'hwaddress'])
1414 # newly created logical interface addresses dont end up in the cache
1415 # read hwaddress from sysfs file for these interfaces
1417 address
= self
.read_file_oneline('/sys/class/net/%s/address'
1421 def link_create(self
, ifacename
, t
, attrs
={}):
1422 """ generic link_create function """
1423 if self
.link_exists(ifacename
):
1426 cmd
+= ' name %s type %s' % (ifacename
, t
)
1428 for k
, v
in attrs
.iteritems():
1432 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1433 self
.add_to_batch(cmd
)
1435 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1436 self
._cache
_update
([ifacename
], {})
1438 def link_delete(self
, ifacename
):
1439 if not self
.link_exists(ifacename
):
1441 cmd
= 'link del %s' % ifacename
1442 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1443 self
.add_to_batch(cmd
)
1445 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1446 self
._cache
_invalidate
()
1448 def link_get_master(self
, ifacename
):
1449 sysfs_master_path
= '/sys/class/net/%s/master' % ifacename
1450 if os
.path
.exists(sysfs_master_path
):
1451 link_path
= os
.readlink(sysfs_master_path
)
1453 return os
.path
.basename(link_path
)
1457 return self
._cache
_get
('link', [ifacename
, 'master'])
1459 def get_brport_peer_link(self
, bridgename
):
1461 return self
._cache
_get
('link', [bridgename
, 'info_slave_data', Link
.IFLA_BRPORT_PEER_LINK
])
1466 def bridge_port_vids_add(bridgeportname
, vids
):
1467 [utils
.exec_command('%s vlan add vid %s dev %s' %
1469 v
, bridgeportname
)) for v
in vids
]
1472 def bridge_port_vids_del(bridgeportname
, vids
):
1475 [utils
.exec_command('%s vlan del vid %s dev %s' %
1477 v
, bridgeportname
)) for v
in vids
]
1480 def bridge_port_vids_flush(bridgeportname
, vid
):
1481 utils
.exec_command('%s vlan del vid %s dev %s' %
1483 vid
, bridgeportname
))
1486 def bridge_port_vids_get(bridgeportname
):
1487 bridgeout
= utils
.exec_command('%s vlan show dev %s' %
1492 brvlanlines
= bridgeout
.readlines()[2:]
1493 vids
= [l
.strip() for l
in brvlanlines
]
1494 return [v
for v
in vids
if v
]
1497 def bridge_port_vids_get_all():
1499 bridgeout
= utils
.exec_command('%s -c vlan show'
1503 brvlanlines
= bridgeout
.splitlines()
1505 for l
in brvlanlines
[1:]:
1506 if l
and not l
.startswith(' ') and not l
.startswith('\t'):
1508 brportname
= attrs
[0].strip()
1509 brvlaninfo
[brportname
] = {'pvid': None, 'vlan': []}
1510 l
= ' '.join(attrs
[1:])
1511 if not brportname
or not l
:
1515 brvlaninfo
[brportname
]['pvid'] = l
.split()[0]
1516 elif 'Egress Untagged' not in l
:
1517 brvlaninfo
[brportname
]['vlan'].append(l
)
1520 def bridge_port_vids_get_all_json(self
):
1521 if not self
.supported_command
['%s -c -json vlan show'
1522 % utils
.bridge_cmd
]:
1526 bridgeout
= utils
.exec_command('%s -c -json vlan show'
1529 self
.supported_command
['%s -c -json vlan show'
1530 % utils
.bridge_cmd
] = False
1531 self
.logger
.info('%s -c -json vlan show: skipping unsupported command'
1534 return self
.get_bridge_vlan_nojson()
1535 except Exception as e
:
1536 self
.logger
.info('bridge: get_bridge_vlan_nojson: %s' % str(e
))
1539 if not bridgeout
: return brvlaninfo
1541 vlan_json_dict
= json
.loads(bridgeout
, encoding
="utf-8")
1542 except Exception, e
:
1543 self
.logger
.info('json loads failed with (%s)' % str(e
))
1545 return vlan_json_dict
1548 def get_bridge_vlan_nojson():
1550 bridgeout
= utils
.exec_commandl([utils
.bridge_cmd
, '-c', 'vlan', 'show'])
1552 output
= [line
.split('\n') for line
in bridgeout
.split('\n\n')]
1553 output
[0] = output
[0][1:]
1561 prefix
, vlan
= entry
.split('\t')
1563 current_swp
= prefix
1564 vlan_json
[prefix
] = []
1568 v
['vlan'] = int(vlan
)
1572 start
, end
= vlan
.split('-')
1574 end
= end
[0:end
.index(' ')]
1575 v
['vlan'] = int(start
)
1576 v
['vlanEnd'] = int(end
)
1578 v
['vlan'] = int(vlan
[0:vlan
.index(' ')])
1581 flags
.append('PVID')
1582 if 'Egress Untagged' in vlan
:
1583 flags
.append('Egress Untagged')
1587 vlan_json
[current_swp
].append(v
)
1590 def bridge_vlan_cache_get(self
, ifacename
, refresh
=False):
1591 if not self
.bridge_vlan_cache_fill_done
or refresh
:
1592 self
.bridge_vlan_cache
= self
.bridge_port_vids_get_all_json()
1593 self
.bridge_vlan_cache_fill_done
= True
1594 return self
.bridge_vlan_cache
.get(ifacename
, {})
1596 def bridge_vlan_get_pvid(self
, ifacename
, refresh
=False):
1599 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1600 v
= vinfo
.get('vlan')
1601 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1606 def bridge_vlan_get_vids(self
, ifacename
, refresh
=False):
1609 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1610 v
= vinfo
.get('vlan')
1611 ispvid
= True if 'PVID' in vinfo
.get('flags', []) else False
1613 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1616 vEnd
= vinfo
.get('vlanEnd')
1618 vids
.extend(range(v
, vEnd
+ 1))
1623 def bridge_vlan_get_vids_n_pvid(self
, ifacename
, refresh
=False):
1627 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1628 v
= vinfo
.get('vlan')
1629 ispvid
= True if 'PVID' in vinfo
.get('flags', []) else False
1631 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1632 vEnd
= vinfo
.get('vlanEnd')
1634 vids
.extend(range(v
, vEnd
+ 1))
1639 def bridge_port_pvid_add(self
, bridgeportname
, pvid
):
1640 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1641 self
.add_to_batch('vlan add vid %s untagged pvid dev %s' %
1642 (pvid
, bridgeportname
))
1644 utils
.exec_command('%s vlan add vid %s untagged pvid dev %s' %
1646 pvid
, bridgeportname
))
1648 def bridge_port_pvid_del(self
, bridgeportname
, pvid
):
1649 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1650 self
.add_to_batch('vlan del vid %s untagged pvid dev %s' %
1651 (pvid
, bridgeportname
))
1653 utils
.exec_command('%s vlan del vid %s untagged pvid dev %s' %
1655 pvid
, bridgeportname
))
1657 def bridge_port_pvids_get(self
, bridgeportname
):
1658 return self
.read_file_oneline('/sys/class/net/%s/brport/pvid'
1661 def bridge_vids_add(self
, bridgeportname
, vids
, bridge
=True):
1662 target
= 'self' if bridge
else ''
1663 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1664 [self
.add_to_batch('vlan add vid %s dev %s %s' %
1665 (v
, bridgeportname
, target
)) for v
in vids
]
1667 [utils
.exec_command('%s vlan add vid %s dev %s %s' %
1669 v
, bridgeportname
, target
)) for v
in vids
]
1671 def bridge_vids_del(self
, bridgeportname
, vids
, bridge
=True):
1672 target
= 'self' if bridge
else ''
1673 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1674 [self
.add_to_batch('vlan del vid %s dev %s %s' %
1675 (v
, bridgeportname
, target
)) for v
in vids
]
1677 [utils
.exec_command('%s vlan del vid %s dev %s %s' %
1679 v
, bridgeportname
, target
)) for v
in vids
]
1682 def bridge_fdb_add(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1683 target
= 'self' if bridge
else ''
1686 vlan_str
= 'vlan %s ' % vlan
1690 dst_str
= 'dst %s ' % remote
1692 utils
.exec_command('%s fdb replace %s dev %s %s %s %s' %
1694 address
, dev
, vlan_str
, target
, dst_str
))
1697 def bridge_fdb_append(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1698 target
= 'self' if bridge
else ''
1701 vlan_str
= 'vlan %s ' % vlan
1705 dst_str
= 'dst %s ' % remote
1707 utils
.exec_command('%s fdb append %s dev %s %s %s %s' %
1709 address
, dev
, vlan_str
, target
, dst_str
))
1712 def bridge_fdb_del(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1713 target
= 'self' if bridge
else ''
1716 vlan_str
= 'vlan %s ' % vlan
1720 dst_str
= 'dst %s ' % remote
1721 utils
.exec_command('%s fdb del %s dev %s %s %s %s' %
1723 address
, dev
, vlan_str
, target
, dst_str
))
1725 def bridge_is_vlan_aware(self
, bridgename
):
1726 filename
= '/sys/class/net/%s/bridge/vlan_filtering' % bridgename
1727 if os
.path
.exists(filename
) and self
.read_file_oneline(filename
) == '1':
1732 def bridge_port_get_bridge_name(bridgeport
):
1733 filename
= '/sys/class/net/%s/brport/bridge' % bridgeport
1735 return os
.path
.basename(os
.readlink(filename
))
1740 def bridge_port_exists(bridge
, bridgeportname
):
1742 return os
.path
.exists('/sys/class/net/%s/brif/%s'
1743 % (bridge
, bridgeportname
))
1747 def bridge_fdb_show_dev(self
, dev
):
1750 output
= utils
.exec_command('%s fdb show dev %s'
1751 % (utils
.bridge_cmd
, dev
))
1753 for fdb_entry
in output
.splitlines():
1755 entries
= fdb_entry
.split()
1756 fdbs
.setdefault(entries
[2], []).append(entries
[0])
1758 self
.logger
.debug('%s: invalid fdb line \'%s\''
1765 def is_bridge(bridge
):
1766 return os
.path
.exists('/sys/class/net/%s/bridge' % bridge
)
1768 def is_link_up(self
, ifacename
):
1771 flags
= self
.read_file_oneline('/sys/class/net/%s/flags' % ifacename
)
1772 iflags
= int(flags
, 16)
1779 def ip_route_get_dev(self
, prefix
, vrf_master
=None):
1782 cmd
= '%s route get %s vrf %s' % (utils
.ip_cmd
, prefix
, vrf_master
)
1784 cmd
= '%s route get %s' % (utils
.ip_cmd
, prefix
)
1786 output
= utils
.exec_command(cmd
)
1788 rline
= output
.splitlines()[0]
1790 rattrs
= rline
.split()
1791 return rattrs
[rattrs
.index('dev') + 1]
1792 except Exception, e
:
1793 self
.logger
.debug('ip_route_get_dev: failed .. %s' % str(e
))
1797 def link_get_lowers(ifacename
):
1799 lowers
= glob
.glob("/sys/class/net/%s/lower_*" % ifacename
)
1802 return [os
.path
.basename(l
)[6:] for l
in lowers
]
1807 def link_get_uppers(ifacename
):
1809 uppers
= glob
.glob("/sys/class/net/%s/upper_*" % ifacename
)
1812 return [os
.path
.basename(u
)[6:] for u
in uppers
]
1816 def link_get_vrfs(self
):
1817 if not LinkUtils
._CACHE
_FILL
_DONE
:
1819 return linkCache
.vrfs
1822 def cache_get_info_slave(attrlist
):
1824 return linkCache
.get_attr(attrlist
)
1828 def get_brport_learning(self
, ifacename
):
1829 learn
= self
.read_file_oneline('/sys/class/net/%s/brport/learning'
1831 if learn
and learn
== '1':
1836 def get_brport_learning_bool(self
, ifacename
):
1837 return utils
.get_boolean_from_string(self
.read_file_oneline('/sys/class/net/%s/brport/learning' % ifacename
))
1839 def set_brport_learning(self
, ifacename
, learn
):
1841 return self
.write_file('/sys/class/net/%s/brport/learning'
1844 return self
.write_file('/sys/class/net/%s/brport/learning'
1847 #################################################################################
1848 ################################### BOND UTILS ##################################
1849 #################################################################################
1851 def _link_cache_get(self
, attrlist
, refresh
=False):
1852 return self
._cache
_get
('link', attrlist
, refresh
)
1854 def cache_delete(self
, attrlist
, value
=None):
1855 return self
._cache
_delete
(attrlist
, value
)
1857 def link_cache_get(self
, attrlist
, refresh
=False):
1858 return self
._link
_cache
_get
(attrlist
, refresh
)
1860 def link_cache_check(self
, attrlist
, value
, refresh
=False):
1861 return self
._link
_cache
_check
(attrlist
, value
, refresh
)
1863 def _link_cache_check(self
, attrlist
, value
, refresh
=False):
1865 return self
._link
_cache
_get
(attrlist
, refresh
) == value
1866 except Exception, e
:
1867 self
.logger
.debug('_cache_check(%s) : [%s]'
1868 % (str(attrlist
), str(e
)))
1873 Link
.IFLA_BOND_MODE
: 'mode',
1874 Link
.IFLA_BOND_MIIMON
: 'miimon',
1875 Link
.IFLA_BOND_USE_CARRIER
: 'use_carrier',
1876 Link
.IFLA_BOND_AD_LACP_RATE
: 'lacp_rate',
1877 Link
.IFLA_BOND_XMIT_HASH_POLICY
: 'xmit_hash_policy',
1878 Link
.IFLA_BOND_MIN_LINKS
: 'min_links',
1879 Link
.IFLA_BOND_NUM_PEER_NOTIF
: 'num_grat_arp',
1880 Link
.IFLA_BOND_AD_ACTOR_SYSTEM
: 'ad_actor_system',
1881 Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
: 'ad_actor_sys_prio',
1882 Link
.IFLA_BOND_AD_LACP_BYPASS
: 'lacp_bypass',
1883 Link
.IFLA_BOND_UPDELAY
: 'updelay',
1884 Link
.IFLA_BOND_DOWNDELAY
: 'downdelay',
1887 def bond_set_attrs_nl(self
, bondname
, ifla_info_data
):
1888 bond_attr_name
= 'None' # for log purpose (in case an exception raised)
1889 for nl_attr
, value
in ifla_info_data
.items():
1891 bond_attr_name
= self
.bondcmd_attrmap
[nl_attr
]
1892 file_path
= '/sys/class/net/%s/bonding/%s' % (bondname
, bond_attr_name
)
1893 if os
.path
.exists(file_path
):
1894 self
.write_file(file_path
, str(value
))
1895 except Exception as e
:
1896 exception_str
= '%s: %s %s: %s' % (bondname
, bond_attr_name
, value
, str(e
))
1897 if ifupdownflags
.flags
.FORCE
:
1898 self
.logger
.warning(exception_str
)
1900 self
.logger
.debug(exception_str
)
1902 def bond_set_attrs(self
, bondname
, attrdict
, prehook
):
1903 for attrname
, attrval
in attrdict
.items():
1904 if (self
._link
_cache
_check
([bondname
, 'linkinfo',
1905 attrname
], attrval
)):
1907 if (attrname
== 'mode'
1908 or attrname
== 'xmit_hash_policy'
1909 or attrname
== 'lacp_rate' or attrname
== 'min_links'):
1913 if ((attrname
not in ['lacp_rate',
1915 self
._link
_cache
_check
([bondname
, 'linkinfo', 'mode'], '802.3ad',
1917 self
.write_file('/sys/class/net/%s/bonding/%s'
1918 % (bondname
, attrname
), attrval
)
1919 except Exception, e
:
1920 if ifupdownflags
.flags
.FORCE
:
1921 self
.logger
.warn(str(e
))
1926 def bond_set_use_carrier(self
, bondname
, use_carrier
):
1927 if not use_carrier
or (use_carrier
!= '0' and use_carrier
!= '1'):
1929 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'use_carrier'],
1932 self
.write_file('/sys/class/net/%s' % bondname
+
1933 '/bonding/use_carrier', use_carrier
)
1934 self
._cache
_update
([bondname
, 'linkinfo',
1935 'use_carrier'], use_carrier
)
1937 def bond_get_use_carrier(self
, bondname
):
1938 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'use_carrier'])
1940 def bond_get_use_carrier_nl(self
, bondname
):
1941 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_USE_CARRIER
])
1943 def bond_set_xmit_hash_policy(self
, bondname
, hash_policy
, prehook
=None):
1944 valid_values
= ['layer2', 'layer3+4', 'layer2+3']
1947 if hash_policy
not in valid_values
:
1948 raise Exception('invalid hash policy value %s' % hash_policy
)
1949 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'xmit_hash_policy'],
1954 self
.write_file('/sys/class/net/%s' % bondname
+
1955 '/bonding/xmit_hash_policy', hash_policy
)
1956 self
._cache
_update
([bondname
, 'linkinfo', 'xmit_hash_policy'],
1959 def bond_get_xmit_hash_policy(self
, bondname
):
1960 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'xmit_hash_policy'])
1962 def bond_get_xmit_hash_policy_nl(self
, bondname
):
1963 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_XMIT_HASH_POLICY
])
1965 def bond_set_miimon(self
, bondname
, miimon
):
1966 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'miimon'],
1969 self
.write_file('/sys/class/net/%s' % bondname
+
1970 '/bonding/miimon', miimon
)
1971 self
._cache
_update
([bondname
, 'linkinfo', 'miimon'], miimon
)
1973 def bond_get_miimon(self
, bondname
):
1974 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'miimon'])
1976 def bond_get_miimon_nl(self
, bondname
):
1977 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MIIMON
])
1979 def bond_set_mode(self
, bondname
, mode
, prehook
=None):
1980 valid_modes
= ['balance-rr', 'active-backup', 'balance-xor',
1981 'broadcast', '802.3ad', 'balance-tlb', 'balance-alb']
1984 if mode
not in valid_modes
:
1985 raise Exception('invalid mode %s' % mode
)
1986 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'mode'],
1991 self
.write_file('/sys/class/net/%s' % bondname
+ '/bonding/mode', mode
)
1992 self
._cache
_update
([bondname
, 'linkinfo', 'mode'], mode
)
1994 def bond_get_mode(self
, bondname
):
1995 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'mode'])
1997 def bond_get_mode_nl(self
, bondname
):
1998 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MODE
])
2000 def bond_set_lacp_rate(self
, bondname
, lacp_rate
, prehook
=None, posthook
=None):
2001 if not lacp_rate
or (lacp_rate
!= '0' and lacp_rate
!= '1'):
2003 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'lacp_rate'],
2009 self
.write_file('/sys/class/net/%s' % bondname
+
2010 '/bonding/lacp_rate', lacp_rate
)
2016 self
._cache
_update
([bondname
, 'linkinfo',
2017 'lacp_rate'], lacp_rate
)
2019 def bond_get_lacp_rate(self
, bondname
):
2020 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'lacp_rate'])
2022 def bond_get_lacp_rate_nl(self
, bondname
):
2023 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_RATE
])
2025 def bond_set_lacp_bypass_allow(self
, bondname
, allow
, prehook
=None, posthook
=None):
2026 if self
._link
_cache
_check
([bondname
, 'linkinfo', 'lacp_bypass'], allow
):
2031 self
.write_file('/sys/class/net/%s' % bondname
+
2032 '/bonding/lacp_bypass', allow
)
2038 self
._cache
_update
([bondname
, 'linkinfo',
2039 'lacp_bypass'], allow
)
2041 def bond_get_lacp_bypass_allow(self
, bondname
):
2042 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'lacp_bypass'])
2044 def bond_get_lacp_bypass_allow_nl(self
, bondname
):
2045 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_BYPASS
])
2047 def bond_set_min_links(self
, bondname
, min_links
, prehook
=None):
2048 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'min_links'],
2053 self
.write_file('/sys/class/net/%s/bonding/min_links' % bondname
,
2055 self
._cache
_update
([bondname
, 'linkinfo', 'min_links'], min_links
)
2057 def bond_get_min_links(self
, bondname
):
2058 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'min_links'])
2060 def get_min_links_nl(self
, bondname
):
2061 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MIN_LINKS
])
2063 def bond_get_ad_actor_system(self
, bondname
):
2064 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'ad_actor_system'])
2066 def bond_get_ad_actor_system_nl(self
, bondname
):
2067 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYSTEM
])
2069 def bond_get_ad_actor_sys_prio(self
, bondname
):
2070 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'ad_actor_sys_prio'])
2072 def bond_get_ad_actor_sys_prio_nl(self
, bondname
):
2073 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
])
2075 def bond_get_num_unsol_na(self
, bondname
):
2076 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'num_unsol_na'])
2078 def bond_get_num_unsol_na_nl(self
, bondname
):
2079 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
])
2081 def bond_get_num_grat_arp(self
, bondname
):
2082 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'num_grat_arp'])
2084 def bond_get_num_grat_arp_nl(self
, bondname
):
2085 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
])
2087 def bond_get_updelay(self
, bondname
):
2088 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'updelay'])
2090 def bond_get_updelay_nl(self
, bondname
):
2091 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_UPDELAY
])
2093 def bond_get_downdelay(self
, bondname
):
2094 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'downdelay'])
2096 def bond_get_downdelay_nl(self
, bondname
):
2097 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_DOWNDELAY
])
2099 def bond_enslave_slave(self
, bondname
, slave
, prehook
=None, posthook
=None):
2100 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2101 if slaves
and slave
in slaves
:
2105 self
.write_file('/sys/class/net/%s' % bondname
+
2106 '/bonding/slaves', '+' + slave
)
2109 self
._cache
_update
([bondname
, 'linkinfo', 'slaves'], slave
)
2111 def bond_remove_slave(self
, bondname
, slave
):
2112 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2113 if not slaves
or slave
not in slaves
:
2115 sysfs_bond_path
= ('/sys/class/net/%s' % bondname
+
2117 if not os
.path
.exists(sysfs_bond_path
):
2119 self
.write_file(sysfs_bond_path
, '-' + slave
)
2120 self
._cache
_delete
([bondname
, 'linkinfo', 'slaves'], slave
)
2122 def bond_remove_slaves_all(self
, bondname
):
2123 if not self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves']):
2126 sysfs_bond_path
= ('/sys/class/net/%s' % bondname
+
2129 with
open(sysfs_bond_path
, 'r') as f
:
2130 slaves
= f
.readline().strip().split()
2132 raise Exception('error reading slaves of bond %s (%s)' % (bondname
, str(e
)))
2133 for slave
in slaves
:
2134 self
.link_down(slave
)
2136 self
.bond_remove_slave(bondname
, slave
)
2137 except Exception, e
:
2138 if not ifupdownflags
.flags
.FORCE
:
2139 raise Exception('error removing slave %s from bond %s (%s)' % (slave
, bondname
, str(e
)))
2142 self
._cache
_delete
([bondname
, 'linkinfo', 'slaves'])
2145 def bond_load_bonding_module():
2146 return utils
.exec_command('%s -q bonding' % utils
.modprobe_cmd
)
2148 def create_bond(self
, bondname
):
2149 if self
.bond_exists(bondname
):
2151 # load_bonding_module() has already been run
2152 self
.write_file('/sys/class/net/bonding_masters', '+' + bondname
)
2153 self
._cache
_update
([bondname
], {})
2155 def delete_bond(self
, bondname
):
2156 if not os
.path
.exists('/sys/class/net/%s' % bondname
):
2158 self
.write_file('/sys/class/net/bonding_masters', '-' + bondname
)
2159 self
._cache
_delete
([bondname
])
2161 def bond_get_slaves(self
, bondname
):
2162 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2165 slavefile
= '/sys/class/net/%s/bonding/slaves' % bondname
2166 if os
.path
.exists(slavefile
):
2167 buf
= self
.read_file_oneline(slavefile
)
2169 slaves
= buf
.split()
2172 self
._cache
_update
([bondname
, 'linkinfo', 'slaves'], slaves
)
2175 def bond_slave_exists(self
, bond
, slave
):
2176 slaves
= self
.bond_get_slaves(bond
)
2179 return slave
in slaves
2182 def bond_exists(bondname
):
2183 return os
.path
.exists('/sys/class/net/%s/bonding' % bondname
)
2185 #################################################################################
2186 ################################## BRIDGE UTILS #################################
2187 #################################################################################
2189 def create_bridge(self
, bridgename
):
2190 if not LinkUtils
.bridge_utils_is_installed
:
2192 if self
.bridge_exists(bridgename
):
2194 utils
.exec_command('%s addbr %s' % (utils
.brctl_cmd
, bridgename
))
2195 self
._cache
_update
([bridgename
], {})
2197 def delete_bridge(self
, bridgename
):
2198 if not LinkUtils
.bridge_utils_is_installed
:
2200 if not self
.bridge_exists(bridgename
):
2202 utils
.exec_command('%s delbr %s' % (utils
.brctl_cmd
, bridgename
))
2203 self
._cache
_invalidate
()
2205 def add_bridge_port(self
, bridgename
, bridgeportname
):
2206 """ Add port to bridge """
2207 if not LinkUtils
.bridge_utils_is_installed
:
2209 ports
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports'])
2210 if ports
and ports
.get(bridgeportname
):
2212 utils
.exec_command('%s addif %s %s' % (utils
.brctl_cmd
, bridgename
, bridgeportname
))
2213 self
._cache
_update
([bridgename
, 'linkinfo', 'ports', bridgeportname
], {})
2215 def delete_bridge_port(self
, bridgename
, bridgeportname
):
2216 """ Delete port from bridge """
2217 if not LinkUtils
.bridge_utils_is_installed
:
2219 ports
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports'])
2220 if not ports
or not ports
.get(bridgeportname
):
2222 utils
.exec_command('%s delif %s %s' % (utils
.brctl_cmd
, bridgename
, bridgeportname
))
2223 self
._cache
_delete
([bridgename
, 'linkinfo', 'ports', 'bridgeportname'])
2225 def set_bridgeport_attrs(self
, bridgename
, bridgeportname
, attrdict
):
2226 portattrs
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports', bridgeportname
])
2227 if portattrs
== None:
2229 for k
, v
in attrdict
.iteritems():
2230 if ifupdownflags
.flags
.CACHE
:
2231 curval
= portattrs
.get(k
)
2232 if curval
and curval
== v
:
2234 if k
== 'unicast-flood':
2235 self
.write_file('/sys/class/net/%s/brport/unicast_flood' % bridgeportname
, v
)
2236 elif k
== 'multicast-flood':
2237 self
.write_file('/sys/class/net/%s/brport/multicast_flood' % bridgeportname
, v
)
2238 elif k
== 'learning':
2239 self
.write_file('/sys/class/net/%s/brport/learning' % bridgeportname
, v
)
2240 elif k
== 'arp-nd-suppress':
2241 self
.write_file('/sys/class/net/%s/brport/neigh_suppress' % bridgeportname
, v
)
2243 if not LinkUtils
.bridge_utils_is_installed
:
2245 utils
.exec_command('%s set%s %s %s %s' % (utils
.brctl_cmd
, k
, bridgename
, bridgeportname
, v
))
2247 def set_bridgeport_attr(self
, bridgename
, bridgeportname
,
2249 if not LinkUtils
.bridge_utils_is_installed
:
2251 if self
._link
_cache
_check
([bridgename
, 'linkinfo', 'ports', bridgeportname
, attrname
], attrval
):
2253 utils
.exec_command('%s set%s %s %s %s' %
2260 def set_bridge_attrs(self
, bridgename
, attrdict
):
2261 for k
, v
in attrdict
.iteritems():
2264 if self
._link
_cache
_check
([bridgename
, 'linkinfo', k
], v
):
2267 if k
== 'igmp-version':
2268 self
.write_file('/sys/class/net/%s/bridge/'
2269 'multicast_igmp_version' % bridgename
, v
)
2270 elif k
== 'mld-version':
2271 self
.write_file('/sys/class/net/%s/bridge/'
2272 'multicast_mld_version' % bridgename
, v
)
2273 elif k
== 'vlan-protocol':
2274 self
.write_file('/sys/class/net/%s/bridge/'
2275 'vlan_protocol' % bridgename
,
2276 VlanProtocols
.ETHERTYPES_TO_ID
.get(v
.upper(),
2278 elif k
== 'vlan-stats':
2279 self
.write_file('/sys/class/net/%s/bridge/'
2280 'vlan_stats_enabled' % bridgename
, v
)
2281 elif k
== 'mcstats':
2282 self
.write_file('/sys/class/net/%s/bridge/'
2283 'multicast_stats_enabled' % bridgename
, v
)
2285 if not LinkUtils
.bridge_utils_is_installed
:
2287 cmd
= ('%s set%s %s %s' %
2288 (utils
.brctl_cmd
, k
, bridgename
, v
))
2289 utils
.exec_command(cmd
)
2290 except Exception, e
:
2291 self
.logger
.warn('%s: %s' % (bridgename
, str(e
)))
2294 def set_bridge_attr(self
, bridgename
, attrname
, attrval
):
2295 if self
._link
_cache
_check
([bridgename
, 'linkinfo', attrname
], attrval
):
2297 if attrname
== 'igmp-version':
2298 self
.write_file('/sys/class/net/%s/bridge/multicast_igmp_version'
2299 % bridgename
, attrval
)
2300 elif attrname
== 'mld-version':
2301 self
.write_file('/sys/class/net/%s/bridge/multicast_mld_version'
2302 % bridgename
, attrval
)
2303 elif attrname
== 'vlan-protocol':
2304 self
.write_file('/sys/class/net/%s/bridge/vlan_protocol'
2305 % bridgename
, VlanProtocols
.ETHERTYPES_TO_ID
[attrval
.upper()])
2306 elif attrname
== 'vlan-stats':
2307 self
.write_file('/sys/class/net/%s/bridge/vlan_stats_enabled'
2308 % bridgename
, attrval
)
2309 elif attrname
== 'mcstats':
2310 self
.write_file('/sys/class/net/%s/bridge/multicast_stats_enabled'
2311 % bridgename
, attrval
)
2313 if not LinkUtils
.bridge_utils_is_installed
:
2315 cmd
= '%s set%s %s %s' % (utils
.brctl_cmd
,
2316 attrname
, bridgename
, attrval
)
2317 utils
.exec_command(cmd
)
2319 def get_bridge_attrs(self
, bridgename
):
2320 attrs
= self
._link
_cache
_get
([bridgename
, 'linkinfo'])
2322 for key
, value
in attrs
.items():
2323 if type(key
) == str:
2324 no_ints_attrs
[key
] = value
2325 return no_ints_attrs
2327 def get_bridgeport_attrs(self
, bridgename
, bridgeportname
):
2328 return self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports',
2331 def get_bridgeport_attr(self
, bridgename
, bridgeportname
, attrname
):
2332 return self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports',
2333 bridgeportname
, attrname
])
2336 def bridge_set_stp(bridge
, stp_state
):
2337 if not LinkUtils
.bridge_utils_is_installed
:
2339 utils
.exec_command('%s stp %s %s' % (utils
.brctl_cmd
, bridge
, stp_state
))
2341 def bridge_get_stp(self
, bridge
):
2342 sysfs_stpstate
= '/sys/class/net/%s/bridge/stp_state' % bridge
2343 if not os
.path
.exists(sysfs_stpstate
):
2345 stpstate
= self
.read_file_oneline(sysfs_stpstate
)
2349 if int(stpstate
) > 0:
2351 elif int(stpstate
) == 0:
2357 def _conv_value_to_user(s
):
2364 def read_value_from_sysfs(self
, filename
, preprocess_func
):
2365 value
= self
.read_file_oneline(filename
)
2368 return preprocess_func(value
)
2371 def bridge_set_ageing(bridge
, ageing
):
2372 if not LinkUtils
.bridge_utils_is_installed
:
2374 utils
.exec_command('%s setageing %s %s' % (utils
.brctl_cmd
, bridge
, ageing
))
2376 def bridge_get_ageing(self
, bridge
):
2377 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/ageing_time'
2378 % bridge
, self
._conv
_value
_to
_user
)
2381 def set_bridgeprio(bridge
, prio
):
2382 if not LinkUtils
.bridge_utils_is_installed
:
2384 utils
.exec_command('%s setbridgeprio %s %s' % (utils
.brctl_cmd
, bridge
, prio
))
2386 def get_bridgeprio(self
, bridge
):
2387 return self
.read_file_oneline(
2388 '/sys/class/net/%s/bridge/priority' % bridge
)
2391 def bridge_set_fd(bridge
, fd
):
2392 if not LinkUtils
.bridge_utils_is_installed
:
2394 utils
.exec_command('%s setfd %s %s' % (utils
.brctl_cmd
, bridge
, fd
))
2396 def bridge_get_fd(self
, bridge
):
2397 return self
.read_value_from_sysfs(
2398 '/sys/class/net/%s/bridge/forward_delay'
2399 % bridge
, self
._conv
_value
_to
_user
)
2401 def bridge_set_gcint(self
, bridge
, gcint
):
2402 raise Exception('set_gcint not implemented')
2405 def bridge_set_hello(bridge
, hello
):
2406 if not LinkUtils
.bridge_utils_is_installed
:
2408 utils
.exec_command('%s sethello %s %s' % (utils
.brctl_cmd
, bridge
, hello
))
2410 def bridge_get_hello(self
, bridge
):
2411 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/hello_time'
2412 % bridge
, self
._conv
_value
_to
_user
)
2415 def bridge_set_maxage(bridge
, maxage
):
2416 if not LinkUtils
.bridge_utils_is_installed
:
2418 utils
.exec_command('%s setmaxage %s %s' % (utils
.brctl_cmd
, bridge
, maxage
))
2420 def bridge_get_maxage(self
, bridge
):
2421 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/max_age'
2422 % bridge
, self
._conv
_value
_to
_user
)
2425 def bridge_set_pathcost(bridge
, port
, pathcost
):
2426 if not LinkUtils
.bridge_utils_is_installed
:
2428 utils
.exec_command('%s setpathcost %s %s %s' % (utils
.brctl_cmd
, bridge
, port
, pathcost
))
2430 def bridge_get_pathcost(self
, bridge
, port
):
2431 return self
.read_file_oneline('/sys/class/net/%s/brport/path_cost'
2435 def bridge_set_portprio(bridge
, port
, prio
):
2436 if not LinkUtils
.bridge_utils_is_installed
:
2438 utils
.exec_command('%s setportprio %s %s %s' % (utils
.brctl_cmd
, bridge
, port
, prio
))
2440 def bridge_get_portprio(self
, bridge
, port
):
2441 return self
.read_file_oneline('/sys/class/net/%s/brport/priority'
2445 def bridge_set_hashmax(bridge
, hashmax
):
2446 if not LinkUtils
.bridge_utils_is_installed
:
2448 utils
.exec_command('%s sethashmax %s %s' % (utils
.brctl_cmd
, bridge
, hashmax
))
2450 def bridge_get_hashmax(self
, bridge
):
2451 return self
.read_file_oneline('/sys/class/net/%s/bridge/hash_max'
2455 def bridge_set_hashel(bridge
, hashel
):
2456 if not LinkUtils
.bridge_utils_is_installed
:
2458 utils
.exec_command('%s sethashel %s %s' % (utils
.brctl_cmd
, bridge
, hashel
))
2460 def bridge_get_hashel(self
, bridge
):
2461 return self
.read_file_oneline('/sys/class/net/%s/bridge/hash_elasticity'
2465 def bridge_set_mclmc(bridge
, mclmc
):
2466 if not LinkUtils
.bridge_utils_is_installed
:
2468 utils
.exec_command('%s setmclmc %s %s' % (utils
.brctl_cmd
, bridge
, mclmc
))
2470 def bridge_get_mclmc(self
, bridge
):
2471 return self
.read_file_oneline(
2472 '/sys/class/net/%s/bridge/multicast_last_member_count'
2476 def bridge_set_mcrouter(bridge
, mcrouter
):
2477 if not LinkUtils
.bridge_utils_is_installed
:
2479 utils
.exec_command('%s setmcrouter %s %s' % (utils
.brctl_cmd
, bridge
, mcrouter
))
2481 def bridge_get_mcrouter(self
, bridge
):
2482 return self
.read_file_oneline(
2483 '/sys/class/net/%s/bridge/multicast_router' % bridge
)
2486 def bridge_set_mcsnoop(bridge
, mcsnoop
):
2487 if not LinkUtils
.bridge_utils_is_installed
:
2489 utils
.exec_command('%s setmcsnoop %s %s' % (utils
.brctl_cmd
, bridge
, mcsnoop
))
2491 def bridge_get_mcsnoop(self
, bridge
):
2492 return self
.read_file_oneline(
2493 '/sys/class/net/%s/bridge/multicast_snooping' % bridge
)
2496 def bridge_set_mcsqc(bridge
, mcsqc
):
2497 if not LinkUtils
.bridge_utils_is_installed
:
2499 utils
.exec_command('%s setmcsqc %s %s' % (utils
.brctl_cmd
, bridge
, mcsqc
))
2501 def bridge_get_mcsqc(self
, bridge
):
2502 return self
.read_file_oneline(
2503 '/sys/class/net/%s/bridge/multicast_startup_query_count'
2507 def bridge_set_mcqifaddr(bridge
, mcqifaddr
):
2508 if not LinkUtils
.bridge_utils_is_installed
:
2510 utils
.exec_command('%s setmcqifaddr %s %s' % (utils
.brctl_cmd
, bridge
, mcqifaddr
))
2512 def bridge_get_mcqifaddr(self
, bridge
):
2513 return self
.read_file_oneline(
2514 '/sys/class/net/%s/bridge/multicast_startup_query_use_ifaddr'
2518 def bridge_set_mcquerier(bridge
, mcquerier
):
2519 if not LinkUtils
.bridge_utils_is_installed
:
2521 utils
.exec_command('%s setmcquerier %s %s' % (utils
.brctl_cmd
, bridge
, mcquerier
))
2523 def bridge_get_mcquerier(self
, bridge
):
2524 return self
.read_file_oneline(
2525 '/sys/class/net/%s/bridge/multicast_querier' % bridge
)
2527 def bridge_set_mcqv4src(self
, bridge
, vlan
, mcquerier
):
2531 self
.logger
.info('%s: set mcqv4src vlan: invalid parameter %s: %s' %(bridge
, vlan
, str(e
)))
2533 if vlan
== 0 or vlan
> 4095:
2534 self
.logger
.warn('mcqv4src vlan \'%d\' invalid range' % vlan
)
2537 ip
= mcquerier
.split('.')
2539 self
.logger
.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier
)
2542 if not k
.isdigit() or int(k
, 10) < 0 or int(k
, 10) > 255:
2543 self
.logger
.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier
)
2546 if not LinkUtils
.bridge_utils_is_installed
:
2549 utils
.exec_command('%s setmcqv4src %s %d %s' %
2550 (utils
.brctl_cmd
, bridge
, vlan
, mcquerier
))
2552 def bridge_del_mcqv4src(self
, bridge
, vlan
):
2553 if not LinkUtils
.bridge_utils_is_installed
:
2558 self
.logger
.info('%s: del mcqv4src vlan: invalid parameter %s: %s' %(bridge
, vlan
, str(e
)))
2560 utils
.exec_command('%s delmcqv4src %s %d' % (utils
.brctl_cmd
, bridge
, vlan
))
2562 def bridge_get_mcqv4src(self
, bridge
, vlan
=None):
2563 if not LinkUtils
.bridge_utils_is_installed
:
2565 if not self
.supported_command
['showmcqv4src']:
2569 mcqout
= utils
.exec_command('%s showmcqv4src %s' %
2570 (utils
.brctl_cmd
, bridge
))
2571 except Exception as e
:
2573 if 'never heard' in s
:
2574 msg
= ('%s showmcqv4src: skipping unsupported command'
2576 self
.logger
.info(msg
)
2577 self
.supported_command
['showmcqv4src'] = False
2582 mcqlines
= mcqout
.splitlines()
2583 for l
in mcqlines
[1:]:
2585 k
, d
, v
= l
.split('\t')
2590 return mcqv4src
.get(vlan
)
2594 def bridge_set_mclmi(bridge
, mclmi
):
2595 if not LinkUtils
.bridge_utils_is_installed
:
2597 utils
.exec_command('%s setmclmi %s %s' % (utils
.brctl_cmd
, bridge
, mclmi
))
2599 def bridge_get_mclmi(self
, bridge
):
2600 return self
.read_file_oneline(
2601 '/sys/class/net/%s/bridge/multicast_last_member_interval'
2605 def bridge_set_mcmi(bridge
, mcmi
):
2606 if not LinkUtils
.bridge_utils_is_installed
:
2608 utils
.exec_command('%s setmcmi %s %s' % (utils
.brctl_cmd
, bridge
, mcmi
))
2610 def bridge_get_mcmi(self
, bridge
):
2611 return self
.read_file_oneline(
2612 '/sys/class/net/%s/bridge/multicast_membership_interval'
2616 def bridge_exists(bridge
):
2617 return os
.path
.exists('/sys/class/net/%s/bridge' % bridge
)
2620 def is_bridge_port(ifacename
):
2621 return os
.path
.exists('/sys/class/net/%s/brport' % ifacename
)
2624 def bridge_port_exists(bridge
, bridgeportname
):
2626 return os
.path
.exists('/sys/class/net/%s/brif/%s' % (bridge
, bridgeportname
))
2631 def get_bridge_ports(bridgename
):
2633 return os
.listdir('/sys/class/net/%s/brif/' % bridgename
)
2637 def ipv6_addrgen(self
, ifname
, addrgen
):
2638 cmd
= 'link set dev %s addrgenmode %s' % (ifname
, 'eui64' if addrgen
else 'none')
2640 is_link_up
= self
.is_link_up(ifname
)
2643 self
.link_down(ifname
)
2645 if LinkUtils
.ipbatch
:
2646 self
.add_to_batch(cmd
)
2648 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
2651 self
.link_up(ifname
)