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