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