]> git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdown2/ifupdownaddons/LinkUtils.py
addons: tunnel: fix tunnel v4 to v6 change
[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
1262 cmd = ''
1263 if '6' in mode:
1264 cmd = ' -6 '
1265
1266 cmd += 'tunnel add'
1267 cmd += ' %s mode %s' %(tunnelname, mode)
1268 if attrs:
1269 for k, v in attrs.iteritems():
1270 cmd += ' %s' %k
1271 if v:
1272 cmd += ' %s' %v
1273 if self.ipbatch and not self.ipbatch_pause:
1274 self.add_to_batch(cmd)
1275 else:
1276 utils.exec_command('ip %s' % cmd)
1277 self._cache_update([tunnelname], {})
1278
1279 def tunnel_change(self, tunnelname, attrs={}):
1280 """ tunnel change function """
1281 if not self.link_exists(tunnelname):
1282 return
1283 cmd = 'tunnel change'
1284 cmd += ' %s' %(tunnelname)
1285 if attrs:
1286 for k, v in attrs.iteritems():
1287 cmd += ' %s' %k
1288 if v:
1289 cmd += ' %s' %v
1290 if self.ipbatch and not self.ipbatch_pause:
1291 self.add_to_batch(cmd)
1292 else:
1293 utils.exec_command('ip %s' % cmd)
1294 self._cache_update([tunnelname], {})
1295
1296 def link_create_vxlan(self, name, vxlanid,
1297 localtunnelip=None,
1298 svcnodeip=None,
1299 remoteips=None,
1300 learning='on',
1301 ageing=None,
1302 anycastip=None):
1303 if svcnodeip and remoteips:
1304 raise Exception("svcnodeip and remoteip is mutually exclusive")
1305 args = ''
1306 if svcnodeip:
1307 args += ' remote %s' % svcnodeip
1308 if ageing:
1309 args += ' ageing %s' % ageing
1310 if learning == 'off':
1311 args += ' nolearning'
1312
1313 if self.link_exists(name):
1314 cmd = 'link set dev %s type vxlan dstport %d' % (name, LinkUtils.VXLAN_UDP_PORT)
1315 vxlanattrs = self.get_vxlandev_attrs(name)
1316 # on ifreload do not overwrite anycast_ip to individual ip if clagd
1317 # has modified
1318 if vxlanattrs:
1319 running_localtunnelip = vxlanattrs.get('local')
1320 if anycastip and running_localtunnelip and anycastip == running_localtunnelip:
1321 localtunnelip = running_localtunnelip
1322 running_svcnode = vxlanattrs.get('svcnode')
1323 if running_svcnode and not svcnodeip:
1324 args += ' noremote'
1325 else:
1326 cmd = 'link add dev %s type vxlan id %s dstport %d' % (name, vxlanid, LinkUtils.VXLAN_UDP_PORT)
1327
1328 if localtunnelip:
1329 args += ' local %s' % localtunnelip
1330 cmd += args
1331
1332 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
1333 self.add_to_batch(cmd)
1334 else:
1335 utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
1336
1337 # XXX: update linkinfo correctly
1338 #self._cache_update([name], {})
1339
1340 @staticmethod
1341 def link_exists(ifacename):
1342 if ifupdownflags.flags.DRYRUN:
1343 return True
1344 return os.path.exists('/sys/class/net/%s' % ifacename)
1345
1346 def link_get_ifindex(self, ifacename):
1347 if ifupdownflags.flags.DRYRUN:
1348 return True
1349 return self.read_file_oneline('/sys/class/net/%s/ifindex' % ifacename)
1350
1351 def is_vlan_device_by_name(self, ifacename):
1352 if re.search(r'\.', ifacename):
1353 return True
1354 return False
1355
1356 @staticmethod
1357 def link_add_macvlan(ifname, macvlan_ifacename):
1358 utils.exec_commandl(['ip', 'link', 'add', 'link', ifname, 'name', macvlan_ifacename, 'type', 'macvlan', 'mode', 'private'])
1359
1360 @staticmethod
1361 def route_add(route):
1362 utils.exec_command('%s route add %s' % (utils.ip_cmd,
1363 route))
1364
1365 @staticmethod
1366 def route6_add(route):
1367 utils.exec_command('%s -6 route add %s' % (utils.ip_cmd,
1368 route))
1369
1370 def get_vlandev_attrs(self, ifacename):
1371 return (self._cache_get('link', [ifacename, 'link']),
1372 self._cache_get('link', [ifacename, 'linkinfo', 'vlanid']),
1373 self._cache_get('link', [ifacename, 'linkinfo', 'vlan_protocol']))
1374
1375 def get_vlan_protocol(self, ifacename):
1376 return self._cache_get('link', [ifacename, 'linkinfo', 'vlan_protocol'])
1377
1378 def get_vxlandev_attrs(self, ifacename):
1379 return self._cache_get('link', [ifacename, 'linkinfo'])
1380
1381 def get_vxlandev_learning(self, ifacename):
1382 return self._cache_get('link', [ifacename, 'linkinfo', Link.IFLA_VXLAN_LEARNING])
1383
1384 def set_vxlandev_learning(self, ifacename, learn):
1385 if learn == 'on':
1386 utils.exec_command('%s link set dev %s type vxlan learning' %
1387 (utils.ip_cmd, ifacename))
1388 self._cache_update([ifacename, 'linkinfo', 'learning'], 'on')
1389 else:
1390 utils.exec_command('%s link set dev %s type vxlan nolearning' %
1391 (utils.ip_cmd, ifacename))
1392 self._cache_update([ifacename, 'linkinfo', 'learning'], 'off')
1393
1394 def link_get_linkinfo_attrs(self, ifacename):
1395 return self._cache_get('link', [ifacename, 'linkinfo'])
1396
1397 def link_get_mtu(self, ifacename, refresh=False):
1398 return self._cache_get('link', [ifacename, 'mtu'], refresh=refresh)
1399
1400 def link_get_mtu_sysfs(self, ifacename):
1401 return self.read_file_oneline('/sys/class/net/%s/mtu'
1402 % ifacename)
1403
1404 def link_get_kind(self, ifacename):
1405 return self._cache_get('link', [ifacename, 'kind'])
1406
1407 def link_get_slave_kind(self, ifacename):
1408 return self._cache_get('link', [ifacename, 'slave_kind'])
1409
1410 def link_get_hwaddress(self, ifacename):
1411 address = self._cache_get('link', [ifacename, 'hwaddress'])
1412 # newly created logical interface addresses dont end up in the cache
1413 # read hwaddress from sysfs file for these interfaces
1414 if not address:
1415 address = self.read_file_oneline('/sys/class/net/%s/address'
1416 % ifacename)
1417 return address
1418
1419 def link_create(self, ifacename, t, attrs={}):
1420 """ generic link_create function """
1421 if self.link_exists(ifacename):
1422 return
1423 cmd = 'link add'
1424 cmd += ' name %s type %s' % (ifacename, t)
1425 if attrs:
1426 for k, v in attrs.iteritems():
1427 cmd += ' %s' % k
1428 if v:
1429 cmd += ' %s' % v
1430 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
1431 self.add_to_batch(cmd)
1432 else:
1433 utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
1434 self._cache_update([ifacename], {})
1435
1436 def link_delete(self, ifacename):
1437 if not self.link_exists(ifacename):
1438 return
1439 cmd = 'link del %s' % ifacename
1440 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
1441 self.add_to_batch(cmd)
1442 else:
1443 utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
1444 self._cache_invalidate()
1445
1446 def link_get_master(self, ifacename):
1447 sysfs_master_path = '/sys/class/net/%s/master' % ifacename
1448 if os.path.exists(sysfs_master_path):
1449 link_path = os.readlink(sysfs_master_path)
1450 if link_path:
1451 return os.path.basename(link_path)
1452 else:
1453 return None
1454 else:
1455 return self._cache_get('link', [ifacename, 'master'])
1456
1457 def get_brport_peer_link(self, bridgename):
1458 try:
1459 return self._cache_get('link', [bridgename, 'info_slave_data', Link.IFLA_BRPORT_PEER_LINK])
1460 except:
1461 return None
1462
1463 @staticmethod
1464 def bridge_port_vids_add(bridgeportname, vids):
1465 [utils.exec_command('%s vlan add vid %s dev %s' %
1466 (utils.bridge_cmd,
1467 v, bridgeportname)) for v in vids]
1468
1469 @staticmethod
1470 def bridge_port_vids_del(bridgeportname, vids):
1471 if not vids:
1472 return
1473 [utils.exec_command('%s vlan del vid %s dev %s' %
1474 (utils.bridge_cmd,
1475 v, bridgeportname)) for v in vids]
1476
1477 @staticmethod
1478 def bridge_port_vids_flush(bridgeportname, vid):
1479 utils.exec_command('%s vlan del vid %s dev %s' %
1480 (utils.bridge_cmd,
1481 vid, bridgeportname))
1482
1483 @staticmethod
1484 def bridge_port_vids_get(bridgeportname):
1485 bridgeout = utils.exec_command('%s vlan show dev %s' %
1486 (utils.bridge_cmd,
1487 bridgeportname))
1488 if not bridgeout:
1489 return []
1490 brvlanlines = bridgeout.readlines()[2:]
1491 vids = [l.strip() for l in brvlanlines]
1492 return [v for v in vids if v]
1493
1494 @staticmethod
1495 def bridge_port_vids_get_all():
1496 brvlaninfo = {}
1497 bridgeout = utils.exec_command('%s -c vlan show'
1498 % utils.bridge_cmd)
1499 if not bridgeout:
1500 return brvlaninfo
1501 brvlanlines = bridgeout.splitlines()
1502 brportname = None
1503 for l in brvlanlines[1:]:
1504 if l and not l.startswith(' ') and not l.startswith('\t'):
1505 attrs = l.split()
1506 brportname = attrs[0].strip()
1507 brvlaninfo[brportname] = {'pvid': None, 'vlan': []}
1508 l = ' '.join(attrs[1:])
1509 if not brportname or not l:
1510 continue
1511 l = l.strip()
1512 if 'PVID' in l:
1513 brvlaninfo[brportname]['pvid'] = l.split()[0]
1514 elif 'Egress Untagged' not in l:
1515 brvlaninfo[brportname]['vlan'].append(l)
1516 return brvlaninfo
1517
1518 def bridge_port_vids_get_all_json(self):
1519 if not self.supported_command['%s -c -json vlan show'
1520 % utils.bridge_cmd]:
1521 return {}
1522 brvlaninfo = {}
1523 try:
1524 bridgeout = utils.exec_command('%s -c -json vlan show'
1525 % utils.bridge_cmd)
1526 except:
1527 self.supported_command['%s -c -json vlan show'
1528 % utils.bridge_cmd] = False
1529 self.logger.info('%s -c -json vlan show: skipping unsupported command'
1530 % utils.bridge_cmd)
1531 try:
1532 return self.get_bridge_vlan_nojson()
1533 except Exception as e:
1534 self.logger.info('bridge: get_bridge_vlan_nojson: %s' % str(e))
1535 return {}
1536
1537 if not bridgeout: return brvlaninfo
1538 try:
1539 vlan_json_dict = json.loads(bridgeout, encoding="utf-8")
1540 except Exception, e:
1541 self.logger.info('json loads failed with (%s)' % str(e))
1542 return {}
1543 return vlan_json_dict
1544
1545 @staticmethod
1546 def get_bridge_vlan_nojson():
1547 vlan_json = {}
1548 bridgeout = utils.exec_commandl([utils.bridge_cmd, '-c', 'vlan', 'show'])
1549 if bridgeout:
1550 output = [line.split('\n') for line in bridgeout.split('\n\n')]
1551 output[0] = output[0][1:]
1552 for line in output:
1553 current_swp = None
1554 if not line:
1555 continue
1556 for entry in line:
1557 if not entry:
1558 continue
1559 prefix, vlan = entry.split('\t')
1560 if prefix:
1561 current_swp = prefix
1562 vlan_json[prefix] = []
1563 v = {}
1564 vlan = vlan[1:]
1565 try:
1566 v['vlan'] = int(vlan)
1567 except:
1568 try:
1569 if '-' in vlan:
1570 start, end = vlan.split('-')
1571 if ' ' in end:
1572 end = end[0:end.index(' ')]
1573 v['vlan'] = int(start)
1574 v['vlanEnd'] = int(end)
1575 else:
1576 v['vlan'] = int(vlan[0:vlan.index(' ')])
1577 flags = []
1578 if 'PVID' in vlan:
1579 flags.append('PVID')
1580 if 'Egress Untagged' in vlan:
1581 flags.append('Egress Untagged')
1582 v['flags'] = flags
1583 except:
1584 continue
1585 vlan_json[current_swp].append(v)
1586 return vlan_json
1587
1588 def bridge_vlan_cache_get(self, ifacename, refresh=False):
1589 if not self.bridge_vlan_cache_fill_done or refresh:
1590 self.bridge_vlan_cache = self.bridge_port_vids_get_all_json()
1591 self.bridge_vlan_cache_fill_done = True
1592 return self.bridge_vlan_cache.get(ifacename, {})
1593
1594 def bridge_vlan_get_pvid(self, ifacename, refresh=False):
1595 pvid = 0
1596
1597 for vinfo in self.bridge_vlan_cache_get(ifacename, refresh):
1598 v = vinfo.get('vlan')
1599 pvid = v if 'PVID' in vinfo.get('flags', []) else 0
1600 if pvid:
1601 return pvid
1602 return pvid
1603
1604 def bridge_vlan_get_vids(self, ifacename, refresh=False):
1605 vids = []
1606
1607 for vinfo in self.bridge_vlan_cache_get(ifacename, refresh):
1608 v = vinfo.get('vlan')
1609 ispvid = True if 'PVID' in vinfo.get('flags', []) else False
1610 if ispvid:
1611 pvid = v if 'PVID' in vinfo.get('flags', []) else 0
1612 if pvid == 1:
1613 continue
1614 vEnd = vinfo.get('vlanEnd')
1615 if vEnd:
1616 vids.extend(range(v, vEnd + 1))
1617 else:
1618 vids.append(v)
1619 return vids
1620
1621 def bridge_vlan_get_vids_n_pvid(self, ifacename, refresh=False):
1622 vids = []
1623 pvid = 0
1624
1625 for vinfo in self.bridge_vlan_cache_get(ifacename, refresh):
1626 v = vinfo.get('vlan')
1627 ispvid = True if 'PVID' in vinfo.get('flags', []) else False
1628 if ispvid:
1629 pvid = v if 'PVID' in vinfo.get('flags', []) else 0
1630 vEnd = vinfo.get('vlanEnd')
1631 if vEnd:
1632 vids.extend(range(v, vEnd + 1))
1633 else:
1634 vids.append(v)
1635 return vids, pvid
1636
1637 def bridge_port_pvid_add(self, bridgeportname, pvid):
1638 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
1639 self.add_to_batch('vlan add vid %s untagged pvid dev %s' %
1640 (pvid, bridgeportname))
1641 else:
1642 utils.exec_command('%s vlan add vid %s untagged pvid dev %s' %
1643 (utils.bridge_cmd,
1644 pvid, bridgeportname))
1645
1646 def bridge_port_pvid_del(self, bridgeportname, pvid):
1647 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
1648 self.add_to_batch('vlan del vid %s untagged pvid dev %s' %
1649 (pvid, bridgeportname))
1650 else:
1651 utils.exec_command('%s vlan del vid %s untagged pvid dev %s' %
1652 (utils.bridge_cmd,
1653 pvid, bridgeportname))
1654
1655 def bridge_port_pvids_get(self, bridgeportname):
1656 return self.read_file_oneline('/sys/class/net/%s/brport/pvid'
1657 % bridgeportname)
1658
1659 def bridge_vids_add(self, bridgeportname, vids, bridge=True):
1660 target = 'self' if bridge else ''
1661 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
1662 [self.add_to_batch('vlan add vid %s dev %s %s' %
1663 (v, bridgeportname, target)) for v in vids]
1664 else:
1665 [utils.exec_command('%s vlan add vid %s dev %s %s' %
1666 (utils.bridge_cmd,
1667 v, bridgeportname, target)) for v in vids]
1668
1669 def bridge_vids_del(self, bridgeportname, vids, bridge=True):
1670 target = 'self' if bridge else ''
1671 if LinkUtils.ipbatch and not LinkUtils.ipbatch_pause:
1672 [self.add_to_batch('vlan del vid %s dev %s %s' %
1673 (v, bridgeportname, target)) for v in vids]
1674 else:
1675 [utils.exec_command('%s vlan del vid %s dev %s %s' %
1676 (utils.bridge_cmd,
1677 v, bridgeportname, target)) for v in vids]
1678
1679 @staticmethod
1680 def bridge_fdb_add(dev, address, vlan=None, bridge=True, remote=None):
1681 target = 'self' if bridge else ''
1682 vlan_str = ''
1683 if vlan:
1684 vlan_str = 'vlan %s ' % vlan
1685
1686 dst_str = ''
1687 if remote:
1688 dst_str = 'dst %s ' % remote
1689
1690 utils.exec_command('%s fdb replace %s dev %s %s %s %s' %
1691 (utils.bridge_cmd,
1692 address, dev, vlan_str, target, dst_str))
1693
1694 @staticmethod
1695 def bridge_fdb_append(dev, address, vlan=None, bridge=True, remote=None):
1696 target = 'self' if bridge else ''
1697 vlan_str = ''
1698 if vlan:
1699 vlan_str = 'vlan %s ' % vlan
1700
1701 dst_str = ''
1702 if remote:
1703 dst_str = 'dst %s ' % remote
1704
1705 utils.exec_command('%s fdb append %s dev %s %s %s %s' %
1706 (utils.bridge_cmd,
1707 address, dev, vlan_str, target, dst_str))
1708
1709 @staticmethod
1710 def bridge_fdb_del(dev, address, vlan=None, bridge=True, remote=None):
1711 target = 'self' if bridge else ''
1712 vlan_str = ''
1713 if vlan:
1714 vlan_str = 'vlan %s ' % vlan
1715
1716 dst_str = ''
1717 if remote:
1718 dst_str = 'dst %s ' % remote
1719 utils.exec_command('%s fdb del %s dev %s %s %s %s' %
1720 (utils.bridge_cmd,
1721 address, dev, vlan_str, target, dst_str))
1722
1723 def bridge_is_vlan_aware(self, bridgename):
1724 filename = '/sys/class/net/%s/bridge/vlan_filtering' % bridgename
1725 if os.path.exists(filename) and self.read_file_oneline(filename) == '1':
1726 return True
1727 return False
1728
1729 @staticmethod
1730 def bridge_port_get_bridge_name(bridgeport):
1731 filename = '/sys/class/net/%s/brport/bridge' % bridgeport
1732 try:
1733 return os.path.basename(os.readlink(filename))
1734 except:
1735 return None
1736
1737 @staticmethod
1738 def bridge_port_exists(bridge, bridgeportname):
1739 try:
1740 return os.path.exists('/sys/class/net/%s/brif/%s'
1741 % (bridge, bridgeportname))
1742 except Exception:
1743 return False
1744
1745 def bridge_fdb_show_dev(self, dev):
1746 try:
1747 fdbs = {}
1748 output = utils.exec_command('%s fdb show dev %s'
1749 % (utils.bridge_cmd, dev))
1750 if output:
1751 for fdb_entry in output.splitlines():
1752 try:
1753 entries = fdb_entry.split()
1754 fdbs.setdefault(entries[2], []).append(entries[0])
1755 except:
1756 self.logger.debug('%s: invalid fdb line \'%s\''
1757 % (dev, fdb_entry))
1758 return fdbs
1759 except Exception:
1760 return None
1761
1762 @staticmethod
1763 def is_bridge(bridge):
1764 return os.path.exists('/sys/class/net/%s/bridge' % bridge)
1765
1766 def is_link_up(self, ifacename):
1767 ret = False
1768 try:
1769 flags = self.read_file_oneline('/sys/class/net/%s/flags' % ifacename)
1770 iflags = int(flags, 16)
1771 if iflags & 0x0001:
1772 ret = True
1773 except:
1774 ret = False
1775 return ret
1776
1777 def ip_route_get_dev(self, prefix, vrf_master=None):
1778 try:
1779 if vrf_master:
1780 cmd = '%s route get %s vrf %s' % (utils.ip_cmd, prefix, vrf_master)
1781 else:
1782 cmd = '%s route get %s' % (utils.ip_cmd, prefix)
1783
1784 output = utils.exec_command(cmd)
1785 if output:
1786 rline = output.splitlines()[0]
1787 if rline:
1788 rattrs = rline.split()
1789 return rattrs[rattrs.index('dev') + 1]
1790 except Exception, e:
1791 self.logger.debug('ip_route_get_dev: failed .. %s' % str(e))
1792 return None
1793
1794 @staticmethod
1795 def link_get_lowers(ifacename):
1796 try:
1797 lowers = glob.glob("/sys/class/net/%s/lower_*" % ifacename)
1798 if not lowers:
1799 return []
1800 return [os.path.basename(l)[6:] for l in lowers]
1801 except:
1802 return []
1803
1804 @staticmethod
1805 def link_get_uppers(ifacename):
1806 try:
1807 uppers = glob.glob("/sys/class/net/%s/upper_*" % ifacename)
1808 if not uppers:
1809 return None
1810 return [os.path.basename(u)[6:] for u in uppers]
1811 except Exception:
1812 return None
1813
1814 def link_get_vrfs(self):
1815 if not LinkUtils._CACHE_FILL_DONE:
1816 self._fill_cache()
1817 return linkCache.vrfs
1818
1819 @staticmethod
1820 def cache_get_info_slave(attrlist):
1821 try:
1822 return linkCache.get_attr(attrlist)
1823 except:
1824 return None
1825
1826 def get_brport_learning(self, ifacename):
1827 learn = self.read_file_oneline('/sys/class/net/%s/brport/learning'
1828 % ifacename)
1829 if learn and learn == '1':
1830 return 'on'
1831 else:
1832 return 'off'
1833
1834 def get_brport_learning_bool(self, ifacename):
1835 return utils.get_boolean_from_string(self.read_file_oneline('/sys/class/net/%s/brport/learning' % ifacename))
1836
1837 def set_brport_learning(self, ifacename, learn):
1838 if learn == 'off':
1839 return self.write_file('/sys/class/net/%s/brport/learning'
1840 % ifacename, '0')
1841 else:
1842 return self.write_file('/sys/class/net/%s/brport/learning'
1843 % ifacename, '1')
1844
1845 #################################################################################
1846 ################################### BOND UTILS ##################################
1847 #################################################################################
1848
1849 def _link_cache_get(self, attrlist, refresh=False):
1850 return self._cache_get('link', attrlist, refresh)
1851
1852 def cache_delete(self, attrlist, value=None):
1853 return self._cache_delete(attrlist, value)
1854
1855 def link_cache_get(self, attrlist, refresh=False):
1856 return self._link_cache_get(attrlist, refresh)
1857
1858 def link_cache_check(self, attrlist, value, refresh=False):
1859 return self._link_cache_check(attrlist, value, refresh)
1860
1861 def _link_cache_check(self, attrlist, value, refresh=False):
1862 try:
1863 return self._link_cache_get(attrlist, refresh) == value
1864 except Exception, e:
1865 self.logger.debug('_cache_check(%s) : [%s]'
1866 % (str(attrlist), str(e)))
1867 pass
1868 return False
1869
1870 bondcmd_attrmap = {
1871 Link.IFLA_BOND_MODE: 'mode',
1872 Link.IFLA_BOND_MIIMON: 'miimon',
1873 Link.IFLA_BOND_USE_CARRIER: 'use_carrier',
1874 Link.IFLA_BOND_AD_LACP_RATE: 'lacp_rate',
1875 Link.IFLA_BOND_XMIT_HASH_POLICY: 'xmit_hash_policy',
1876 Link.IFLA_BOND_MIN_LINKS: 'min_links',
1877 Link.IFLA_BOND_NUM_PEER_NOTIF: 'num_grat_arp',
1878 Link.IFLA_BOND_AD_ACTOR_SYSTEM: 'ad_actor_system',
1879 Link.IFLA_BOND_AD_ACTOR_SYS_PRIO: 'ad_actor_sys_prio',
1880 Link.IFLA_BOND_AD_LACP_BYPASS: 'lacp_bypass',
1881 Link.IFLA_BOND_UPDELAY: 'updelay',
1882 Link.IFLA_BOND_DOWNDELAY: 'downdelay',
1883 }
1884
1885 def bond_set_attrs_nl(self, bondname, ifla_info_data):
1886 bond_attr_name = 'None' # for log purpose (in case an exception raised)
1887 for nl_attr, value in ifla_info_data.items():
1888 try:
1889 bond_attr_name = self.bondcmd_attrmap[nl_attr]
1890 file_path = '/sys/class/net/%s/bonding/%s' % (bondname, bond_attr_name)
1891 if os.path.exists(file_path):
1892 self.write_file(file_path, str(value))
1893 except Exception as e:
1894 exception_str = '%s: %s %s: %s' % (bondname, bond_attr_name, value, str(e))
1895 if ifupdownflags.flags.FORCE:
1896 self.logger.warning(exception_str)
1897 else:
1898 self.logger.debug(exception_str)
1899
1900 def bond_set_attrs(self, bondname, attrdict, prehook):
1901 for attrname, attrval in attrdict.items():
1902 if (self._link_cache_check([bondname, 'linkinfo',
1903 attrname], attrval)):
1904 continue
1905 if (attrname == 'mode'
1906 or attrname == 'xmit_hash_policy'
1907 or attrname == 'lacp_rate' or attrname == 'min_links'):
1908 if prehook:
1909 prehook(bondname)
1910 try:
1911 if ((attrname not in ['lacp_rate',
1912 'lacp_bypass']) or
1913 self._link_cache_check([bondname, 'linkinfo', 'mode'], '802.3ad',
1914 True)):
1915 self.write_file('/sys/class/net/%s/bonding/%s'
1916 % (bondname, attrname), attrval)
1917 except Exception, e:
1918 if ifupdownflags.flags.FORCE:
1919 self.logger.warn(str(e))
1920 pass
1921 else:
1922 raise
1923
1924 def bond_set_use_carrier(self, bondname, use_carrier):
1925 if not use_carrier or (use_carrier != '0' and use_carrier != '1'):
1926 return
1927 if (self._link_cache_check([bondname, 'linkinfo', 'use_carrier'],
1928 use_carrier)):
1929 return
1930 self.write_file('/sys/class/net/%s' % bondname +
1931 '/bonding/use_carrier', use_carrier)
1932 self._cache_update([bondname, 'linkinfo',
1933 'use_carrier'], use_carrier)
1934
1935 def bond_get_use_carrier(self, bondname):
1936 return self._link_cache_get([bondname, 'linkinfo', 'use_carrier'])
1937
1938 def bond_get_use_carrier_nl(self, bondname):
1939 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_USE_CARRIER])
1940
1941 def bond_set_xmit_hash_policy(self, bondname, hash_policy, prehook=None):
1942 valid_values = ['layer2', 'layer3+4', 'layer2+3']
1943 if not hash_policy:
1944 return
1945 if hash_policy not in valid_values:
1946 raise Exception('invalid hash policy value %s' % hash_policy)
1947 if (self._link_cache_check([bondname, 'linkinfo', 'xmit_hash_policy'],
1948 hash_policy)):
1949 return
1950 if prehook:
1951 prehook(bondname)
1952 self.write_file('/sys/class/net/%s' % bondname +
1953 '/bonding/xmit_hash_policy', hash_policy)
1954 self._cache_update([bondname, 'linkinfo', 'xmit_hash_policy'],
1955 hash_policy)
1956
1957 def bond_get_xmit_hash_policy(self, bondname):
1958 return self._link_cache_get([bondname, 'linkinfo', 'xmit_hash_policy'])
1959
1960 def bond_get_xmit_hash_policy_nl(self, bondname):
1961 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_XMIT_HASH_POLICY])
1962
1963 def bond_set_miimon(self, bondname, miimon):
1964 if (self._link_cache_check([bondname, 'linkinfo', 'miimon'],
1965 miimon)):
1966 return
1967 self.write_file('/sys/class/net/%s' % bondname +
1968 '/bonding/miimon', miimon)
1969 self._cache_update([bondname, 'linkinfo', 'miimon'], miimon)
1970
1971 def bond_get_miimon(self, bondname):
1972 return self._link_cache_get([bondname, 'linkinfo', 'miimon'])
1973
1974 def bond_get_miimon_nl(self, bondname):
1975 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_MIIMON])
1976
1977 def bond_set_mode(self, bondname, mode, prehook=None):
1978 valid_modes = ['balance-rr', 'active-backup', 'balance-xor',
1979 'broadcast', '802.3ad', 'balance-tlb', 'balance-alb']
1980 if not mode:
1981 return
1982 if mode not in valid_modes:
1983 raise Exception('invalid mode %s' % mode)
1984 if (self._link_cache_check([bondname, 'linkinfo', 'mode'],
1985 mode)):
1986 return
1987 if prehook:
1988 prehook(bondname)
1989 self.write_file('/sys/class/net/%s' % bondname + '/bonding/mode', mode)
1990 self._cache_update([bondname, 'linkinfo', 'mode'], mode)
1991
1992 def bond_get_mode(self, bondname):
1993 return self._link_cache_get([bondname, 'linkinfo', 'mode'])
1994
1995 def bond_get_mode_nl(self, bondname):
1996 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_MODE])
1997
1998 def bond_set_lacp_rate(self, bondname, lacp_rate, prehook=None, posthook=None):
1999 if not lacp_rate or (lacp_rate != '0' and lacp_rate != '1'):
2000 return
2001 if (self._link_cache_check([bondname, 'linkinfo', 'lacp_rate'],
2002 lacp_rate)):
2003 return
2004 if prehook:
2005 prehook(bondname)
2006 try:
2007 self.write_file('/sys/class/net/%s' % bondname +
2008 '/bonding/lacp_rate', lacp_rate)
2009 except:
2010 raise
2011 finally:
2012 if posthook:
2013 prehook(bondname)
2014 self._cache_update([bondname, 'linkinfo',
2015 'lacp_rate'], lacp_rate)
2016
2017 def bond_get_lacp_rate(self, bondname):
2018 return self._link_cache_get([bondname, 'linkinfo', 'lacp_rate'])
2019
2020 def bond_get_lacp_rate_nl(self, bondname):
2021 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_AD_LACP_RATE])
2022
2023 def bond_set_lacp_bypass_allow(self, bondname, allow, prehook=None, posthook=None):
2024 if self._link_cache_check([bondname, 'linkinfo', 'lacp_bypass'], allow):
2025 return
2026 if prehook:
2027 prehook(bondname)
2028 try:
2029 self.write_file('/sys/class/net/%s' % bondname +
2030 '/bonding/lacp_bypass', allow)
2031 except:
2032 raise
2033 finally:
2034 if posthook:
2035 posthook(bondname)
2036 self._cache_update([bondname, 'linkinfo',
2037 'lacp_bypass'], allow)
2038
2039 def bond_get_lacp_bypass_allow(self, bondname):
2040 return self._link_cache_get([bondname, 'linkinfo', 'lacp_bypass'])
2041
2042 def bond_get_lacp_bypass_allow_nl(self, bondname):
2043 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_AD_LACP_BYPASS])
2044
2045 def bond_set_min_links(self, bondname, min_links, prehook=None):
2046 if (self._link_cache_check([bondname, 'linkinfo', 'min_links'],
2047 min_links)):
2048 return
2049 if prehook:
2050 prehook(bondname)
2051 self.write_file('/sys/class/net/%s/bonding/min_links' % bondname,
2052 min_links)
2053 self._cache_update([bondname, 'linkinfo', 'min_links'], min_links)
2054
2055 def bond_get_min_links(self, bondname):
2056 return self._link_cache_get([bondname, 'linkinfo', 'min_links'])
2057
2058 def get_min_links_nl(self, bondname):
2059 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_MIN_LINKS])
2060
2061 def bond_get_ad_actor_system(self, bondname):
2062 return self._link_cache_get([bondname, 'linkinfo', 'ad_actor_system'])
2063
2064 def bond_get_ad_actor_system_nl(self, bondname):
2065 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_AD_ACTOR_SYSTEM])
2066
2067 def bond_get_ad_actor_sys_prio(self, bondname):
2068 return self._link_cache_get([bondname, 'linkinfo', 'ad_actor_sys_prio'])
2069
2070 def bond_get_ad_actor_sys_prio_nl(self, bondname):
2071 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_AD_ACTOR_SYS_PRIO])
2072
2073 def bond_get_num_unsol_na(self, bondname):
2074 return self._link_cache_get([bondname, 'linkinfo', 'num_unsol_na'])
2075
2076 def bond_get_num_unsol_na_nl(self, bondname):
2077 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_NUM_PEER_NOTIF])
2078
2079 def bond_get_num_grat_arp(self, bondname):
2080 return self._link_cache_get([bondname, 'linkinfo', 'num_grat_arp'])
2081
2082 def bond_get_num_grat_arp_nl(self, bondname):
2083 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_NUM_PEER_NOTIF])
2084
2085 def bond_get_updelay(self, bondname):
2086 return self._link_cache_get([bondname, 'linkinfo', 'updelay'])
2087
2088 def bond_get_updelay_nl(self, bondname):
2089 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_UPDELAY])
2090
2091 def bond_get_downdelay(self, bondname):
2092 return self._link_cache_get([bondname, 'linkinfo', 'downdelay'])
2093
2094 def bond_get_downdelay_nl(self, bondname):
2095 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_DOWNDELAY])
2096
2097 def bond_enslave_slave(self, bondname, slave, prehook=None, posthook=None):
2098 slaves = self._link_cache_get([bondname, 'linkinfo', 'slaves'])
2099 if slaves and slave in slaves:
2100 return
2101 if prehook:
2102 prehook(slave)
2103 self.write_file('/sys/class/net/%s' % bondname +
2104 '/bonding/slaves', '+' + slave)
2105 if posthook:
2106 posthook(slave)
2107 self._cache_update([bondname, 'linkinfo', 'slaves'], slave)
2108
2109 def bond_remove_slave(self, bondname, slave):
2110 slaves = self._link_cache_get([bondname, 'linkinfo', 'slaves'])
2111 if not slaves or slave not in slaves:
2112 return
2113 sysfs_bond_path = ('/sys/class/net/%s' % bondname +
2114 '/bonding/slaves')
2115 if not os.path.exists(sysfs_bond_path):
2116 return
2117 self.write_file(sysfs_bond_path, '-' + slave)
2118 self._cache_delete([bondname, 'linkinfo', 'slaves'], slave)
2119
2120 def bond_remove_slaves_all(self, bondname):
2121 if not self._link_cache_get([bondname, 'linkinfo', 'slaves']):
2122 return
2123 slaves = None
2124 sysfs_bond_path = ('/sys/class/net/%s' % bondname +
2125 '/bonding/slaves')
2126 try:
2127 with open(sysfs_bond_path, 'r') as f:
2128 slaves = f.readline().strip().split()
2129 except IOError, e:
2130 raise Exception('error reading slaves of bond %s (%s)' % (bondname, str(e)))
2131 for slave in slaves:
2132 self.link_down(slave)
2133 try:
2134 self.bond_remove_slave(bondname, slave)
2135 except Exception, e:
2136 if not ifupdownflags.flags.FORCE:
2137 raise Exception('error removing slave %s from bond %s (%s)' % (slave, bondname, str(e)))
2138 else:
2139 pass
2140 self._cache_delete([bondname, 'linkinfo', 'slaves'])
2141
2142 @staticmethod
2143 def bond_load_bonding_module():
2144 return utils.exec_command('%s -q bonding' % utils.modprobe_cmd)
2145
2146 def create_bond(self, bondname):
2147 if self.bond_exists(bondname):
2148 return
2149 # load_bonding_module() has already been run
2150 self.write_file('/sys/class/net/bonding_masters', '+' + bondname)
2151 self._cache_update([bondname], {})
2152
2153 def delete_bond(self, bondname):
2154 if not os.path.exists('/sys/class/net/%s' % bondname):
2155 return
2156 self.write_file('/sys/class/net/bonding_masters', '-' + bondname)
2157 self._cache_delete([bondname])
2158
2159 def bond_get_slaves(self, bondname):
2160 slaves = self._link_cache_get([bondname, 'linkinfo', 'slaves'])
2161 if slaves:
2162 return list(slaves)
2163 slavefile = '/sys/class/net/%s/bonding/slaves' % bondname
2164 if os.path.exists(slavefile):
2165 buf = self.read_file_oneline(slavefile)
2166 if buf:
2167 slaves = buf.split()
2168 if not slaves:
2169 return []
2170 self._cache_update([bondname, 'linkinfo', 'slaves'], slaves)
2171 return list(slaves)
2172
2173 def bond_slave_exists(self, bond, slave):
2174 slaves = self.bond_get_slaves(bond)
2175 if not slaves:
2176 return False
2177 return slave in slaves
2178
2179 @staticmethod
2180 def bond_exists(bondname):
2181 return os.path.exists('/sys/class/net/%s/bonding' % bondname)
2182
2183 #################################################################################
2184 ################################## BRIDGE UTILS #################################
2185 #################################################################################
2186
2187 def create_bridge(self, bridgename):
2188 if not LinkUtils.bridge_utils_is_installed:
2189 return
2190 if self.bridge_exists(bridgename):
2191 return
2192 utils.exec_command('%s addbr %s' % (utils.brctl_cmd, bridgename))
2193 self._cache_update([bridgename], {})
2194
2195 def delete_bridge(self, bridgename):
2196 if not LinkUtils.bridge_utils_is_installed:
2197 return
2198 if not self.bridge_exists(bridgename):
2199 return
2200 utils.exec_command('%s delbr %s' % (utils.brctl_cmd, bridgename))
2201 self._cache_invalidate()
2202
2203 def add_bridge_port(self, bridgename, bridgeportname):
2204 """ Add port to bridge """
2205 if not LinkUtils.bridge_utils_is_installed:
2206 return
2207 ports = self._link_cache_get([bridgename, 'linkinfo', 'ports'])
2208 if ports and ports.get(bridgeportname):
2209 return
2210 utils.exec_command('%s addif %s %s' % (utils.brctl_cmd, bridgename, bridgeportname))
2211 self._cache_update([bridgename, 'linkinfo', 'ports', bridgeportname], {})
2212
2213 def delete_bridge_port(self, bridgename, bridgeportname):
2214 """ Delete port from bridge """
2215 if not LinkUtils.bridge_utils_is_installed:
2216 return
2217 ports = self._link_cache_get([bridgename, 'linkinfo', 'ports'])
2218 if not ports or not ports.get(bridgeportname):
2219 return
2220 utils.exec_command('%s delif %s %s' % (utils.brctl_cmd, bridgename, bridgeportname))
2221 self._cache_delete([bridgename, 'linkinfo', 'ports', 'bridgeportname'])
2222
2223 def set_bridgeport_attrs(self, bridgename, bridgeportname, attrdict):
2224 portattrs = self._link_cache_get([bridgename, 'linkinfo', 'ports', bridgeportname])
2225 if portattrs == None:
2226 portattrs = {}
2227 for k, v in attrdict.iteritems():
2228 if ifupdownflags.flags.CACHE:
2229 curval = portattrs.get(k)
2230 if curval and curval == v:
2231 continue
2232 if k == 'unicast-flood':
2233 self.write_file('/sys/class/net/%s/brport/unicast_flood' % bridgeportname, v)
2234 elif k == 'multicast-flood':
2235 self.write_file('/sys/class/net/%s/brport/multicast_flood' % bridgeportname, v)
2236 elif k == 'learning':
2237 self.write_file('/sys/class/net/%s/brport/learning' % bridgeportname, v)
2238 elif k == 'arp-nd-suppress':
2239 self.write_file('/sys/class/net/%s/brport/neigh_suppress' % bridgeportname, v)
2240 else:
2241 if not LinkUtils.bridge_utils_is_installed:
2242 continue
2243 utils.exec_command('%s set%s %s %s %s' % (utils.brctl_cmd, k, bridgename, bridgeportname, v))
2244
2245 def set_bridgeport_attr(self, bridgename, bridgeportname,
2246 attrname, attrval):
2247 if not LinkUtils.bridge_utils_is_installed:
2248 return
2249 if self._link_cache_check([bridgename, 'linkinfo', 'ports', bridgeportname, attrname], attrval):
2250 return
2251 utils.exec_command('%s set%s %s %s %s' %
2252 (utils.brctl_cmd,
2253 attrname,
2254 bridgename,
2255 bridgeportname,
2256 attrval))
2257
2258 def set_bridge_attrs(self, bridgename, attrdict):
2259 for k, v in attrdict.iteritems():
2260 if not v:
2261 continue
2262 if self._link_cache_check([bridgename, 'linkinfo', k], v):
2263 continue
2264 try:
2265 if k == 'igmp-version':
2266 self.write_file('/sys/class/net/%s/bridge/'
2267 'multicast_igmp_version' % bridgename, v)
2268 elif k == 'mld-version':
2269 self.write_file('/sys/class/net/%s/bridge/'
2270 'multicast_mld_version' % bridgename, v)
2271 elif k == 'vlan-protocol':
2272 self.write_file('/sys/class/net/%s/bridge/'
2273 'vlan_protocol' % bridgename,
2274 VlanProtocols.ETHERTYPES_TO_ID.get(v.upper(),
2275 None))
2276 elif k == 'vlan-stats':
2277 self.write_file('/sys/class/net/%s/bridge/'
2278 'vlan_stats_enabled' % bridgename, v)
2279 elif k == 'mcstats':
2280 self.write_file('/sys/class/net/%s/bridge/'
2281 'multicast_stats_enabled' % bridgename, v)
2282 else:
2283 if not LinkUtils.bridge_utils_is_installed:
2284 continue
2285 cmd = ('%s set%s %s %s' %
2286 (utils.brctl_cmd, k, bridgename, v))
2287 utils.exec_command(cmd)
2288 except Exception, e:
2289 self.logger.warn('%s: %s' % (bridgename, str(e)))
2290 pass
2291
2292 def set_bridge_attr(self, bridgename, attrname, attrval):
2293 if self._link_cache_check([bridgename, 'linkinfo', attrname], attrval):
2294 return
2295 if attrname == 'igmp-version':
2296 self.write_file('/sys/class/net/%s/bridge/multicast_igmp_version'
2297 % bridgename, attrval)
2298 elif attrname == 'mld-version':
2299 self.write_file('/sys/class/net/%s/bridge/multicast_mld_version'
2300 % bridgename, attrval)
2301 elif attrname == 'vlan-protocol':
2302 self.write_file('/sys/class/net/%s/bridge/vlan_protocol'
2303 % bridgename, VlanProtocols.ETHERTYPES_TO_ID[attrval.upper()])
2304 elif attrname == 'vlan-stats':
2305 self.write_file('/sys/class/net/%s/bridge/vlan_stats_enabled'
2306 % bridgename, attrval)
2307 elif attrname == 'mcstats':
2308 self.write_file('/sys/class/net/%s/bridge/multicast_stats_enabled'
2309 % bridgename, attrval)
2310 else:
2311 if not LinkUtils.bridge_utils_is_installed:
2312 return
2313 cmd = '%s set%s %s %s' % (utils.brctl_cmd,
2314 attrname, bridgename, attrval)
2315 utils.exec_command(cmd)
2316
2317 def get_bridge_attrs(self, bridgename):
2318 attrs = self._link_cache_get([bridgename, 'linkinfo'])
2319 no_ints_attrs = {}
2320 for key, value in attrs.items():
2321 if type(key) == str:
2322 no_ints_attrs[key] = value
2323 return no_ints_attrs
2324
2325 def get_bridgeport_attrs(self, bridgename, bridgeportname):
2326 return self._link_cache_get([bridgename, 'linkinfo', 'ports',
2327 bridgeportname])
2328
2329 def get_bridgeport_attr(self, bridgename, bridgeportname, attrname):
2330 return self._link_cache_get([bridgename, 'linkinfo', 'ports',
2331 bridgeportname, attrname])
2332
2333 @staticmethod
2334 def bridge_set_stp(bridge, stp_state):
2335 if not LinkUtils.bridge_utils_is_installed:
2336 return
2337 utils.exec_command('%s stp %s %s' % (utils.brctl_cmd, bridge, stp_state))
2338
2339 def bridge_get_stp(self, bridge):
2340 sysfs_stpstate = '/sys/class/net/%s/bridge/stp_state' % bridge
2341 if not os.path.exists(sysfs_stpstate):
2342 return 'error'
2343 stpstate = self.read_file_oneline(sysfs_stpstate)
2344 if not stpstate:
2345 return 'error'
2346 try:
2347 if int(stpstate) > 0:
2348 return 'yes'
2349 elif int(stpstate) == 0:
2350 return 'no'
2351 except:
2352 return 'unknown'
2353
2354 @staticmethod
2355 def _conv_value_to_user(s):
2356 try:
2357 ret = int(s) / 100
2358 return '%d' % ret
2359 except:
2360 return None
2361
2362 def read_value_from_sysfs(self, filename, preprocess_func):
2363 value = self.read_file_oneline(filename)
2364 if not value:
2365 return None
2366 return preprocess_func(value)
2367
2368 @staticmethod
2369 def bridge_set_ageing(bridge, ageing):
2370 if not LinkUtils.bridge_utils_is_installed:
2371 return
2372 utils.exec_command('%s setageing %s %s' % (utils.brctl_cmd, bridge, ageing))
2373
2374 def bridge_get_ageing(self, bridge):
2375 return self.read_value_from_sysfs('/sys/class/net/%s/bridge/ageing_time'
2376 % bridge, self._conv_value_to_user)
2377
2378 @staticmethod
2379 def set_bridgeprio(bridge, prio):
2380 if not LinkUtils.bridge_utils_is_installed:
2381 return
2382 utils.exec_command('%s setbridgeprio %s %s' % (utils.brctl_cmd, bridge, prio))
2383
2384 def get_bridgeprio(self, bridge):
2385 return self.read_file_oneline(
2386 '/sys/class/net/%s/bridge/priority' % bridge)
2387
2388 @staticmethod
2389 def bridge_set_fd(bridge, fd):
2390 if not LinkUtils.bridge_utils_is_installed:
2391 return
2392 utils.exec_command('%s setfd %s %s' % (utils.brctl_cmd, bridge, fd))
2393
2394 def bridge_get_fd(self, bridge):
2395 return self.read_value_from_sysfs(
2396 '/sys/class/net/%s/bridge/forward_delay'
2397 % bridge, self._conv_value_to_user)
2398
2399 def bridge_set_gcint(self, bridge, gcint):
2400 raise Exception('set_gcint not implemented')
2401
2402 @staticmethod
2403 def bridge_set_hello(bridge, hello):
2404 if not LinkUtils.bridge_utils_is_installed:
2405 return
2406 utils.exec_command('%s sethello %s %s' % (utils.brctl_cmd, bridge, hello))
2407
2408 def bridge_get_hello(self, bridge):
2409 return self.read_value_from_sysfs('/sys/class/net/%s/bridge/hello_time'
2410 % bridge, self._conv_value_to_user)
2411
2412 @staticmethod
2413 def bridge_set_maxage(bridge, maxage):
2414 if not LinkUtils.bridge_utils_is_installed:
2415 return
2416 utils.exec_command('%s setmaxage %s %s' % (utils.brctl_cmd, bridge, maxage))
2417
2418 def bridge_get_maxage(self, bridge):
2419 return self.read_value_from_sysfs('/sys/class/net/%s/bridge/max_age'
2420 % bridge, self._conv_value_to_user)
2421
2422 @staticmethod
2423 def bridge_set_pathcost(bridge, port, pathcost):
2424 if not LinkUtils.bridge_utils_is_installed:
2425 return
2426 utils.exec_command('%s setpathcost %s %s %s' % (utils.brctl_cmd, bridge, port, pathcost))
2427
2428 def bridge_get_pathcost(self, bridge, port):
2429 return self.read_file_oneline('/sys/class/net/%s/brport/path_cost'
2430 % port)
2431
2432 @staticmethod
2433 def bridge_set_portprio(bridge, port, prio):
2434 if not LinkUtils.bridge_utils_is_installed:
2435 return
2436 utils.exec_command('%s setportprio %s %s %s' % (utils.brctl_cmd, bridge, port, prio))
2437
2438 def bridge_get_portprio(self, bridge, port):
2439 return self.read_file_oneline('/sys/class/net/%s/brport/priority'
2440 % port)
2441
2442 @staticmethod
2443 def bridge_set_hashmax(bridge, hashmax):
2444 if not LinkUtils.bridge_utils_is_installed:
2445 return
2446 utils.exec_command('%s sethashmax %s %s' % (utils.brctl_cmd, bridge, hashmax))
2447
2448 def bridge_get_hashmax(self, bridge):
2449 return self.read_file_oneline('/sys/class/net/%s/bridge/hash_max'
2450 % bridge)
2451
2452 @staticmethod
2453 def bridge_set_hashel(bridge, hashel):
2454 if not LinkUtils.bridge_utils_is_installed:
2455 return
2456 utils.exec_command('%s sethashel %s %s' % (utils.brctl_cmd, bridge, hashel))
2457
2458 def bridge_get_hashel(self, bridge):
2459 return self.read_file_oneline('/sys/class/net/%s/bridge/hash_elasticity'
2460 % bridge)
2461
2462 @staticmethod
2463 def bridge_set_mclmc(bridge, mclmc):
2464 if not LinkUtils.bridge_utils_is_installed:
2465 return
2466 utils.exec_command('%s setmclmc %s %s' % (utils.brctl_cmd, bridge, mclmc))
2467
2468 def bridge_get_mclmc(self, bridge):
2469 return self.read_file_oneline(
2470 '/sys/class/net/%s/bridge/multicast_last_member_count'
2471 % bridge)
2472
2473 @staticmethod
2474 def bridge_set_mcrouter(bridge, mcrouter):
2475 if not LinkUtils.bridge_utils_is_installed:
2476 return
2477 utils.exec_command('%s setmcrouter %s %s' % (utils.brctl_cmd, bridge, mcrouter))
2478
2479 def bridge_get_mcrouter(self, bridge):
2480 return self.read_file_oneline(
2481 '/sys/class/net/%s/bridge/multicast_router' % bridge)
2482
2483 @staticmethod
2484 def bridge_set_mcsnoop(bridge, mcsnoop):
2485 if not LinkUtils.bridge_utils_is_installed:
2486 return
2487 utils.exec_command('%s setmcsnoop %s %s' % (utils.brctl_cmd, bridge, mcsnoop))
2488
2489 def bridge_get_mcsnoop(self, bridge):
2490 return self.read_file_oneline(
2491 '/sys/class/net/%s/bridge/multicast_snooping' % bridge)
2492
2493 @staticmethod
2494 def bridge_set_mcsqc(bridge, mcsqc):
2495 if not LinkUtils.bridge_utils_is_installed:
2496 return
2497 utils.exec_command('%s setmcsqc %s %s' % (utils.brctl_cmd, bridge, mcsqc))
2498
2499 def bridge_get_mcsqc(self, bridge):
2500 return self.read_file_oneline(
2501 '/sys/class/net/%s/bridge/multicast_startup_query_count'
2502 % bridge)
2503
2504 @staticmethod
2505 def bridge_set_mcqifaddr(bridge, mcqifaddr):
2506 if not LinkUtils.bridge_utils_is_installed:
2507 return
2508 utils.exec_command('%s setmcqifaddr %s %s' % (utils.brctl_cmd, bridge, mcqifaddr))
2509
2510 def bridge_get_mcqifaddr(self, bridge):
2511 return self.read_file_oneline(
2512 '/sys/class/net/%s/bridge/multicast_startup_query_use_ifaddr'
2513 % bridge)
2514
2515 @staticmethod
2516 def bridge_set_mcquerier(bridge, mcquerier):
2517 if not LinkUtils.bridge_utils_is_installed:
2518 return
2519 utils.exec_command('%s setmcquerier %s %s' % (utils.brctl_cmd, bridge, mcquerier))
2520
2521 def bridge_get_mcquerier(self, bridge):
2522 return self.read_file_oneline(
2523 '/sys/class/net/%s/bridge/multicast_querier' % bridge)
2524
2525 def bridge_set_mcqv4src(self, bridge, vlan, mcquerier):
2526 try:
2527 vlan = int(vlan)
2528 except:
2529 self.logger.info('%s: set mcqv4src vlan: invalid parameter %s: %s' %(bridge, vlan, str(e)))
2530 return
2531 if vlan == 0 or vlan > 4095:
2532 self.logger.warn('mcqv4src vlan \'%d\' invalid range' % vlan)
2533 return
2534
2535 ip = mcquerier.split('.')
2536 if len(ip) != 4:
2537 self.logger.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier)
2538 return
2539 for k in ip:
2540 if not k.isdigit() or int(k, 10) < 0 or int(k, 10) > 255:
2541 self.logger.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier)
2542 return
2543
2544 if not LinkUtils.bridge_utils_is_installed:
2545 return
2546
2547 utils.exec_command('%s setmcqv4src %s %d %s' %
2548 (utils.brctl_cmd, bridge, vlan, mcquerier))
2549
2550 def bridge_del_mcqv4src(self, bridge, vlan):
2551 if not LinkUtils.bridge_utils_is_installed:
2552 return
2553 try:
2554 vlan = int(vlan)
2555 except:
2556 self.logger.info('%s: del mcqv4src vlan: invalid parameter %s: %s' %(bridge, vlan, str(e)))
2557 return
2558 utils.exec_command('%s delmcqv4src %s %d' % (utils.brctl_cmd, bridge, vlan))
2559
2560 def bridge_get_mcqv4src(self, bridge, vlan=None):
2561 if not LinkUtils.bridge_utils_is_installed:
2562 return {}
2563 if not self.supported_command['showmcqv4src']:
2564 return {}
2565 mcqv4src = {}
2566 try:
2567 mcqout = utils.exec_command('%s showmcqv4src %s' %
2568 (utils.brctl_cmd, bridge))
2569 except Exception as e:
2570 s = str(e).lower()
2571 if 'never heard' in s:
2572 msg = ('%s showmcqv4src: skipping unsupported command'
2573 % utils.brctl_cmd)
2574 self.logger.info(msg)
2575 self.supported_command['showmcqv4src'] = False
2576 return {}
2577 raise
2578 if not mcqout:
2579 return {}
2580 mcqlines = mcqout.splitlines()
2581 for l in mcqlines[1:]:
2582 l = l.strip()
2583 k, d, v = l.split('\t')
2584 if not k or not v:
2585 continue
2586 mcqv4src[k] = v
2587 if vlan:
2588 return mcqv4src.get(vlan)
2589 return mcqv4src
2590
2591 @staticmethod
2592 def bridge_set_mclmi(bridge, mclmi):
2593 if not LinkUtils.bridge_utils_is_installed:
2594 return
2595 utils.exec_command('%s setmclmi %s %s' % (utils.brctl_cmd, bridge, mclmi))
2596
2597 def bridge_get_mclmi(self, bridge):
2598 return self.read_file_oneline(
2599 '/sys/class/net/%s/bridge/multicast_last_member_interval'
2600 % bridge)
2601
2602 @staticmethod
2603 def bridge_set_mcmi(bridge, mcmi):
2604 if not LinkUtils.bridge_utils_is_installed:
2605 return
2606 utils.exec_command('%s setmcmi %s %s' % (utils.brctl_cmd, bridge, mcmi))
2607
2608 def bridge_get_mcmi(self, bridge):
2609 return self.read_file_oneline(
2610 '/sys/class/net/%s/bridge/multicast_membership_interval'
2611 % bridge)
2612
2613 @staticmethod
2614 def bridge_exists(bridge):
2615 return os.path.exists('/sys/class/net/%s/bridge' % bridge)
2616
2617 @staticmethod
2618 def is_bridge_port(ifacename):
2619 return os.path.exists('/sys/class/net/%s/brport' % ifacename)
2620
2621 @staticmethod
2622 def bridge_port_exists(bridge, bridgeportname):
2623 try:
2624 return os.path.exists('/sys/class/net/%s/brif/%s' % (bridge, bridgeportname))
2625 except:
2626 return False
2627
2628 @staticmethod
2629 def get_bridge_ports(bridgename):
2630 try:
2631 return os.listdir('/sys/class/net/%s/brif/' % bridgename)
2632 except:
2633 return []
2634
2635 def ipv6_addrgen(self, ifname, addrgen):
2636 cmd = 'link set dev %s addrgenmode %s' % (ifname, 'eui64' if addrgen else 'none')
2637
2638 is_link_up = self.is_link_up(ifname)
2639
2640 if is_link_up:
2641 self.link_down(ifname)
2642
2643 if LinkUtils.ipbatch:
2644 self.add_to_batch(cmd)
2645 else:
2646 utils.exec_command('%s %s' % (utils.ip_cmd, cmd))
2647
2648 if is_link_up:
2649 self.link_up(ifname)