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