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
)
1349 def link_exists_nodryrun(ifname
):
1350 return os
.path
.exists('/sys/class/net/%s' % ifname
)
1352 def link_get_ifindex(self
, ifacename
):
1353 if ifupdownflags
.flags
.DRYRUN
:
1355 return self
.read_file_oneline('/sys/class/net/%s/ifindex' % ifacename
)
1357 def is_vlan_device_by_name(self
, ifacename
):
1358 if re
.search(r
'\.', ifacename
):
1363 def link_add_macvlan(ifname
, macvlan_ifacename
):
1364 utils
.exec_commandl(['ip', 'link', 'add', 'link', ifname
, 'name', macvlan_ifacename
, 'type', 'macvlan', 'mode', 'private'])
1367 def route_add(route
):
1368 utils
.exec_command('%s route add %s' % (utils
.ip_cmd
,
1372 def route6_add(route
):
1373 utils
.exec_command('%s -6 route add %s' % (utils
.ip_cmd
,
1376 def get_vlandev_attrs(self
, ifacename
):
1377 return (self
._cache
_get
('link', [ifacename
, 'link']),
1378 self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlanid']),
1379 self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlan_protocol']))
1381 def get_vlan_protocol(self
, ifacename
):
1382 return self
._cache
_get
('link', [ifacename
, 'linkinfo', 'vlan_protocol'])
1384 def get_vxlandev_attrs(self
, ifacename
):
1385 return self
._cache
_get
('link', [ifacename
, 'linkinfo'])
1387 def get_vxlandev_learning(self
, ifacename
):
1388 return self
._cache
_get
('link', [ifacename
, 'linkinfo', Link
.IFLA_VXLAN_LEARNING
])
1390 def set_vxlandev_learning(self
, ifacename
, learn
):
1392 utils
.exec_command('%s link set dev %s type vxlan learning' %
1393 (utils
.ip_cmd
, ifacename
))
1394 self
._cache
_update
([ifacename
, 'linkinfo', 'learning'], 'on')
1396 utils
.exec_command('%s link set dev %s type vxlan nolearning' %
1397 (utils
.ip_cmd
, ifacename
))
1398 self
._cache
_update
([ifacename
, 'linkinfo', 'learning'], 'off')
1400 def link_get_linkinfo_attrs(self
, ifacename
):
1401 return self
._cache
_get
('link', [ifacename
, 'linkinfo'])
1403 def link_get_mtu(self
, ifacename
, refresh
=False):
1404 return self
._cache
_get
('link', [ifacename
, 'mtu'], refresh
=refresh
)
1406 def link_get_mtu_sysfs(self
, ifacename
):
1407 return self
.read_file_oneline('/sys/class/net/%s/mtu'
1410 def link_get_kind(self
, ifacename
):
1411 return self
._cache
_get
('link', [ifacename
, 'kind'])
1413 def link_get_slave_kind(self
, ifacename
):
1414 return self
._cache
_get
('link', [ifacename
, 'slave_kind'])
1416 def link_get_hwaddress(self
, ifacename
):
1417 address
= self
._cache
_get
('link', [ifacename
, 'hwaddress'])
1418 # newly created logical interface addresses dont end up in the cache
1419 # read hwaddress from sysfs file for these interfaces
1421 address
= self
.read_file_oneline('/sys/class/net/%s/address'
1425 def link_create(self
, ifacename
, t
, attrs
={}):
1426 """ generic link_create function """
1427 if self
.link_exists(ifacename
):
1430 cmd
+= ' name %s type %s' % (ifacename
, t
)
1432 for k
, v
in attrs
.iteritems():
1436 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1437 self
.add_to_batch(cmd
)
1439 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1440 self
._cache
_update
([ifacename
], {})
1442 def link_delete(self
, ifacename
):
1443 if not self
.link_exists(ifacename
):
1445 cmd
= 'link del %s' % ifacename
1446 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1447 self
.add_to_batch(cmd
)
1449 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
1450 self
._cache
_invalidate
()
1452 def link_get_master(self
, ifacename
):
1453 sysfs_master_path
= '/sys/class/net/%s/master' % ifacename
1454 if os
.path
.exists(sysfs_master_path
):
1455 link_path
= os
.readlink(sysfs_master_path
)
1457 return os
.path
.basename(link_path
)
1461 return self
._cache
_get
('link', [ifacename
, 'master'])
1463 def get_brport_peer_link(self
, bridgename
):
1465 return self
._cache
_get
('link', [bridgename
, 'info_slave_data', Link
.IFLA_BRPORT_PEER_LINK
])
1470 def bridge_port_vids_add(bridgeportname
, vids
):
1471 [utils
.exec_command('%s vlan add vid %s dev %s' %
1473 v
, bridgeportname
)) for v
in vids
]
1476 def bridge_port_vids_del(bridgeportname
, vids
):
1479 [utils
.exec_command('%s vlan del vid %s dev %s' %
1481 v
, bridgeportname
)) for v
in vids
]
1484 def bridge_port_vids_flush(bridgeportname
, vid
):
1485 utils
.exec_command('%s vlan del vid %s dev %s' %
1487 vid
, bridgeportname
))
1490 def bridge_port_vids_get(bridgeportname
):
1491 bridgeout
= utils
.exec_command('%s vlan show dev %s' %
1496 brvlanlines
= bridgeout
.readlines()[2:]
1497 vids
= [l
.strip() for l
in brvlanlines
]
1498 return [v
for v
in vids
if v
]
1501 def bridge_port_vids_get_all():
1503 bridgeout
= utils
.exec_command('%s -c vlan show'
1507 brvlanlines
= bridgeout
.splitlines()
1509 for l
in brvlanlines
[1:]:
1510 if l
and not l
.startswith(' ') and not l
.startswith('\t'):
1512 brportname
= attrs
[0].strip()
1513 brvlaninfo
[brportname
] = {'pvid': None, 'vlan': []}
1514 l
= ' '.join(attrs
[1:])
1515 if not brportname
or not l
:
1519 brvlaninfo
[brportname
]['pvid'] = l
.split()[0]
1520 elif 'Egress Untagged' not in l
:
1521 brvlaninfo
[brportname
]['vlan'].append(l
)
1524 def bridge_port_vids_get_all_json(self
):
1525 if not self
.supported_command
['%s -c -json vlan show'
1526 % utils
.bridge_cmd
]:
1530 bridgeout
= utils
.exec_command('%s -c -json vlan show'
1533 self
.supported_command
['%s -c -json vlan show'
1534 % utils
.bridge_cmd
] = False
1535 self
.logger
.info('%s -c -json vlan show: skipping unsupported command'
1538 return self
.get_bridge_vlan_nojson()
1539 except Exception as e
:
1540 self
.logger
.info('bridge: get_bridge_vlan_nojson: %s' % str(e
))
1543 if not bridgeout
: return brvlaninfo
1545 vlan_json_dict
= json
.loads(bridgeout
, encoding
="utf-8")
1546 except Exception, e
:
1547 self
.logger
.info('json loads failed with (%s)' % str(e
))
1549 return vlan_json_dict
1552 def get_bridge_vlan_nojson():
1554 bridgeout
= utils
.exec_commandl([utils
.bridge_cmd
, '-c', 'vlan', 'show'])
1556 output
= [line
.split('\n') for line
in bridgeout
.split('\n\n')]
1557 output
[0] = output
[0][1:]
1565 prefix
, vlan
= entry
.split('\t')
1567 current_swp
= prefix
1568 vlan_json
[prefix
] = []
1572 v
['vlan'] = int(vlan
)
1576 start
, end
= vlan
.split('-')
1578 end
= end
[0:end
.index(' ')]
1579 v
['vlan'] = int(start
)
1580 v
['vlanEnd'] = int(end
)
1582 v
['vlan'] = int(vlan
[0:vlan
.index(' ')])
1585 flags
.append('PVID')
1586 if 'Egress Untagged' in vlan
:
1587 flags
.append('Egress Untagged')
1591 vlan_json
[current_swp
].append(v
)
1594 def bridge_vlan_cache_get(self
, ifacename
, refresh
=False):
1595 if not self
.bridge_vlan_cache_fill_done
or refresh
:
1596 self
.bridge_vlan_cache
= self
.bridge_port_vids_get_all_json()
1597 self
.bridge_vlan_cache_fill_done
= True
1598 return self
.bridge_vlan_cache
.get(ifacename
, {})
1600 def bridge_vlan_get_pvid(self
, ifacename
, refresh
=False):
1603 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1604 v
= vinfo
.get('vlan')
1605 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1610 def bridge_vlan_get_vids(self
, ifacename
, refresh
=False):
1613 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1614 v
= vinfo
.get('vlan')
1615 ispvid
= True if 'PVID' in vinfo
.get('flags', []) else False
1617 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1620 vEnd
= vinfo
.get('vlanEnd')
1622 vids
.extend(range(v
, vEnd
+ 1))
1627 def bridge_vlan_get_vids_n_pvid(self
, ifacename
, refresh
=False):
1631 for vinfo
in self
.bridge_vlan_cache_get(ifacename
, refresh
):
1632 v
= vinfo
.get('vlan')
1633 ispvid
= True if 'PVID' in vinfo
.get('flags', []) else False
1635 pvid
= v
if 'PVID' in vinfo
.get('flags', []) else 0
1636 vEnd
= vinfo
.get('vlanEnd')
1638 vids
.extend(range(v
, vEnd
+ 1))
1643 def bridge_port_pvid_add(self
, bridgeportname
, pvid
):
1644 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1645 self
.add_to_batch('vlan add vid %s untagged pvid dev %s' %
1646 (pvid
, bridgeportname
))
1648 utils
.exec_command('%s vlan add vid %s untagged pvid dev %s' %
1650 pvid
, bridgeportname
))
1652 def bridge_port_pvid_del(self
, bridgeportname
, pvid
):
1653 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1654 self
.add_to_batch('vlan del vid %s untagged pvid dev %s' %
1655 (pvid
, bridgeportname
))
1657 utils
.exec_command('%s vlan del vid %s untagged pvid dev %s' %
1659 pvid
, bridgeportname
))
1661 def bridge_port_pvids_get(self
, bridgeportname
):
1662 return self
.read_file_oneline('/sys/class/net/%s/brport/pvid'
1665 def bridge_vids_add(self
, bridgeportname
, vids
, bridge
=True):
1666 target
= 'self' if bridge
else ''
1667 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1668 [self
.add_to_batch('vlan add vid %s dev %s %s' %
1669 (v
, bridgeportname
, target
)) for v
in vids
]
1671 [utils
.exec_command('%s vlan add vid %s dev %s %s' %
1673 v
, bridgeportname
, target
)) for v
in vids
]
1675 def bridge_vids_del(self
, bridgeportname
, vids
, bridge
=True):
1676 target
= 'self' if bridge
else ''
1677 if LinkUtils
.ipbatch
and not LinkUtils
.ipbatch_pause
:
1678 [self
.add_to_batch('vlan del vid %s dev %s %s' %
1679 (v
, bridgeportname
, target
)) for v
in vids
]
1681 [utils
.exec_command('%s vlan del vid %s dev %s %s' %
1683 v
, bridgeportname
, target
)) for v
in vids
]
1686 def bridge_fdb_add(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1687 target
= 'self' if bridge
else ''
1690 vlan_str
= 'vlan %s ' % vlan
1694 dst_str
= 'dst %s ' % remote
1696 utils
.exec_command('%s fdb replace %s dev %s %s %s %s' %
1698 address
, dev
, vlan_str
, target
, dst_str
))
1701 def bridge_fdb_append(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1702 target
= 'self' if bridge
else ''
1705 vlan_str
= 'vlan %s ' % vlan
1709 dst_str
= 'dst %s ' % remote
1711 utils
.exec_command('%s fdb append %s dev %s %s %s %s' %
1713 address
, dev
, vlan_str
, target
, dst_str
))
1716 def bridge_fdb_del(dev
, address
, vlan
=None, bridge
=True, remote
=None):
1717 target
= 'self' if bridge
else ''
1720 vlan_str
= 'vlan %s ' % vlan
1724 dst_str
= 'dst %s ' % remote
1725 utils
.exec_command('%s fdb del %s dev %s %s %s %s' %
1727 address
, dev
, vlan_str
, target
, dst_str
))
1729 def bridge_is_vlan_aware(self
, bridgename
):
1730 filename
= '/sys/class/net/%s/bridge/vlan_filtering' % bridgename
1731 if os
.path
.exists(filename
) and self
.read_file_oneline(filename
) == '1':
1736 def bridge_port_get_bridge_name(bridgeport
):
1737 filename
= '/sys/class/net/%s/brport/bridge' % bridgeport
1739 return os
.path
.basename(os
.readlink(filename
))
1744 def bridge_port_exists(bridge
, bridgeportname
):
1746 return os
.path
.exists('/sys/class/net/%s/brif/%s'
1747 % (bridge
, bridgeportname
))
1751 def bridge_fdb_show_dev(self
, dev
):
1754 output
= utils
.exec_command('%s fdb show dev %s'
1755 % (utils
.bridge_cmd
, dev
))
1757 for fdb_entry
in output
.splitlines():
1759 entries
= fdb_entry
.split()
1760 fdbs
.setdefault(entries
[2], []).append(entries
[0])
1762 self
.logger
.debug('%s: invalid fdb line \'%s\''
1769 def is_bridge(bridge
):
1770 return os
.path
.exists('/sys/class/net/%s/bridge' % bridge
)
1772 def is_link_up(self
, ifacename
):
1775 flags
= self
.read_file_oneline('/sys/class/net/%s/flags' % ifacename
)
1776 iflags
= int(flags
, 16)
1783 def ip_route_get_dev(self
, prefix
, vrf_master
=None):
1786 cmd
= '%s route get %s vrf %s' % (utils
.ip_cmd
, prefix
, vrf_master
)
1788 cmd
= '%s route get %s' % (utils
.ip_cmd
, prefix
)
1790 output
= utils
.exec_command(cmd
)
1792 rline
= output
.splitlines()[0]
1794 rattrs
= rline
.split()
1795 return rattrs
[rattrs
.index('dev') + 1]
1796 except Exception, e
:
1797 self
.logger
.debug('ip_route_get_dev: failed .. %s' % str(e
))
1801 def link_get_lowers(ifacename
):
1803 lowers
= glob
.glob("/sys/class/net/%s/lower_*" % ifacename
)
1806 return [os
.path
.basename(l
)[6:] for l
in lowers
]
1811 def link_get_uppers(ifacename
):
1813 uppers
= glob
.glob("/sys/class/net/%s/upper_*" % ifacename
)
1816 return [os
.path
.basename(u
)[6:] for u
in uppers
]
1820 def link_get_vrfs(self
):
1821 if not LinkUtils
._CACHE
_FILL
_DONE
:
1823 return linkCache
.vrfs
1826 def cache_get_info_slave(attrlist
):
1828 return linkCache
.get_attr(attrlist
)
1832 def get_brport_learning(self
, ifacename
):
1833 learn
= self
.read_file_oneline('/sys/class/net/%s/brport/learning'
1835 if learn
and learn
== '1':
1840 def get_brport_learning_bool(self
, ifacename
):
1841 return utils
.get_boolean_from_string(self
.read_file_oneline('/sys/class/net/%s/brport/learning' % ifacename
))
1843 def set_brport_learning(self
, ifacename
, learn
):
1845 return self
.write_file('/sys/class/net/%s/brport/learning'
1848 return self
.write_file('/sys/class/net/%s/brport/learning'
1851 #################################################################################
1852 ################################### BOND UTILS ##################################
1853 #################################################################################
1855 def _link_cache_get(self
, attrlist
, refresh
=False):
1856 return self
._cache
_get
('link', attrlist
, refresh
)
1858 def cache_delete(self
, attrlist
, value
=None):
1859 return self
._cache
_delete
(attrlist
, value
)
1861 def link_cache_get(self
, attrlist
, refresh
=False):
1862 return self
._link
_cache
_get
(attrlist
, refresh
)
1864 def link_cache_check(self
, attrlist
, value
, refresh
=False):
1865 return self
._link
_cache
_check
(attrlist
, value
, refresh
)
1867 def _link_cache_check(self
, attrlist
, value
, refresh
=False):
1869 return self
._link
_cache
_get
(attrlist
, refresh
) == value
1870 except Exception, e
:
1871 self
.logger
.debug('_cache_check(%s) : [%s]'
1872 % (str(attrlist
), str(e
)))
1877 Link
.IFLA_BOND_MODE
: 'mode',
1878 Link
.IFLA_BOND_MIIMON
: 'miimon',
1879 Link
.IFLA_BOND_USE_CARRIER
: 'use_carrier',
1880 Link
.IFLA_BOND_AD_LACP_RATE
: 'lacp_rate',
1881 Link
.IFLA_BOND_XMIT_HASH_POLICY
: 'xmit_hash_policy',
1882 Link
.IFLA_BOND_MIN_LINKS
: 'min_links',
1883 Link
.IFLA_BOND_NUM_PEER_NOTIF
: 'num_grat_arp',
1884 Link
.IFLA_BOND_AD_ACTOR_SYSTEM
: 'ad_actor_system',
1885 Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
: 'ad_actor_sys_prio',
1886 Link
.IFLA_BOND_AD_LACP_BYPASS
: 'lacp_bypass',
1887 Link
.IFLA_BOND_UPDELAY
: 'updelay',
1888 Link
.IFLA_BOND_DOWNDELAY
: 'downdelay',
1891 def bond_set_attrs_nl(self
, bondname
, ifla_info_data
):
1892 bond_attr_name
= 'None' # for log purpose (in case an exception raised)
1893 for nl_attr
, value
in ifla_info_data
.items():
1895 bond_attr_name
= self
.bondcmd_attrmap
[nl_attr
]
1896 file_path
= '/sys/class/net/%s/bonding/%s' % (bondname
, bond_attr_name
)
1897 if os
.path
.exists(file_path
):
1898 self
.write_file(file_path
, str(value
))
1899 except Exception as e
:
1900 exception_str
= '%s: %s %s: %s' % (bondname
, bond_attr_name
, value
, str(e
))
1901 if ifupdownflags
.flags
.FORCE
:
1902 self
.logger
.warning(exception_str
)
1904 self
.logger
.debug(exception_str
)
1906 def bond_set_attrs(self
, bondname
, attrdict
, prehook
):
1907 for attrname
, attrval
in attrdict
.items():
1908 if (self
._link
_cache
_check
([bondname
, 'linkinfo',
1909 attrname
], attrval
)):
1911 if (attrname
== 'mode'
1912 or attrname
== 'xmit_hash_policy'
1913 or attrname
== 'lacp_rate' or attrname
== 'min_links'):
1917 if ((attrname
not in ['lacp_rate',
1919 self
._link
_cache
_check
([bondname
, 'linkinfo', 'mode'], '802.3ad',
1921 self
.write_file('/sys/class/net/%s/bonding/%s'
1922 % (bondname
, attrname
), attrval
)
1923 except Exception, e
:
1924 if ifupdownflags
.flags
.FORCE
:
1925 self
.logger
.warn(str(e
))
1930 def bond_set_use_carrier(self
, bondname
, use_carrier
):
1931 if not use_carrier
or (use_carrier
!= '0' and use_carrier
!= '1'):
1933 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'use_carrier'],
1936 self
.write_file('/sys/class/net/%s' % bondname
+
1937 '/bonding/use_carrier', use_carrier
)
1938 self
._cache
_update
([bondname
, 'linkinfo',
1939 'use_carrier'], use_carrier
)
1941 def bond_get_use_carrier(self
, bondname
):
1942 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'use_carrier'])
1944 def bond_get_use_carrier_nl(self
, bondname
):
1945 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_USE_CARRIER
])
1947 def bond_set_xmit_hash_policy(self
, bondname
, hash_policy
, prehook
=None):
1948 valid_values
= ['layer2', 'layer3+4', 'layer2+3']
1951 if hash_policy
not in valid_values
:
1952 raise Exception('invalid hash policy value %s' % hash_policy
)
1953 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'xmit_hash_policy'],
1958 self
.write_file('/sys/class/net/%s' % bondname
+
1959 '/bonding/xmit_hash_policy', hash_policy
)
1960 self
._cache
_update
([bondname
, 'linkinfo', 'xmit_hash_policy'],
1963 def bond_get_xmit_hash_policy(self
, bondname
):
1964 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'xmit_hash_policy'])
1966 def bond_get_xmit_hash_policy_nl(self
, bondname
):
1967 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_XMIT_HASH_POLICY
])
1969 def bond_set_miimon(self
, bondname
, miimon
):
1970 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'miimon'],
1973 self
.write_file('/sys/class/net/%s' % bondname
+
1974 '/bonding/miimon', miimon
)
1975 self
._cache
_update
([bondname
, 'linkinfo', 'miimon'], miimon
)
1977 def bond_get_miimon(self
, bondname
):
1978 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'miimon'])
1980 def bond_get_miimon_nl(self
, bondname
):
1981 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MIIMON
])
1983 def bond_set_mode(self
, bondname
, mode
, prehook
=None):
1984 valid_modes
= ['balance-rr', 'active-backup', 'balance-xor',
1985 'broadcast', '802.3ad', 'balance-tlb', 'balance-alb']
1988 if mode
not in valid_modes
:
1989 raise Exception('invalid mode %s' % mode
)
1990 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'mode'],
1995 self
.write_file('/sys/class/net/%s' % bondname
+ '/bonding/mode', mode
)
1996 self
._cache
_update
([bondname
, 'linkinfo', 'mode'], mode
)
1998 def bond_get_mode(self
, bondname
):
1999 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'mode'])
2001 def bond_get_mode_nl(self
, bondname
):
2002 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MODE
])
2004 def bond_set_lacp_rate(self
, bondname
, lacp_rate
, prehook
=None, posthook
=None):
2005 if not lacp_rate
or (lacp_rate
!= '0' and lacp_rate
!= '1'):
2007 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'lacp_rate'],
2013 self
.write_file('/sys/class/net/%s' % bondname
+
2014 '/bonding/lacp_rate', lacp_rate
)
2020 self
._cache
_update
([bondname
, 'linkinfo',
2021 'lacp_rate'], lacp_rate
)
2023 def bond_get_lacp_rate(self
, bondname
):
2024 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'lacp_rate'])
2026 def bond_get_lacp_rate_nl(self
, bondname
):
2027 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_RATE
])
2029 def bond_set_lacp_bypass_allow(self
, bondname
, allow
, prehook
=None, posthook
=None):
2030 if self
._link
_cache
_check
([bondname
, 'linkinfo', 'lacp_bypass'], allow
):
2035 self
.write_file('/sys/class/net/%s' % bondname
+
2036 '/bonding/lacp_bypass', allow
)
2042 self
._cache
_update
([bondname
, 'linkinfo',
2043 'lacp_bypass'], allow
)
2045 def bond_get_lacp_bypass_allow(self
, bondname
):
2046 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'lacp_bypass'])
2048 def bond_get_lacp_bypass_allow_nl(self
, bondname
):
2049 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_LACP_BYPASS
])
2051 def bond_set_min_links(self
, bondname
, min_links
, prehook
=None):
2052 if (self
._link
_cache
_check
([bondname
, 'linkinfo', 'min_links'],
2057 self
.write_file('/sys/class/net/%s/bonding/min_links' % bondname
,
2059 self
._cache
_update
([bondname
, 'linkinfo', 'min_links'], min_links
)
2061 def bond_get_min_links(self
, bondname
):
2062 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'min_links'])
2064 def get_min_links_nl(self
, bondname
):
2065 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_MIN_LINKS
])
2067 def bond_get_ad_actor_system(self
, bondname
):
2068 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'ad_actor_system'])
2070 def bond_get_ad_actor_system_nl(self
, bondname
):
2071 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYSTEM
])
2073 def bond_get_ad_actor_sys_prio(self
, bondname
):
2074 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'ad_actor_sys_prio'])
2076 def bond_get_ad_actor_sys_prio_nl(self
, bondname
):
2077 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_AD_ACTOR_SYS_PRIO
])
2079 def bond_get_num_unsol_na(self
, bondname
):
2080 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'num_unsol_na'])
2082 def bond_get_num_unsol_na_nl(self
, bondname
):
2083 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
])
2085 def bond_get_num_grat_arp(self
, bondname
):
2086 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'num_grat_arp'])
2088 def bond_get_num_grat_arp_nl(self
, bondname
):
2089 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_NUM_PEER_NOTIF
])
2091 def bond_get_updelay(self
, bondname
):
2092 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'updelay'])
2094 def bond_get_updelay_nl(self
, bondname
):
2095 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_UPDELAY
])
2097 def bond_get_downdelay(self
, bondname
):
2098 return self
._link
_cache
_get
([bondname
, 'linkinfo', 'downdelay'])
2100 def bond_get_downdelay_nl(self
, bondname
):
2101 return self
._link
_cache
_get
([bondname
, 'linkinfo', Link
.IFLA_BOND_DOWNDELAY
])
2103 def bond_enslave_slave(self
, bondname
, slave
, prehook
=None, posthook
=None):
2104 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2105 if slaves
and slave
in slaves
:
2109 self
.write_file('/sys/class/net/%s' % bondname
+
2110 '/bonding/slaves', '+' + slave
)
2113 self
._cache
_update
([bondname
, 'linkinfo', 'slaves'], slave
)
2115 def bond_remove_slave(self
, bondname
, slave
):
2116 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2117 if not slaves
or slave
not in slaves
:
2119 sysfs_bond_path
= ('/sys/class/net/%s' % bondname
+
2121 if not os
.path
.exists(sysfs_bond_path
):
2123 self
.write_file(sysfs_bond_path
, '-' + slave
)
2124 self
._cache
_delete
([bondname
, 'linkinfo', 'slaves'], slave
)
2126 def bond_remove_slaves_all(self
, bondname
):
2127 if not self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves']):
2130 sysfs_bond_path
= ('/sys/class/net/%s' % bondname
+
2133 with
open(sysfs_bond_path
, 'r') as f
:
2134 slaves
= f
.readline().strip().split()
2136 raise Exception('error reading slaves of bond %s (%s)' % (bondname
, str(e
)))
2137 for slave
in slaves
:
2138 self
.link_down(slave
)
2140 self
.bond_remove_slave(bondname
, slave
)
2141 except Exception, e
:
2142 if not ifupdownflags
.flags
.FORCE
:
2143 raise Exception('error removing slave %s from bond %s (%s)' % (slave
, bondname
, str(e
)))
2146 self
._cache
_delete
([bondname
, 'linkinfo', 'slaves'])
2149 def bond_load_bonding_module():
2150 return utils
.exec_command('%s -q bonding' % utils
.modprobe_cmd
)
2152 def create_bond(self
, bondname
):
2153 if self
.bond_exists(bondname
):
2155 # load_bonding_module() has already been run
2156 self
.write_file('/sys/class/net/bonding_masters', '+' + bondname
)
2157 self
._cache
_update
([bondname
], {})
2159 def delete_bond(self
, bondname
):
2160 if not os
.path
.exists('/sys/class/net/%s' % bondname
):
2162 self
.write_file('/sys/class/net/bonding_masters', '-' + bondname
)
2163 self
._cache
_delete
([bondname
])
2165 def bond_get_slaves(self
, bondname
):
2166 slaves
= self
._link
_cache
_get
([bondname
, 'linkinfo', 'slaves'])
2169 slavefile
= '/sys/class/net/%s/bonding/slaves' % bondname
2170 if os
.path
.exists(slavefile
):
2171 buf
= self
.read_file_oneline(slavefile
)
2173 slaves
= buf
.split()
2176 self
._cache
_update
([bondname
, 'linkinfo', 'slaves'], slaves
)
2179 def bond_slave_exists(self
, bond
, slave
):
2180 slaves
= self
.bond_get_slaves(bond
)
2183 return slave
in slaves
2186 def bond_exists(bondname
):
2187 return os
.path
.exists('/sys/class/net/%s/bonding' % bondname
)
2189 #################################################################################
2190 ################################## BRIDGE UTILS #################################
2191 #################################################################################
2193 def create_bridge(self
, bridgename
):
2194 if not LinkUtils
.bridge_utils_is_installed
:
2196 if self
.bridge_exists(bridgename
):
2198 utils
.exec_command('%s addbr %s' % (utils
.brctl_cmd
, bridgename
))
2199 self
._cache
_update
([bridgename
], {})
2201 def delete_bridge(self
, bridgename
):
2202 if not LinkUtils
.bridge_utils_is_installed
:
2204 if not self
.bridge_exists(bridgename
):
2206 utils
.exec_command('%s delbr %s' % (utils
.brctl_cmd
, bridgename
))
2207 self
._cache
_invalidate
()
2209 def add_bridge_port(self
, bridgename
, bridgeportname
):
2210 """ Add port to bridge """
2211 if not LinkUtils
.bridge_utils_is_installed
:
2213 ports
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports'])
2214 if ports
and ports
.get(bridgeportname
):
2216 utils
.exec_command('%s addif %s %s' % (utils
.brctl_cmd
, bridgename
, bridgeportname
))
2217 self
._cache
_update
([bridgename
, 'linkinfo', 'ports', bridgeportname
], {})
2219 def delete_bridge_port(self
, bridgename
, bridgeportname
):
2220 """ Delete port from bridge """
2221 if not LinkUtils
.bridge_utils_is_installed
:
2223 ports
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports'])
2224 if not ports
or not ports
.get(bridgeportname
):
2226 utils
.exec_command('%s delif %s %s' % (utils
.brctl_cmd
, bridgename
, bridgeportname
))
2227 self
._cache
_delete
([bridgename
, 'linkinfo', 'ports', 'bridgeportname'])
2229 def set_bridgeport_attrs(self
, bridgename
, bridgeportname
, attrdict
):
2230 portattrs
= self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports', bridgeportname
])
2231 if portattrs
== None:
2233 for k
, v
in attrdict
.iteritems():
2234 if ifupdownflags
.flags
.CACHE
:
2235 curval
= portattrs
.get(k
)
2236 if curval
and curval
== v
:
2238 if k
== 'unicast-flood':
2239 self
.write_file('/sys/class/net/%s/brport/unicast_flood' % bridgeportname
, v
)
2240 elif k
== 'multicast-flood':
2241 self
.write_file('/sys/class/net/%s/brport/multicast_flood' % bridgeportname
, v
)
2242 elif k
== 'learning':
2243 self
.write_file('/sys/class/net/%s/brport/learning' % bridgeportname
, v
)
2244 elif k
== 'arp-nd-suppress':
2245 self
.write_file('/sys/class/net/%s/brport/neigh_suppress' % bridgeportname
, v
)
2247 if not LinkUtils
.bridge_utils_is_installed
:
2249 utils
.exec_command('%s set%s %s %s %s' % (utils
.brctl_cmd
, k
, bridgename
, bridgeportname
, v
))
2251 def set_bridgeport_attr(self
, bridgename
, bridgeportname
,
2253 if not LinkUtils
.bridge_utils_is_installed
:
2255 if self
._link
_cache
_check
([bridgename
, 'linkinfo', 'ports', bridgeportname
, attrname
], attrval
):
2257 utils
.exec_command('%s set%s %s %s %s' %
2264 def set_bridge_attrs(self
, bridgename
, attrdict
):
2265 for k
, v
in attrdict
.iteritems():
2268 if self
._link
_cache
_check
([bridgename
, 'linkinfo', k
], v
):
2271 if k
== 'igmp-version':
2272 self
.write_file('/sys/class/net/%s/bridge/'
2273 'multicast_igmp_version' % bridgename
, v
)
2274 elif k
== 'mld-version':
2275 self
.write_file('/sys/class/net/%s/bridge/'
2276 'multicast_mld_version' % bridgename
, v
)
2277 elif k
== 'vlan-protocol':
2278 self
.write_file('/sys/class/net/%s/bridge/'
2279 'vlan_protocol' % bridgename
,
2280 VlanProtocols
.ETHERTYPES_TO_ID
.get(v
.upper(),
2282 elif k
== 'vlan-stats':
2283 self
.write_file('/sys/class/net/%s/bridge/'
2284 'vlan_stats_enabled' % bridgename
, v
)
2285 elif k
== 'mcstats':
2286 self
.write_file('/sys/class/net/%s/bridge/'
2287 'multicast_stats_enabled' % bridgename
, v
)
2289 if not LinkUtils
.bridge_utils_is_installed
:
2291 cmd
= ('%s set%s %s %s' %
2292 (utils
.brctl_cmd
, k
, bridgename
, v
))
2293 utils
.exec_command(cmd
)
2294 except Exception, e
:
2295 self
.logger
.warn('%s: %s' % (bridgename
, str(e
)))
2298 def set_bridge_attr(self
, bridgename
, attrname
, attrval
):
2299 if self
._link
_cache
_check
([bridgename
, 'linkinfo', attrname
], attrval
):
2301 if attrname
== 'igmp-version':
2302 self
.write_file('/sys/class/net/%s/bridge/multicast_igmp_version'
2303 % bridgename
, attrval
)
2304 elif attrname
== 'mld-version':
2305 self
.write_file('/sys/class/net/%s/bridge/multicast_mld_version'
2306 % bridgename
, attrval
)
2307 elif attrname
== 'vlan-protocol':
2308 self
.write_file('/sys/class/net/%s/bridge/vlan_protocol'
2309 % bridgename
, VlanProtocols
.ETHERTYPES_TO_ID
[attrval
.upper()])
2310 elif attrname
== 'vlan-stats':
2311 self
.write_file('/sys/class/net/%s/bridge/vlan_stats_enabled'
2312 % bridgename
, attrval
)
2313 elif attrname
== 'mcstats':
2314 self
.write_file('/sys/class/net/%s/bridge/multicast_stats_enabled'
2315 % bridgename
, attrval
)
2317 if not LinkUtils
.bridge_utils_is_installed
:
2319 cmd
= '%s set%s %s %s' % (utils
.brctl_cmd
,
2320 attrname
, bridgename
, attrval
)
2321 utils
.exec_command(cmd
)
2323 def get_bridge_attrs(self
, bridgename
):
2324 attrs
= self
._link
_cache
_get
([bridgename
, 'linkinfo'])
2326 for key
, value
in attrs
.items():
2327 if type(key
) == str:
2328 no_ints_attrs
[key
] = value
2329 return no_ints_attrs
2331 def get_bridgeport_attrs(self
, bridgename
, bridgeportname
):
2332 return self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports',
2335 def get_bridgeport_attr(self
, bridgename
, bridgeportname
, attrname
):
2336 return self
._link
_cache
_get
([bridgename
, 'linkinfo', 'ports',
2337 bridgeportname
, attrname
])
2340 def bridge_set_stp(bridge
, stp_state
):
2341 if not LinkUtils
.bridge_utils_is_installed
:
2343 utils
.exec_command('%s stp %s %s' % (utils
.brctl_cmd
, bridge
, stp_state
))
2345 def bridge_get_stp(self
, bridge
):
2346 sysfs_stpstate
= '/sys/class/net/%s/bridge/stp_state' % bridge
2347 if not os
.path
.exists(sysfs_stpstate
):
2349 stpstate
= self
.read_file_oneline(sysfs_stpstate
)
2353 if int(stpstate
) > 0:
2355 elif int(stpstate
) == 0:
2361 def _conv_value_to_user(s
):
2368 def read_value_from_sysfs(self
, filename
, preprocess_func
):
2369 value
= self
.read_file_oneline(filename
)
2372 return preprocess_func(value
)
2375 def bridge_set_ageing(bridge
, ageing
):
2376 if not LinkUtils
.bridge_utils_is_installed
:
2378 utils
.exec_command('%s setageing %s %s' % (utils
.brctl_cmd
, bridge
, ageing
))
2380 def bridge_get_ageing(self
, bridge
):
2381 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/ageing_time'
2382 % bridge
, self
._conv
_value
_to
_user
)
2385 def set_bridgeprio(bridge
, prio
):
2386 if not LinkUtils
.bridge_utils_is_installed
:
2388 utils
.exec_command('%s setbridgeprio %s %s' % (utils
.brctl_cmd
, bridge
, prio
))
2390 def get_bridgeprio(self
, bridge
):
2391 return self
.read_file_oneline(
2392 '/sys/class/net/%s/bridge/priority' % bridge
)
2395 def bridge_set_fd(bridge
, fd
):
2396 if not LinkUtils
.bridge_utils_is_installed
:
2398 utils
.exec_command('%s setfd %s %s' % (utils
.brctl_cmd
, bridge
, fd
))
2400 def bridge_get_fd(self
, bridge
):
2401 return self
.read_value_from_sysfs(
2402 '/sys/class/net/%s/bridge/forward_delay'
2403 % bridge
, self
._conv
_value
_to
_user
)
2405 def bridge_set_gcint(self
, bridge
, gcint
):
2406 raise Exception('set_gcint not implemented')
2409 def bridge_set_hello(bridge
, hello
):
2410 if not LinkUtils
.bridge_utils_is_installed
:
2412 utils
.exec_command('%s sethello %s %s' % (utils
.brctl_cmd
, bridge
, hello
))
2414 def bridge_get_hello(self
, bridge
):
2415 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/hello_time'
2416 % bridge
, self
._conv
_value
_to
_user
)
2419 def bridge_set_maxage(bridge
, maxage
):
2420 if not LinkUtils
.bridge_utils_is_installed
:
2422 utils
.exec_command('%s setmaxage %s %s' % (utils
.brctl_cmd
, bridge
, maxage
))
2424 def bridge_get_maxage(self
, bridge
):
2425 return self
.read_value_from_sysfs('/sys/class/net/%s/bridge/max_age'
2426 % bridge
, self
._conv
_value
_to
_user
)
2429 def bridge_set_pathcost(bridge
, port
, pathcost
):
2430 if not LinkUtils
.bridge_utils_is_installed
:
2432 utils
.exec_command('%s setpathcost %s %s %s' % (utils
.brctl_cmd
, bridge
, port
, pathcost
))
2434 def bridge_get_pathcost(self
, bridge
, port
):
2435 return self
.read_file_oneline('/sys/class/net/%s/brport/path_cost'
2439 def bridge_set_portprio(bridge
, port
, prio
):
2440 if not LinkUtils
.bridge_utils_is_installed
:
2442 utils
.exec_command('%s setportprio %s %s %s' % (utils
.brctl_cmd
, bridge
, port
, prio
))
2444 def bridge_get_portprio(self
, bridge
, port
):
2445 return self
.read_file_oneline('/sys/class/net/%s/brport/priority'
2449 def bridge_set_hashmax(bridge
, hashmax
):
2450 if not LinkUtils
.bridge_utils_is_installed
:
2452 utils
.exec_command('%s sethashmax %s %s' % (utils
.brctl_cmd
, bridge
, hashmax
))
2454 def bridge_get_hashmax(self
, bridge
):
2455 return self
.read_file_oneline('/sys/class/net/%s/bridge/hash_max'
2459 def bridge_set_hashel(bridge
, hashel
):
2460 if not LinkUtils
.bridge_utils_is_installed
:
2462 utils
.exec_command('%s sethashel %s %s' % (utils
.brctl_cmd
, bridge
, hashel
))
2464 def bridge_get_hashel(self
, bridge
):
2465 return self
.read_file_oneline('/sys/class/net/%s/bridge/hash_elasticity'
2469 def bridge_set_mclmc(bridge
, mclmc
):
2470 if not LinkUtils
.bridge_utils_is_installed
:
2472 utils
.exec_command('%s setmclmc %s %s' % (utils
.brctl_cmd
, bridge
, mclmc
))
2474 def bridge_get_mclmc(self
, bridge
):
2475 return self
.read_file_oneline(
2476 '/sys/class/net/%s/bridge/multicast_last_member_count'
2480 def bridge_set_mcrouter(bridge
, mcrouter
):
2481 if not LinkUtils
.bridge_utils_is_installed
:
2483 utils
.exec_command('%s setmcrouter %s %s' % (utils
.brctl_cmd
, bridge
, mcrouter
))
2485 def bridge_get_mcrouter(self
, bridge
):
2486 return self
.read_file_oneline(
2487 '/sys/class/net/%s/bridge/multicast_router' % bridge
)
2490 def bridge_set_mcsnoop(bridge
, mcsnoop
):
2491 if not LinkUtils
.bridge_utils_is_installed
:
2493 utils
.exec_command('%s setmcsnoop %s %s' % (utils
.brctl_cmd
, bridge
, mcsnoop
))
2495 def bridge_get_mcsnoop(self
, bridge
):
2496 return self
.read_file_oneline(
2497 '/sys/class/net/%s/bridge/multicast_snooping' % bridge
)
2500 def bridge_set_mcsqc(bridge
, mcsqc
):
2501 if not LinkUtils
.bridge_utils_is_installed
:
2503 utils
.exec_command('%s setmcsqc %s %s' % (utils
.brctl_cmd
, bridge
, mcsqc
))
2505 def bridge_get_mcsqc(self
, bridge
):
2506 return self
.read_file_oneline(
2507 '/sys/class/net/%s/bridge/multicast_startup_query_count'
2511 def bridge_set_mcqifaddr(bridge
, mcqifaddr
):
2512 if not LinkUtils
.bridge_utils_is_installed
:
2514 utils
.exec_command('%s setmcqifaddr %s %s' % (utils
.brctl_cmd
, bridge
, mcqifaddr
))
2516 def bridge_get_mcqifaddr(self
, bridge
):
2517 return self
.read_file_oneline(
2518 '/sys/class/net/%s/bridge/multicast_startup_query_use_ifaddr'
2522 def bridge_set_mcquerier(bridge
, mcquerier
):
2523 if not LinkUtils
.bridge_utils_is_installed
:
2525 utils
.exec_command('%s setmcquerier %s %s' % (utils
.brctl_cmd
, bridge
, mcquerier
))
2527 def bridge_get_mcquerier(self
, bridge
):
2528 return self
.read_file_oneline(
2529 '/sys/class/net/%s/bridge/multicast_querier' % bridge
)
2531 def bridge_set_mcqv4src(self
, bridge
, vlan
, mcquerier
):
2535 self
.logger
.info('%s: set mcqv4src vlan: invalid parameter %s: %s' %(bridge
, vlan
, str(e
)))
2537 if vlan
== 0 or vlan
> 4095:
2538 self
.logger
.warn('mcqv4src vlan \'%d\' invalid range' % vlan
)
2541 ip
= mcquerier
.split('.')
2543 self
.logger
.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier
)
2546 if not k
.isdigit() or int(k
, 10) < 0 or int(k
, 10) > 255:
2547 self
.logger
.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier
)
2550 if not LinkUtils
.bridge_utils_is_installed
:
2553 utils
.exec_command('%s setmcqv4src %s %d %s' %
2554 (utils
.brctl_cmd
, bridge
, vlan
, mcquerier
))
2556 def bridge_del_mcqv4src(self
, bridge
, vlan
):
2557 if not LinkUtils
.bridge_utils_is_installed
:
2562 self
.logger
.info('%s: del mcqv4src vlan: invalid parameter %s: %s' %(bridge
, vlan
, str(e
)))
2564 utils
.exec_command('%s delmcqv4src %s %d' % (utils
.brctl_cmd
, bridge
, vlan
))
2566 def bridge_get_mcqv4src(self
, bridge
, vlan
=None):
2567 if not LinkUtils
.bridge_utils_is_installed
:
2569 if not self
.supported_command
['showmcqv4src']:
2573 mcqout
= utils
.exec_command('%s showmcqv4src %s' %
2574 (utils
.brctl_cmd
, bridge
))
2575 except Exception as e
:
2577 if 'never heard' in s
:
2578 msg
= ('%s showmcqv4src: skipping unsupported command'
2580 self
.logger
.info(msg
)
2581 self
.supported_command
['showmcqv4src'] = False
2586 mcqlines
= mcqout
.splitlines()
2587 for l
in mcqlines
[1:]:
2589 k
, d
, v
= l
.split('\t')
2594 return mcqv4src
.get(vlan
)
2598 def bridge_set_mclmi(bridge
, mclmi
):
2599 if not LinkUtils
.bridge_utils_is_installed
:
2601 utils
.exec_command('%s setmclmi %s %s' % (utils
.brctl_cmd
, bridge
, mclmi
))
2603 def bridge_get_mclmi(self
, bridge
):
2604 return self
.read_file_oneline(
2605 '/sys/class/net/%s/bridge/multicast_last_member_interval'
2609 def bridge_set_mcmi(bridge
, mcmi
):
2610 if not LinkUtils
.bridge_utils_is_installed
:
2612 utils
.exec_command('%s setmcmi %s %s' % (utils
.brctl_cmd
, bridge
, mcmi
))
2614 def bridge_get_mcmi(self
, bridge
):
2615 return self
.read_file_oneline(
2616 '/sys/class/net/%s/bridge/multicast_membership_interval'
2620 def bridge_exists(bridge
):
2621 return os
.path
.exists('/sys/class/net/%s/bridge' % bridge
)
2624 def is_bridge_port(ifacename
):
2625 return os
.path
.exists('/sys/class/net/%s/brport' % ifacename
)
2628 def bridge_port_exists(bridge
, bridgeportname
):
2630 return os
.path
.exists('/sys/class/net/%s/brif/%s' % (bridge
, bridgeportname
))
2635 def get_bridge_ports(bridgename
):
2637 return os
.listdir('/sys/class/net/%s/brif/' % bridgename
)
2641 def ipv6_addrgen(self
, ifname
, addrgen
):
2642 cmd
= 'link set dev %s addrgenmode %s' % (ifname
, 'eui64' if addrgen
else 'none')
2644 is_link_up
= self
.is_link_up(ifname
)
2647 self
.link_down(ifname
)
2649 if LinkUtils
.ipbatch
:
2650 self
.add_to_batch(cmd
)
2652 utils
.exec_command('%s %s' % (utils
.ip_cmd
, cmd
))
2655 self
.link_up(ifname
)