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