]> git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdown2/ifupdownaddons/LinkUtils.py
addons: addressvirtual: if device is VRF slave check vrf route table
[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, vrf_master=None):
1691 try:
1692 if vrf_master:
1693 cmd = '%s route get %s vrf %s' % (utils.ip_cmd, prefix, vrf_master)
1694 else:
1695 cmd = '%s route get %s' % (utils.ip_cmd, prefix)
1696
1697 output = utils.exec_command(cmd)
1698 if output:
1699 rline = output.splitlines()[0]
1700 if rline:
1701 rattrs = rline.split()
1702 return rattrs[rattrs.index('dev') + 1]
1703 except Exception, e:
1704 self.logger.debug('ip_route_get_dev: failed .. %s' % str(e))
1705 return None
1706
1707 @staticmethod
1708 def link_get_lowers(ifacename):
1709 try:
1710 lowers = glob.glob("/sys/class/net/%s/lower_*" % ifacename)
1711 if not lowers:
1712 return []
1713 return [os.path.basename(l)[6:] for l in lowers]
1714 except:
1715 return []
1716
1717 @staticmethod
1718 def link_get_uppers(ifacename):
1719 try:
1720 uppers = glob.glob("/sys/class/net/%s/upper_*" % ifacename)
1721 if not uppers:
1722 return None
1723 return [os.path.basename(u)[6:] for u in uppers]
1724 except Exception:
1725 return None
1726
1727 def link_get_vrfs(self):
1728 if not LinkUtils._CACHE_FILL_DONE:
1729 self._fill_cache()
1730 return linkCache.vrfs
1731
1732 @staticmethod
1733 def cache_get_info_slave(attrlist):
1734 try:
1735 return linkCache.get_attr(attrlist)
1736 except:
1737 return None
1738
1739 def get_brport_learning(self, ifacename):
1740 learn = self.read_file_oneline('/sys/class/net/%s/brport/learning'
1741 % ifacename)
1742 if learn and learn == '1':
1743 return 'on'
1744 else:
1745 return 'off'
1746
1747 def get_brport_learning_bool(self, ifacename):
1748 return utils.get_boolean_from_string(self.read_file_oneline('/sys/class/net/%s/brport/learning' % ifacename))
1749
1750 def set_brport_learning(self, ifacename, learn):
1751 if learn == 'off':
1752 return self.write_file('/sys/class/net/%s/brport/learning'
1753 % ifacename, '0')
1754 else:
1755 return self.write_file('/sys/class/net/%s/brport/learning'
1756 % ifacename, '1')
1757
1758 #################################################################################
1759 ################################### BOND UTILS ##################################
1760 #################################################################################
1761
1762 def _link_cache_get(self, attrlist, refresh=False):
1763 return self._cache_get('link', attrlist, refresh)
1764
1765 def cache_delete(self, attrlist, value=None):
1766 return self._cache_delete(attrlist, value)
1767
1768 def link_cache_get(self, attrlist, refresh=False):
1769 return self._link_cache_get(attrlist, refresh)
1770
1771 def link_cache_check(self, attrlist, value, refresh=False):
1772 return self._link_cache_check(attrlist, value, refresh)
1773
1774 def _link_cache_check(self, attrlist, value, refresh=False):
1775 try:
1776 return self._link_cache_get(attrlist, refresh) == value
1777 except Exception, e:
1778 self.logger.debug('_cache_check(%s) : [%s]'
1779 % (str(attrlist), str(e)))
1780 pass
1781 return False
1782
1783 bondcmd_attrmap = {
1784 Link.IFLA_BOND_MODE: 'mode',
1785 Link.IFLA_BOND_MIIMON: 'miimon',
1786 Link.IFLA_BOND_USE_CARRIER: 'use_carrier',
1787 Link.IFLA_BOND_AD_LACP_RATE: 'lacp_rate',
1788 Link.IFLA_BOND_XMIT_HASH_POLICY: 'xmit_hash_policy',
1789 Link.IFLA_BOND_MIN_LINKS: 'min_links',
1790 Link.IFLA_BOND_NUM_PEER_NOTIF: 'num_grat_arp',
1791 Link.IFLA_BOND_AD_ACTOR_SYSTEM: 'ad_actor_system',
1792 Link.IFLA_BOND_AD_ACTOR_SYS_PRIO: 'ad_actor_sys_prio',
1793 Link.IFLA_BOND_AD_LACP_BYPASS: 'lacp_bypass',
1794 Link.IFLA_BOND_UPDELAY: 'updelay',
1795 Link.IFLA_BOND_DOWNDELAY: 'downdelay',
1796 }
1797
1798 def bond_set_attrs_nl(self, bondname, ifla_info_data):
1799 bond_attr_name = 'None' # for log purpose (in case an exception raised)
1800 for nl_attr, value in ifla_info_data.items():
1801 try:
1802 bond_attr_name = self.bondcmd_attrmap[nl_attr]
1803 file_path = '/sys/class/net/%s/bonding/%s' % (bondname, bond_attr_name)
1804 if os.path.exists(file_path):
1805 self.write_file(file_path, str(value))
1806 except Exception as e:
1807 exception_str = '%s: %s %s: %s' % (bondname, bond_attr_name, value, str(e))
1808 if ifupdownflags.flags.FORCE:
1809 self.logger.warning(exception_str)
1810 else:
1811 self.logger.debug(exception_str)
1812
1813 def bond_set_attrs(self, bondname, attrdict, prehook):
1814 for attrname, attrval in attrdict.items():
1815 if (self._link_cache_check([bondname, 'linkinfo',
1816 attrname], attrval)):
1817 continue
1818 if (attrname == 'mode'
1819 or attrname == 'xmit_hash_policy'
1820 or attrname == 'lacp_rate' or attrname == 'min_links'):
1821 if prehook:
1822 prehook(bondname)
1823 try:
1824 if ((attrname not in ['lacp_rate',
1825 'lacp_bypass']) or
1826 self._link_cache_check([bondname, 'linkinfo', 'mode'], '802.3ad',
1827 True)):
1828 self.write_file('/sys/class/net/%s/bonding/%s'
1829 % (bondname, attrname), attrval)
1830 except Exception, e:
1831 if ifupdownflags.flags.FORCE:
1832 self.logger.warn(str(e))
1833 pass
1834 else:
1835 raise
1836
1837 def bond_set_use_carrier(self, bondname, use_carrier):
1838 if not use_carrier or (use_carrier != '0' and use_carrier != '1'):
1839 return
1840 if (self._link_cache_check([bondname, 'linkinfo', 'use_carrier'],
1841 use_carrier)):
1842 return
1843 self.write_file('/sys/class/net/%s' % bondname +
1844 '/bonding/use_carrier', use_carrier)
1845 self._cache_update([bondname, 'linkinfo',
1846 'use_carrier'], use_carrier)
1847
1848 def bond_get_use_carrier(self, bondname):
1849 return self._link_cache_get([bondname, 'linkinfo', 'use_carrier'])
1850
1851 def bond_get_use_carrier_nl(self, bondname):
1852 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_USE_CARRIER])
1853
1854 def bond_set_xmit_hash_policy(self, bondname, hash_policy, prehook=None):
1855 valid_values = ['layer2', 'layer3+4', 'layer2+3']
1856 if not hash_policy:
1857 return
1858 if hash_policy not in valid_values:
1859 raise Exception('invalid hash policy value %s' % hash_policy)
1860 if (self._link_cache_check([bondname, 'linkinfo', 'xmit_hash_policy'],
1861 hash_policy)):
1862 return
1863 if prehook:
1864 prehook(bondname)
1865 self.write_file('/sys/class/net/%s' % bondname +
1866 '/bonding/xmit_hash_policy', hash_policy)
1867 self._cache_update([bondname, 'linkinfo', 'xmit_hash_policy'],
1868 hash_policy)
1869
1870 def bond_get_xmit_hash_policy(self, bondname):
1871 return self._link_cache_get([bondname, 'linkinfo', 'xmit_hash_policy'])
1872
1873 def bond_get_xmit_hash_policy_nl(self, bondname):
1874 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_XMIT_HASH_POLICY])
1875
1876 def bond_set_miimon(self, bondname, miimon):
1877 if (self._link_cache_check([bondname, 'linkinfo', 'miimon'],
1878 miimon)):
1879 return
1880 self.write_file('/sys/class/net/%s' % bondname +
1881 '/bonding/miimon', miimon)
1882 self._cache_update([bondname, 'linkinfo', 'miimon'], miimon)
1883
1884 def bond_get_miimon(self, bondname):
1885 return self._link_cache_get([bondname, 'linkinfo', 'miimon'])
1886
1887 def bond_get_miimon_nl(self, bondname):
1888 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_MIIMON])
1889
1890 def bond_set_mode(self, bondname, mode, prehook=None):
1891 valid_modes = ['balance-rr', 'active-backup', 'balance-xor',
1892 'broadcast', '802.3ad', 'balance-tlb', 'balance-alb']
1893 if not mode:
1894 return
1895 if mode not in valid_modes:
1896 raise Exception('invalid mode %s' % mode)
1897 if (self._link_cache_check([bondname, 'linkinfo', 'mode'],
1898 mode)):
1899 return
1900 if prehook:
1901 prehook(bondname)
1902 self.write_file('/sys/class/net/%s' % bondname + '/bonding/mode', mode)
1903 self._cache_update([bondname, 'linkinfo', 'mode'], mode)
1904
1905 def bond_get_mode(self, bondname):
1906 return self._link_cache_get([bondname, 'linkinfo', 'mode'])
1907
1908 def bond_get_mode_nl(self, bondname):
1909 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_MODE])
1910
1911 def bond_set_lacp_rate(self, bondname, lacp_rate, prehook=None, posthook=None):
1912 if not lacp_rate or (lacp_rate != '0' and lacp_rate != '1'):
1913 return
1914 if (self._link_cache_check([bondname, 'linkinfo', 'lacp_rate'],
1915 lacp_rate)):
1916 return
1917 if prehook:
1918 prehook(bondname)
1919 try:
1920 self.write_file('/sys/class/net/%s' % bondname +
1921 '/bonding/lacp_rate', lacp_rate)
1922 except:
1923 raise
1924 finally:
1925 if posthook:
1926 prehook(bondname)
1927 self._cache_update([bondname, 'linkinfo',
1928 'lacp_rate'], lacp_rate)
1929
1930 def bond_get_lacp_rate(self, bondname):
1931 return self._link_cache_get([bondname, 'linkinfo', 'lacp_rate'])
1932
1933 def bond_get_lacp_rate_nl(self, bondname):
1934 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_AD_LACP_RATE])
1935
1936 def bond_set_lacp_bypass_allow(self, bondname, allow, prehook=None, posthook=None):
1937 if self._link_cache_check([bondname, 'linkinfo', 'lacp_bypass'], allow):
1938 return
1939 if prehook:
1940 prehook(bondname)
1941 try:
1942 self.write_file('/sys/class/net/%s' % bondname +
1943 '/bonding/lacp_bypass', allow)
1944 except:
1945 raise
1946 finally:
1947 if posthook:
1948 posthook(bondname)
1949 self._cache_update([bondname, 'linkinfo',
1950 'lacp_bypass'], allow)
1951
1952 def bond_get_lacp_bypass_allow(self, bondname):
1953 return self._link_cache_get([bondname, 'linkinfo', 'lacp_bypass'])
1954
1955 def bond_get_lacp_bypass_allow_nl(self, bondname):
1956 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_AD_LACP_BYPASS])
1957
1958 def bond_set_min_links(self, bondname, min_links, prehook=None):
1959 if (self._link_cache_check([bondname, 'linkinfo', 'min_links'],
1960 min_links)):
1961 return
1962 if prehook:
1963 prehook(bondname)
1964 self.write_file('/sys/class/net/%s/bonding/min_links' % bondname,
1965 min_links)
1966 self._cache_update([bondname, 'linkinfo', 'min_links'], min_links)
1967
1968 def bond_get_min_links(self, bondname):
1969 return self._link_cache_get([bondname, 'linkinfo', 'min_links'])
1970
1971 def get_min_links_nl(self, bondname):
1972 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_MIN_LINKS])
1973
1974 def bond_get_ad_actor_system(self, bondname):
1975 return self._link_cache_get([bondname, 'linkinfo', 'ad_actor_system'])
1976
1977 def bond_get_ad_actor_system_nl(self, bondname):
1978 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_AD_ACTOR_SYSTEM])
1979
1980 def bond_get_ad_actor_sys_prio(self, bondname):
1981 return self._link_cache_get([bondname, 'linkinfo', 'ad_actor_sys_prio'])
1982
1983 def bond_get_ad_actor_sys_prio_nl(self, bondname):
1984 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_AD_ACTOR_SYS_PRIO])
1985
1986 def bond_get_num_unsol_na(self, bondname):
1987 return self._link_cache_get([bondname, 'linkinfo', 'num_unsol_na'])
1988
1989 def bond_get_num_unsol_na_nl(self, bondname):
1990 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_NUM_PEER_NOTIF])
1991
1992 def bond_get_num_grat_arp(self, bondname):
1993 return self._link_cache_get([bondname, 'linkinfo', 'num_grat_arp'])
1994
1995 def bond_get_num_grat_arp_nl(self, bondname):
1996 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_NUM_PEER_NOTIF])
1997
1998 def bond_get_updelay(self, bondname):
1999 return self._link_cache_get([bondname, 'linkinfo', 'updelay'])
2000
2001 def bond_get_updelay_nl(self, bondname):
2002 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_UPDELAY])
2003
2004 def bond_get_downdelay(self, bondname):
2005 return self._link_cache_get([bondname, 'linkinfo', 'downdelay'])
2006
2007 def bond_get_downdelay_nl(self, bondname):
2008 return self._link_cache_get([bondname, 'linkinfo', Link.IFLA_BOND_DOWNDELAY])
2009
2010 def bond_enslave_slave(self, bondname, slave, prehook=None, posthook=None):
2011 slaves = self._link_cache_get([bondname, 'linkinfo', 'slaves'])
2012 if slaves and slave in slaves:
2013 return
2014 if prehook:
2015 prehook(slave)
2016 self.write_file('/sys/class/net/%s' % bondname +
2017 '/bonding/slaves', '+' + slave)
2018 if posthook:
2019 posthook(slave)
2020 self._cache_update([bondname, 'linkinfo', 'slaves'], slave)
2021
2022 def bond_remove_slave(self, bondname, slave):
2023 slaves = self._link_cache_get([bondname, 'linkinfo', 'slaves'])
2024 if not slaves or slave not in slaves:
2025 return
2026 sysfs_bond_path = ('/sys/class/net/%s' % bondname +
2027 '/bonding/slaves')
2028 if not os.path.exists(sysfs_bond_path):
2029 return
2030 self.write_file(sysfs_bond_path, '-' + slave)
2031 self._cache_delete([bondname, 'linkinfo', 'slaves'], slave)
2032
2033 def bond_remove_slaves_all(self, bondname):
2034 if not self._link_cache_get([bondname, 'linkinfo', 'slaves']):
2035 return
2036 slaves = None
2037 sysfs_bond_path = ('/sys/class/net/%s' % bondname +
2038 '/bonding/slaves')
2039 try:
2040 with open(sysfs_bond_path, 'r') as f:
2041 slaves = f.readline().strip().split()
2042 except IOError, e:
2043 raise Exception('error reading slaves of bond %s (%s)' % (bondname, str(e)))
2044 for slave in slaves:
2045 self.link_down(slave)
2046 try:
2047 self.bond_remove_slave(bondname, slave)
2048 except Exception, e:
2049 if not ifupdownflags.flags.FORCE:
2050 raise Exception('error removing slave %s from bond %s (%s)' % (slave, bondname, str(e)))
2051 else:
2052 pass
2053 self._cache_delete([bondname, 'linkinfo', 'slaves'])
2054
2055 @staticmethod
2056 def bond_load_bonding_module():
2057 return utils.exec_command('%s -q bonding' % utils.modprobe_cmd)
2058
2059 def create_bond(self, bondname):
2060 if self.bond_exists(bondname):
2061 return
2062 # load_bonding_module() has already been run
2063 self.write_file('/sys/class/net/bonding_masters', '+' + bondname)
2064 self._cache_update([bondname], {})
2065
2066 def delete_bond(self, bondname):
2067 if not os.path.exists('/sys/class/net/%s' % bondname):
2068 return
2069 self.write_file('/sys/class/net/bonding_masters', '-' + bondname)
2070 self._cache_delete([bondname])
2071
2072 def bond_get_slaves(self, bondname):
2073 slaves = self._link_cache_get([bondname, 'linkinfo', 'slaves'])
2074 if slaves:
2075 return list(slaves)
2076 slavefile = '/sys/class/net/%s/bonding/slaves' % bondname
2077 if os.path.exists(slavefile):
2078 buf = self.read_file_oneline(slavefile)
2079 if buf:
2080 slaves = buf.split()
2081 if not slaves:
2082 return []
2083 self._cache_update([bondname, 'linkinfo', 'slaves'], slaves)
2084 return list(slaves)
2085
2086 def bond_slave_exists(self, bond, slave):
2087 slaves = self.bond_get_slaves(bond)
2088 if not slaves:
2089 return False
2090 return slave in slaves
2091
2092 @staticmethod
2093 def bond_exists(bondname):
2094 return os.path.exists('/sys/class/net/%s/bonding' % bondname)
2095
2096 #################################################################################
2097 ################################## BRIDGE UTILS #################################
2098 #################################################################################
2099
2100 def create_bridge(self, bridgename):
2101 if not LinkUtils.bridge_utils_is_installed:
2102 return
2103 if self.bridge_exists(bridgename):
2104 return
2105 utils.exec_command('%s addbr %s' % (utils.brctl_cmd, bridgename))
2106 self._cache_update([bridgename], {})
2107
2108 def delete_bridge(self, bridgename):
2109 if not LinkUtils.bridge_utils_is_installed:
2110 return
2111 if not self.bridge_exists(bridgename):
2112 return
2113 utils.exec_command('%s delbr %s' % (utils.brctl_cmd, bridgename))
2114 self._cache_invalidate()
2115
2116 def add_bridge_port(self, bridgename, bridgeportname):
2117 """ Add port to bridge """
2118 if not LinkUtils.bridge_utils_is_installed:
2119 return
2120 ports = self._link_cache_get([bridgename, 'linkinfo', 'ports'])
2121 if ports and ports.get(bridgeportname):
2122 return
2123 utils.exec_command('%s addif %s %s' % (utils.brctl_cmd, bridgename, bridgeportname))
2124 self._cache_update([bridgename, 'linkinfo', 'ports', bridgeportname], {})
2125
2126 def delete_bridge_port(self, bridgename, bridgeportname):
2127 """ Delete port from bridge """
2128 if not LinkUtils.bridge_utils_is_installed:
2129 return
2130 ports = self._link_cache_get([bridgename, 'linkinfo', 'ports'])
2131 if not ports or not ports.get(bridgeportname):
2132 return
2133 utils.exec_command('%s delif %s %s' % (utils.brctl_cmd, bridgename, bridgeportname))
2134 self._cache_delete([bridgename, 'linkinfo', 'ports', 'bridgeportname'])
2135
2136 def set_bridgeport_attrs(self, bridgename, bridgeportname, attrdict):
2137 portattrs = self._link_cache_get([bridgename, 'linkinfo', 'ports', bridgeportname])
2138 if portattrs == None:
2139 portattrs = {}
2140 for k, v in attrdict.iteritems():
2141 if ifupdownflags.flags.CACHE:
2142 curval = portattrs.get(k)
2143 if curval and curval == v:
2144 continue
2145 if k == 'unicast-flood':
2146 self.write_file('/sys/class/net/%s/brport/unicast_flood' % bridgeportname, v)
2147 elif k == 'multicast-flood':
2148 self.write_file('/sys/class/net/%s/brport/multicast_flood' % bridgeportname, v)
2149 elif k == 'learning':
2150 self.write_file('/sys/class/net/%s/brport/learning' % bridgeportname, v)
2151 elif k == 'arp-nd-suppress':
2152 self.write_file('/sys/class/net/%s/brport/neigh_suppress' % bridgeportname, v)
2153 else:
2154 if not LinkUtils.bridge_utils_is_installed:
2155 continue
2156 utils.exec_command('%s set%s %s %s %s' % (utils.brctl_cmd, k, bridgename, bridgeportname, v))
2157
2158 def set_bridgeport_attr(self, bridgename, bridgeportname,
2159 attrname, attrval):
2160 if not LinkUtils.bridge_utils_is_installed:
2161 return
2162 if self._link_cache_check([bridgename, 'linkinfo', 'ports', bridgeportname, attrname], attrval):
2163 return
2164 utils.exec_command('%s set%s %s %s %s' %
2165 (utils.brctl_cmd,
2166 attrname,
2167 bridgename,
2168 bridgeportname,
2169 attrval))
2170
2171 def set_bridge_attrs(self, bridgename, attrdict):
2172 for k, v in attrdict.iteritems():
2173 if not v:
2174 continue
2175 if self._link_cache_check([bridgename, 'linkinfo', k], v):
2176 continue
2177 try:
2178 if k == 'igmp-version':
2179 self.write_file('/sys/class/net/%s/bridge/'
2180 'multicast_igmp_version' % bridgename, v)
2181 elif k == 'mld-version':
2182 self.write_file('/sys/class/net/%s/bridge/'
2183 'multicast_mld_version' % bridgename, v)
2184 elif k == 'vlan-protocol':
2185 self.write_file('/sys/class/net/%s/bridge/'
2186 'vlan_protocol' % bridgename,
2187 VlanProtocols.ETHERTYPES_TO_ID.get(v.upper(),
2188 None))
2189 elif k == 'vlan-stats':
2190 self.write_file('/sys/class/net/%s/bridge/'
2191 'vlan_stats_enabled' % bridgename, v)
2192 elif k == 'mcstats':
2193 self.write_file('/sys/class/net/%s/bridge/'
2194 'multicast_stats_enabled' % bridgename, v)
2195 else:
2196 if not LinkUtils.bridge_utils_is_installed:
2197 continue
2198 cmd = ('%s set%s %s %s' %
2199 (utils.brctl_cmd, k, bridgename, v))
2200 utils.exec_command(cmd)
2201 except Exception, e:
2202 self.logger.warn('%s: %s' % (bridgename, str(e)))
2203 pass
2204
2205 def set_bridge_attr(self, bridgename, attrname, attrval):
2206 if self._link_cache_check([bridgename, 'linkinfo', attrname], attrval):
2207 return
2208 if attrname == 'igmp-version':
2209 self.write_file('/sys/class/net/%s/bridge/multicast_igmp_version'
2210 % bridgename, attrval)
2211 elif attrname == 'mld-version':
2212 self.write_file('/sys/class/net/%s/bridge/multicast_mld_version'
2213 % bridgename, attrval)
2214 elif attrname == 'vlan-protocol':
2215 self.write_file('/sys/class/net/%s/bridge/vlan_protocol'
2216 % bridgename, VlanProtocols.ETHERTYPES_TO_ID[attrval.upper()])
2217 elif attrname == 'vlan-stats':
2218 self.write_file('/sys/class/net/%s/bridge/vlan_stats_enabled'
2219 % bridgename, attrval)
2220 elif attrname == 'mcstats':
2221 self.write_file('/sys/class/net/%s/bridge/multicast_stats_enabled'
2222 % bridgename, attrval)
2223 else:
2224 if not LinkUtils.bridge_utils_is_installed:
2225 return
2226 cmd = '%s set%s %s %s' % (utils.brctl_cmd,
2227 attrname, bridgename, attrval)
2228 utils.exec_command(cmd)
2229
2230 def get_bridge_attrs(self, bridgename):
2231 attrs = self._link_cache_get([bridgename, 'linkinfo'])
2232 no_ints_attrs = {}
2233 for key, value in attrs.items():
2234 if type(key) == str:
2235 no_ints_attrs[key] = value
2236 return no_ints_attrs
2237
2238 def get_bridgeport_attrs(self, bridgename, bridgeportname):
2239 return self._link_cache_get([bridgename, 'linkinfo', 'ports',
2240 bridgeportname])
2241
2242 def get_bridgeport_attr(self, bridgename, bridgeportname, attrname):
2243 return self._link_cache_get([bridgename, 'linkinfo', 'ports',
2244 bridgeportname, attrname])
2245
2246 @staticmethod
2247 def bridge_set_stp(bridge, stp_state):
2248 if not LinkUtils.bridge_utils_is_installed:
2249 return
2250 utils.exec_command('%s stp %s %s' % (utils.brctl_cmd, bridge, stp_state))
2251
2252 def bridge_get_stp(self, bridge):
2253 sysfs_stpstate = '/sys/class/net/%s/bridge/stp_state' % bridge
2254 if not os.path.exists(sysfs_stpstate):
2255 return 'error'
2256 stpstate = self.read_file_oneline(sysfs_stpstate)
2257 if not stpstate:
2258 return 'error'
2259 try:
2260 if int(stpstate) > 0:
2261 return 'yes'
2262 elif int(stpstate) == 0:
2263 return 'no'
2264 except:
2265 return 'unknown'
2266
2267 @staticmethod
2268 def _conv_value_to_user(s):
2269 try:
2270 ret = int(s) / 100
2271 return '%d' % ret
2272 except:
2273 return None
2274
2275 def read_value_from_sysfs(self, filename, preprocess_func):
2276 value = self.read_file_oneline(filename)
2277 if not value:
2278 return None
2279 return preprocess_func(value)
2280
2281 @staticmethod
2282 def bridge_set_ageing(bridge, ageing):
2283 if not LinkUtils.bridge_utils_is_installed:
2284 return
2285 utils.exec_command('%s setageing %s %s' % (utils.brctl_cmd, bridge, ageing))
2286
2287 def bridge_get_ageing(self, bridge):
2288 return self.read_value_from_sysfs('/sys/class/net/%s/bridge/ageing_time'
2289 % bridge, self._conv_value_to_user)
2290
2291 @staticmethod
2292 def set_bridgeprio(bridge, prio):
2293 if not LinkUtils.bridge_utils_is_installed:
2294 return
2295 utils.exec_command('%s setbridgeprio %s %s' % (utils.brctl_cmd, bridge, prio))
2296
2297 def get_bridgeprio(self, bridge):
2298 return self.read_file_oneline(
2299 '/sys/class/net/%s/bridge/priority' % bridge)
2300
2301 @staticmethod
2302 def bridge_set_fd(bridge, fd):
2303 if not LinkUtils.bridge_utils_is_installed:
2304 return
2305 utils.exec_command('%s setfd %s %s' % (utils.brctl_cmd, bridge, fd))
2306
2307 def bridge_get_fd(self, bridge):
2308 return self.read_value_from_sysfs(
2309 '/sys/class/net/%s/bridge/forward_delay'
2310 % bridge, self._conv_value_to_user)
2311
2312 def bridge_set_gcint(self, bridge, gcint):
2313 raise Exception('set_gcint not implemented')
2314
2315 @staticmethod
2316 def bridge_set_hello(bridge, hello):
2317 if not LinkUtils.bridge_utils_is_installed:
2318 return
2319 utils.exec_command('%s sethello %s %s' % (utils.brctl_cmd, bridge, hello))
2320
2321 def bridge_get_hello(self, bridge):
2322 return self.read_value_from_sysfs('/sys/class/net/%s/bridge/hello_time'
2323 % bridge, self._conv_value_to_user)
2324
2325 @staticmethod
2326 def bridge_set_maxage(bridge, maxage):
2327 if not LinkUtils.bridge_utils_is_installed:
2328 return
2329 utils.exec_command('%s setmaxage %s %s' % (utils.brctl_cmd, bridge, maxage))
2330
2331 def bridge_get_maxage(self, bridge):
2332 return self.read_value_from_sysfs('/sys/class/net/%s/bridge/max_age'
2333 % bridge, self._conv_value_to_user)
2334
2335 @staticmethod
2336 def bridge_set_pathcost(bridge, port, pathcost):
2337 if not LinkUtils.bridge_utils_is_installed:
2338 return
2339 utils.exec_command('%s setpathcost %s %s %s' % (utils.brctl_cmd, bridge, port, pathcost))
2340
2341 def bridge_get_pathcost(self, bridge, port):
2342 return self.read_file_oneline('/sys/class/net/%s/brport/path_cost'
2343 % port)
2344
2345 @staticmethod
2346 def bridge_set_portprio(bridge, port, prio):
2347 if not LinkUtils.bridge_utils_is_installed:
2348 return
2349 utils.exec_command('%s setportprio %s %s %s' % (utils.brctl_cmd, bridge, port, prio))
2350
2351 def bridge_get_portprio(self, bridge, port):
2352 return self.read_file_oneline('/sys/class/net/%s/brport/priority'
2353 % port)
2354
2355 @staticmethod
2356 def bridge_set_hashmax(bridge, hashmax):
2357 if not LinkUtils.bridge_utils_is_installed:
2358 return
2359 utils.exec_command('%s sethashmax %s %s' % (utils.brctl_cmd, bridge, hashmax))
2360
2361 def bridge_get_hashmax(self, bridge):
2362 return self.read_file_oneline('/sys/class/net/%s/bridge/hash_max'
2363 % bridge)
2364
2365 @staticmethod
2366 def bridge_set_hashel(bridge, hashel):
2367 if not LinkUtils.bridge_utils_is_installed:
2368 return
2369 utils.exec_command('%s sethashel %s %s' % (utils.brctl_cmd, bridge, hashel))
2370
2371 def bridge_get_hashel(self, bridge):
2372 return self.read_file_oneline('/sys/class/net/%s/bridge/hash_elasticity'
2373 % bridge)
2374
2375 @staticmethod
2376 def bridge_set_mclmc(bridge, mclmc):
2377 if not LinkUtils.bridge_utils_is_installed:
2378 return
2379 utils.exec_command('%s setmclmc %s %s' % (utils.brctl_cmd, bridge, mclmc))
2380
2381 def bridge_get_mclmc(self, bridge):
2382 return self.read_file_oneline(
2383 '/sys/class/net/%s/bridge/multicast_last_member_count'
2384 % bridge)
2385
2386 @staticmethod
2387 def bridge_set_mcrouter(bridge, mcrouter):
2388 if not LinkUtils.bridge_utils_is_installed:
2389 return
2390 utils.exec_command('%s setmcrouter %s %s' % (utils.brctl_cmd, bridge, mcrouter))
2391
2392 def bridge_get_mcrouter(self, bridge):
2393 return self.read_file_oneline(
2394 '/sys/class/net/%s/bridge/multicast_router' % bridge)
2395
2396 @staticmethod
2397 def bridge_set_mcsnoop(bridge, mcsnoop):
2398 if not LinkUtils.bridge_utils_is_installed:
2399 return
2400 utils.exec_command('%s setmcsnoop %s %s' % (utils.brctl_cmd, bridge, mcsnoop))
2401
2402 def bridge_get_mcsnoop(self, bridge):
2403 return self.read_file_oneline(
2404 '/sys/class/net/%s/bridge/multicast_snooping' % bridge)
2405
2406 @staticmethod
2407 def bridge_set_mcsqc(bridge, mcsqc):
2408 if not LinkUtils.bridge_utils_is_installed:
2409 return
2410 utils.exec_command('%s setmcsqc %s %s' % (utils.brctl_cmd, bridge, mcsqc))
2411
2412 def bridge_get_mcsqc(self, bridge):
2413 return self.read_file_oneline(
2414 '/sys/class/net/%s/bridge/multicast_startup_query_count'
2415 % bridge)
2416
2417 @staticmethod
2418 def bridge_set_mcqifaddr(bridge, mcqifaddr):
2419 if not LinkUtils.bridge_utils_is_installed:
2420 return
2421 utils.exec_command('%s setmcqifaddr %s %s' % (utils.brctl_cmd, bridge, mcqifaddr))
2422
2423 def bridge_get_mcqifaddr(self, bridge):
2424 return self.read_file_oneline(
2425 '/sys/class/net/%s/bridge/multicast_startup_query_use_ifaddr'
2426 % bridge)
2427
2428 @staticmethod
2429 def bridge_set_mcquerier(bridge, mcquerier):
2430 if not LinkUtils.bridge_utils_is_installed:
2431 return
2432 utils.exec_command('%s setmcquerier %s %s' % (utils.brctl_cmd, bridge, mcquerier))
2433
2434 def bridge_get_mcquerier(self, bridge):
2435 return self.read_file_oneline(
2436 '/sys/class/net/%s/bridge/multicast_querier' % bridge)
2437
2438 def bridge_set_mcqv4src(self, bridge, vlan, mcquerier):
2439 try:
2440 vlan = int(vlan)
2441 except:
2442 self.logger.info('%s: set mcqv4src vlan: invalid parameter %s: %s' %(bridge, vlan, str(e)))
2443 return
2444 if vlan == 0 or vlan > 4095:
2445 self.logger.warn('mcqv4src vlan \'%d\' invalid range' % vlan)
2446 return
2447
2448 ip = mcquerier.split('.')
2449 if len(ip) != 4:
2450 self.logger.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier)
2451 return
2452 for k in ip:
2453 if not k.isdigit() or int(k, 10) < 0 or int(k, 10) > 255:
2454 self.logger.warn('mcqv4src \'%s\' invalid IPv4 address' % mcquerier)
2455 return
2456
2457 if not LinkUtils.bridge_utils_is_installed:
2458 return
2459
2460 utils.exec_command('%s setmcqv4src %s %d %s' %
2461 (utils.brctl_cmd, bridge, vlan, mcquerier))
2462
2463 def bridge_del_mcqv4src(self, bridge, vlan):
2464 if not LinkUtils.bridge_utils_is_installed:
2465 return
2466 try:
2467 vlan = int(vlan)
2468 except:
2469 self.logger.info('%s: del mcqv4src vlan: invalid parameter %s: %s' %(bridge, vlan, str(e)))
2470 return
2471 utils.exec_command('%s delmcqv4src %s %d' % (utils.brctl_cmd, bridge, vlan))
2472
2473 def bridge_get_mcqv4src(self, bridge, vlan=None):
2474 if not LinkUtils.bridge_utils_is_installed:
2475 return {}
2476 if not self.supported_command['showmcqv4src']:
2477 return {}
2478 mcqv4src = {}
2479 try:
2480 mcqout = utils.exec_command('%s showmcqv4src %s' %
2481 (utils.brctl_cmd, bridge))
2482 except Exception as e:
2483 s = str(e).lower()
2484 if 'never heard' in s:
2485 msg = ('%s showmcqv4src: skipping unsupported command'
2486 % utils.brctl_cmd)
2487 self.logger.info(msg)
2488 self.supported_command['showmcqv4src'] = False
2489 return {}
2490 raise
2491 if not mcqout:
2492 return {}
2493 mcqlines = mcqout.splitlines()
2494 for l in mcqlines[1:]:
2495 l = l.strip()
2496 k, d, v = l.split('\t')
2497 if not k or not v:
2498 continue
2499 mcqv4src[k] = v
2500 if vlan:
2501 return mcqv4src.get(vlan)
2502 return mcqv4src
2503
2504 @staticmethod
2505 def bridge_set_mclmi(bridge, mclmi):
2506 if not LinkUtils.bridge_utils_is_installed:
2507 return
2508 utils.exec_command('%s setmclmi %s %s' % (utils.brctl_cmd, bridge, mclmi))
2509
2510 def bridge_get_mclmi(self, bridge):
2511 return self.read_file_oneline(
2512 '/sys/class/net/%s/bridge/multicast_last_member_interval'
2513 % bridge)
2514
2515 @staticmethod
2516 def bridge_set_mcmi(bridge, mcmi):
2517 if not LinkUtils.bridge_utils_is_installed:
2518 return
2519 utils.exec_command('%s setmcmi %s %s' % (utils.brctl_cmd, bridge, mcmi))
2520
2521 def bridge_get_mcmi(self, bridge):
2522 return self.read_file_oneline(
2523 '/sys/class/net/%s/bridge/multicast_membership_interval'
2524 % bridge)
2525
2526 @staticmethod
2527 def bridge_exists(bridge):
2528 return os.path.exists('/sys/class/net/%s/bridge' % bridge)
2529
2530 @staticmethod
2531 def is_bridge_port(ifacename):
2532 return os.path.exists('/sys/class/net/%s/brport' % ifacename)
2533
2534 @staticmethod
2535 def bridge_port_exists(bridge, bridgeportname):
2536 try:
2537 return os.path.exists('/sys/class/net/%s/brif/%s' % (bridge, bridgeportname))
2538 except:
2539 return False
2540
2541 @staticmethod
2542 def get_bridge_ports(bridgename):
2543 try:
2544 return os.listdir('/sys/class/net/%s/brif/' % bridgename)
2545 except:
2546 return []