]> git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdown2/ifupdownaddons/LinkUtils.py
addons: ppp: Add support for master-next
[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] == 'link/ppp':
550 linkattrs['kind'] = 'ppp'
551 elif citems[i] == 'vlan':
552 vlanid = self._get_vland_id(citems, i, warn)
553 if vlanid:
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],
561 'svcnode': None,
562 'remote': [],
563 'ageing': citems[i + 2],
564 'learning': 'on'}
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
577 break
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
583 break
584 elif citems[i] == 'veth':
585 linkattrs['kind'] = 'veth'
586 elif citems[i] == 'vrf_slave':
587 linkattrs['slave_kind'] = 'vrf_slave'
588 break
589 elif citems[i] == 'macvlan' and citems[i + 1] == 'mode':
590 linkattrs['kind'] = 'macvlan'
591 except Exception as e:
592 if warn:
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' %
597 (ifname, str(e)))
598 warn = False
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()]
604
605 @staticmethod
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:
609 return True
610 if scope and scope == 'link':
611 return True
612 return False
613
614 def _addr_fill(self, ifacename=None, refresh=False):
615 """ fills cache with address information
616
617 if ifacename argument given, fill cache for ifacename, else
618 fill cache for all interfaces in the system
619 """
620 if LinkUtils._CACHE_FILL_DONE and not refresh:
621 return
622 try:
623 # Check if ifacename is already full, in which case, return
624 if ifacename and not refresh:
625 linkCache.get_attr([ifacename, 'addrs'])
626 return
627 except:
628 pass
629
630 if True:
631 try:
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))
636
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.
644
645 else:
646 self._addr_fill_iproute2_cmd(ifacename, refresh)
647
648 def _addr_fill_iproute2_cmd(self, ifacename=None, refresh=False):
649 """ fills cache with address information
650
651 if ifacename argument given, fill cache for ifacename, else
652 fill cache for all interfaces in the system
653 """
654 linkout = {}
655 if LinkUtils._CACHE_FILL_DONE and not refresh:
656 return
657 try:
658 # Check if ifacename is already full, in which case, return
659 if ifacename and not refresh:
660 linkCache.get_attr([ifacename, 'addrs'])
661 return
662 except:
663 pass
664 cmdout = self.addr_show(ifacename=ifacename)
665 if not cmdout:
666 return
667 for c in cmdout.splitlines():
668 citems = c.split()
669 ifnamenlink = citems[1].split('@')
670 if len(ifnamenlink) > 1:
671 ifname = ifnamenlink[0]
672 else:
673 ifname = ifnamenlink[0].strip(':')
674 if not linkout.get(ifname):
675 linkattrs = dict()
676 linkattrs['addrs'] = OrderedDict({})
677 try:
678 linkout[ifname].update(linkattrs)
679 except KeyError:
680 linkout[ifname] = linkattrs
681 if citems[2] == 'inet':
682 if self._addr_filter(ifname, citems[3], scope=citems[5]):
683 continue
684 addrattrs = dict()
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]):
690 continue
691 if citems[5] == 'link':
692 continue # skip 'link' addresses
693 addrattrs = dict()
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()]
699
700 def cache_get(self, t, attrlist, refresh=False):
701 return self._cache_get(t, attrlist, refresh)
702
703 def _cache_get(self, t, attrlist, refresh=False):
704 try:
705 if ifupdownflags.flags.DRYRUN:
706 return False
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)
711 if not refresh:
712 return linkCache.get_attr(attrlist)
713 if t == 'link':
714 self._link_fill(attrlist[0], refresh)
715 elif t == 'addr':
716 self._addr_fill(attrlist[0], refresh)
717 else:
718 self._link_fill(attrlist[0], refresh)
719 self._addr_fill(attrlist[0], refresh)
720 return linkCache.get_attr(attrlist)
721 except Exception, e:
722 self.logger.debug('_cache_get(%s) : [%s]' % (str(attrlist), str(e)))
723 return None
724
725 def cache_check(self, attrlist, value, refresh=False):
726 return self._cache_check('link', attrlist, value, refresh=refresh)
727
728 def _cache_check(self, t, attrlist, value, refresh=False):
729 try:
730 return self._cache_get(t, attrlist, refresh) == value
731 except Exception, e:
732 self.logger.debug('_cache_check(%s) : [%s]'
733 % (str(attrlist), str(e)))
734 return False
735
736 def cache_update(self, attrlist, value):
737 return self._cache_update(attrlist, value)
738
739 @staticmethod
740 def _cache_update(attrlist, value):
741 if ifupdownflags.flags.DRYRUN:
742 return
743 try:
744 if attrlist[-1] == 'slaves':
745 linkCache.append_to_attrlist(attrlist, value)
746 return
747 linkCache.set_attr(attrlist, value)
748 except:
749 pass
750
751 @staticmethod
752 def _cache_delete(attrlist, value=None):
753 if ifupdownflags.flags.DRYRUN:
754 return
755 try:
756 if value:
757 linkCache.remove_from_attrlist(attrlist, value)
758 else:
759 linkCache.del_attr(attrlist)
760 except:
761 pass
762
763 @staticmethod
764 def _cache_invalidate():
765 linkCache.invalidate()
766 LinkUtils._CACHE_FILL_DONE = False
767
768 @staticmethod
769 def batch_start():
770 LinkUtils.ipbatcbuf = ''
771 LinkUtils.ipbatch = True
772 LinkUtils.ipbatch_pause = False
773
774 @staticmethod
775 def add_to_batch(cmd):
776 LinkUtils.ipbatchbuf += cmd + '\n'
777
778 @staticmethod
779 def batch_pause():
780 LinkUtils.ipbatch_pause = True
781
782 @staticmethod
783 def batch_resume():
784 LinkUtils.ipbatch_pause = False
785
786 def batch_commit(self):
787 if not LinkUtils.ipbatchbuf:
788 LinkUtils.ipbatchbuf = ''
789 LinkUtils.ipbatch = False
790 LinkUtils.ipbatch_pause = False
791 return
792 try:
793 utils.exec_command('%s -force -batch -' % utils.ip_cmd,
794 stdin=self.ipbatchbuf)
795 except:
796 raise
797 finally:
798 LinkUtils.ipbatchbuf = ''
799 LinkUtils.ipbatch = False
800 LinkUtils.ipbatch_pause = False
801
802 def bridge_batch_commit(self):
803 if not LinkUtils.ipbatchbuf:
804 LinkUtils.ipbatchbuf = ''
805 LinkUtils.ipbatch = False
806 LinkUtils.ipbatch_pause = False
807 return
808 try:
809 utils.exec_command('%s -force -batch -'
810 % utils.bridge_cmd, stdin=self.ipbatchbuf)
811 except:
812 raise
813 finally:
814 LinkUtils.ipbatchbuf = ''
815 LinkUtils.ipbatch = False
816 LinkUtils.ipbatch_pause = False
817
818 def addr_show(self, ifacename=None):
819 if ifacename:
820 if not self.link_exists(ifacename):
821 return
822 return utils.exec_commandl([utils.ip_cmd,
823 '-o', 'addr', 'show', 'dev', ifacename])
824 else:
825 return utils.exec_commandl([utils.ip_cmd,
826 '-o', 'addr', 'show'])
827
828 @staticmethod
829 def link_show(ifacename=None):
830 if ifacename:
831 return utils.exec_commandl([utils.ip_cmd,
832 '-o', '-d', 'link', 'show', 'dev', ifacename])
833 else:
834 return utils.exec_commandl([utils.ip_cmd,
835 '-o', '-d', 'link', 'show'])
836
837 def addr_add(self, ifacename, address, broadcast=None,
838 peer=None, scope=None, preferred_lifetime=None, metric=None):
839 if not address:
840 return
841 cmd = 'addr add %s' % address
842 if broadcast:
843 cmd += ' broadcast %s' % broadcast
844 if peer:
845 cmd += ' peer %s' % peer
846 if scope:
847 cmd += ' scope %s' % scope
848 if preferred_lifetime:
849 cmd += ' preferred_lft %s' % preferred_lifetime
850 cmd += ' dev %s' % ifacename
851
852 if metric:
853 cmd += ' metric %s' % metric
854
855 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
856 self.add_to_batch(cmd)
857 else:
858 utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
859 self._cache_update([ifacename, 'addrs', address], {})
860
861 def addr_del(self, ifacename, address, broadcast=None,
862 peer=None, scope=None):
863 """ Delete ipv4 address """
864 if not address:
865 return
866 if not self._cache_get('addr', [ifacename, 'addrs', address]):
867 return
868 cmd = 'addr del %s' % address
869 if broadcast:
870 cmd += 'broadcast %s' % broadcast
871 if peer:
872 cmd += 'peer %s' % peer
873 if scope:
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])
878
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)
883 else:
884 utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
885 self._cache_delete([ifacename, 'addrs'])
886
887 def del_addr_all(self, ifacename, skip_addrs=[]):
888 if not skip_addrs:
889 skip_addrs = []
890 runningaddrsdict = self.get_running_addrs(ifname=ifacename)
891 try:
892 # XXX: ignore errors. Fix this to delete secondary addresses
893 # first
894 [self.addr_del(ifacename, a) for a in
895 set(runningaddrsdict.keys()).difference(skip_addrs)]
896 except:
897 # ignore errors
898 pass
899
900 def addr_get(self, ifacename, details=True, refresh=False):
901 addrs = self._cache_get('addr', [ifacename, 'addrs'], refresh=refresh)
902 if not addrs:
903 return None
904 if details:
905 return addrs
906 return addrs.keys()
907
908 def get_running_addrs(self, ifaceobj=None, ifname=None, details=True, addr_virtual_ifaceobj=None):
909 """
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.
913
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
922 """
923 if not ifaceobj and not ifname:
924 return None
925
926 config_addrs = set()
927
928 if ifaceobj:
929 interface_name = ifaceobj.name
930 else:
931 interface_name = ifname
932
933 if addr_virtual_ifaceobj:
934 for virtual in addr_virtual_ifaceobj.get_attr_value('address-virtual') or []:
935 for ip in virtual.split():
936 try:
937 IPNetwork(ip)
938 config_addrs.add(ip)
939 except:
940 pass
941
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():
946 try:
947 IPNetwork(ip)
948 config_addrs.add(ip)
949 except:
950 pass
951 else:
952 if ifaceobj:
953 for addr in ifaceobj.get_attr_value('address') or []:
954 config_addrs.add(addr)
955
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)
960
961 running_addrs = OrderedDict()
962 cached_addrs = self.addr_get(interface_name)
963 if cached_addrs:
964 for addr, addr_details in cached_addrs.items():
965 try:
966 scope = int(addr_details['scope'])
967 except Exception:
968 try:
969 d = {}
970 addr_obj = IPNetwork(addr)
971 if isinstance(addr_obj, IPv6Network):
972 d['family'] = 'inet6'
973 else:
974 d['family'] = 'inet'
975 running_addrs[addr] = d
976 except:
977 running_addrs[addr] = {}
978 continue
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
981 else:
982 return None
983
984 if details:
985 return running_addrs
986 return running_addrs.keys()
987
988 @staticmethod
989 def compare_user_config_vs_running_state(running_addrs, user_addrs):
990 ip4 = []
991 ip6 = []
992
993 for ip in user_addrs or []:
994 obj = IPNetwork(ip)
995
996 if type(obj) == IPv6Network:
997 ip6.append(obj)
998 else:
999 ip4.append(obj)
1000
1001 running_ipobj = []
1002 for ip in running_addrs or []:
1003 running_ipobj.append(IPNetwork(ip))
1004
1005 return running_ipobj == (ip4 + ip6)
1006
1007 def addr_add_multiple(self, ifaceobj, ifacename, addrs, purge_existing=False, metric=None):
1008 # purges address
1009 if purge_existing:
1010 # if perfmode is not set and also if iface has no sibling
1011 # objects, purge addresses that are not present in the new
1012 # config
1013 runningaddrs = self.get_running_addrs(
1014 ifname=ifacename,
1015 details=False,
1016 addr_virtual_ifaceobj=ifaceobj
1017 )
1018 addrs = utils.get_normalized_ip_addr(ifacename, addrs)
1019
1020 if self.compare_user_config_vs_running_state(runningaddrs, addrs):
1021 return
1022 try:
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)
1028 else:
1029 self.del_addr_all(ifacename, addrs)
1030 except Exception, e:
1031 self.logger.warning('%s: %s' % (ifacename, str(e)))
1032 for a in addrs:
1033 try:
1034 self.addr_add(ifacename, a, metric=metric)
1035 except Exception, e:
1036 self.logger.error(str(e))
1037
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)
1045 else:
1046 utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
1047
1048 def link_up(self, ifacename):
1049 self._link_set_ifflag(ifacename, 'UP')
1050
1051 def link_down(self, ifacename):
1052 self._link_set_ifflag(ifacename, 'DOWN')
1053
1054 def link_set(self, ifacename, key, value=None,
1055 force=False, t=None, state=None):
1056 if not force:
1057 if (key not in ['master', 'nomaster'] and
1058 self._cache_check('link', [ifacename, key], value)):
1059 return
1060 cmd = 'link set dev %s' % ifacename
1061 if t:
1062 cmd += ' type %s' % t
1063 cmd += ' %s' % key
1064 if value:
1065 cmd += ' %s' % value
1066 if state:
1067 cmd += ' %s' % state
1068 if LinkUtils.ipbatch:
1069 self.add_to_batch(cmd)
1070 else:
1071 utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
1072 if key not in ['master', 'nomaster']:
1073 self._cache_update([ifacename, key], value)
1074
1075 def link_set_hwaddress(self, ifacename, hwaddress, force=False):
1076 if not force:
1077 if self._cache_check('link', [ifacename, 'hwaddress'], hwaddress):
1078 return
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)
1083 else:
1084 utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
1085 self.link_up(ifacename)
1086 self._cache_update([ifacename, 'hwaddress'], hwaddress)
1087
1088 def link_set_mtu(self, ifacename, mtu):
1089 if ifupdownflags.flags.DRYRUN:
1090 return True
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)
1094
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)
1098
1099 def link_get_alias(self, ifacename):
1100 return self.read_file_oneline('/sys/class/net/%s/ifalias'
1101 % ifacename)
1102
1103 def link_isloopback(self, ifacename):
1104 flags = self._cache_get('link', [ifacename, 'flags'])
1105 if not flags:
1106 return
1107 if 'LOOPBACK' in flags:
1108 return True
1109 return False
1110
1111 def link_get_status(self, ifacename):
1112 return self._cache_get('link', [ifacename, 'ifflag'], refresh=True)
1113
1114 @staticmethod
1115 def route_add_gateway(ifacename, gateway, vrf=None, metric=None):
1116 if not gateway:
1117 return
1118 if not vrf:
1119 cmd = '%s route add default via %s proto kernel' % (utils.ip_cmd,
1120 gateway)
1121 else:
1122 cmd = ('%s route add table %s default via %s proto kernel' %
1123 (utils.ip_cmd, vrf, gateway))
1124 # Add metric
1125 if metric:
1126 cmd += 'metric %s' % metric
1127 cmd += ' dev %s' % ifacename
1128 utils.exec_command(cmd)
1129
1130 @staticmethod
1131 def route_del_gateway(ifacename, gateway, vrf=None, metric=None):
1132 # delete default gw
1133 if not gateway:
1134 return
1135 if not vrf:
1136 cmd = ('%s route del default via %s proto kernel' %
1137 (utils.ip_cmd, gateway))
1138 else:
1139 cmd = ('%s route del table %s default via %s proto kernel' %
1140 (utils.ip_cmd, vrf, gateway))
1141 if metric:
1142 cmd += ' metric %s' % metric
1143 cmd += ' dev %s' % ifacename
1144 utils.exec_command(cmd)
1145
1146 @staticmethod
1147 def _get_vrf_id(ifacename):
1148 try:
1149 return linkCache.vrfs[ifacename]['table']
1150 except KeyError:
1151 dump = netlink.link_dump(ifacename)
1152
1153 [linkCache.update_attrdict([ifname], linkattrs)
1154 for ifname, linkattrs in dump.items()]
1155
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}
1159 return vrf_table
1160
1161 return None
1162
1163 def fix_ipv6_route_metric(self, ifaceobj, macvlan_ifacename, ips):
1164 vrf_table = None
1165
1166 if ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE:
1167 try:
1168 for upper_iface in ifaceobj.upperifaces:
1169 vrf_table = self._get_vrf_id(upper_iface)
1170 if vrf_table:
1171 break
1172 except:
1173 pass
1174
1175 ip_route_del = []
1176 for ip in ips:
1177 ip_network_obj = IPNetwork(ip)
1178
1179 if type(ip_network_obj) == IPv6Network:
1180 route_prefix = '%s/%d' % (ip_network_obj.network, ip_network_obj.prefixlen)
1181
1182 if vrf_table:
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))
1185 else:
1186 utils.exec_commandl([utils.ip_cmd, 'route', 'del', route_prefix, 'table', vrf_table, 'dev', macvlan_ifacename])
1187 else:
1188 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
1189 LinkUtils.add_to_batch('route del %s dev %s' % (route_prefix, macvlan_ifacename))
1190 else:
1191 utils.exec_commandl([utils.ip_cmd, 'route', 'del', route_prefix, 'dev', macvlan_ifacename])
1192 ip_route_del.append((route_prefix, vrf_table))
1193
1194 for ip, vrf_table in ip_route_del:
1195 if vrf_table:
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))
1198 else:
1199 utils.exec_commandl([utils.ip_cmd, 'route', 'add', ip, 'table', vrf_table, 'dev', macvlan_ifacename, 'proto', 'kernel' 'metric', '9999'])
1200 else:
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))
1203 else:
1204 utils.exec_commandl([utils.ip_cmd, 'route', 'add', ip, 'dev', macvlan_ifacename, 'proto', 'kernel' 'metric', '9999'])
1205
1206 def link_create_vlan(self, vlan_device_name, vlan_raw_device, vlanid):
1207 if self.link_exists(vlan_device_name):
1208 return
1209 utils.exec_command('%s link add link %s name %s type vlan id %d' %
1210 (utils.ip_cmd,
1211 vlan_raw_device, vlan_device_name, vlanid))
1212 self._cache_update([vlan_device_name], {})
1213
1214 def link_create_vlan_from_name(self, vlan_device_name):
1215 v = vlan_device_name.split('.')
1216 if len(v) != 2:
1217 self.logger.warn('invalid vlan device name %s' % vlan_device_name)
1218 return
1219 self.link_create_vlan(vlan_device_name, v[0], v[1])
1220
1221 def link_create_macvlan(self, name, linkdev, mode='private'):
1222 if self.link_exists(name):
1223 return
1224 cmd = ('link add link %s' % linkdev +
1225 ' name %s' % name +
1226 ' type macvlan mode %s' % mode)
1227 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
1228 self.add_to_batch(cmd)
1229 else:
1230 utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
1231 self._cache_update([name], {})
1232
1233 def get_vxlan_peers(self, dev, svcnodeip):
1234 cmd = '%s fdb show brport %s' % (utils.bridge_cmd,
1235 dev)
1236 cur_peers = []
1237 try:
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)
1241 ps.wait()
1242 utils.disable_subprocess_signal_forwarding(signal.SIGINT)
1243 try:
1244 ppat = re.compile('\s+dst\s+(\d+.\d+.\d+.\d+)\s+')
1245 for l in output.split('\n'):
1246 m = ppat.search(l)
1247 if m and m.group(1) != svcnodeip:
1248 cur_peers.append(m.group(1))
1249 except:
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))
1254 finally:
1255 utils.disable_subprocess_signal_forwarding(signal.SIGINT)
1256
1257 return cur_peers
1258
1259 def tunnel_create(self, tunnelname, mode, attrs={}):
1260 """ generic link_create function """
1261 if self.link_exists(tunnelname):
1262 return
1263
1264 cmd = ''
1265 if '6' in mode:
1266 cmd = ' -6 '
1267
1268 cmd += 'tunnel add'
1269 cmd += ' %s mode %s' %(tunnelname, mode)
1270 if attrs:
1271 for k, v in attrs.iteritems():
1272 cmd += ' %s' %k
1273 if v:
1274 cmd += ' %s' %v
1275 if self.ipbatch and not self.ipbatch_pause:
1276 self.add_to_batch(cmd)
1277 else:
1278 utils.exec_command('ip %s' % cmd)
1279 self._cache_update([tunnelname], {})
1280
1281 def tunnel_change(self, tunnelname, attrs={}):
1282 """ tunnel change function """
1283 if not self.link_exists(tunnelname):
1284 return
1285 cmd = 'tunnel change'
1286 cmd += ' %s' %(tunnelname)
1287 if attrs:
1288 for k, v in attrs.iteritems():
1289 cmd += ' %s' %k
1290 if v:
1291 cmd += ' %s' %v
1292 if self.ipbatch and not self.ipbatch_pause:
1293 self.add_to_batch(cmd)
1294 else:
1295 utils.exec_command('ip %s' % cmd)
1296 self._cache_update([tunnelname], {})
1297
1298 def link_create_vxlan(self, name, vxlanid,
1299 localtunnelip=None,
1300 svcnodeip=None,
1301 remoteips=None,
1302 learning='on',
1303 ageing=None,
1304 anycastip=None):
1305 if svcnodeip and remoteips:
1306 raise Exception("svcnodeip and remoteip is mutually exclusive")
1307 args = ''
1308 if svcnodeip:
1309 args += ' remote %s' % svcnodeip
1310 if ageing:
1311 args += ' ageing %s' % ageing
1312 if learning == 'off':
1313 args += ' nolearning'
1314
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
1319 # has modified
1320 if vxlanattrs:
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:
1326 args += ' noremote'
1327 else:
1328 cmd = 'link add dev %s type vxlan id %s dstport %d' % (name, vxlanid, LinkUtils.VXLAN_UDP_PORT)
1329
1330 if localtunnelip:
1331 args += ' local %s' % localtunnelip
1332 cmd += args
1333
1334 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
1335 self.add_to_batch(cmd)
1336 else:
1337 utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
1338
1339 # XXX: update linkinfo correctly
1340 #self._cache_update([name], {})
1341
1342 @staticmethod
1343 def link_exists(ifacename):
1344 if ifupdownflags.flags.DRYRUN:
1345 return True
1346 return os.path.exists('/sys/class/net/%s' % ifacename)
1347
1348 def link_get_ifindex(self, ifacename):
1349 if ifupdownflags.flags.DRYRUN:
1350 return True
1351 return self.read_file_oneline('/sys/class/net/%s/ifindex' % ifacename)
1352
1353 def is_vlan_device_by_name(self, ifacename):
1354 if re.search(r'\.', ifacename):
1355 return True
1356 return False
1357
1358 @staticmethod
1359 def link_add_macvlan(ifname, macvlan_ifacename):
1360 utils.exec_commandl(['ip', 'link', 'add', 'link', ifname, 'name', macvlan_ifacename, 'type', 'macvlan', 'mode', 'private'])
1361
1362 @staticmethod
1363 def route_add(route):
1364 utils.exec_command('%s route add %s' % (utils.ip_cmd,
1365 route))
1366
1367 @staticmethod
1368 def route6_add(route):
1369 utils.exec_command('%s -6 route add %s' % (utils.ip_cmd,
1370 route))
1371
1372 def get_vlandev_attrs(self, ifacename):
1373 return (self._cache_get('link', [ifacename, 'link']),
1374 self._cache_get('link', [ifacename, 'linkinfo', 'vlanid']),
1375 self._cache_get('link', [ifacename, 'linkinfo', 'vlan_protocol']))
1376
1377 def get_vlan_protocol(self, ifacename):
1378 return self._cache_get('link', [ifacename, 'linkinfo', 'vlan_protocol'])
1379
1380 def get_vxlandev_attrs(self, ifacename):
1381 return self._cache_get('link', [ifacename, 'linkinfo'])
1382
1383 def get_vxlandev_learning(self, ifacename):
1384 return self._cache_get('link', [ifacename, 'linkinfo', Link.IFLA_VXLAN_LEARNING])
1385
1386 def set_vxlandev_learning(self, ifacename, learn):
1387 if learn == 'on':
1388 utils.exec_command('%s link set dev %s type vxlan learning' %
1389 (utils.ip_cmd, ifacename))
1390 self._cache_update([ifacename, 'linkinfo', 'learning'], 'on')
1391 else:
1392 utils.exec_command('%s link set dev %s type vxlan nolearning' %
1393 (utils.ip_cmd, ifacename))
1394 self._cache_update([ifacename, 'linkinfo', 'learning'], 'off')
1395
1396 def link_get_linkinfo_attrs(self, ifacename):
1397 return self._cache_get('link', [ifacename, 'linkinfo'])
1398
1399 def link_get_mtu(self, ifacename, refresh=False):
1400 return self._cache_get('link', [ifacename, 'mtu'], refresh=refresh)
1401
1402 def link_get_mtu_sysfs(self, ifacename):
1403 return self.read_file_oneline('/sys/class/net/%s/mtu'
1404 % ifacename)
1405
1406 def link_get_kind(self, ifacename):
1407 return self._cache_get('link', [ifacename, 'kind'])
1408
1409 def link_get_slave_kind(self, ifacename):
1410 return self._cache_get('link', [ifacename, 'slave_kind'])
1411
1412 def link_get_hwaddress(self, ifacename):
1413 address = self._cache_get('link', [ifacename, 'hwaddress'])
1414 # newly created logical interface addresses dont end up in the cache
1415 # read hwaddress from sysfs file for these interfaces
1416 if not address:
1417 address = self.read_file_oneline('/sys/class/net/%s/address'
1418 % ifacename)
1419 return address
1420
1421 def link_create(self, ifacename, t, attrs={}):
1422 """ generic link_create function """
1423 if self.link_exists(ifacename):
1424 return
1425 cmd = 'link add'
1426 cmd += ' name %s type %s' % (ifacename, t)
1427 if attrs:
1428 for k, v in attrs.iteritems():
1429 cmd += ' %s' % k
1430 if v:
1431 cmd += ' %s' % v
1432 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
1433 self.add_to_batch(cmd)
1434 else:
1435 utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
1436 self._cache_update([ifacename], {})
1437
1438 def link_delete(self, ifacename):
1439 if not self.link_exists(ifacename):
1440 return
1441 cmd = 'link del %s' % ifacename
1442 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
1443 self.add_to_batch(cmd)
1444 else:
1445 utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
1446 self._cache_invalidate()
1447
1448 def link_get_master(self, ifacename):
1449 sysfs_master_path = '/sys/class/net/%s/master' % ifacename
1450 if os.path.exists(sysfs_master_path):
1451 link_path = os.readlink(sysfs_master_path)
1452 if link_path:
1453 return os.path.basename(link_path)
1454 else:
1455 return None
1456 else:
1457 return self._cache_get('link', [ifacename, 'master'])
1458
1459 def get_brport_peer_link(self, bridgename):
1460 try:
1461 return self._cache_get('link', [bridgename, 'info_slave_data', Link.IFLA_BRPORT_PEER_LINK])
1462 except:
1463 return None
1464
1465 @staticmethod
1466 def bridge_port_vids_add(bridgeportname, vids):
1467 [utils.exec_command('%s vlan add vid %s dev %s' %
1468 (utils.bridge_cmd,
1469 v, bridgeportname)) for v in vids]
1470
1471 @staticmethod
1472 def bridge_port_vids_del(bridgeportname, vids):
1473 if not vids:
1474 return
1475 [utils.exec_command('%s vlan del vid %s dev %s' %
1476 (utils.bridge_cmd,
1477 v, bridgeportname)) for v in vids]
1478
1479 @staticmethod
1480 def bridge_port_vids_flush(bridgeportname, vid):
1481 utils.exec_command('%s vlan del vid %s dev %s' %
1482 (utils.bridge_cmd,
1483 vid, bridgeportname))
1484
1485 @staticmethod
1486 def bridge_port_vids_get(bridgeportname):
1487 bridgeout = utils.exec_command('%s vlan show dev %s' %
1488 (utils.bridge_cmd,
1489 bridgeportname))
1490 if not bridgeout:
1491 return []
1492 brvlanlines = bridgeout.readlines()[2:]
1493 vids = [l.strip() for l in brvlanlines]
1494 return [v for v in vids if v]
1495
1496 @staticmethod
1497 def bridge_port_vids_get_all():
1498 brvlaninfo = {}
1499 bridgeout = utils.exec_command('%s -c vlan show'
1500 % utils.bridge_cmd)
1501 if not bridgeout:
1502 return brvlaninfo
1503 brvlanlines = bridgeout.splitlines()
1504 brportname = None
1505 for l in brvlanlines[1:]:
1506 if l and not l.startswith(' ') and not l.startswith('\t'):
1507 attrs = l.split()
1508 brportname = attrs[0].strip()
1509 brvlaninfo[brportname] = {'pvid': None, 'vlan': []}
1510 l = ' '.join(attrs[1:])
1511 if not brportname or not l:
1512 continue
1513 l = l.strip()
1514 if 'PVID' in l:
1515 brvlaninfo[brportname]['pvid'] = l.split()[0]
1516 elif 'Egress Untagged' not in l:
1517 brvlaninfo[brportname]['vlan'].append(l)
1518 return brvlaninfo
1519
1520 def bridge_port_vids_get_all_json(self):
1521 if not self.supported_command['%s -c -json vlan show'
1522 % utils.bridge_cmd]:
1523 return {}
1524 brvlaninfo = {}
1525 try:
1526 bridgeout = utils.exec_command('%s -c -json vlan show'
1527 % utils.bridge_cmd)
1528 except:
1529 self.supported_command['%s -c -json vlan show'
1530 % utils.bridge_cmd] = False
1531 self.logger.info('%s -c -json vlan show: skipping unsupported command'
1532 % utils.bridge_cmd)
1533 try:
1534 return self.get_bridge_vlan_nojson()
1535 except Exception as e:
1536 self.logger.info('bridge: get_bridge_vlan_nojson: %s' % str(e))
1537 return {}
1538
1539 if not bridgeout: return brvlaninfo
1540 try:
1541 vlan_json_dict = json.loads(bridgeout, encoding="utf-8")
1542 except Exception, e:
1543 self.logger.info('json loads failed with (%s)' % str(e))
1544 return {}
1545 return vlan_json_dict
1546
1547 @staticmethod
1548 def get_bridge_vlan_nojson():
1549 vlan_json = {}
1550 bridgeout = utils.exec_commandl([utils.bridge_cmd, '-c', 'vlan', 'show'])
1551 if bridgeout:
1552 output = [line.split('\n') for line in bridgeout.split('\n\n')]
1553 output[0] = output[0][1:]
1554 for line in output:
1555 current_swp = None
1556 if not line:
1557 continue
1558 for entry in line:
1559 if not entry:
1560 continue
1561 prefix, vlan = entry.split('\t')
1562 if prefix:
1563 current_swp = prefix
1564 vlan_json[prefix] = []
1565 v = {}
1566 vlan = vlan[1:]
1567 try:
1568 v['vlan'] = int(vlan)
1569 except:
1570 try:
1571 if '-' in vlan:
1572 start, end = vlan.split('-')
1573 if ' ' in end:
1574 end = end[0:end.index(' ')]
1575 v['vlan'] = int(start)
1576 v['vlanEnd'] = int(end)
1577 else:
1578 v['vlan'] = int(vlan[0:vlan.index(' ')])
1579 flags = []
1580 if 'PVID' in vlan:
1581 flags.append('PVID')
1582 if 'Egress Untagged' in vlan:
1583 flags.append('Egress Untagged')
1584 v['flags'] = flags
1585 except:
1586 continue
1587 vlan_json[current_swp].append(v)
1588 return vlan_json
1589
1590 def bridge_vlan_cache_get(self, ifacename, refresh=False):
1591 if not self.bridge_vlan_cache_fill_done or refresh:
1592 self.bridge_vlan_cache = self.bridge_port_vids_get_all_json()
1593 self.bridge_vlan_cache_fill_done = True
1594 return self.bridge_vlan_cache.get(ifacename, {})
1595
1596 def bridge_vlan_get_pvid(self, ifacename, refresh=False):
1597 pvid = 0
1598
1599 for vinfo in self.bridge_vlan_cache_get(ifacename, refresh):
1600 v = vinfo.get('vlan')
1601 pvid = v if 'PVID' in vinfo.get('flags', []) else 0
1602 if pvid:
1603 return pvid
1604 return pvid
1605
1606 def bridge_vlan_get_vids(self, ifacename, refresh=False):
1607 vids = []
1608
1609 for vinfo in self.bridge_vlan_cache_get(ifacename, refresh):
1610 v = vinfo.get('vlan')
1611 ispvid = True if 'PVID' in vinfo.get('flags', []) else False
1612 if ispvid:
1613 pvid = v if 'PVID' in vinfo.get('flags', []) else 0
1614 if pvid == 1:
1615 continue
1616 vEnd = vinfo.get('vlanEnd')
1617 if vEnd:
1618 vids.extend(range(v, vEnd + 1))
1619 else:
1620 vids.append(v)
1621 return vids
1622
1623 def bridge_vlan_get_vids_n_pvid(self, ifacename, refresh=False):
1624 vids = []
1625 pvid = 0
1626
1627 for vinfo in self.bridge_vlan_cache_get(ifacename, refresh):
1628 v = vinfo.get('vlan')
1629 ispvid = True if 'PVID' in vinfo.get('flags', []) else False
1630 if ispvid:
1631 pvid = v if 'PVID' in vinfo.get('flags', []) else 0
1632 vEnd = vinfo.get('vlanEnd')
1633 if vEnd:
1634 vids.extend(range(v, vEnd + 1))
1635 else:
1636 vids.append(v)
1637 return vids, pvid
1638
1639 def bridge_port_pvid_add(self, bridgeportname, pvid):
1640 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
1641 self.add_to_batch('vlan add vid %s untagged pvid dev %s' %
1642 (pvid, bridgeportname))
1643 else:
1644 utils.exec_command('%s vlan add vid %s untagged pvid dev %s' %
1645 (utils.bridge_cmd,
1646 pvid, bridgeportname))
1647
1648 def bridge_port_pvid_del(self, bridgeportname, pvid):
1649 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
1650 self.add_to_batch('vlan del vid %s untagged pvid dev %s' %
1651 (pvid, bridgeportname))
1652 else:
1653 utils.exec_command('%s vlan del vid %s untagged pvid dev %s' %
1654 (utils.bridge_cmd,
1655 pvid, bridgeportname))
1656
1657 def bridge_port_pvids_get(self, bridgeportname):
1658 return self.read_file_oneline('/sys/class/net/%s/brport/pvid'
1659 % bridgeportname)
1660
1661 def bridge_vids_add(self, bridgeportname, vids, bridge=True):
1662 target = 'self' if bridge else ''
1663 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
1664 [self.add_to_batch('vlan add vid %s dev %s %s' %
1665 (v, bridgeportname, target)) for v in vids]
1666 else:
1667 [utils.exec_command('%s vlan add vid %s dev %s %s' %
1668 (utils.bridge_cmd,
1669 v, bridgeportname, target)) for v in vids]
1670
1671 def bridge_vids_del(self, bridgeportname, vids, bridge=True):
1672 target = 'self' if bridge else ''
1673 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
1674 [self.add_to_batch('vlan del vid %s dev %s %s' %
1675 (v, bridgeportname, target)) for v in vids]
1676 else:
1677 [utils.exec_command('%s vlan del vid %s dev %s %s' %
1678 (utils.bridge_cmd,
1679 v, bridgeportname, target)) for v in vids]
1680
1681 @staticmethod
1682 def bridge_fdb_add(dev, address, vlan=None, bridge=True, remote=None):
1683 target = 'self' if bridge else ''
1684 vlan_str = ''
1685 if vlan:
1686 vlan_str = 'vlan %s ' % vlan
1687
1688 dst_str = ''
1689 if remote:
1690 dst_str = 'dst %s ' % remote
1691
1692 utils.exec_command('%s fdb replace %s dev %s %s %s %s' %
1693 (utils.bridge_cmd,
1694 address, dev, vlan_str, target, dst_str))
1695
1696 @staticmethod
1697 def bridge_fdb_append(dev, address, vlan=None, bridge=True, remote=None):
1698 target = 'self' if bridge else ''
1699 vlan_str = ''
1700 if vlan:
1701 vlan_str = 'vlan %s ' % vlan
1702
1703 dst_str = ''
1704 if remote:
1705 dst_str = 'dst %s ' % remote
1706
1707 utils.exec_command('%s fdb append %s dev %s %s %s %s' %
1708 (utils.bridge_cmd,
1709 address, dev, vlan_str, target, dst_str))
1710
1711 @staticmethod
1712 def bridge_fdb_del(dev, address, vlan=None, bridge=True, remote=None):
1713 target = 'self' if bridge else ''
1714 vlan_str = ''
1715 if vlan:
1716 vlan_str = 'vlan %s ' % vlan
1717
1718 dst_str = ''
1719 if remote:
1720 dst_str = 'dst %s ' % remote
1721 utils.exec_command('%s fdb del %s dev %s %s %s %s' %
1722 (utils.bridge_cmd,
1723 address, dev, vlan_str, target, dst_str))
1724
1725 def bridge_is_vlan_aware(self, bridgename):
1726 filename = '/sys/class/net/%s/bridge/vlan_filtering' % bridgename
1727 if os.path.exists(filename) and self.read_file_oneline(filename) == '1':
1728 return True
1729 return False
1730
1731 @staticmethod
1732 def bridge_port_get_bridge_name(bridgeport):
1733 filename = '/sys/class/net/%s/brport/bridge' % bridgeport
1734 try:
1735 return os.path.basename(os.readlink(filename))
1736 except:
1737 return None
1738
1739 @staticmethod
1740 def bridge_port_exists(bridge, bridgeportname):
1741 try:
1742 return os.path.exists('/sys/class/net/%s/brif/%s'
1743 % (bridge, bridgeportname))
1744 except Exception:
1745 return False
1746
1747 def bridge_fdb_show_dev(self, dev):
1748 try:
1749 fdbs = {}
1750 output = utils.exec_command('%s fdb show dev %s'
1751 % (utils.bridge_cmd, dev))
1752 if output:
1753 for fdb_entry in output.splitlines():
1754 try:
1755 entries = fdb_entry.split()
1756 fdbs.setdefault(entries[2], []).append(entries[0])
1757 except:
1758 self.logger.debug('%s: invalid fdb line \'%s\''
1759 % (dev, fdb_entry))
1760 return fdbs
1761 except Exception:
1762 return None
1763
1764 @staticmethod
1765 def is_bridge(bridge):
1766 return os.path.exists('/sys/class/net/%s/bridge' % bridge)
1767
1768 def is_link_up(self, ifacename):
1769 ret = False
1770 try:
1771 flags = self.read_file_oneline('/sys/class/net/%s/flags' % ifacename)
1772 iflags = int(flags, 16)
1773 if iflags & 0x0001:
1774 ret = True
1775 except:
1776 ret = False
1777 return ret
1778
1779 def ip_route_get_dev(self, prefix, vrf_master=None):
1780 try:
1781 if vrf_master:
1782 cmd = '%s route get %s vrf %s' % (utils.ip_cmd, prefix, vrf_master)
1783 else:
1784 cmd = '%s route get %s' % (utils.ip_cmd, prefix)
1785
1786 output = utils.exec_command(cmd)
1787 if output:
1788 rline = output.splitlines()[0]
1789 if rline:
1790 rattrs = rline.split()
1791 return rattrs[rattrs.index('dev') + 1]
1792 except Exception, e:
1793 self.logger.debug('ip_route_get_dev: failed .. %s' % str(e))
1794 return None
1795
1796 @staticmethod
1797 def link_get_lowers(ifacename):
1798 try:
1799 lowers = glob.glob("/sys/class/net/%s/lower_*" % ifacename)
1800 if not lowers:
1801 return []
1802 return [os.path.basename(l)[6:] for l in lowers]
1803 except:
1804 return []
1805
1806 @staticmethod
1807 def link_get_uppers(ifacename):
1808 try:
1809 uppers = glob.glob("/sys/class/net/%s/upper_*" % ifacename)
1810 if not uppers:
1811 return None
1812 return [os.path.basename(u)[6:] for u in uppers]
1813 except Exception:
1814 return None
1815
1816 def link_get_vrfs(self):
1817 if not LinkUtils._CACHE_FILL_DONE:
1818 self._fill_cache()
1819 return linkCache.vrfs
1820
1821 @staticmethod
1822 def cache_get_info_slave(attrlist):
1823 try:
1824 return linkCache.get_attr(attrlist)
1825 except:
1826 return None
1827
1828 def get_brport_learning(self, ifacename):
1829 learn = self.read_file_oneline('/sys/class/net/%s/brport/learning'
1830 % ifacename)
1831 if learn and learn == '1':
1832 return 'on'
1833 else:
1834 return 'off'
1835
1836 def get_brport_learning_bool(self, ifacename):
1837 return utils.get_boolean_from_string(self.read_file_oneline('/sys/class/net/%s/brport/learning' % ifacename))
1838
1839 def set_brport_learning(self, ifacename, learn):
1840 if learn == 'off':
1841 return self.write_file('/sys/class/net/%s/brport/learning'
1842 % ifacename, '0')
1843 else:
1844 return self.write_file('/sys/class/net/%s/brport/learning'
1845 % ifacename, '1')
1846
1847 #################################################################################
1848 ################################### BOND UTILS ##################################
1849 #################################################################################
1850
1851 def _link_cache_get(self, attrlist, refresh=False):
1852 return self._cache_get('link', attrlist, refresh)
1853
1854 def cache_delete(self, attrlist, value=None):
1855 return self._cache_delete(attrlist, value)
1856
1857 def link_cache_get(self, attrlist, refresh=False):
1858 return self._link_cache_get(attrlist, refresh)
1859
1860 def link_cache_check(self, attrlist, value, refresh=False):
1861 return self._link_cache_check(attrlist, value, refresh)
1862
1863 def _link_cache_check(self, attrlist, value, refresh=False):
1864 try:
1865 return self._link_cache_get(attrlist, refresh) == value
1866 except Exception, e:
1867 self.logger.debug('_cache_check(%s) : [%s]'
1868 % (str(attrlist), str(e)))
1869 pass
1870 return False
1871
1872 bondcmd_attrmap = {
1873 Link.IFLA_BOND_MODE: 'mode',
1874 Link.IFLA_BOND_MIIMON: 'miimon',
1875 Link.IFLA_BOND_USE_CARRIER: 'use_carrier',
1876 Link.IFLA_BOND_AD_LACP_RATE: 'lacp_rate',
1877 Link.IFLA_BOND_XMIT_HASH_POLICY: 'xmit_hash_policy',
1878 Link.IFLA_BOND_MIN_LINKS: 'min_links',
1879 Link.IFLA_BOND_NUM_PEER_NOTIF: 'num_grat_arp',
1880 Link.IFLA_BOND_AD_ACTOR_SYSTEM: 'ad_actor_system',
1881 Link.IFLA_BOND_AD_ACTOR_SYS_PRIO: 'ad_actor_sys_prio',
1882 Link.IFLA_BOND_AD_LACP_BYPASS: 'lacp_bypass',
1883 Link.IFLA_BOND_UPDELAY: 'updelay',
1884 Link.IFLA_BOND_DOWNDELAY: 'downdelay',
1885 }
1886
1887 def bond_set_attrs_nl(self, bondname, ifla_info_data):
1888 bond_attr_name = 'None' # for log purpose (in case an exception raised)
1889 for nl_attr, value in ifla_info_data.items():
1890 try:
1891 bond_attr_name = self.bondcmd_attrmap[nl_attr]
1892 file_path = '/sys/class/net/%s/bonding/%s' % (bondname, bond_attr_name)
1893 if os.path.exists(file_path):
1894 self.write_file(file_path, str(value))
1895 except Exception as e:
1896 exception_str = '%s: %s %s: %s' % (bondname, bond_attr_name, value, str(e))
1897 if ifupdownflags.flags.FORCE:
1898 self.logger.warning(exception_str)
1899 else:
1900 self.logger.debug(exception_str)
1901
1902 def bond_set_attrs(self, bondname, attrdict, prehook):
1903 for attrname, attrval in attrdict.items():
1904 if (self._link_cache_check([bondname, 'linkinfo',
1905 attrname], attrval)):
1906 continue
1907 if (attrname == 'mode'
1908 or attrname == 'xmit_hash_policy'
1909 or attrname == 'lacp_rate' or attrname == 'min_links'):
1910 if prehook:
1911 prehook(bondname)
1912 try:
1913 if ((attrname not in ['lacp_rate',
1914 'lacp_bypass']) or
1915 self._link_cache_check([bondname, 'linkinfo', 'mode'], '802.3ad',
1916 True)):
1917 self.write_file('/sys/class/net/%s/bonding/%s'
1918 % (bondname, attrname), attrval)
1919 except Exception, e:
1920 if ifupdownflags.flags.FORCE:
1921 self.logger.warn(str(e))
1922 pass
1923 else:
1924 raise
1925
1926 def bond_set_use_carrier(self, bondname, use_carrier):
1927 if not use_carrier or (use_carrier != '0' and use_carrier != '1'):
1928 return
1929 if (self._link_cache_check([bondname, 'linkinfo', 'use_carrier'],
1930 use_carrier)):
1931 return
1932 self.write_file('/sys/class/net/%s' % bondname +
1933 '/bonding/use_carrier', use_carrier)
1934 self._cache_update([bondname, 'linkinfo',
1935 'use_carrier'], use_carrier)
1936
1937 def bond_get_use_carrier(self, bondname):
1938 return self._link_cache_get([bondname, 'linkinfo', 'use_carrier'])
1939
1940 def bond_get_use_carrier_nl(self, bondname):
1941 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_USE_CARRIER])
1942
1943 def bond_set_xmit_hash_policy(self, bondname, hash_policy, prehook=None):
1944 valid_values = ['layer2', 'layer3+4', 'layer2+3']
1945 if not hash_policy:
1946 return
1947 if hash_policy not in valid_values:
1948 raise Exception('invalid hash policy value %s' % hash_policy)
1949 if (self._link_cache_check([bondname, 'linkinfo', 'xmit_hash_policy'],
1950 hash_policy)):
1951 return
1952 if prehook:
1953 prehook(bondname)
1954 self.write_file('/sys/class/net/%s' % bondname +
1955 '/bonding/xmit_hash_policy', hash_policy)
1956 self._cache_update([bondname, 'linkinfo', 'xmit_hash_policy'],
1957 hash_policy)
1958
1959 def bond_get_xmit_hash_policy(self, bondname):
1960 return self._link_cache_get([bondname, 'linkinfo', 'xmit_hash_policy'])
1961
1962 def bond_get_xmit_hash_policy_nl(self, bondname):
1963 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_XMIT_HASH_POLICY])
1964
1965 def bond_set_miimon(self, bondname, miimon):
1966 if (self._link_cache_check([bondname, 'linkinfo', 'miimon'],
1967 miimon)):
1968 return
1969 self.write_file('/sys/class/net/%s' % bondname +
1970 '/bonding/miimon', miimon)
1971 self._cache_update([bondname, 'linkinfo', 'miimon'], miimon)
1972
1973 def bond_get_miimon(self, bondname):
1974 return self._link_cache_get([bondname, 'linkinfo', 'miimon'])
1975
1976 def bond_get_miimon_nl(self, bondname):
1977 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_MIIMON])
1978
1979 def bond_set_mode(self, bondname, mode, prehook=None):
1980 valid_modes = ['balance-rr', 'active-backup', 'balance-xor',
1981 'broadcast', '802.3ad', 'balance-tlb', 'balance-alb']
1982 if not mode:
1983 return
1984 if mode not in valid_modes:
1985 raise Exception('invalid mode %s' % mode)
1986 if (self._link_cache_check([bondname, 'linkinfo', 'mode'],
1987 mode)):
1988 return
1989 if prehook:
1990 prehook(bondname)
1991 self.write_file('/sys/class/net/%s' % bondname + '/bonding/mode', mode)
1992 self._cache_update([bondname, 'linkinfo', 'mode'], mode)
1993
1994 def bond_get_mode(self, bondname):
1995 return self._link_cache_get([bondname, 'linkinfo', 'mode'])
1996
1997 def bond_get_mode_nl(self, bondname):
1998 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_MODE])
1999
2000 def bond_set_lacp_rate(self, bondname, lacp_rate, prehook=None, posthook=None):
2001 if not lacp_rate or (lacp_rate != '0' and lacp_rate != '1'):
2002 return
2003 if (self._link_cache_check([bondname, 'linkinfo', 'lacp_rate'],
2004 lacp_rate)):
2005 return
2006 if prehook:
2007 prehook(bondname)
2008 try:
2009 self.write_file('/sys/class/net/%s' % bondname +
2010 '/bonding/lacp_rate', lacp_rate)
2011 except:
2012 raise
2013 finally:
2014 if posthook:
2015 prehook(bondname)
2016 self._cache_update([bondname, 'linkinfo',
2017 'lacp_rate'], lacp_rate)
2018
2019 def bond_get_lacp_rate(self, bondname):
2020 return self._link_cache_get([bondname, 'linkinfo', 'lacp_rate'])
2021
2022 def bond_get_lacp_rate_nl(self, bondname):
2023 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_AD_LACP_RATE])
2024
2025 def bond_set_lacp_bypass_allow(self, bondname, allow, prehook=None, posthook=None):
2026 if self._link_cache_check([bondname, 'linkinfo', 'lacp_bypass'], allow):
2027 return
2028 if prehook:
2029 prehook(bondname)
2030 try:
2031 self.write_file('/sys/class/net/%s' % bondname +
2032 '/bonding/lacp_bypass', allow)
2033 except:
2034 raise
2035 finally:
2036 if posthook:
2037 posthook(bondname)
2038 self._cache_update([bondname, 'linkinfo',
2039 'lacp_bypass'], allow)
2040
2041 def bond_get_lacp_bypass_allow(self, bondname):
2042 return self._link_cache_get([bondname, 'linkinfo', 'lacp_bypass'])
2043
2044 def bond_get_lacp_bypass_allow_nl(self, bondname):
2045 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_AD_LACP_BYPASS])
2046
2047 def bond_set_min_links(self, bondname, min_links, prehook=None):
2048 if (self._link_cache_check([bondname, 'linkinfo', 'min_links'],
2049 min_links)):
2050 return
2051 if prehook:
2052 prehook(bondname)
2053 self.write_file('/sys/class/net/%s/bonding/min_links' % bondname,
2054 min_links)
2055 self._cache_update([bondname, 'linkinfo', 'min_links'], min_links)
2056
2057 def bond_get_min_links(self, bondname):
2058 return self._link_cache_get([bondname, 'linkinfo', 'min_links'])
2059
2060 def get_min_links_nl(self, bondname):
2061 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_MIN_LINKS])
2062
2063 def bond_get_ad_actor_system(self, bondname):
2064 return self._link_cache_get([bondname, 'linkinfo', 'ad_actor_system'])
2065
2066 def bond_get_ad_actor_system_nl(self, bondname):
2067 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_AD_ACTOR_SYSTEM])
2068
2069 def bond_get_ad_actor_sys_prio(self, bondname):
2070 return self._link_cache_get([bondname, 'linkinfo', 'ad_actor_sys_prio'])
2071
2072 def bond_get_ad_actor_sys_prio_nl(self, bondname):
2073 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_AD_ACTOR_SYS_PRIO])
2074
2075 def bond_get_num_unsol_na(self, bondname):
2076 return self._link_cache_get([bondname, 'linkinfo', 'num_unsol_na'])
2077
2078 def bond_get_num_unsol_na_nl(self, bondname):
2079 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_NUM_PEER_NOTIF])
2080
2081 def bond_get_num_grat_arp(self, bondname):
2082 return self._link_cache_get([bondname, 'linkinfo', 'num_grat_arp'])
2083
2084 def bond_get_num_grat_arp_nl(self, bondname):
2085 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_NUM_PEER_NOTIF])
2086
2087 def bond_get_updelay(self, bondname):
2088 return self._link_cache_get([bondname, 'linkinfo', 'updelay'])
2089
2090 def bond_get_updelay_nl(self, bondname):
2091 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_UPDELAY])
2092
2093 def bond_get_downdelay(self, bondname):
2094 return self._link_cache_get([bondname, 'linkinfo', 'downdelay'])
2095
2096 def bond_get_downdelay_nl(self, bondname):
2097 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_DOWNDELAY])
2098
2099 def bond_enslave_slave(self, bondname, slave, prehook=None, posthook=None):
2100 slaves = self._link_cache_get([bondname, 'linkinfo', 'slaves'])
2101 if slaves and slave in slaves:
2102 return
2103 if prehook:
2104 prehook(slave)
2105 self.write_file('/sys/class/net/%s' % bondname +
2106 '/bonding/slaves', '+' + slave)
2107 if posthook:
2108 posthook(slave)
2109 self._cache_update([bondname, 'linkinfo', 'slaves'], slave)
2110
2111 def bond_remove_slave(self, bondname, slave):
2112 slaves = self._link_cache_get([bondname, 'linkinfo', 'slaves'])
2113 if not slaves or slave not in slaves:
2114 return
2115 sysfs_bond_path = ('/sys/class/net/%s' % bondname +
2116 '/bonding/slaves')
2117 if not os.path.exists(sysfs_bond_path):
2118 return
2119 self.write_file(sysfs_bond_path, '-' + slave)
2120 self._cache_delete([bondname, 'linkinfo', 'slaves'], slave)
2121
2122 def bond_remove_slaves_all(self, bondname):
2123 if not self._link_cache_get([bondname, 'linkinfo', 'slaves']):
2124 return
2125 slaves = None
2126 sysfs_bond_path = ('/sys/class/net/%s' % bondname +
2127 '/bonding/slaves')
2128 try:
2129 with open(sysfs_bond_path, 'r') as f:
2130 slaves = f.readline().strip().split()
2131 except IOError, e:
2132 raise Exception('error reading slaves of bond %s (%s)' % (bondname, str(e)))
2133 for slave in slaves:
2134 self.link_down(slave)
2135 try:
2136 self.bond_remove_slave(bondname, slave)
2137 except Exception, e:
2138 if not ifupdownflags.flags.FORCE:
2139 raise Exception('error removing slave %s from bond %s (%s)' % (slave, bondname, str(e)))
2140 else:
2141 pass
2142 self._cache_delete([bondname, 'linkinfo', 'slaves'])
2143
2144 @staticmethod
2145 def bond_load_bonding_module():
2146 return utils.exec_command('%s -q bonding' % utils.modprobe_cmd)
2147
2148 def create_bond(self, bondname):
2149 if self.bond_exists(bondname):
2150 return
2151 # load_bonding_module() has already been run
2152 self.write_file('/sys/class/net/bonding_masters', '+' + bondname)
2153 self._cache_update([bondname], {})
2154
2155 def delete_bond(self, bondname):
2156 if not os.path.exists('/sys/class/net/%s' % bondname):
2157 return
2158 self.write_file('/sys/class/net/bonding_masters', '-' + bondname)
2159 self._cache_delete([bondname])
2160
2161 def bond_get_slaves(self, bondname):
2162 slaves = self._link_cache_get([bondname, 'linkinfo', 'slaves'])
2163 if slaves:
2164 return list(slaves)
2165 slavefile = '/sys/class/net/%s/bonding/slaves' % bondname
2166 if os.path.exists(slavefile):
2167 buf = self.read_file_oneline(slavefile)
2168 if buf:
2169 slaves = buf.split()
2170 if not slaves:
2171 return []
2172 self._cache_update([bondname, 'linkinfo', 'slaves'], slaves)
2173 return list(slaves)
2174
2175 def bond_slave_exists(self, bond, slave):
2176 slaves = self.bond_get_slaves(bond)
2177 if not slaves:
2178 return False
2179 return slave in slaves
2180
2181 @staticmethod
2182 def bond_exists(bondname):
2183 return os.path.exists('/sys/class/net/%s/bonding' % bondname)
2184
2185 #################################################################################
2186 ################################## BRIDGE UTILS #################################
2187 #################################################################################
2188
2189 def create_bridge(self, bridgename):
2190 if not LinkUtils.bridge_utils_is_installed:
2191 return
2192 if self.bridge_exists(bridgename):
2193 return
2194 utils.exec_command('%s addbr %s' % (utils.brctl_cmd, bridgename))
2195 self._cache_update([bridgename], {})
2196
2197 def delete_bridge(self, bridgename):
2198 if not LinkUtils.bridge_utils_is_installed:
2199 return
2200 if not self.bridge_exists(bridgename):
2201 return
2202 utils.exec_command('%s delbr %s' % (utils.brctl_cmd, bridgename))
2203 self._cache_invalidate()
2204
2205 def add_bridge_port(self, bridgename, bridgeportname):
2206 """ Add port to bridge """
2207 if not LinkUtils.bridge_utils_is_installed:
2208 return
2209 ports = self._link_cache_get([bridgename, 'linkinfo', 'ports'])
2210 if ports and ports.get(bridgeportname):
2211 return
2212 utils.exec_command('%s addif %s %s' % (utils.brctl_cmd, bridgename, bridgeportname))
2213 self._cache_update([bridgename, 'linkinfo', 'ports', bridgeportname], {})
2214
2215 def delete_bridge_port(self, bridgename, bridgeportname):
2216 """ Delete port from bridge """
2217 if not LinkUtils.bridge_utils_is_installed:
2218 return
2219 ports = self._link_cache_get([bridgename, 'linkinfo', 'ports'])
2220 if not ports or not ports.get(bridgeportname):
2221 return
2222 utils.exec_command('%s delif %s %s' % (utils.brctl_cmd, bridgename, bridgeportname))
2223 self._cache_delete([bridgename, 'linkinfo', 'ports', 'bridgeportname'])
2224
2225 def set_bridgeport_attrs(self, bridgename, bridgeportname, attrdict):
2226 portattrs = self._link_cache_get([bridgename, 'linkinfo', 'ports', bridgeportname])
2227 if portattrs == None:
2228 portattrs = {}
2229 for k, v in attrdict.iteritems():
2230 if ifupdownflags.flags.CACHE:
2231 curval = portattrs.get(k)
2232 if curval and curval == v:
2233 continue
2234 if k == 'unicast-flood':
2235 self.write_file('/sys/class/net/%s/brport/unicast_flood' % bridgeportname, v)
2236 elif k == 'multicast-flood':
2237 self.write_file('/sys/class/net/%s/brport/multicast_flood' % bridgeportname, v)
2238 elif k == 'learning':
2239 self.write_file('/sys/class/net/%s/brport/learning' % bridgeportname, v)
2240 elif k == 'arp-nd-suppress':
2241 self.write_file('/sys/class/net/%s/brport/neigh_suppress' % bridgeportname, v)
2242 else:
2243 if not LinkUtils.bridge_utils_is_installed:
2244 continue
2245 utils.exec_command('%s set%s %s %s %s' % (utils.brctl_cmd, k, bridgename, bridgeportname, v))
2246
2247 def set_bridgeport_attr(self, bridgename, bridgeportname,
2248 attrname, attrval):
2249 if not LinkUtils.bridge_utils_is_installed:
2250 return
2251 if self._link_cache_check([bridgename, 'linkinfo', 'ports', bridgeportname, attrname], attrval):
2252 return
2253 utils.exec_command('%s set%s %s %s %s' %
2254 (utils.brctl_cmd,
2255 attrname,
2256 bridgename,
2257 bridgeportname,
2258 attrval))
2259
2260 def set_bridge_attrs(self, bridgename, attrdict):
2261 for k, v in attrdict.iteritems():
2262 if not v:
2263 continue
2264 if self._link_cache_check([bridgename, 'linkinfo', k], v):
2265 continue
2266 try:
2267 if k == 'igmp-version':
2268 self.write_file('/sys/class/net/%s/bridge/'
2269 'multicast_igmp_version' % bridgename, v)
2270 elif k == 'mld-version':
2271 self.write_file('/sys/class/net/%s/bridge/'
2272 'multicast_mld_version' % bridgename, v)
2273 elif k == 'vlan-protocol':
2274 self.write_file('/sys/class/net/%s/bridge/'
2275 'vlan_protocol' % bridgename,
2276 VlanProtocols.ETHERTYPES_TO_ID.get(v.upper(),
2277 None))
2278 elif k == 'vlan-stats':
2279 self.write_file('/sys/class/net/%s/bridge/'
2280 'vlan_stats_enabled' % bridgename, v)
2281 elif k == 'mcstats':
2282 self.write_file('/sys/class/net/%s/bridge/'
2283 'multicast_stats_enabled' % bridgename, v)
2284 else:
2285 if not LinkUtils.bridge_utils_is_installed:
2286 continue
2287 cmd = ('%s set%s %s %s' %
2288 (utils.brctl_cmd, k, bridgename, v))
2289 utils.exec_command(cmd)
2290 except Exception, e:
2291 self.logger.warn('%s: %s' % (bridgename, str(e)))
2292 pass
2293
2294 def set_bridge_attr(self, bridgename, attrname, attrval):
2295 if self._link_cache_check([bridgename, 'linkinfo', attrname], attrval):
2296 return
2297 if attrname == 'igmp-version':
2298 self.write_file('/sys/class/net/%s/bridge/multicast_igmp_version'
2299 % bridgename, attrval)
2300 elif attrname == 'mld-version':
2301 self.write_file('/sys/class/net/%s/bridge/multicast_mld_version'
2302 % bridgename, attrval)
2303 elif attrname == 'vlan-protocol':
2304 self.write_file('/sys/class/net/%s/bridge/vlan_protocol'
2305 % bridgename, VlanProtocols.ETHERTYPES_TO_ID[attrval.upper()])
2306 elif attrname == 'vlan-stats':
2307 self.write_file('/sys/class/net/%s/bridge/vlan_stats_enabled'
2308 % bridgename, attrval)
2309 elif attrname == 'mcstats':
2310 self.write_file('/sys/class/net/%s/bridge/multicast_stats_enabled'
2311 % bridgename, attrval)
2312 else:
2313 if not LinkUtils.bridge_utils_is_installed:
2314 return
2315 cmd = '%s set%s %s %s' % (utils.brctl_cmd,
2316 attrname, bridgename, attrval)
2317 utils.exec_command(cmd)
2318
2319 def get_bridge_attrs(self, bridgename):
2320 attrs = self._link_cache_get([bridgename, 'linkinfo'])
2321 no_ints_attrs = {}
2322 for key, value in attrs.items():
2323 if type(key) == str:
2324 no_ints_attrs[key] = value
2325 return no_ints_attrs
2326
2327 def get_bridgeport_attrs(self, bridgename, bridgeportname):
2328 return self._link_cache_get([bridgename, 'linkinfo', 'ports',
2329 bridgeportname])
2330
2331 def get_bridgeport_attr(self, bridgename, bridgeportname, attrname):
2332 return self._link_cache_get([bridgename, 'linkinfo', 'ports',
2333 bridgeportname, attrname])
2334
2335 @staticmethod
2336 def bridge_set_stp(bridge, stp_state):
2337 if not LinkUtils.bridge_utils_is_installed:
2338 return
2339 utils.exec_command('%s stp %s %s' % (utils.brctl_cmd, bridge, stp_state))
2340
2341 def bridge_get_stp(self, bridge):
2342 sysfs_stpstate = '/sys/class/net/%s/bridge/stp_state' % bridge
2343 if not os.path.exists(sysfs_stpstate):
2344 return 'error'
2345 stpstate = self.read_file_oneline(sysfs_stpstate)
2346 if not stpstate:
2347 return 'error'
2348 try:
2349 if int(stpstate) > 0:
2350 return 'yes'
2351 elif int(stpstate) == 0:
2352 return 'no'
2353 except:
2354 return 'unknown'
2355
2356 @staticmethod
2357 def _conv_value_to_user(s):
2358 try:
2359 ret = int(s) / 100
2360 return '%d' % ret
2361 except:
2362 return None
2363
2364 def read_value_from_sysfs(self, filename, preprocess_func):
2365 value = self.read_file_oneline(filename)
2366 if not value:
2367 return None
2368 return preprocess_func(value)
2369
2370 @staticmethod
2371 def bridge_set_ageing(bridge, ageing):
2372 if not LinkUtils.bridge_utils_is_installed:
2373 return
2374 utils.exec_command('%s setageing %s %s' % (utils.brctl_cmd, bridge, ageing))
2375
2376 def bridge_get_ageing(self, bridge):
2377 return self.read_value_from_sysfs('/sys/class/net/%s/bridge/ageing_time'
2378 % bridge, self._conv_value_to_user)
2379
2380 @staticmethod
2381 def set_bridgeprio(bridge, prio):
2382 if not LinkUtils.bridge_utils_is_installed:
2383 return
2384 utils.exec_command('%s setbridgeprio %s %s' % (utils.brctl_cmd, bridge, prio))
2385
2386 def get_bridgeprio(self, bridge):
2387 return self.read_file_oneline(
2388 '/sys/class/net/%s/bridge/priority' % bridge)
2389
2390 @staticmethod
2391 def bridge_set_fd(bridge, fd):
2392 if not LinkUtils.bridge_utils_is_installed:
2393 return
2394 utils.exec_command('%s setfd %s %s' % (utils.brctl_cmd, bridge, fd))
2395
2396 def bridge_get_fd(self, bridge):
2397 return self.read_value_from_sysfs(
2398 '/sys/class/net/%s/bridge/forward_delay'
2399 % bridge, self._conv_value_to_user)
2400
2401 def bridge_set_gcint(self, bridge, gcint):
2402 raise Exception('set_gcint not implemented')
2403
2404 @staticmethod
2405 def bridge_set_hello(bridge, hello):
2406 if not LinkUtils.bridge_utils_is_installed:
2407 return
2408 utils.exec_command('%s sethello %s %s' % (utils.brctl_cmd, bridge, hello))
2409
2410 def bridge_get_hello(self, bridge):
2411 return self.read_value_from_sysfs('/sys/class/net/%s/bridge/hello_time'
2412 % bridge, self._conv_value_to_user)
2413
2414 @staticmethod
2415 def bridge_set_maxage(bridge, maxage):
2416 if not LinkUtils.bridge_utils_is_installed:
2417 return
2418 utils.exec_command('%s setmaxage %s %s' % (utils.brctl_cmd, bridge, maxage))
2419
2420 def bridge_get_maxage(self, bridge):
2421 return self.read_value_from_sysfs('/sys/class/net/%s/bridge/max_age'
2422 % bridge, self._conv_value_to_user)
2423
2424 @staticmethod
2425 def bridge_set_pathcost(bridge, port, pathcost):
2426 if not LinkUtils.bridge_utils_is_installed:
2427 return
2428 utils.exec_command('%s setpathcost %s %s %s' % (utils.brctl_cmd, bridge, port, pathcost))
2429
2430 def bridge_get_pathcost(self, bridge, port):
2431 return self.read_file_oneline('/sys/class/net/%s/brport/path_cost'
2432 % port)
2433
2434 @staticmethod
2435 def bridge_set_portprio(bridge, port, prio):
2436 if not LinkUtils.bridge_utils_is_installed:
2437 return
2438 utils.exec_command('%s setportprio %s %s %s' % (utils.brctl_cmd, bridge, port, prio))
2439
2440 def bridge_get_portprio(self, bridge, port):
2441 return self.read_file_oneline('/sys/class/net/%s/brport/priority'
2442 % port)
2443
2444 @staticmethod
2445 def bridge_set_hashmax(bridge, hashmax):
2446 if not LinkUtils.bridge_utils_is_installed:
2447 return
2448 utils.exec_command('%s sethashmax %s %s' % (utils.brctl_cmd, bridge, hashmax))
2449
2450 def bridge_get_hashmax(self, bridge):
2451 return self.read_file_oneline('/sys/class/net/%s/bridge/hash_max'
2452 % bridge)
2453
2454 @staticmethod
2455 def bridge_set_hashel(bridge, hashel):
2456 if not LinkUtils.bridge_utils_is_installed:
2457 return
2458 utils.exec_command('%s sethashel %s %s' % (utils.brctl_cmd, bridge, hashel))
2459
2460 def bridge_get_hashel(self, bridge):
2461 return self.read_file_oneline('/sys/class/net/%s/bridge/hash_elasticity'
2462 % bridge)
2463
2464 @staticmethod
2465 def bridge_set_mclmc(bridge, mclmc):
2466 if not LinkUtils.bridge_utils_is_installed:
2467 return
2468 utils.exec_command('%s setmclmc %s %s' % (utils.brctl_cmd, bridge, mclmc))
2469
2470 def bridge_get_mclmc(self, bridge):
2471 return self.read_file_oneline(
2472 '/sys/class/net/%s/bridge/multicast_last_member_count'
2473 % bridge)
2474
2475 @staticmethod
2476 def bridge_set_mcrouter(bridge, mcrouter):
2477 if not LinkUtils.bridge_utils_is_installed:
2478 return
2479 utils.exec_command('%s setmcrouter %s %s' % (utils.brctl_cmd, bridge, mcrouter))
2480
2481 def bridge_get_mcrouter(self, bridge):
2482 return self.read_file_oneline(
2483 '/sys/class/net/%s/bridge/multicast_router' % bridge)
2484
2485 @staticmethod
2486 def bridge_set_mcsnoop(bridge, mcsnoop):
2487 if not LinkUtils.bridge_utils_is_installed:
2488 return
2489 utils.exec_command('%s setmcsnoop %s %s' % (utils.brctl_cmd, bridge, mcsnoop))
2490
2491 def bridge_get_mcsnoop(self, bridge):
2492 return self.read_file_oneline(
2493 '/sys/class/net/%s/bridge/multicast_snooping' % bridge)
2494
2495 @staticmethod
2496 def bridge_set_mcsqc(bridge, mcsqc):
2497 if not LinkUtils.bridge_utils_is_installed:
2498 return
2499 utils.exec_command('%s setmcsqc %s %s' % (utils.brctl_cmd, bridge, mcsqc))
2500
2501 def bridge_get_mcsqc(self, bridge):
2502 return self.read_file_oneline(
2503 '/sys/class/net/%s/bridge/multicast_startup_query_count'
2504 % bridge)
2505
2506 @staticmethod
2507 def bridge_set_mcqifaddr(bridge, mcqifaddr):
2508 if not LinkUtils.bridge_utils_is_installed:
2509 return
2510 utils.exec_command('%s setmcqifaddr %s %s' % (utils.brctl_cmd, bridge, mcqifaddr))
2511
2512 def bridge_get_mcqifaddr(self, bridge):
2513 return self.read_file_oneline(
2514 '/sys/class/net/%s/bridge/multicast_startup_query_use_ifaddr'
2515 % bridge)
2516
2517 @staticmethod
2518 def bridge_set_mcquerier(bridge, mcquerier):
2519 if not LinkUtils.bridge_utils_is_installed:
2520 return
2521 utils.exec_command('%s setmcquerier %s %s' % (utils.brctl_cmd, bridge, mcquerier))
2522
2523 def bridge_get_mcquerier(self, bridge):
2524 return self.read_file_oneline(
2525 '/sys/class/net/%s/bridge/multicast_querier' % bridge)
2526
2527 def bridge_set_mcqv4src(self, bridge, vlan, mcquerier):
2528 try:
2529 vlan = int(vlan)
2530 except:
2531 self.logger.info('%s: set mcqv4src vlan: invalid parameter %s: %s' %(bridge, vlan, str(e)))
2532 return
2533 if vlan == 0 or vlan > 4095:
2534 self.logger.warn('mcqv4src vlan \'%d\' invalid range' % vlan)
2535 return
2536
2537 ip = mcquerier.split('.')
2538 if len(ip) != 4:
2539 self.logger.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier)
2540 return
2541 for k in ip:
2542 if not k.isdigit() or int(k, 10) < 0 or int(k, 10) > 255:
2543 self.logger.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier)
2544 return
2545
2546 if not LinkUtils.bridge_utils_is_installed:
2547 return
2548
2549 utils.exec_command('%s setmcqv4src %s %d %s' %
2550 (utils.brctl_cmd, bridge, vlan, mcquerier))
2551
2552 def bridge_del_mcqv4src(self, bridge, vlan):
2553 if not LinkUtils.bridge_utils_is_installed:
2554 return
2555 try:
2556 vlan = int(vlan)
2557 except:
2558 self.logger.info('%s: del mcqv4src vlan: invalid parameter %s: %s' %(bridge, vlan, str(e)))
2559 return
2560 utils.exec_command('%s delmcqv4src %s %d' % (utils.brctl_cmd, bridge, vlan))
2561
2562 def bridge_get_mcqv4src(self, bridge, vlan=None):
2563 if not LinkUtils.bridge_utils_is_installed:
2564 return {}
2565 if not self.supported_command['showmcqv4src']:
2566 return {}
2567 mcqv4src = {}
2568 try:
2569 mcqout = utils.exec_command('%s showmcqv4src %s' %
2570 (utils.brctl_cmd, bridge))
2571 except Exception as e:
2572 s = str(e).lower()
2573 if 'never heard' in s:
2574 msg = ('%s showmcqv4src: skipping unsupported command'
2575 % utils.brctl_cmd)
2576 self.logger.info(msg)
2577 self.supported_command['showmcqv4src'] = False
2578 return {}
2579 raise
2580 if not mcqout:
2581 return {}
2582 mcqlines = mcqout.splitlines()
2583 for l in mcqlines[1:]:
2584 l = l.strip()
2585 k, d, v = l.split('\t')
2586 if not k or not v:
2587 continue
2588 mcqv4src[k] = v
2589 if vlan:
2590 return mcqv4src.get(vlan)
2591 return mcqv4src
2592
2593 @staticmethod
2594 def bridge_set_mclmi(bridge, mclmi):
2595 if not LinkUtils.bridge_utils_is_installed:
2596 return
2597 utils.exec_command('%s setmclmi %s %s' % (utils.brctl_cmd, bridge, mclmi))
2598
2599 def bridge_get_mclmi(self, bridge):
2600 return self.read_file_oneline(
2601 '/sys/class/net/%s/bridge/multicast_last_member_interval'
2602 % bridge)
2603
2604 @staticmethod
2605 def bridge_set_mcmi(bridge, mcmi):
2606 if not LinkUtils.bridge_utils_is_installed:
2607 return
2608 utils.exec_command('%s setmcmi %s %s' % (utils.brctl_cmd, bridge, mcmi))
2609
2610 def bridge_get_mcmi(self, bridge):
2611 return self.read_file_oneline(
2612 '/sys/class/net/%s/bridge/multicast_membership_interval'
2613 % bridge)
2614
2615 @staticmethod
2616 def bridge_exists(bridge):
2617 return os.path.exists('/sys/class/net/%s/bridge' % bridge)
2618
2619 @staticmethod
2620 def is_bridge_port(ifacename):
2621 return os.path.exists('/sys/class/net/%s/brport' % ifacename)
2622
2623 @staticmethod
2624 def bridge_port_exists(bridge, bridgeportname):
2625 try:
2626 return os.path.exists('/sys/class/net/%s/brif/%s' % (bridge, bridgeportname))
2627 except:
2628 return False
2629
2630 @staticmethod
2631 def get_bridge_ports(bridgename):
2632 try:
2633 return os.listdir('/sys/class/net/%s/brif/' % bridgename)
2634 except:
2635 return []
2636
2637 def ipv6_addrgen(self, ifname, addrgen):
2638 cmd = 'link set dev %s addrgenmode %s' % (ifname, 'eui64' if addrgen else 'none')
2639
2640 is_link_up = self.is_link_up(ifname)
2641
2642 if is_link_up:
2643 self.link_down(ifname)
2644
2645 if LinkUtils.ipbatch:
2646 self.add_to_batch(cmd)
2647 else:
2648 utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
2649
2650 if is_link_up:
2651 self.link_up(ifname)