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