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