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