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