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