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