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