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