]> git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdown2/ifupdownaddons/LinkUtils.py
addons: tunnel: add support for vti, ip6gre, ipip6, ip6ip6, vti6 tunnels
[mirror_ifupdown2.git] / ifupdown2 / ifupdownaddons / LinkUtils.py
1 #!/usr/bin/python
2 #
3 # Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
5 # Julien Fortin, julien@cumulusnetworks.com
6 #
7
8 import os
9 import re
10 import glob
11 import shlex
12 import signal
13 import subprocess
14
15 from ipaddr import IPNetwork, IPv6Network
16
17 try:
18 import ifupdown2.ifupdown.statemanager as statemanager
19 import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
20
21 from ifupdown2.nlmanager.nlmanager import Link, Route
22
23 from ifupdown2.ifupdown.iface import *
24 from ifupdown2.ifupdown.utils import utils
25 from ifupdown2.ifupdown.netlink import netlink
26
27 from ifupdown2.ifupdownaddons.utilsbase import utilsBase
28 from ifupdown2.ifupdownaddons.cache import linkCache, MSTPAttrsCache
29 except ImportError:
30 import ifupdown.ifupdownflags as ifupdownflags
31 import ifupdown.statemanager as statemanager
32
33 from nlmanager.nlmanager import Link, Route
34
35 from ifupdown.iface import *
36 from ifupdown.utils import utils
37 from ifupdown.netlink import netlink
38
39 from ifupdownaddons.utilsbase import utilsBase
40 from ifupdownaddons.cache import linkCache, MSTPAttrsCache
41
42
43 class LinkUtils(utilsBase):
44 """
45 This class contains helper methods to cache and manipulate interfaces through
46 non-netlink APIs (sysfs, iproute2, brctl...)
47 """
48 _CACHE_FILL_DONE = False
49 VXLAN_UDP_PORT = 4789
50
51 ipbatchbuf = ''
52 ipbatch = False
53 ipbatch_pause = False
54
55 bridge_utils_is_installed = os.path.exists(utils.brctl_cmd)
56 bridge_utils_missing_warning = True
57
58 DEFAULT_IP_METRIC = 1024
59 ADDR_METRIC_SUPPORT = None
60
61 def __init__(self, *args, **kargs):
62 utilsBase.__init__(self, *args, **kargs)
63
64 self.supported_command = {
65 '%s -c -json vlan show' % utils.bridge_cmd: True,
66 'showmcqv4src': True
67 }
68 self.bridge_vlan_cache = {}
69 self.bridge_vlan_cache_fill_done = False
70
71 if not ifupdownflags.flags.PERFMODE and not LinkUtils._CACHE_FILL_DONE:
72 self._fill_cache()
73
74 if LinkUtils.ADDR_METRIC_SUPPORT is None:
75 try:
76 cmd = [utils.ip_cmd, 'addr', 'help']
77 self.logger.info('executing %s addr help' % utils.ip_cmd)
78
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'))
83 except Exception:
84 LinkUtils.ADDR_METRIC_SUPPORT = False
85 self.logger.info('address metric support: KO')
86
87 @classmethod
88 def addr_metric_support(cls):
89 return cls.ADDR_METRIC_SUPPORT
90
91 @classmethod
92 def get_default_ip_metric(cls):
93 return cls.DEFAULT_IP_METRIC
94
95 @classmethod
96 def reset(cls):
97 LinkUtils._CACHE_FILL_DONE = False
98 LinkUtils.ipbatchbuf = ''
99 LinkUtils.ipbatch = False
100 LinkUtils.ipbatch_pause = False
101
102 def _fill_cache(self):
103 if not LinkUtils._CACHE_FILL_DONE:
104 self._link_fill()
105 self._addr_fill()
106 LinkUtils._CACHE_FILL_DONE = True
107 return True
108 return False
109
110 @staticmethod
111 def _get_vland_id(citems, i, warn):
112 try:
113 sub = citems[i:]
114 index = sub.index('id')
115 int(sub[index + 1])
116 return sub[index + 1]
117 except:
118 if warn:
119 raise Exception('invalid use of \'vlan\' keyword')
120 return None
121
122 def _link_fill(self, ifacename=None, refresh=False):
123 """ fills cache with link information
124
125 if ifacename argument given, fill cache for ifacename, else
126 fill cache for all interfaces in the system
127 """
128
129 if LinkUtils._CACHE_FILL_DONE and not refresh:
130 return
131 try:
132 # if ifacename already present, return
133 if (ifacename and not refresh and
134 linkCache.get_attr([ifacename, 'ifflag'])):
135 return
136 except:
137 pass
138
139 if True:
140 try:
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.
152 else:
153 self._link_fill_iproute2_cmd(ifacename, refresh)
154
155 self._fill_bond_info(ifacename)
156 self._fill_bridge_info(ifacename)
157
158 def _fill_bridge_info(self, ifacename):
159
160 if True: # netlink
161 brports = {}
162
163 if ifacename:
164 cache_dict = {ifacename: linkCache.links.get(ifacename, {})}
165 else:
166 cache_dict = linkCache.links
167
168 for ifname, obj in cache_dict.items():
169 slave_kind = obj.get('slave_kind')
170 if not slave_kind and slave_kind != 'bridge':
171 continue
172
173 info_slave_data = obj.get('info_slave_data')
174 if not info_slave_data:
175 continue
176
177 ifla_master = obj.get('master')
178 if not ifla_master:
179 raise Exception('No master associated with bridge port %s' % ifname)
180
181 for nl_attr in [
182 Link.IFLA_BRPORT_STATE,
183 Link.IFLA_BRPORT_COST,
184 Link.IFLA_BRPORT_PRIORITY,
185 ]:
186 if nl_attr not in info_slave_data and LinkUtils.bridge_utils_is_installed:
187 self._fill_bridge_info_brctl()
188 return
189
190 brport_attrs = {
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))
200 }
201
202 if ifla_master in brports:
203 brports[ifla_master][ifname] = brport_attrs
204 else:
205 brports[ifla_master] = {ifname: brport_attrs}
206
207 linkCache.update_attrdict([ifla_master, 'linkinfo', 'ports'], brports[ifla_master])
208 else:
209 if LinkUtils.bridge_utils_is_installed:
210 self._fill_bridge_info_brctl()
211
212 def _fill_bridge_info_brctl(self):
213 brctlout = utils.exec_command('%s show' % utils.brctl_cmd)
214 if not brctlout:
215 return
216
217 for bline in brctlout.splitlines()[1:]:
218 bitems = bline.split()
219 if len(bitems) < 2:
220 continue
221 try:
222 linkCache.update_attrdict([bitems[0], 'linkinfo'],
223 {'stp': bitems[2]})
224 except KeyError:
225 linkCache.update_attrdict([bitems[0]],
226 {'linkinfo': {'stp': bitems[2]}})
227 self._bridge_attrs_fill(bitems[0])
228
229 def _bridge_attrs_fill(self, bridgename):
230 battrs = {}
231 bports = {}
232
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)
235
236 try:
237 # Get all bridge attributes
238 broutlines = chunks[0].splitlines()
239 # battrs['pathcost'] = broutlines[3].split('path cost')[1].strip()
240
241 try:
242 battrs['maxage'] = broutlines[4].split('bridge max age')[
243 1].strip().replace('.00', '')
244 except:
245 pass
246
247 try:
248 battrs['hello'] = broutlines[5].split('bridge hello time')[
249 1].strip().replace('.00', '')
250 except:
251 pass
252
253 try:
254 battrs['fd'] = broutlines[6].split('bridge forward delay')[
255 1].strip().replace('.00', '')
256 except:
257 pass
258
259 try:
260 battrs['ageing'] = broutlines[7].split('ageing time')[
261 1].strip().replace('.00', '')
262 except:
263 pass
264
265 try:
266 battrs['mcrouter'] = broutlines[12].split('mc router')[
267 1].strip().split('\t\t\t')[0]
268 except:
269 pass
270
271 try:
272 battrs['bridgeprio'] = self.read_file_oneline(
273 '/sys/class/net/%s/bridge/priority' % bridgename)
274 except:
275 pass
276
277 try:
278 battrs['vlan-protocol'] = VlanProtocols.ID_TO_ETHERTYPES[
279 self.read_file_oneline(
280 '/sys/class/net/%s/bridge/vlan_protocol' % bridgename)]
281 except:
282 pass
283
284 try:
285 battrs.update(self._bridge_get_mcattrs_from_sysfs(bridgename))
286 except:
287 pass
288
289 # XXX: comment this out until mc attributes become available
290 # with brctl again
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()
298 except Exception, e:
299 self.logger.warn('%s: error while processing bridge attributes: %s' % (bridgename, str(e)))
300 pass
301
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] == ' ':
306 continue
307 bplines = bpout.splitlines()
308 pname = bplines[0].split()[0]
309 bportattrs = {}
310 try:
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()
331 except Exception, e:
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)
335
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',
355 }
356
357 def _bridge_get_mcattrs_from_sysfs(self, bridgename):
358 mcattrsdivby100 = ['mclmi', 'mcmi', 'mcqpi', 'mcqi', 'mcqri', 'mcsqi']
359 mcattrs = {}
360
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:
364 try:
365 v = int(n) / 100
366 mcattrs[m] = str(v)
367 except Exception, e:
368 self.logger.warn('error getting mc attr %s (%s)' % (m, str(e)))
369 pass
370 else:
371 mcattrs[m] = n
372 return mcattrs
373
374 def _fill_bond_info(self, ifacename):
375 bonding_masters = self.read_file_oneline('/sys/class/net/bonding_masters')
376 if not bonding_masters:
377 return
378
379 bond_masters_list = bonding_masters.split()
380
381 if ifacename:
382 if ifacename in bond_masters_list:
383 bond_masters_list = [ifacename]
384 else:
385 # we want to refresh this interface only if it's a bond master
386 return
387
388 for bondname in bond_masters_list:
389 try:
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'
394 % bondname).split())
395 try:
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
402 break
403 except:
404 self._fill_bond_info_sysfs(bondname)
405
406 except Exception as e:
407 self.logger.debug('LinkUtils: bond cache error: %s' % str(e))
408
409 def _fill_bond_info_sysfs(self, bondname):
410 try:
411 linkCache.set_attr([bondname, 'linkinfo', Link.IFLA_BOND_MIN_LINKS],
412 self.read_file_oneline(
413 '/sys/class/net/%s/bonding/min_links'
414 % bondname))
415 except Exception as e:
416 self.logger.debug(str(e))
417
418 try:
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))
424 try:
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))
431 try:
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))
437 try:
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'
440 % bondname))
441 except Exception as e:
442 self.logger.debug(str(e))
443 try:
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'
446 % bondname))
447 except Exception as e:
448 self.logger.debug(str(e))
449 try:
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))
455 try:
456 linkCache.set_attr([bondname, 'linkinfo', Link.IFLA_BOND_UPDELAY],
457 self.read_file_oneline('/sys/class/net/%s/bonding/updelay'
458 % bondname))
459 except Exception as e:
460 self.logger.debug(str(e))
461 try:
462 linkCache.set_attr([bondname, 'linkinfo', Link.IFLA_BOND_DOWNDELAY],
463 self.read_file_oneline('/sys/class/net/%s/bonding/downdelay'
464 % bondname))
465 except Exception as e:
466 self.logger.debug(str(e))
467
468 try:
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))
473
474 try:
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))
479
480 try:
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))
485
486 try:
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))
491
492
493 def _link_fill_iproute2_cmd(self, ifacename=None, refresh=False):
494 warn = True
495 linkout = {}
496 if LinkUtils._CACHE_FILL_DONE and not refresh:
497 return
498 try:
499 # if ifacename already present, return
500 if (ifacename and not refresh and
501 linkCache.get_attr([ifacename, 'ifflag'])):
502 return
503 except:
504 pass
505 cmdout = self.link_show(ifacename=ifacename)
506 if not cmdout:
507 return
508 for c in cmdout.splitlines():
509 citems = c.split()
510 ifnamenlink = citems[1].split('@')
511 if len(ifnamenlink) > 1:
512 ifname = ifnamenlink[0]
513 iflink = ifnamenlink[1].strip(':')
514 else:
515 ifname = ifnamenlink[0].strip(':')
516 iflink = None
517 linkattrs = dict()
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)):
524 try:
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],
534 'endpoint' : None,
535 'local' : None,
536 'ttl' : None,
537 'physdev' : None}
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
548 break
549 elif citems[i] == 'vlan':
550 vlanid = self._get_vland_id(citems, i, warn)
551 if vlanid:
552 linkattrs['linkinfo'] = {'vlanid': vlanid}
553 linkattrs['kind'] = 'vlan'
554 elif citems[i] == 'dummy':
555 linkattrs['kind'] = 'dummy'
556 elif citems[i] == 'vxlan' and citems[i + 1] == 'id':
557 linkattrs['kind'] = 'vxlan'
558 vattrs = {'vxlanid': citems[i + 2],
559 'svcnode': None,
560 'remote': [],
561 'ageing': citems[i + 2],
562 'learning': 'on'}
563 for j in range(i + 2, len(citems)):
564 if citems[j] == 'local':
565 vattrs['local'] = citems[j + 1]
566 elif citems[j] == 'remote':
567 vattrs['svcnode'] = citems[j + 1]
568 elif citems[j] == 'ageing':
569 vattrs['ageing'] = citems[j + 1]
570 elif citems[j] == 'nolearning':
571 vattrs['learning'] = 'off'
572 elif citems[j] == 'dev':
573 vattrs['physdev'] = citems[j + 1]
574 linkattrs['linkinfo'] = vattrs
575 break
576 elif citems[i] == 'vrf' and citems[i + 1] == 'table':
577 vattrs = {'table': citems[i + 2]}
578 linkattrs['linkinfo'] = vattrs
579 linkattrs['kind'] = 'vrf'
580 linkCache.vrfs[ifname] = vattrs
581 break
582 elif citems[i] == 'veth':
583 linkattrs['kind'] = 'veth'
584 elif citems[i] == 'vrf_slave':
585 linkattrs['slave_kind'] = 'vrf_slave'
586 break
587 elif citems[i] == 'macvlan' and citems[i + 1] == 'mode':
588 linkattrs['kind'] = 'macvlan'
589 except Exception as e:
590 if warn:
591 self.logger.debug('%s: parsing error: id, mtu, state, '
592 'link/ether, vlan, dummy, vxlan, local, '
593 'remote, ageing, nolearning, vrf, table, '
594 'vrf_slave are reserved keywords: %s' %
595 (ifname, str(e)))
596 warn = False
597 # linkattrs['alias'] = self.read_file_oneline(
598 # '/sys/class/net/%s/ifalias' %ifname)
599 linkout[ifname] = linkattrs
600 [linkCache.update_attrdict([ifname], linkattrs)
601 for ifname, linkattrs in linkout.items()]
602
603 @staticmethod
604 def _addr_filter(ifname, addr, scope=None):
605 default_addrs = ['127.0.0.1/8', '::1/128', '0.0.0.0']
606 if ifname == 'lo' and addr in default_addrs:
607 return True
608 if scope and scope == 'link':
609 return True
610 return False
611
612 def _addr_fill(self, ifacename=None, refresh=False):
613 """ fills cache with address information
614
615 if ifacename argument given, fill cache for ifacename, else
616 fill cache for all interfaces in the system
617 """
618 if LinkUtils._CACHE_FILL_DONE and not refresh:
619 return
620 try:
621 # Check if ifacename is already full, in which case, return
622 if ifacename and not refresh:
623 linkCache.get_attr([ifacename, 'addrs'])
624 return
625 except:
626 pass
627
628 if True:
629 try:
630 [linkCache.update_attrdict([ifname], linkattrs)
631 for ifname, linkattrs in netlink.addr_dump(ifname=ifacename).items()]
632 except Exception as e:
633 self.logger.info(str(e))
634
635 # this netlink call replaces the call to _addr_fill_iproute2_cmd()
636 # We shouldn't have netlink calls in the iproute2 module, this will
637 # be removed in the future. We plan to release, a flexible backend
638 # (netlink+iproute2) by default we will use netlink backend but with
639 # a CLI arg we can switch to iproute2 backend.
640 # Until we decide to create this "backend" switch capability,
641 # we have to put the netlink call inside the iproute2 module.
642
643 else:
644 self._addr_fill_iproute2_cmd(ifacename, refresh)
645
646 def _addr_fill_iproute2_cmd(self, ifacename=None, refresh=False):
647 """ fills cache with address information
648
649 if ifacename argument given, fill cache for ifacename, else
650 fill cache for all interfaces in the system
651 """
652 linkout = {}
653 if LinkUtils._CACHE_FILL_DONE and not refresh:
654 return
655 try:
656 # Check if ifacename is already full, in which case, return
657 if ifacename and not refresh:
658 linkCache.get_attr([ifacename, 'addrs'])
659 return
660 except:
661 pass
662 cmdout = self.addr_show(ifacename=ifacename)
663 if not cmdout:
664 return
665 for c in cmdout.splitlines():
666 citems = c.split()
667 ifnamenlink = citems[1].split('@')
668 if len(ifnamenlink) > 1:
669 ifname = ifnamenlink[0]
670 else:
671 ifname = ifnamenlink[0].strip(':')
672 if not linkout.get(ifname):
673 linkattrs = dict()
674 linkattrs['addrs'] = OrderedDict({})
675 try:
676 linkout[ifname].update(linkattrs)
677 except KeyError:
678 linkout[ifname] = linkattrs
679 if citems[2] == 'inet':
680 if self._addr_filter(ifname, citems[3], scope=citems[5]):
681 continue
682 addrattrs = dict()
683 addrattrs['scope'] = citems[5]
684 addrattrs['type'] = 'inet'
685 linkout[ifname]['addrs'][citems[3]] = addrattrs
686 elif citems[2] == 'inet6':
687 if self._addr_filter(ifname, citems[3], scope=citems[5]):
688 continue
689 if citems[5] == 'link':
690 continue # skip 'link' addresses
691 addrattrs = dict()
692 addrattrs['scope'] = citems[5]
693 addrattrs['type'] = 'inet6'
694 linkout[ifname]['addrs'][citems[3]] = addrattrs
695 [linkCache.update_attrdict([ifname], linkattrs)
696 for ifname, linkattrs in linkout.items()]
697
698 def cache_get(self, t, attrlist, refresh=False):
699 return self._cache_get(t, attrlist, refresh)
700
701 def _cache_get(self, t, attrlist, refresh=False):
702 try:
703 if ifupdownflags.flags.DRYRUN:
704 return False
705 if ifupdownflags.flags.CACHE:
706 if self._fill_cache():
707 # if we filled the cache, return new data
708 return linkCache.get_attr(attrlist)
709 if not refresh:
710 return linkCache.get_attr(attrlist)
711 if t == 'link':
712 self._link_fill(attrlist[0], refresh)
713 elif t == 'addr':
714 self._addr_fill(attrlist[0], refresh)
715 else:
716 self._link_fill(attrlist[0], refresh)
717 self._addr_fill(attrlist[0], refresh)
718 return linkCache.get_attr(attrlist)
719 except Exception, e:
720 self.logger.debug('_cache_get(%s) : [%s]' % (str(attrlist), str(e)))
721 return None
722
723 def cache_check(self, attrlist, value, refresh=False):
724 return self._cache_check('link', attrlist, value, refresh=refresh)
725
726 def _cache_check(self, t, attrlist, value, refresh=False):
727 try:
728 return self._cache_get(t, attrlist, refresh) == value
729 except Exception, e:
730 self.logger.debug('_cache_check(%s) : [%s]'
731 % (str(attrlist), str(e)))
732 return False
733
734 def cache_update(self, attrlist, value):
735 return self._cache_update(attrlist, value)
736
737 @staticmethod
738 def _cache_update(attrlist, value):
739 if ifupdownflags.flags.DRYRUN:
740 return
741 try:
742 if attrlist[-1] == 'slaves':
743 linkCache.append_to_attrlist(attrlist, value)
744 return
745 linkCache.set_attr(attrlist, value)
746 except:
747 pass
748
749 @staticmethod
750 def _cache_delete(attrlist, value=None):
751 if ifupdownflags.flags.DRYRUN:
752 return
753 try:
754 if value:
755 linkCache.remove_from_attrlist(attrlist, value)
756 else:
757 linkCache.del_attr(attrlist)
758 except:
759 pass
760
761 @staticmethod
762 def _cache_invalidate():
763 linkCache.invalidate()
764 LinkUtils._CACHE_FILL_DONE = False
765
766 @staticmethod
767 def batch_start():
768 LinkUtils.ipbatcbuf = ''
769 LinkUtils.ipbatch = True
770 LinkUtils.ipbatch_pause = False
771
772 @staticmethod
773 def add_to_batch(cmd):
774 LinkUtils.ipbatchbuf += cmd + '\n'
775
776 @staticmethod
777 def batch_pause():
778 LinkUtils.ipbatch_pause = True
779
780 @staticmethod
781 def batch_resume():
782 LinkUtils.ipbatch_pause = False
783
784 def batch_commit(self):
785 if not LinkUtils.ipbatchbuf:
786 LinkUtils.ipbatchbuf = ''
787 LinkUtils.ipbatch = False
788 LinkUtils.ipbatch_pause = False
789 return
790 try:
791 utils.exec_command('%s -force -batch -' % utils.ip_cmd,
792 stdin=self.ipbatchbuf)
793 except:
794 raise
795 finally:
796 LinkUtils.ipbatchbuf = ''
797 LinkUtils.ipbatch = False
798 LinkUtils.ipbatch_pause = False
799
800 def bridge_batch_commit(self):
801 if not LinkUtils.ipbatchbuf:
802 LinkUtils.ipbatchbuf = ''
803 LinkUtils.ipbatch = False
804 LinkUtils.ipbatch_pause = False
805 return
806 try:
807 utils.exec_command('%s -force -batch -'
808 % utils.bridge_cmd, stdin=self.ipbatchbuf)
809 except:
810 raise
811 finally:
812 LinkUtils.ipbatchbuf = ''
813 LinkUtils.ipbatch = False
814 LinkUtils.ipbatch_pause = False
815
816 def addr_show(self, ifacename=None):
817 if ifacename:
818 if not self.link_exists(ifacename):
819 return
820 return utils.exec_commandl([utils.ip_cmd,
821 '-o', 'addr', 'show', 'dev', ifacename])
822 else:
823 return utils.exec_commandl([utils.ip_cmd,
824 '-o', 'addr', 'show'])
825
826 @staticmethod
827 def link_show(ifacename=None):
828 if ifacename:
829 return utils.exec_commandl([utils.ip_cmd,
830 '-o', '-d', 'link', 'show', 'dev', ifacename])
831 else:
832 return utils.exec_commandl([utils.ip_cmd,
833 '-o', '-d', 'link', 'show'])
834
835 def addr_add(self, ifacename, address, broadcast=None,
836 peer=None, scope=None, preferred_lifetime=None, metric=None):
837 if not address:
838 return
839 cmd = 'addr add %s' % address
840 if broadcast:
841 cmd += ' broadcast %s' % broadcast
842 if peer:
843 cmd += ' peer %s' % peer
844 if scope:
845 cmd += ' scope %s' % scope
846 if preferred_lifetime:
847 cmd += ' preferred_lft %s' % preferred_lifetime
848 cmd += ' dev %s' % ifacename
849
850 if metric:
851 cmd += ' metric %s' % metric
852
853 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
854 self.add_to_batch(cmd)
855 else:
856 utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
857 self._cache_update([ifacename, 'addrs', address], {})
858
859 def addr_del(self, ifacename, address, broadcast=None,
860 peer=None, scope=None):
861 """ Delete ipv4 address """
862 if not address:
863 return
864 if not self._cache_get('addr', [ifacename, 'addrs', address]):
865 return
866 cmd = 'addr del %s' % address
867 if broadcast:
868 cmd += 'broadcast %s' % broadcast
869 if peer:
870 cmd += 'peer %s' % peer
871 if scope:
872 cmd += 'scope %s' % scope
873 cmd += ' dev %s' % ifacename
874 utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
875 self._cache_delete([ifacename, 'addrs', address])
876
877 def addr_flush(self, ifacename):
878 cmd = 'addr flush dev %s' % ifacename
879 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
880 self.add_to_batch(cmd)
881 else:
882 utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
883 self._cache_delete([ifacename, 'addrs'])
884
885 def del_addr_all(self, ifacename, skip_addrs=[]):
886 if not skip_addrs:
887 skip_addrs = []
888 runningaddrsdict = self.get_running_addrs(ifname=ifacename)
889 try:
890 # XXX: ignore errors. Fix this to delete secondary addresses
891 # first
892 [self.addr_del(ifacename, a) for a in
893 set(runningaddrsdict.keys()).difference(skip_addrs)]
894 except:
895 # ignore errors
896 pass
897
898 def addr_get(self, ifacename, details=True, refresh=False):
899 addrs = self._cache_get('addr', [ifacename, 'addrs'], refresh=refresh)
900 if not addrs:
901 return None
902 if details:
903 return addrs
904 return addrs.keys()
905
906 def get_running_addrs(self, ifaceobj=None, ifname=None, details=True, addr_virtual_ifaceobj=None):
907 """
908 We now support addr with link scope. Since the kernel may add it's
909 own link address to some interfaces we need to filter them out and
910 make sure we only deal with the addresses set by ifupdown2.
911
912 To do so we look at the previous configuration made by ifupdown2
913 (with the help of the statemanager) together with the addresses
914 specified by the user in /etc/network/interfaces, these addresses
915 are then compared to the running state of the intf (ip addr show)
916 made via a netlink addr dump.
917 For each configured addresses of scope link, we check if it was
918 previously configured by ifupdown2 to create a final set of the
919 addresses watched by ifupdown2
920 """
921 if not ifaceobj and not ifname:
922 return None
923
924 config_addrs = set()
925
926 if ifaceobj:
927 interface_name = ifaceobj.name
928 else:
929 interface_name = ifname
930
931 if addr_virtual_ifaceobj:
932 for virtual in addr_virtual_ifaceobj.get_attr_value('address-virtual') or []:
933 for ip in virtual.split():
934 try:
935 IPNetwork(ip)
936 config_addrs.add(ip)
937 except:
938 pass
939
940 saved_ifaceobjs = statemanager.statemanager_api.get_ifaceobjs(addr_virtual_ifaceobj.name)
941 for saved_ifaceobj in saved_ifaceobjs or []:
942 for virtual in saved_ifaceobj.get_attr_value('address-virtual') or []:
943 for ip in virtual.split():
944 try:
945 IPNetwork(ip)
946 config_addrs.add(ip)
947 except:
948 pass
949 else:
950 if ifaceobj:
951 for addr in ifaceobj.get_attr_value('address') or []:
952 config_addrs.add(addr)
953
954 saved_ifaceobjs = statemanager.statemanager_api.get_ifaceobjs(interface_name)
955 for saved_ifaceobj in saved_ifaceobjs or []:
956 for addr in saved_ifaceobj.get_attr_value('address') or []:
957 config_addrs.add(addr)
958
959 running_addrs = OrderedDict()
960 cached_addrs = self.addr_get(interface_name)
961 if cached_addrs:
962 for addr, addr_details in cached_addrs.items():
963 try:
964 scope = int(addr_details['scope'])
965 except Exception:
966 try:
967 d = {}
968 addr_obj = IPNetwork(addr)
969 if isinstance(addr_obj, IPv6Network):
970 d['family'] = 'inet6'
971 else:
972 d['family'] = 'inet'
973 running_addrs[addr] = d
974 except:
975 running_addrs[addr] = {}
976 continue
977 if (scope & Route.RT_SCOPE_LINK and addr in config_addrs) or not scope & Route.RT_SCOPE_LINK:
978 running_addrs[addr] = addr_details
979 else:
980 return None
981
982 if details:
983 return running_addrs
984 return running_addrs.keys()
985
986 @staticmethod
987 def compare_user_config_vs_running_state(running_addrs, user_addrs):
988 ip4 = []
989 ip6 = []
990
991 for ip in user_addrs or []:
992 obj = IPNetwork(ip)
993
994 if type(obj) == IPv6Network:
995 ip6.append(obj)
996 else:
997 ip4.append(obj)
998
999 running_ipobj = []
1000 for ip in running_addrs or []:
1001 running_ipobj.append(IPNetwork(ip))
1002
1003 return running_ipobj == (ip4 + ip6)
1004
1005 def addr_add_multiple(self, ifaceobj, ifacename, addrs, purge_existing=False, metric=None):
1006 # purges address
1007 if purge_existing:
1008 # if perfmode is not set and also if iface has no sibling
1009 # objects, purge addresses that are not present in the new
1010 # config
1011 runningaddrs = self.get_running_addrs(
1012 ifname=ifacename,
1013 details=False,
1014 addr_virtual_ifaceobj=ifaceobj
1015 )
1016 addrs = utils.get_normalized_ip_addr(ifacename, addrs)
1017
1018 if self.compare_user_config_vs_running_state(runningaddrs, addrs):
1019 return
1020 try:
1021 # if primary address is not same, there is no need to keep any.
1022 # reset all addresses
1023 if (addrs and runningaddrs and
1024 (addrs[0] != runningaddrs[0])):
1025 self.del_addr_all(ifacename)
1026 else:
1027 self.del_addr_all(ifacename, addrs)
1028 except Exception, e:
1029 self.logger.warning('%s: %s' % (ifacename, str(e)))
1030 for a in addrs:
1031 try:
1032 self.addr_add(ifacename, a, metric=metric)
1033 except Exception, e:
1034 self.logger.error(str(e))
1035
1036 def _link_set_ifflag(self, ifacename, value):
1037 # Dont look at the cache, the cache may have stale value
1038 # because link status can be changed by external
1039 # entity (One such entity is ifupdown main program)
1040 cmd = 'link set dev %s %s' % (ifacename, value.lower())
1041 if LinkUtils.ipbatch:
1042 self.add_to_batch(cmd)
1043 else:
1044 utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
1045
1046 def link_up(self, ifacename):
1047 self._link_set_ifflag(ifacename, 'UP')
1048
1049 def link_down(self, ifacename):
1050 self._link_set_ifflag(ifacename, 'DOWN')
1051
1052 def link_set(self, ifacename, key, value=None,
1053 force=False, t=None, state=None):
1054 if not force:
1055 if (key not in ['master', 'nomaster'] and
1056 self._cache_check('link', [ifacename, key], value)):
1057 return
1058 cmd = 'link set dev %s' % ifacename
1059 if t:
1060 cmd += ' type %s' % t
1061 cmd += ' %s' % key
1062 if value:
1063 cmd += ' %s' % value
1064 if state:
1065 cmd += ' %s' % state
1066 if LinkUtils.ipbatch:
1067 self.add_to_batch(cmd)
1068 else:
1069 utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
1070 if key not in ['master', 'nomaster']:
1071 self._cache_update([ifacename, key], value)
1072
1073 def link_set_hwaddress(self, ifacename, hwaddress, force=False):
1074 if not force:
1075 if self._cache_check('link', [ifacename, 'hwaddress'], hwaddress):
1076 return
1077 self.link_down(ifacename)
1078 cmd = 'link set dev %s address %s' % (ifacename, hwaddress)
1079 if LinkUtils.ipbatch:
1080 self.add_to_batch(cmd)
1081 else:
1082 utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
1083 self.link_up(ifacename)
1084 self._cache_update([ifacename, 'hwaddress'], hwaddress)
1085
1086 def link_set_mtu(self, ifacename, mtu):
1087 if ifupdownflags.flags.DRYRUN:
1088 return True
1089 if not mtu or not ifacename: return
1090 self.write_file('/sys/class/net/%s/mtu' % ifacename, mtu)
1091 self._cache_update([ifacename, 'mtu'], mtu)
1092
1093 def link_set_alias(self, ifacename, alias):
1094 self.write_file('/sys/class/net/%s/ifalias' % ifacename,
1095 '\n' if not alias else alias)
1096
1097 def link_get_alias(self, ifacename):
1098 return self.read_file_oneline('/sys/class/net/%s/ifalias'
1099 % ifacename)
1100
1101 def link_isloopback(self, ifacename):
1102 flags = self._cache_get('link', [ifacename, 'flags'])
1103 if not flags:
1104 return
1105 if 'LOOPBACK' in flags:
1106 return True
1107 return False
1108
1109 def link_get_status(self, ifacename):
1110 return self._cache_get('link', [ifacename, 'ifflag'], refresh=True)
1111
1112 @staticmethod
1113 def route_add_gateway(ifacename, gateway, vrf=None, metric=None):
1114 if not gateway:
1115 return
1116 if not vrf:
1117 cmd = '%s route add default via %s proto kernel' % (utils.ip_cmd,
1118 gateway)
1119 else:
1120 cmd = ('%s route add table %s default via %s proto kernel' %
1121 (utils.ip_cmd, vrf, gateway))
1122 # Add metric
1123 if metric:
1124 cmd += 'metric %s' % metric
1125 cmd += ' dev %s' % ifacename
1126 utils.exec_command(cmd)
1127
1128 @staticmethod
1129 def route_del_gateway(ifacename, gateway, vrf=None, metric=None):
1130 # delete default gw
1131 if not gateway:
1132 return
1133 if not vrf:
1134 cmd = ('%s route del default via %s proto kernel' %
1135 (utils.ip_cmd, gateway))
1136 else:
1137 cmd = ('%s route del table %s default via %s proto kernel' %
1138 (utils.ip_cmd, vrf, gateway))
1139 if metric:
1140 cmd += ' metric %s' % metric
1141 cmd += ' dev %s' % ifacename
1142 utils.exec_command(cmd)
1143
1144 @staticmethod
1145 def _get_vrf_id(ifacename):
1146 try:
1147 return linkCache.vrfs[ifacename]['table']
1148 except KeyError:
1149 dump = netlink.link_dump(ifacename)
1150
1151 [linkCache.update_attrdict([ifname], linkattrs)
1152 for ifname, linkattrs in dump.items()]
1153
1154 if dump and dump.get(ifacename, {}).get('kind') == 'vrf':
1155 vrf_table = dump.get(ifacename, {}).get('linkinfo', {}).get('table')
1156 linkCache.vrfs[ifacename] = {'table': vrf_table}
1157 return vrf_table
1158
1159 return None
1160
1161 def fix_ipv6_route_metric(self, ifaceobj, macvlan_ifacename, ips):
1162 vrf_table = None
1163
1164 if ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE:
1165 try:
1166 for upper_iface in ifaceobj.upperifaces:
1167 vrf_table = self._get_vrf_id(upper_iface)
1168 if vrf_table:
1169 break
1170 except:
1171 pass
1172
1173 ip_route_del = []
1174 for ip in ips:
1175 ip_network_obj = IPNetwork(ip)
1176
1177 if type(ip_network_obj) == IPv6Network:
1178 route_prefix = '%s/%d' % (ip_network_obj.network, ip_network_obj.prefixlen)
1179
1180 if vrf_table:
1181 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
1182 LinkUtils.add_to_batch('route del %s table %s dev %s' % (route_prefix, vrf_table, macvlan_ifacename))
1183 else:
1184 utils.exec_commandl([utils.ip_cmd, 'route', 'del', route_prefix, 'table', vrf_table, 'dev', macvlan_ifacename])
1185 else:
1186 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
1187 LinkUtils.add_to_batch('route del %s dev %s' % (route_prefix, macvlan_ifacename))
1188 else:
1189 utils.exec_commandl([utils.ip_cmd, 'route', 'del', route_prefix, 'dev', macvlan_ifacename])
1190 ip_route_del.append((route_prefix, vrf_table))
1191
1192 for ip, vrf_table in ip_route_del:
1193 if vrf_table:
1194 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
1195 LinkUtils.add_to_batch('route add %s table %s dev %s proto kernel metric 9999' % (ip, vrf_table, macvlan_ifacename))
1196 else:
1197 utils.exec_commandl([utils.ip_cmd, 'route', 'add', ip, 'table', vrf_table, 'dev', macvlan_ifacename, 'proto', 'kernel' 'metric', '9999'])
1198 else:
1199 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
1200 LinkUtils.add_to_batch('route add %s dev %s proto kernel metric 9999' % (ip, macvlan_ifacename))
1201 else:
1202 utils.exec_commandl([utils.ip_cmd, 'route', 'add', ip, 'dev', macvlan_ifacename, 'proto', 'kernel' 'metric', '9999'])
1203
1204 def link_create_vlan(self, vlan_device_name, vlan_raw_device, vlanid):
1205 if self.link_exists(vlan_device_name):
1206 return
1207 utils.exec_command('%s link add link %s name %s type vlan id %d' %
1208 (utils.ip_cmd,
1209 vlan_raw_device, vlan_device_name, vlanid))
1210 self._cache_update([vlan_device_name], {})
1211
1212 def link_create_vlan_from_name(self, vlan_device_name):
1213 v = vlan_device_name.split('.')
1214 if len(v) != 2:
1215 self.logger.warn('invalid vlan device name %s' % vlan_device_name)
1216 return
1217 self.link_create_vlan(vlan_device_name, v[0], v[1])
1218
1219 def link_create_macvlan(self, name, linkdev, mode='private'):
1220 if self.link_exists(name):
1221 return
1222 cmd = ('link add link %s' % linkdev +
1223 ' name %s' % name +
1224 ' type macvlan mode %s' % mode)
1225 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
1226 self.add_to_batch(cmd)
1227 else:
1228 utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
1229 self._cache_update([name], {})
1230
1231 def get_vxlan_peers(self, dev, svcnodeip):
1232 cmd = '%s fdb show brport %s' % (utils.bridge_cmd,
1233 dev)
1234 cur_peers = []
1235 try:
1236 ps = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, close_fds=False)
1237 utils.enable_subprocess_signal_forwarding(ps, signal.SIGINT)
1238 output = subprocess.check_output(('grep', '00:00:00:00:00:00'), stdin=ps.stdout)
1239 ps.wait()
1240 utils.disable_subprocess_signal_forwarding(signal.SIGINT)
1241 try:
1242 ppat = re.compile('\s+dst\s+(\d+.\d+.\d+.\d+)\s+')
1243 for l in output.split('\n'):
1244 m = ppat.search(l)
1245 if m and m.group(1) != svcnodeip:
1246 cur_peers.append(m.group(1))
1247 except:
1248 self.logger.warn('error parsing ip link output')
1249 except subprocess.CalledProcessError as e:
1250 if e.returncode != 1:
1251 self.logger.error(str(e))
1252 finally:
1253 utils.disable_subprocess_signal_forwarding(signal.SIGINT)
1254
1255 return cur_peers
1256
1257 def tunnel_create(self, tunnelname, mode, attrs={}):
1258 """ generic link_create function """
1259 if self.link_exists(tunnelname):
1260 return
1261 cmd = 'tunnel add'
1262 cmd += ' %s mode %s' %(tunnelname, mode)
1263 if attrs:
1264 for k, v in attrs.iteritems():
1265 cmd += ' %s' %k
1266 if v:
1267 cmd += ' %s' %v
1268 if self.ipbatch and not self.ipbatch_pause:
1269 self.add_to_batch(cmd)
1270 else:
1271 utils.exec_command('ip %s' % cmd)
1272 self._cache_update([tunnelname], {})
1273
1274 def tunnel_change(self, tunnelname, attrs={}):
1275 """ tunnel change function """
1276 if not self.link_exists(tunnelname):
1277 return
1278 cmd = 'tunnel change'
1279 cmd += ' %s' %(tunnelname)
1280 if attrs:
1281 for k, v in attrs.iteritems():
1282 cmd += ' %s' %k
1283 if v:
1284 cmd += ' %s' %v
1285 if self.ipbatch and not self.ipbatch_pause:
1286 self.add_to_batch(cmd)
1287 else:
1288 utils.exec_command('ip %s' % cmd)
1289 self._cache_update([tunnelname], {})
1290
1291 def link_create_vxlan(self, name, vxlanid,
1292 localtunnelip=None,
1293 svcnodeip=None,
1294 remoteips=None,
1295 learning='on',
1296 ageing=None,
1297 anycastip=None):
1298 if svcnodeip and remoteips:
1299 raise Exception("svcnodeip and remoteip is mutually exclusive")
1300 args = ''
1301 if svcnodeip:
1302 args += ' remote %s' % svcnodeip
1303 if ageing:
1304 args += ' ageing %s' % ageing
1305 if learning == 'off':
1306 args += ' nolearning'
1307
1308 if self.link_exists(name):
1309 cmd = 'link set dev %s type vxlan dstport %d' % (name, LinkUtils.VXLAN_UDP_PORT)
1310 vxlanattrs = self.get_vxlandev_attrs(name)
1311 # on ifreload do not overwrite anycast_ip to individual ip if clagd
1312 # has modified
1313 if vxlanattrs:
1314 running_localtunnelip = vxlanattrs.get('local')
1315 if anycastip and running_localtunnelip and anycastip == running_localtunnelip:
1316 localtunnelip = running_localtunnelip
1317 running_svcnode = vxlanattrs.get('svcnode')
1318 if running_svcnode and not svcnodeip:
1319 args += ' noremote'
1320 else:
1321 cmd = 'link add dev %s type vxlan id %s dstport %d' % (name, vxlanid, LinkUtils.VXLAN_UDP_PORT)
1322
1323 if localtunnelip:
1324 args += ' local %s' % localtunnelip
1325 cmd += args
1326
1327 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
1328 self.add_to_batch(cmd)
1329 else:
1330 utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
1331
1332 # XXX: update linkinfo correctly
1333 #self._cache_update([name], {})
1334
1335 @staticmethod
1336 def link_exists(ifacename):
1337 if ifupdownflags.flags.DRYRUN:
1338 return True
1339 return os.path.exists('/sys/class/net/%s' % ifacename)
1340
1341 def link_get_ifindex(self, ifacename):
1342 if ifupdownflags.flags.DRYRUN:
1343 return True
1344 return self.read_file_oneline('/sys/class/net/%s/ifindex' % ifacename)
1345
1346 def is_vlan_device_by_name(self, ifacename):
1347 if re.search(r'\.', ifacename):
1348 return True
1349 return False
1350
1351 @staticmethod
1352 def link_add_macvlan(ifname, macvlan_ifacename):
1353 utils.exec_commandl(['ip', 'link', 'add', 'link', ifname, 'name', macvlan_ifacename, 'type', 'macvlan', 'mode', 'private'])
1354
1355 @staticmethod
1356 def route_add(route):
1357 utils.exec_command('%s route add %s' % (utils.ip_cmd,
1358 route))
1359
1360 @staticmethod
1361 def route6_add(route):
1362 utils.exec_command('%s -6 route add %s' % (utils.ip_cmd,
1363 route))
1364
1365 def get_vlandev_attrs(self, ifacename):
1366 return (self._cache_get('link', [ifacename, 'link']),
1367 self._cache_get('link', [ifacename, 'linkinfo', 'vlanid']),
1368 self._cache_get('link', [ifacename, 'linkinfo', 'vlan_protocol']))
1369
1370 def get_vlan_protocol(self, ifacename):
1371 return self._cache_get('link', [ifacename, 'linkinfo', 'vlan_protocol'])
1372
1373 def get_vxlandev_attrs(self, ifacename):
1374 return self._cache_get('link', [ifacename, 'linkinfo'])
1375
1376 def get_vxlandev_learning(self, ifacename):
1377 return self._cache_get('link', [ifacename, 'linkinfo', Link.IFLA_VXLAN_LEARNING])
1378
1379 def set_vxlandev_learning(self, ifacename, learn):
1380 if learn == 'on':
1381 utils.exec_command('%s link set dev %s type vxlan learning' %
1382 (utils.ip_cmd, ifacename))
1383 self._cache_update([ifacename, 'linkinfo', 'learning'], 'on')
1384 else:
1385 utils.exec_command('%s link set dev %s type vxlan nolearning' %
1386 (utils.ip_cmd, ifacename))
1387 self._cache_update([ifacename, 'linkinfo', 'learning'], 'off')
1388
1389 def link_get_linkinfo_attrs(self, ifacename):
1390 return self._cache_get('link', [ifacename, 'linkinfo'])
1391
1392 def link_get_mtu(self, ifacename, refresh=False):
1393 return self._cache_get('link', [ifacename, 'mtu'], refresh=refresh)
1394
1395 def link_get_mtu_sysfs(self, ifacename):
1396 return self.read_file_oneline('/sys/class/net/%s/mtu'
1397 % ifacename)
1398
1399 def link_get_kind(self, ifacename):
1400 return self._cache_get('link', [ifacename, 'kind'])
1401
1402 def link_get_slave_kind(self, ifacename):
1403 return self._cache_get('link', [ifacename, 'slave_kind'])
1404
1405 def link_get_hwaddress(self, ifacename):
1406 address = self._cache_get('link', [ifacename, 'hwaddress'])
1407 # newly created logical interface addresses dont end up in the cache
1408 # read hwaddress from sysfs file for these interfaces
1409 if not address:
1410 address = self.read_file_oneline('/sys/class/net/%s/address'
1411 % ifacename)
1412 return address
1413
1414 def link_create(self, ifacename, t, attrs={}):
1415 """ generic link_create function """
1416 if self.link_exists(ifacename):
1417 return
1418 cmd = 'link add'
1419 cmd += ' name %s type %s' % (ifacename, t)
1420 if attrs:
1421 for k, v in attrs.iteritems():
1422 cmd += ' %s' % k
1423 if v:
1424 cmd += ' %s' % v
1425 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
1426 self.add_to_batch(cmd)
1427 else:
1428 utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
1429 self._cache_update([ifacename], {})
1430
1431 def link_delete(self, ifacename):
1432 if not self.link_exists(ifacename):
1433 return
1434 cmd = 'link del %s' % ifacename
1435 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
1436 self.add_to_batch(cmd)
1437 else:
1438 utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
1439 self._cache_invalidate()
1440
1441 def link_get_master(self, ifacename):
1442 sysfs_master_path = '/sys/class/net/%s/master' % ifacename
1443 if os.path.exists(sysfs_master_path):
1444 link_path = os.readlink(sysfs_master_path)
1445 if link_path:
1446 return os.path.basename(link_path)
1447 else:
1448 return None
1449 else:
1450 return self._cache_get('link', [ifacename, 'master'])
1451
1452 def get_brport_peer_link(self, bridgename):
1453 try:
1454 return self._cache_get('link', [bridgename, 'info_slave_data', Link.IFLA_BRPORT_PEER_LINK])
1455 except:
1456 return None
1457
1458 @staticmethod
1459 def bridge_port_vids_add(bridgeportname, vids):
1460 [utils.exec_command('%s vlan add vid %s dev %s' %
1461 (utils.bridge_cmd,
1462 v, bridgeportname)) for v in vids]
1463
1464 @staticmethod
1465 def bridge_port_vids_del(bridgeportname, vids):
1466 if not vids:
1467 return
1468 [utils.exec_command('%s vlan del vid %s dev %s' %
1469 (utils.bridge_cmd,
1470 v, bridgeportname)) for v in vids]
1471
1472 @staticmethod
1473 def bridge_port_vids_flush(bridgeportname, vid):
1474 utils.exec_command('%s vlan del vid %s dev %s' %
1475 (utils.bridge_cmd,
1476 vid, bridgeportname))
1477
1478 @staticmethod
1479 def bridge_port_vids_get(bridgeportname):
1480 bridgeout = utils.exec_command('%s vlan show dev %s' %
1481 (utils.bridge_cmd,
1482 bridgeportname))
1483 if not bridgeout:
1484 return []
1485 brvlanlines = bridgeout.readlines()[2:]
1486 vids = [l.strip() for l in brvlanlines]
1487 return [v for v in vids if v]
1488
1489 @staticmethod
1490 def bridge_port_vids_get_all():
1491 brvlaninfo = {}
1492 bridgeout = utils.exec_command('%s -c vlan show'
1493 % utils.bridge_cmd)
1494 if not bridgeout:
1495 return brvlaninfo
1496 brvlanlines = bridgeout.splitlines()
1497 brportname = None
1498 for l in brvlanlines[1:]:
1499 if l and not l.startswith(' ') and not l.startswith('\t'):
1500 attrs = l.split()
1501 brportname = attrs[0].strip()
1502 brvlaninfo[brportname] = {'pvid': None, 'vlan': []}
1503 l = ' '.join(attrs[1:])
1504 if not brportname or not l:
1505 continue
1506 l = l.strip()
1507 if 'PVID' in l:
1508 brvlaninfo[brportname]['pvid'] = l.split()[0]
1509 elif 'Egress Untagged' not in l:
1510 brvlaninfo[brportname]['vlan'].append(l)
1511 return brvlaninfo
1512
1513 def bridge_port_vids_get_all_json(self):
1514 if not self.supported_command['%s -c -json vlan show'
1515 % utils.bridge_cmd]:
1516 return {}
1517 brvlaninfo = {}
1518 try:
1519 bridgeout = utils.exec_command('%s -c -json vlan show'
1520 % utils.bridge_cmd)
1521 except:
1522 self.supported_command['%s -c -json vlan show'
1523 % utils.bridge_cmd] = False
1524 self.logger.info('%s -c -json vlan show: skipping unsupported command'
1525 % utils.bridge_cmd)
1526 try:
1527 return self.get_bridge_vlan_nojson()
1528 except Exception as e:
1529 self.logger.info('bridge: get_bridge_vlan_nojson: %s' % str(e))
1530 return {}
1531
1532 if not bridgeout: return brvlaninfo
1533 try:
1534 vlan_json_dict = json.loads(bridgeout, encoding="utf-8")
1535 except Exception, e:
1536 self.logger.info('json loads failed with (%s)' % str(e))
1537 return {}
1538 return vlan_json_dict
1539
1540 @staticmethod
1541 def get_bridge_vlan_nojson():
1542 vlan_json = {}
1543 bridgeout = utils.exec_commandl([utils.bridge_cmd, '-c', 'vlan', 'show'])
1544 if bridgeout:
1545 output = [line.split('\n') for line in bridgeout.split('\n\n')]
1546 output[0] = output[0][1:]
1547 for line in output:
1548 current_swp = None
1549 if not line:
1550 continue
1551 for entry in line:
1552 if not entry:
1553 continue
1554 prefix, vlan = entry.split('\t')
1555 if prefix:
1556 current_swp = prefix
1557 vlan_json[prefix] = []
1558 v = {}
1559 vlan = vlan[1:]
1560 try:
1561 v['vlan'] = int(vlan)
1562 except:
1563 try:
1564 if '-' in vlan:
1565 start, end = vlan.split('-')
1566 if ' ' in end:
1567 end = end[0:end.index(' ')]
1568 v['vlan'] = int(start)
1569 v['vlanEnd'] = int(end)
1570 else:
1571 v['vlan'] = int(vlan[0:vlan.index(' ')])
1572 flags = []
1573 if 'PVID' in vlan:
1574 flags.append('PVID')
1575 if 'Egress Untagged' in vlan:
1576 flags.append('Egress Untagged')
1577 v['flags'] = flags
1578 except:
1579 continue
1580 vlan_json[current_swp].append(v)
1581 return vlan_json
1582
1583 def bridge_vlan_cache_get(self, ifacename, refresh=False):
1584 if not self.bridge_vlan_cache_fill_done or refresh:
1585 self.bridge_vlan_cache = self.bridge_port_vids_get_all_json()
1586 self.bridge_vlan_cache_fill_done = True
1587 return self.bridge_vlan_cache.get(ifacename, {})
1588
1589 def bridge_vlan_get_pvid(self, ifacename, refresh=False):
1590 pvid = 0
1591
1592 for vinfo in self.bridge_vlan_cache_get(ifacename, refresh):
1593 v = vinfo.get('vlan')
1594 pvid = v if 'PVID' in vinfo.get('flags', []) else 0
1595 if pvid:
1596 return pvid
1597 return pvid
1598
1599 def bridge_vlan_get_vids(self, ifacename, refresh=False):
1600 vids = []
1601
1602 for vinfo in self.bridge_vlan_cache_get(ifacename, refresh):
1603 v = vinfo.get('vlan')
1604 ispvid = True if 'PVID' in vinfo.get('flags', []) else False
1605 if ispvid:
1606 pvid = v if 'PVID' in vinfo.get('flags', []) else 0
1607 if pvid == 1:
1608 continue
1609 vEnd = vinfo.get('vlanEnd')
1610 if vEnd:
1611 vids.extend(range(v, vEnd + 1))
1612 else:
1613 vids.append(v)
1614 return vids
1615
1616 def bridge_vlan_get_vids_n_pvid(self, ifacename, refresh=False):
1617 vids = []
1618 pvid = 0
1619
1620 for vinfo in self.bridge_vlan_cache_get(ifacename, refresh):
1621 v = vinfo.get('vlan')
1622 ispvid = True if 'PVID' in vinfo.get('flags', []) else False
1623 if ispvid:
1624 pvid = v if 'PVID' in vinfo.get('flags', []) else 0
1625 vEnd = vinfo.get('vlanEnd')
1626 if vEnd:
1627 vids.extend(range(v, vEnd + 1))
1628 else:
1629 vids.append(v)
1630 return vids, pvid
1631
1632 def bridge_port_pvid_add(self, bridgeportname, pvid):
1633 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
1634 self.add_to_batch('vlan add vid %s untagged pvid dev %s' %
1635 (pvid, bridgeportname))
1636 else:
1637 utils.exec_command('%s vlan add vid %s untagged pvid dev %s' %
1638 (utils.bridge_cmd,
1639 pvid, bridgeportname))
1640
1641 def bridge_port_pvid_del(self, bridgeportname, pvid):
1642 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
1643 self.add_to_batch('vlan del vid %s untagged pvid dev %s' %
1644 (pvid, bridgeportname))
1645 else:
1646 utils.exec_command('%s vlan del vid %s untagged pvid dev %s' %
1647 (utils.bridge_cmd,
1648 pvid, bridgeportname))
1649
1650 def bridge_port_pvids_get(self, bridgeportname):
1651 return self.read_file_oneline('/sys/class/net/%s/brport/pvid'
1652 % bridgeportname)
1653
1654 def bridge_vids_add(self, bridgeportname, vids, bridge=True):
1655 target = 'self' if bridge else ''
1656 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
1657 [self.add_to_batch('vlan add vid %s dev %s %s' %
1658 (v, bridgeportname, target)) for v in vids]
1659 else:
1660 [utils.exec_command('%s vlan add vid %s dev %s %s' %
1661 (utils.bridge_cmd,
1662 v, bridgeportname, target)) for v in vids]
1663
1664 def bridge_vids_del(self, bridgeportname, vids, bridge=True):
1665 target = 'self' if bridge else ''
1666 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
1667 [self.add_to_batch('vlan del vid %s dev %s %s' %
1668 (v, bridgeportname, target)) for v in vids]
1669 else:
1670 [utils.exec_command('%s vlan del vid %s dev %s %s' %
1671 (utils.bridge_cmd,
1672 v, bridgeportname, target)) for v in vids]
1673
1674 @staticmethod
1675 def bridge_fdb_add(dev, address, vlan=None, bridge=True, remote=None):
1676 target = 'self' if bridge else ''
1677 vlan_str = ''
1678 if vlan:
1679 vlan_str = 'vlan %s ' % vlan
1680
1681 dst_str = ''
1682 if remote:
1683 dst_str = 'dst %s ' % remote
1684
1685 utils.exec_command('%s fdb replace %s dev %s %s %s %s' %
1686 (utils.bridge_cmd,
1687 address, dev, vlan_str, target, dst_str))
1688
1689 @staticmethod
1690 def bridge_fdb_append(dev, address, vlan=None, bridge=True, remote=None):
1691 target = 'self' if bridge else ''
1692 vlan_str = ''
1693 if vlan:
1694 vlan_str = 'vlan %s ' % vlan
1695
1696 dst_str = ''
1697 if remote:
1698 dst_str = 'dst %s ' % remote
1699
1700 utils.exec_command('%s fdb append %s dev %s %s %s %s' %
1701 (utils.bridge_cmd,
1702 address, dev, vlan_str, target, dst_str))
1703
1704 @staticmethod
1705 def bridge_fdb_del(dev, address, vlan=None, bridge=True, remote=None):
1706 target = 'self' if bridge else ''
1707 vlan_str = ''
1708 if vlan:
1709 vlan_str = 'vlan %s ' % vlan
1710
1711 dst_str = ''
1712 if remote:
1713 dst_str = 'dst %s ' % remote
1714 utils.exec_command('%s fdb del %s dev %s %s %s %s' %
1715 (utils.bridge_cmd,
1716 address, dev, vlan_str, target, dst_str))
1717
1718 def bridge_is_vlan_aware(self, bridgename):
1719 filename = '/sys/class/net/%s/bridge/vlan_filtering' % bridgename
1720 if os.path.exists(filename) and self.read_file_oneline(filename) == '1':
1721 return True
1722 return False
1723
1724 @staticmethod
1725 def bridge_port_get_bridge_name(bridgeport):
1726 filename = '/sys/class/net/%s/brport/bridge' % bridgeport
1727 try:
1728 return os.path.basename(os.readlink(filename))
1729 except:
1730 return None
1731
1732 @staticmethod
1733 def bridge_port_exists(bridge, bridgeportname):
1734 try:
1735 return os.path.exists('/sys/class/net/%s/brif/%s'
1736 % (bridge, bridgeportname))
1737 except Exception:
1738 return False
1739
1740 def bridge_fdb_show_dev(self, dev):
1741 try:
1742 fdbs = {}
1743 output = utils.exec_command('%s fdb show dev %s'
1744 % (utils.bridge_cmd, dev))
1745 if output:
1746 for fdb_entry in output.splitlines():
1747 try:
1748 entries = fdb_entry.split()
1749 fdbs.setdefault(entries[2], []).append(entries[0])
1750 except:
1751 self.logger.debug('%s: invalid fdb line \'%s\''
1752 % (dev, fdb_entry))
1753 return fdbs
1754 except Exception:
1755 return None
1756
1757 @staticmethod
1758 def is_bridge(bridge):
1759 return os.path.exists('/sys/class/net/%s/bridge' % bridge)
1760
1761 def is_link_up(self, ifacename):
1762 ret = False
1763 try:
1764 flags = self.read_file_oneline('/sys/class/net/%s/flags' % ifacename)
1765 iflags = int(flags, 16)
1766 if iflags & 0x0001:
1767 ret = True
1768 except:
1769 ret = False
1770 return ret
1771
1772 def ip_route_get_dev(self, prefix, vrf_master=None):
1773 try:
1774 if vrf_master:
1775 cmd = '%s route get %s vrf %s' % (utils.ip_cmd, prefix, vrf_master)
1776 else:
1777 cmd = '%s route get %s' % (utils.ip_cmd, prefix)
1778
1779 output = utils.exec_command(cmd)
1780 if output:
1781 rline = output.splitlines()[0]
1782 if rline:
1783 rattrs = rline.split()
1784 return rattrs[rattrs.index('dev') + 1]
1785 except Exception, e:
1786 self.logger.debug('ip_route_get_dev: failed .. %s' % str(e))
1787 return None
1788
1789 @staticmethod
1790 def link_get_lowers(ifacename):
1791 try:
1792 lowers = glob.glob("/sys/class/net/%s/lower_*" % ifacename)
1793 if not lowers:
1794 return []
1795 return [os.path.basename(l)[6:] for l in lowers]
1796 except:
1797 return []
1798
1799 @staticmethod
1800 def link_get_uppers(ifacename):
1801 try:
1802 uppers = glob.glob("/sys/class/net/%s/upper_*" % ifacename)
1803 if not uppers:
1804 return None
1805 return [os.path.basename(u)[6:] for u in uppers]
1806 except Exception:
1807 return None
1808
1809 def link_get_vrfs(self):
1810 if not LinkUtils._CACHE_FILL_DONE:
1811 self._fill_cache()
1812 return linkCache.vrfs
1813
1814 @staticmethod
1815 def cache_get_info_slave(attrlist):
1816 try:
1817 return linkCache.get_attr(attrlist)
1818 except:
1819 return None
1820
1821 def get_brport_learning(self, ifacename):
1822 learn = self.read_file_oneline('/sys/class/net/%s/brport/learning'
1823 % ifacename)
1824 if learn and learn == '1':
1825 return 'on'
1826 else:
1827 return 'off'
1828
1829 def get_brport_learning_bool(self, ifacename):
1830 return utils.get_boolean_from_string(self.read_file_oneline('/sys/class/net/%s/brport/learning' % ifacename))
1831
1832 def set_brport_learning(self, ifacename, learn):
1833 if learn == 'off':
1834 return self.write_file('/sys/class/net/%s/brport/learning'
1835 % ifacename, '0')
1836 else:
1837 return self.write_file('/sys/class/net/%s/brport/learning'
1838 % ifacename, '1')
1839
1840 #################################################################################
1841 ################################### BOND UTILS ##################################
1842 #################################################################################
1843
1844 def _link_cache_get(self, attrlist, refresh=False):
1845 return self._cache_get('link', attrlist, refresh)
1846
1847 def cache_delete(self, attrlist, value=None):
1848 return self._cache_delete(attrlist, value)
1849
1850 def link_cache_get(self, attrlist, refresh=False):
1851 return self._link_cache_get(attrlist, refresh)
1852
1853 def link_cache_check(self, attrlist, value, refresh=False):
1854 return self._link_cache_check(attrlist, value, refresh)
1855
1856 def _link_cache_check(self, attrlist, value, refresh=False):
1857 try:
1858 return self._link_cache_get(attrlist, refresh) == value
1859 except Exception, e:
1860 self.logger.debug('_cache_check(%s) : [%s]'
1861 % (str(attrlist), str(e)))
1862 pass
1863 return False
1864
1865 bondcmd_attrmap = {
1866 Link.IFLA_BOND_MODE: 'mode',
1867 Link.IFLA_BOND_MIIMON: 'miimon',
1868 Link.IFLA_BOND_USE_CARRIER: 'use_carrier',
1869 Link.IFLA_BOND_AD_LACP_RATE: 'lacp_rate',
1870 Link.IFLA_BOND_XMIT_HASH_POLICY: 'xmit_hash_policy',
1871 Link.IFLA_BOND_MIN_LINKS: 'min_links',
1872 Link.IFLA_BOND_NUM_PEER_NOTIF: 'num_grat_arp',
1873 Link.IFLA_BOND_AD_ACTOR_SYSTEM: 'ad_actor_system',
1874 Link.IFLA_BOND_AD_ACTOR_SYS_PRIO: 'ad_actor_sys_prio',
1875 Link.IFLA_BOND_AD_LACP_BYPASS: 'lacp_bypass',
1876 Link.IFLA_BOND_UPDELAY: 'updelay',
1877 Link.IFLA_BOND_DOWNDELAY: 'downdelay',
1878 }
1879
1880 def bond_set_attrs_nl(self, bondname, ifla_info_data):
1881 bond_attr_name = 'None' # for log purpose (in case an exception raised)
1882 for nl_attr, value in ifla_info_data.items():
1883 try:
1884 bond_attr_name = self.bondcmd_attrmap[nl_attr]
1885 file_path = '/sys/class/net/%s/bonding/%s' % (bondname, bond_attr_name)
1886 if os.path.exists(file_path):
1887 self.write_file(file_path, str(value))
1888 except Exception as e:
1889 exception_str = '%s: %s %s: %s' % (bondname, bond_attr_name, value, str(e))
1890 if ifupdownflags.flags.FORCE:
1891 self.logger.warning(exception_str)
1892 else:
1893 self.logger.debug(exception_str)
1894
1895 def bond_set_attrs(self, bondname, attrdict, prehook):
1896 for attrname, attrval in attrdict.items():
1897 if (self._link_cache_check([bondname, 'linkinfo',
1898 attrname], attrval)):
1899 continue
1900 if (attrname == 'mode'
1901 or attrname == 'xmit_hash_policy'
1902 or attrname == 'lacp_rate' or attrname == 'min_links'):
1903 if prehook:
1904 prehook(bondname)
1905 try:
1906 if ((attrname not in ['lacp_rate',
1907 'lacp_bypass']) or
1908 self._link_cache_check([bondname, 'linkinfo', 'mode'], '802.3ad',
1909 True)):
1910 self.write_file('/sys/class/net/%s/bonding/%s'
1911 % (bondname, attrname), attrval)
1912 except Exception, e:
1913 if ifupdownflags.flags.FORCE:
1914 self.logger.warn(str(e))
1915 pass
1916 else:
1917 raise
1918
1919 def bond_set_use_carrier(self, bondname, use_carrier):
1920 if not use_carrier or (use_carrier != '0' and use_carrier != '1'):
1921 return
1922 if (self._link_cache_check([bondname, 'linkinfo', 'use_carrier'],
1923 use_carrier)):
1924 return
1925 self.write_file('/sys/class/net/%s' % bondname +
1926 '/bonding/use_carrier', use_carrier)
1927 self._cache_update([bondname, 'linkinfo',
1928 'use_carrier'], use_carrier)
1929
1930 def bond_get_use_carrier(self, bondname):
1931 return self._link_cache_get([bondname, 'linkinfo', 'use_carrier'])
1932
1933 def bond_get_use_carrier_nl(self, bondname):
1934 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_USE_CARRIER])
1935
1936 def bond_set_xmit_hash_policy(self, bondname, hash_policy, prehook=None):
1937 valid_values = ['layer2', 'layer3+4', 'layer2+3']
1938 if not hash_policy:
1939 return
1940 if hash_policy not in valid_values:
1941 raise Exception('invalid hash policy value %s' % hash_policy)
1942 if (self._link_cache_check([bondname, 'linkinfo', 'xmit_hash_policy'],
1943 hash_policy)):
1944 return
1945 if prehook:
1946 prehook(bondname)
1947 self.write_file('/sys/class/net/%s' % bondname +
1948 '/bonding/xmit_hash_policy', hash_policy)
1949 self._cache_update([bondname, 'linkinfo', 'xmit_hash_policy'],
1950 hash_policy)
1951
1952 def bond_get_xmit_hash_policy(self, bondname):
1953 return self._link_cache_get([bondname, 'linkinfo', 'xmit_hash_policy'])
1954
1955 def bond_get_xmit_hash_policy_nl(self, bondname):
1956 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_XMIT_HASH_POLICY])
1957
1958 def bond_set_miimon(self, bondname, miimon):
1959 if (self._link_cache_check([bondname, 'linkinfo', 'miimon'],
1960 miimon)):
1961 return
1962 self.write_file('/sys/class/net/%s' % bondname +
1963 '/bonding/miimon', miimon)
1964 self._cache_update([bondname, 'linkinfo', 'miimon'], miimon)
1965
1966 def bond_get_miimon(self, bondname):
1967 return self._link_cache_get([bondname, 'linkinfo', 'miimon'])
1968
1969 def bond_get_miimon_nl(self, bondname):
1970 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_MIIMON])
1971
1972 def bond_set_mode(self, bondname, mode, prehook=None):
1973 valid_modes = ['balance-rr', 'active-backup', 'balance-xor',
1974 'broadcast', '802.3ad', 'balance-tlb', 'balance-alb']
1975 if not mode:
1976 return
1977 if mode not in valid_modes:
1978 raise Exception('invalid mode %s' % mode)
1979 if (self._link_cache_check([bondname, 'linkinfo', 'mode'],
1980 mode)):
1981 return
1982 if prehook:
1983 prehook(bondname)
1984 self.write_file('/sys/class/net/%s' % bondname + '/bonding/mode', mode)
1985 self._cache_update([bondname, 'linkinfo', 'mode'], mode)
1986
1987 def bond_get_mode(self, bondname):
1988 return self._link_cache_get([bondname, 'linkinfo', 'mode'])
1989
1990 def bond_get_mode_nl(self, bondname):
1991 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_MODE])
1992
1993 def bond_set_lacp_rate(self, bondname, lacp_rate, prehook=None, posthook=None):
1994 if not lacp_rate or (lacp_rate != '0' and lacp_rate != '1'):
1995 return
1996 if (self._link_cache_check([bondname, 'linkinfo', 'lacp_rate'],
1997 lacp_rate)):
1998 return
1999 if prehook:
2000 prehook(bondname)
2001 try:
2002 self.write_file('/sys/class/net/%s' % bondname +
2003 '/bonding/lacp_rate', lacp_rate)
2004 except:
2005 raise
2006 finally:
2007 if posthook:
2008 prehook(bondname)
2009 self._cache_update([bondname, 'linkinfo',
2010 'lacp_rate'], lacp_rate)
2011
2012 def bond_get_lacp_rate(self, bondname):
2013 return self._link_cache_get([bondname, 'linkinfo', 'lacp_rate'])
2014
2015 def bond_get_lacp_rate_nl(self, bondname):
2016 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_AD_LACP_RATE])
2017
2018 def bond_set_lacp_bypass_allow(self, bondname, allow, prehook=None, posthook=None):
2019 if self._link_cache_check([bondname, 'linkinfo', 'lacp_bypass'], allow):
2020 return
2021 if prehook:
2022 prehook(bondname)
2023 try:
2024 self.write_file('/sys/class/net/%s' % bondname +
2025 '/bonding/lacp_bypass', allow)
2026 except:
2027 raise
2028 finally:
2029 if posthook:
2030 posthook(bondname)
2031 self._cache_update([bondname, 'linkinfo',
2032 'lacp_bypass'], allow)
2033
2034 def bond_get_lacp_bypass_allow(self, bondname):
2035 return self._link_cache_get([bondname, 'linkinfo', 'lacp_bypass'])
2036
2037 def bond_get_lacp_bypass_allow_nl(self, bondname):
2038 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_AD_LACP_BYPASS])
2039
2040 def bond_set_min_links(self, bondname, min_links, prehook=None):
2041 if (self._link_cache_check([bondname, 'linkinfo', 'min_links'],
2042 min_links)):
2043 return
2044 if prehook:
2045 prehook(bondname)
2046 self.write_file('/sys/class/net/%s/bonding/min_links' % bondname,
2047 min_links)
2048 self._cache_update([bondname, 'linkinfo', 'min_links'], min_links)
2049
2050 def bond_get_min_links(self, bondname):
2051 return self._link_cache_get([bondname, 'linkinfo', 'min_links'])
2052
2053 def get_min_links_nl(self, bondname):
2054 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_MIN_LINKS])
2055
2056 def bond_get_ad_actor_system(self, bondname):
2057 return self._link_cache_get([bondname, 'linkinfo', 'ad_actor_system'])
2058
2059 def bond_get_ad_actor_system_nl(self, bondname):
2060 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_AD_ACTOR_SYSTEM])
2061
2062 def bond_get_ad_actor_sys_prio(self, bondname):
2063 return self._link_cache_get([bondname, 'linkinfo', 'ad_actor_sys_prio'])
2064
2065 def bond_get_ad_actor_sys_prio_nl(self, bondname):
2066 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_AD_ACTOR_SYS_PRIO])
2067
2068 def bond_get_num_unsol_na(self, bondname):
2069 return self._link_cache_get([bondname, 'linkinfo', 'num_unsol_na'])
2070
2071 def bond_get_num_unsol_na_nl(self, bondname):
2072 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_NUM_PEER_NOTIF])
2073
2074 def bond_get_num_grat_arp(self, bondname):
2075 return self._link_cache_get([bondname, 'linkinfo', 'num_grat_arp'])
2076
2077 def bond_get_num_grat_arp_nl(self, bondname):
2078 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_NUM_PEER_NOTIF])
2079
2080 def bond_get_updelay(self, bondname):
2081 return self._link_cache_get([bondname, 'linkinfo', 'updelay'])
2082
2083 def bond_get_updelay_nl(self, bondname):
2084 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_UPDELAY])
2085
2086 def bond_get_downdelay(self, bondname):
2087 return self._link_cache_get([bondname, 'linkinfo', 'downdelay'])
2088
2089 def bond_get_downdelay_nl(self, bondname):
2090 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_DOWNDELAY])
2091
2092 def bond_enslave_slave(self, bondname, slave, prehook=None, posthook=None):
2093 slaves = self._link_cache_get([bondname, 'linkinfo', 'slaves'])
2094 if slaves and slave in slaves:
2095 return
2096 if prehook:
2097 prehook(slave)
2098 self.write_file('/sys/class/net/%s' % bondname +
2099 '/bonding/slaves', '+' + slave)
2100 if posthook:
2101 posthook(slave)
2102 self._cache_update([bondname, 'linkinfo', 'slaves'], slave)
2103
2104 def bond_remove_slave(self, bondname, slave):
2105 slaves = self._link_cache_get([bondname, 'linkinfo', 'slaves'])
2106 if not slaves or slave not in slaves:
2107 return
2108 sysfs_bond_path = ('/sys/class/net/%s' % bondname +
2109 '/bonding/slaves')
2110 if not os.path.exists(sysfs_bond_path):
2111 return
2112 self.write_file(sysfs_bond_path, '-' + slave)
2113 self._cache_delete([bondname, 'linkinfo', 'slaves'], slave)
2114
2115 def bond_remove_slaves_all(self, bondname):
2116 if not self._link_cache_get([bondname, 'linkinfo', 'slaves']):
2117 return
2118 slaves = None
2119 sysfs_bond_path = ('/sys/class/net/%s' % bondname +
2120 '/bonding/slaves')
2121 try:
2122 with open(sysfs_bond_path, 'r') as f:
2123 slaves = f.readline().strip().split()
2124 except IOError, e:
2125 raise Exception('error reading slaves of bond %s (%s)' % (bondname, str(e)))
2126 for slave in slaves:
2127 self.link_down(slave)
2128 try:
2129 self.bond_remove_slave(bondname, slave)
2130 except Exception, e:
2131 if not ifupdownflags.flags.FORCE:
2132 raise Exception('error removing slave %s from bond %s (%s)' % (slave, bondname, str(e)))
2133 else:
2134 pass
2135 self._cache_delete([bondname, 'linkinfo', 'slaves'])
2136
2137 @staticmethod
2138 def bond_load_bonding_module():
2139 return utils.exec_command('%s -q bonding' % utils.modprobe_cmd)
2140
2141 def create_bond(self, bondname):
2142 if self.bond_exists(bondname):
2143 return
2144 # load_bonding_module() has already been run
2145 self.write_file('/sys/class/net/bonding_masters', '+' + bondname)
2146 self._cache_update([bondname], {})
2147
2148 def delete_bond(self, bondname):
2149 if not os.path.exists('/sys/class/net/%s' % bondname):
2150 return
2151 self.write_file('/sys/class/net/bonding_masters', '-' + bondname)
2152 self._cache_delete([bondname])
2153
2154 def bond_get_slaves(self, bondname):
2155 slaves = self._link_cache_get([bondname, 'linkinfo', 'slaves'])
2156 if slaves:
2157 return list(slaves)
2158 slavefile = '/sys/class/net/%s/bonding/slaves' % bondname
2159 if os.path.exists(slavefile):
2160 buf = self.read_file_oneline(slavefile)
2161 if buf:
2162 slaves = buf.split()
2163 if not slaves:
2164 return []
2165 self._cache_update([bondname, 'linkinfo', 'slaves'], slaves)
2166 return list(slaves)
2167
2168 def bond_slave_exists(self, bond, slave):
2169 slaves = self.bond_get_slaves(bond)
2170 if not slaves:
2171 return False
2172 return slave in slaves
2173
2174 @staticmethod
2175 def bond_exists(bondname):
2176 return os.path.exists('/sys/class/net/%s/bonding' % bondname)
2177
2178 #################################################################################
2179 ################################## BRIDGE UTILS #################################
2180 #################################################################################
2181
2182 def create_bridge(self, bridgename):
2183 if not LinkUtils.bridge_utils_is_installed:
2184 return
2185 if self.bridge_exists(bridgename):
2186 return
2187 utils.exec_command('%s addbr %s' % (utils.brctl_cmd, bridgename))
2188 self._cache_update([bridgename], {})
2189
2190 def delete_bridge(self, bridgename):
2191 if not LinkUtils.bridge_utils_is_installed:
2192 return
2193 if not self.bridge_exists(bridgename):
2194 return
2195 utils.exec_command('%s delbr %s' % (utils.brctl_cmd, bridgename))
2196 self._cache_invalidate()
2197
2198 def add_bridge_port(self, bridgename, bridgeportname):
2199 """ Add port to bridge """
2200 if not LinkUtils.bridge_utils_is_installed:
2201 return
2202 ports = self._link_cache_get([bridgename, 'linkinfo', 'ports'])
2203 if ports and ports.get(bridgeportname):
2204 return
2205 utils.exec_command('%s addif %s %s' % (utils.brctl_cmd, bridgename, bridgeportname))
2206 self._cache_update([bridgename, 'linkinfo', 'ports', bridgeportname], {})
2207
2208 def delete_bridge_port(self, bridgename, bridgeportname):
2209 """ Delete port from bridge """
2210 if not LinkUtils.bridge_utils_is_installed:
2211 return
2212 ports = self._link_cache_get([bridgename, 'linkinfo', 'ports'])
2213 if not ports or not ports.get(bridgeportname):
2214 return
2215 utils.exec_command('%s delif %s %s' % (utils.brctl_cmd, bridgename, bridgeportname))
2216 self._cache_delete([bridgename, 'linkinfo', 'ports', 'bridgeportname'])
2217
2218 def set_bridgeport_attrs(self, bridgename, bridgeportname, attrdict):
2219 portattrs = self._link_cache_get([bridgename, 'linkinfo', 'ports', bridgeportname])
2220 if portattrs == None:
2221 portattrs = {}
2222 for k, v in attrdict.iteritems():
2223 if ifupdownflags.flags.CACHE:
2224 curval = portattrs.get(k)
2225 if curval and curval == v:
2226 continue
2227 if k == 'unicast-flood':
2228 self.write_file('/sys/class/net/%s/brport/unicast_flood' % bridgeportname, v)
2229 elif k == 'multicast-flood':
2230 self.write_file('/sys/class/net/%s/brport/multicast_flood' % bridgeportname, v)
2231 elif k == 'learning':
2232 self.write_file('/sys/class/net/%s/brport/learning' % bridgeportname, v)
2233 elif k == 'arp-nd-suppress':
2234 self.write_file('/sys/class/net/%s/brport/neigh_suppress' % bridgeportname, v)
2235 else:
2236 if not LinkUtils.bridge_utils_is_installed:
2237 continue
2238 utils.exec_command('%s set%s %s %s %s' % (utils.brctl_cmd, k, bridgename, bridgeportname, v))
2239
2240 def set_bridgeport_attr(self, bridgename, bridgeportname,
2241 attrname, attrval):
2242 if not LinkUtils.bridge_utils_is_installed:
2243 return
2244 if self._link_cache_check([bridgename, 'linkinfo', 'ports', bridgeportname, attrname], attrval):
2245 return
2246 utils.exec_command('%s set%s %s %s %s' %
2247 (utils.brctl_cmd,
2248 attrname,
2249 bridgename,
2250 bridgeportname,
2251 attrval))
2252
2253 def set_bridge_attrs(self, bridgename, attrdict):
2254 for k, v in attrdict.iteritems():
2255 if not v:
2256 continue
2257 if self._link_cache_check([bridgename, 'linkinfo', k], v):
2258 continue
2259 try:
2260 if k == 'igmp-version':
2261 self.write_file('/sys/class/net/%s/bridge/'
2262 'multicast_igmp_version' % bridgename, v)
2263 elif k == 'mld-version':
2264 self.write_file('/sys/class/net/%s/bridge/'
2265 'multicast_mld_version' % bridgename, v)
2266 elif k == 'vlan-protocol':
2267 self.write_file('/sys/class/net/%s/bridge/'
2268 'vlan_protocol' % bridgename,
2269 VlanProtocols.ETHERTYPES_TO_ID.get(v.upper(),
2270 None))
2271 elif k == 'vlan-stats':
2272 self.write_file('/sys/class/net/%s/bridge/'
2273 'vlan_stats_enabled' % bridgename, v)
2274 elif k == 'mcstats':
2275 self.write_file('/sys/class/net/%s/bridge/'
2276 'multicast_stats_enabled' % bridgename, v)
2277 else:
2278 if not LinkUtils.bridge_utils_is_installed:
2279 continue
2280 cmd = ('%s set%s %s %s' %
2281 (utils.brctl_cmd, k, bridgename, v))
2282 utils.exec_command(cmd)
2283 except Exception, e:
2284 self.logger.warn('%s: %s' % (bridgename, str(e)))
2285 pass
2286
2287 def set_bridge_attr(self, bridgename, attrname, attrval):
2288 if self._link_cache_check([bridgename, 'linkinfo', attrname], attrval):
2289 return
2290 if attrname == 'igmp-version':
2291 self.write_file('/sys/class/net/%s/bridge/multicast_igmp_version'
2292 % bridgename, attrval)
2293 elif attrname == 'mld-version':
2294 self.write_file('/sys/class/net/%s/bridge/multicast_mld_version'
2295 % bridgename, attrval)
2296 elif attrname == 'vlan-protocol':
2297 self.write_file('/sys/class/net/%s/bridge/vlan_protocol'
2298 % bridgename, VlanProtocols.ETHERTYPES_TO_ID[attrval.upper()])
2299 elif attrname == 'vlan-stats':
2300 self.write_file('/sys/class/net/%s/bridge/vlan_stats_enabled'
2301 % bridgename, attrval)
2302 elif attrname == 'mcstats':
2303 self.write_file('/sys/class/net/%s/bridge/multicast_stats_enabled'
2304 % bridgename, attrval)
2305 else:
2306 if not LinkUtils.bridge_utils_is_installed:
2307 return
2308 cmd = '%s set%s %s %s' % (utils.brctl_cmd,
2309 attrname, bridgename, attrval)
2310 utils.exec_command(cmd)
2311
2312 def get_bridge_attrs(self, bridgename):
2313 attrs = self._link_cache_get([bridgename, 'linkinfo'])
2314 no_ints_attrs = {}
2315 for key, value in attrs.items():
2316 if type(key) == str:
2317 no_ints_attrs[key] = value
2318 return no_ints_attrs
2319
2320 def get_bridgeport_attrs(self, bridgename, bridgeportname):
2321 return self._link_cache_get([bridgename, 'linkinfo', 'ports',
2322 bridgeportname])
2323
2324 def get_bridgeport_attr(self, bridgename, bridgeportname, attrname):
2325 return self._link_cache_get([bridgename, 'linkinfo', 'ports',
2326 bridgeportname, attrname])
2327
2328 @staticmethod
2329 def bridge_set_stp(bridge, stp_state):
2330 if not LinkUtils.bridge_utils_is_installed:
2331 return
2332 utils.exec_command('%s stp %s %s' % (utils.brctl_cmd, bridge, stp_state))
2333
2334 def bridge_get_stp(self, bridge):
2335 sysfs_stpstate = '/sys/class/net/%s/bridge/stp_state' % bridge
2336 if not os.path.exists(sysfs_stpstate):
2337 return 'error'
2338 stpstate = self.read_file_oneline(sysfs_stpstate)
2339 if not stpstate:
2340 return 'error'
2341 try:
2342 if int(stpstate) > 0:
2343 return 'yes'
2344 elif int(stpstate) == 0:
2345 return 'no'
2346 except:
2347 return 'unknown'
2348
2349 @staticmethod
2350 def _conv_value_to_user(s):
2351 try:
2352 ret = int(s) / 100
2353 return '%d' % ret
2354 except:
2355 return None
2356
2357 def read_value_from_sysfs(self, filename, preprocess_func):
2358 value = self.read_file_oneline(filename)
2359 if not value:
2360 return None
2361 return preprocess_func(value)
2362
2363 @staticmethod
2364 def bridge_set_ageing(bridge, ageing):
2365 if not LinkUtils.bridge_utils_is_installed:
2366 return
2367 utils.exec_command('%s setageing %s %s' % (utils.brctl_cmd, bridge, ageing))
2368
2369 def bridge_get_ageing(self, bridge):
2370 return self.read_value_from_sysfs('/sys/class/net/%s/bridge/ageing_time'
2371 % bridge, self._conv_value_to_user)
2372
2373 @staticmethod
2374 def set_bridgeprio(bridge, prio):
2375 if not LinkUtils.bridge_utils_is_installed:
2376 return
2377 utils.exec_command('%s setbridgeprio %s %s' % (utils.brctl_cmd, bridge, prio))
2378
2379 def get_bridgeprio(self, bridge):
2380 return self.read_file_oneline(
2381 '/sys/class/net/%s/bridge/priority' % bridge)
2382
2383 @staticmethod
2384 def bridge_set_fd(bridge, fd):
2385 if not LinkUtils.bridge_utils_is_installed:
2386 return
2387 utils.exec_command('%s setfd %s %s' % (utils.brctl_cmd, bridge, fd))
2388
2389 def bridge_get_fd(self, bridge):
2390 return self.read_value_from_sysfs(
2391 '/sys/class/net/%s/bridge/forward_delay'
2392 % bridge, self._conv_value_to_user)
2393
2394 def bridge_set_gcint(self, bridge, gcint):
2395 raise Exception('set_gcint not implemented')
2396
2397 @staticmethod
2398 def bridge_set_hello(bridge, hello):
2399 if not LinkUtils.bridge_utils_is_installed:
2400 return
2401 utils.exec_command('%s sethello %s %s' % (utils.brctl_cmd, bridge, hello))
2402
2403 def bridge_get_hello(self, bridge):
2404 return self.read_value_from_sysfs('/sys/class/net/%s/bridge/hello_time'
2405 % bridge, self._conv_value_to_user)
2406
2407 @staticmethod
2408 def bridge_set_maxage(bridge, maxage):
2409 if not LinkUtils.bridge_utils_is_installed:
2410 return
2411 utils.exec_command('%s setmaxage %s %s' % (utils.brctl_cmd, bridge, maxage))
2412
2413 def bridge_get_maxage(self, bridge):
2414 return self.read_value_from_sysfs('/sys/class/net/%s/bridge/max_age'
2415 % bridge, self._conv_value_to_user)
2416
2417 @staticmethod
2418 def bridge_set_pathcost(bridge, port, pathcost):
2419 if not LinkUtils.bridge_utils_is_installed:
2420 return
2421 utils.exec_command('%s setpathcost %s %s %s' % (utils.brctl_cmd, bridge, port, pathcost))
2422
2423 def bridge_get_pathcost(self, bridge, port):
2424 return self.read_file_oneline('/sys/class/net/%s/brport/path_cost'
2425 % port)
2426
2427 @staticmethod
2428 def bridge_set_portprio(bridge, port, prio):
2429 if not LinkUtils.bridge_utils_is_installed:
2430 return
2431 utils.exec_command('%s setportprio %s %s %s' % (utils.brctl_cmd, bridge, port, prio))
2432
2433 def bridge_get_portprio(self, bridge, port):
2434 return self.read_file_oneline('/sys/class/net/%s/brport/priority'
2435 % port)
2436
2437 @staticmethod
2438 def bridge_set_hashmax(bridge, hashmax):
2439 if not LinkUtils.bridge_utils_is_installed:
2440 return
2441 utils.exec_command('%s sethashmax %s %s' % (utils.brctl_cmd, bridge, hashmax))
2442
2443 def bridge_get_hashmax(self, bridge):
2444 return self.read_file_oneline('/sys/class/net/%s/bridge/hash_max'
2445 % bridge)
2446
2447 @staticmethod
2448 def bridge_set_hashel(bridge, hashel):
2449 if not LinkUtils.bridge_utils_is_installed:
2450 return
2451 utils.exec_command('%s sethashel %s %s' % (utils.brctl_cmd, bridge, hashel))
2452
2453 def bridge_get_hashel(self, bridge):
2454 return self.read_file_oneline('/sys/class/net/%s/bridge/hash_elasticity'
2455 % bridge)
2456
2457 @staticmethod
2458 def bridge_set_mclmc(bridge, mclmc):
2459 if not LinkUtils.bridge_utils_is_installed:
2460 return
2461 utils.exec_command('%s setmclmc %s %s' % (utils.brctl_cmd, bridge, mclmc))
2462
2463 def bridge_get_mclmc(self, bridge):
2464 return self.read_file_oneline(
2465 '/sys/class/net/%s/bridge/multicast_last_member_count'
2466 % bridge)
2467
2468 @staticmethod
2469 def bridge_set_mcrouter(bridge, mcrouter):
2470 if not LinkUtils.bridge_utils_is_installed:
2471 return
2472 utils.exec_command('%s setmcrouter %s %s' % (utils.brctl_cmd, bridge, mcrouter))
2473
2474 def bridge_get_mcrouter(self, bridge):
2475 return self.read_file_oneline(
2476 '/sys/class/net/%s/bridge/multicast_router' % bridge)
2477
2478 @staticmethod
2479 def bridge_set_mcsnoop(bridge, mcsnoop):
2480 if not LinkUtils.bridge_utils_is_installed:
2481 return
2482 utils.exec_command('%s setmcsnoop %s %s' % (utils.brctl_cmd, bridge, mcsnoop))
2483
2484 def bridge_get_mcsnoop(self, bridge):
2485 return self.read_file_oneline(
2486 '/sys/class/net/%s/bridge/multicast_snooping' % bridge)
2487
2488 @staticmethod
2489 def bridge_set_mcsqc(bridge, mcsqc):
2490 if not LinkUtils.bridge_utils_is_installed:
2491 return
2492 utils.exec_command('%s setmcsqc %s %s' % (utils.brctl_cmd, bridge, mcsqc))
2493
2494 def bridge_get_mcsqc(self, bridge):
2495 return self.read_file_oneline(
2496 '/sys/class/net/%s/bridge/multicast_startup_query_count'
2497 % bridge)
2498
2499 @staticmethod
2500 def bridge_set_mcqifaddr(bridge, mcqifaddr):
2501 if not LinkUtils.bridge_utils_is_installed:
2502 return
2503 utils.exec_command('%s setmcqifaddr %s %s' % (utils.brctl_cmd, bridge, mcqifaddr))
2504
2505 def bridge_get_mcqifaddr(self, bridge):
2506 return self.read_file_oneline(
2507 '/sys/class/net/%s/bridge/multicast_startup_query_use_ifaddr'
2508 % bridge)
2509
2510 @staticmethod
2511 def bridge_set_mcquerier(bridge, mcquerier):
2512 if not LinkUtils.bridge_utils_is_installed:
2513 return
2514 utils.exec_command('%s setmcquerier %s %s' % (utils.brctl_cmd, bridge, mcquerier))
2515
2516 def bridge_get_mcquerier(self, bridge):
2517 return self.read_file_oneline(
2518 '/sys/class/net/%s/bridge/multicast_querier' % bridge)
2519
2520 def bridge_set_mcqv4src(self, bridge, vlan, mcquerier):
2521 try:
2522 vlan = int(vlan)
2523 except:
2524 self.logger.info('%s: set mcqv4src vlan: invalid parameter %s: %s' %(bridge, vlan, str(e)))
2525 return
2526 if vlan == 0 or vlan > 4095:
2527 self.logger.warn('mcqv4src vlan \'%d\' invalid range' % vlan)
2528 return
2529
2530 ip = mcquerier.split('.')
2531 if len(ip) != 4:
2532 self.logger.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier)
2533 return
2534 for k in ip:
2535 if not k.isdigit() or int(k, 10) < 0 or int(k, 10) > 255:
2536 self.logger.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier)
2537 return
2538
2539 if not LinkUtils.bridge_utils_is_installed:
2540 return
2541
2542 utils.exec_command('%s setmcqv4src %s %d %s' %
2543 (utils.brctl_cmd, bridge, vlan, mcquerier))
2544
2545 def bridge_del_mcqv4src(self, bridge, vlan):
2546 if not LinkUtils.bridge_utils_is_installed:
2547 return
2548 try:
2549 vlan = int(vlan)
2550 except:
2551 self.logger.info('%s: del mcqv4src vlan: invalid parameter %s: %s' %(bridge, vlan, str(e)))
2552 return
2553 utils.exec_command('%s delmcqv4src %s %d' % (utils.brctl_cmd, bridge, vlan))
2554
2555 def bridge_get_mcqv4src(self, bridge, vlan=None):
2556 if not LinkUtils.bridge_utils_is_installed:
2557 return {}
2558 if not self.supported_command['showmcqv4src']:
2559 return {}
2560 mcqv4src = {}
2561 try:
2562 mcqout = utils.exec_command('%s showmcqv4src %s' %
2563 (utils.brctl_cmd, bridge))
2564 except Exception as e:
2565 s = str(e).lower()
2566 if 'never heard' in s:
2567 msg = ('%s showmcqv4src: skipping unsupported command'
2568 % utils.brctl_cmd)
2569 self.logger.info(msg)
2570 self.supported_command['showmcqv4src'] = False
2571 return {}
2572 raise
2573 if not mcqout:
2574 return {}
2575 mcqlines = mcqout.splitlines()
2576 for l in mcqlines[1:]:
2577 l = l.strip()
2578 k, d, v = l.split('\t')
2579 if not k or not v:
2580 continue
2581 mcqv4src[k] = v
2582 if vlan:
2583 return mcqv4src.get(vlan)
2584 return mcqv4src
2585
2586 @staticmethod
2587 def bridge_set_mclmi(bridge, mclmi):
2588 if not LinkUtils.bridge_utils_is_installed:
2589 return
2590 utils.exec_command('%s setmclmi %s %s' % (utils.brctl_cmd, bridge, mclmi))
2591
2592 def bridge_get_mclmi(self, bridge):
2593 return self.read_file_oneline(
2594 '/sys/class/net/%s/bridge/multicast_last_member_interval'
2595 % bridge)
2596
2597 @staticmethod
2598 def bridge_set_mcmi(bridge, mcmi):
2599 if not LinkUtils.bridge_utils_is_installed:
2600 return
2601 utils.exec_command('%s setmcmi %s %s' % (utils.brctl_cmd, bridge, mcmi))
2602
2603 def bridge_get_mcmi(self, bridge):
2604 return self.read_file_oneline(
2605 '/sys/class/net/%s/bridge/multicast_membership_interval'
2606 % bridge)
2607
2608 @staticmethod
2609 def bridge_exists(bridge):
2610 return os.path.exists('/sys/class/net/%s/bridge' % bridge)
2611
2612 @staticmethod
2613 def is_bridge_port(ifacename):
2614 return os.path.exists('/sys/class/net/%s/brport' % ifacename)
2615
2616 @staticmethod
2617 def bridge_port_exists(bridge, bridgeportname):
2618 try:
2619 return os.path.exists('/sys/class/net/%s/brif/%s' % (bridge, bridgeportname))
2620 except:
2621 return False
2622
2623 @staticmethod
2624 def get_bridge_ports(bridgename):
2625 try:
2626 return os.listdir('/sys/class/net/%s/brif/' % bridgename)
2627 except:
2628 return []
2629
2630 def ipv6_addrgen(self, ifname, addrgen):
2631 cmd = 'link set dev %s addrgenmode %s' % (ifname, 'eui64' if addrgen else 'none')
2632
2633 is_link_up = self.is_link_up(ifname)
2634
2635 if is_link_up:
2636 self.link_down(ifname)
2637
2638 if LinkUtils.ipbatch:
2639 self.add_to_batch(cmd)
2640 else:
2641 utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
2642
2643 if is_link_up:
2644 self.link_up(ifname)