]> git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdownaddons/iproute2.py
Update README.rst (#11)
[mirror_ifupdown2.git] / ifupdownaddons / iproute2.py
1 #!/usr/bin/python
2 #
3 # Copyright 2014 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
5 #
6
7 import os
8 import glob
9 import shlex
10 import signal
11 import subprocess
12
13 from ifupdown.utils import utils
14 from collections import OrderedDict
15 from utilsbase import *
16 from systemutils import *
17 from cache import *
18 import ifupdown.ifupdownflags as ifupdownflags
19
20 VXLAN_UDP_PORT = 4789
21
22 class iproute2(utilsBase):
23 """ This class contains helper methods to cache and interact with the
24 commands in the iproute2 package """
25
26 _cache_fill_done = False
27 ipbatchbuf = ''
28 ipbatch = False
29 ipbatch_pause = False
30
31 def __init__(self, *args, **kargs):
32 utilsBase.__init__(self, *args, **kargs)
33 if ifupdownflags.flags.CACHE:
34 self._fill_cache()
35 self.supported_command = {
36 '/sbin/bridge -c -json vlan show': True
37 }
38
39 def _fill_cache(self):
40 if not iproute2._cache_fill_done:
41 self._link_fill()
42 self._addr_fill()
43 iproute2._cache_fill_done = True
44 return True
45 return False
46
47 def _get_vland_id(self, citems, i, warn):
48 try:
49 sub = citems[i:]
50 index = sub.index('id')
51 int(sub[index + 1])
52 return sub[index + 1]
53 except:
54 if warn:
55 raise Exception('invalid use of \'vlan\' keyword')
56 return None
57
58 def _link_fill(self, ifacename=None, refresh=False):
59 """ fills cache with link information
60
61 if ifacename argument given, fill cache for ifacename, else
62 fill cache for all interfaces in the system
63 """
64
65 warn = True
66 linkout = {}
67 vxrd_running = False
68 if iproute2._cache_fill_done and not refresh: return
69 try:
70 # if ifacename already present, return
71 if (ifacename and not refresh and
72 linkCache.get_attr([ifacename, 'ifflag'])):
73 return
74 except:
75 pass
76 cmdout = self.link_show(ifacename=ifacename)
77 if not cmdout:
78 return
79 # read vxrd.pid and cache the running state before going through
80 # every interface in the system
81 if systemUtils.is_service_running(None, '/var/run/vxrd.pid'):
82 vxrd_running = True
83 for c in cmdout.splitlines():
84 citems = c.split()
85 ifnamenlink = citems[1].split('@')
86 if len(ifnamenlink) > 1:
87 ifname = ifnamenlink[0]
88 iflink = ifnamenlink[1].strip(':')
89 else:
90 ifname = ifnamenlink[0].strip(':')
91 iflink = None
92 linkattrs = {}
93 linkattrs['link'] = iflink
94 linkattrs['ifindex'] = citems[0].strip(':')
95 flags = citems[2].strip('<>').split(',')
96 linkattrs['flags'] = flags
97 linkattrs['ifflag'] = 'UP' if 'UP' in flags else 'DOWN'
98 for i in range(0, len(citems)):
99 try:
100 if citems[i] == 'mtu':
101 linkattrs['mtu'] = citems[i + 1]
102 elif citems[i] == 'state':
103 linkattrs['state'] = citems[i + 1]
104 elif citems[i] == 'link/ether':
105 linkattrs['hwaddress'] = citems[i + 1]
106 elif citems[i] == 'vlan':
107 vlanid = self._get_vland_id(citems, i, warn)
108 if vlanid:
109 linkattrs['linkinfo'] = {'vlanid': vlanid}
110 linkattrs['kind'] = 'vlan'
111 elif citems[i] == 'dummy':
112 linkattrs['kind'] = 'dummy'
113 elif citems[i] == 'vxlan' and citems[i + 1] == 'id':
114 linkattrs['kind'] = 'vxlan'
115 vattrs = {'vxlanid': citems[i + 2],
116 'svcnode': None,
117 'remote': [],
118 'ageing': citems[i + 2],
119 'learning': 'on'}
120 for j in range(i + 2, len(citems)):
121 if citems[j] == 'local':
122 vattrs['local'] = citems[j + 1]
123 elif citems[j] == 'remote':
124 vattrs['svcnode'] = citems[j + 1]
125 elif citems[j] == 'ageing':
126 vattrs['ageing'] = citems[j + 1]
127 elif citems[j] == 'nolearning':
128 vattrs['learning'] = 'off'
129 # get vxlan peer nodes if provisioned by user and not by vxrd
130 if not vxrd_running:
131 peers = self.get_vxlan_peers(ifname, vattrs['svcnode'])
132 if peers:
133 vattrs['remote'] = peers
134 linkattrs['linkinfo'] = vattrs
135 break
136 elif citems[i] == 'vrf' and citems[i + 1] == 'table':
137 vattrs = {'table': citems[i + 2]}
138 linkattrs['linkinfo'] = vattrs
139 linkattrs['kind'] = 'vrf'
140 linkCache.vrfs[ifname] = vattrs
141 break
142 elif citems[i] == 'vrf_slave':
143 linkattrs['kind'] = 'vrf_slave'
144 break
145 elif citems[i] == 'macvlan' and citems[i + 1] == 'mode':
146 linkattrs['kind'] = 'macvlan'
147 except Exception as e:
148 if warn:
149 self.logger.debug('%s: parsing error: id, mtu, state, link/ether, vlan, dummy, vxlan, local, remote, ageing, nolearning, vrf, table, vrf_slave are reserved keywords: %s' % (ifname, str(e)))
150 warn = False
151 #linkattrs['alias'] = self.read_file_oneline(
152 # '/sys/class/net/%s/ifalias' %ifname)
153 linkout[ifname] = linkattrs
154 [linkCache.update_attrdict([ifname], linkattrs)
155 for ifname, linkattrs in linkout.items()]
156
157 def _addr_filter(self, ifname, addr, scope=None):
158 default_addrs = ['127.0.0.1/8', '::1/128' , '0.0.0.0']
159 if ifname == 'lo' and addr in default_addrs:
160 return True
161 if scope and scope == 'link':
162 return True
163 return False
164
165 def _addr_fill(self, ifacename=None, refresh=False):
166 """ fills cache with address information
167
168 if ifacename argument given, fill cache for ifacename, else
169 fill cache for all interfaces in the system
170 """
171 linkout = {}
172 if iproute2._cache_fill_done and not refresh: return
173
174 try:
175 # Check if ifacename is already full, in which case, return
176 if ifacename and not refresh:
177 linkCache.get_attr([ifacename, 'addrs'])
178 return
179 except:
180 pass
181 cmdout = self.addr_show(ifacename=ifacename)
182 if not cmdout:
183 return
184 for c in cmdout.splitlines():
185 citems = c.split()
186 ifnamenlink = citems[1].split('@')
187 if len(ifnamenlink) > 1:
188 ifname = ifnamenlink[0]
189 else:
190 ifname = ifnamenlink[0].strip(':')
191 if not linkout.get(ifname):
192 linkattrs = {}
193 linkattrs['addrs'] = OrderedDict({})
194 try:
195 linkout[ifname].update(linkattrs)
196 except KeyError:
197 linkout[ifname] = linkattrs
198 if citems[2] == 'inet':
199 if self._addr_filter(ifname, citems[3], scope=citems[5]):
200 continue
201 addrattrs = {}
202 addrattrs['scope'] = citems[5]
203 addrattrs['type'] = 'inet'
204 linkout[ifname]['addrs'][citems[3]] = addrattrs
205 elif citems[2] == 'inet6':
206 if self._addr_filter(ifname, citems[3], scope=citems[5]):
207 continue
208 if citems[5] == 'link': continue #skip 'link' addresses
209 addrattrs = {}
210 addrattrs['scope'] = citems[5]
211 addrattrs['type'] = 'inet6'
212 linkout[ifname]['addrs'][citems[3]] = addrattrs
213 [linkCache.update_attrdict([ifname], linkattrs)
214 for ifname, linkattrs in linkout.items()]
215
216 def _cache_get(self, type, attrlist, refresh=False):
217 try:
218 if ifupdownflags.flags.DRYRUN:
219 return False
220 if ifupdownflags.flags.CACHE:
221 if self._fill_cache():
222 # if we filled the cache, return new data
223 return linkCache.get_attr(attrlist)
224 if not refresh:
225 return linkCache.get_attr(attrlist)
226 if type == 'link':
227 self._link_fill(attrlist[0], refresh)
228 elif type == 'addr':
229 self._addr_fill(attrlist[0], refresh)
230 else:
231 self._link_fill(attrlist[0], refresh)
232 self._addr_fill(attrlist[0], refresh)
233 return linkCache.get_attr(attrlist)
234 except Exception, e:
235 self.logger.debug('_cache_get(%s) : [%s]'
236 %(str(attrlist), str(e)))
237 pass
238 return None
239
240 def _cache_check(self, type, attrlist, value, refresh=False):
241 try:
242 attrvalue = self._cache_get(type, attrlist, refresh)
243 if attrvalue and attrvalue == value:
244 return True
245 except Exception, e:
246 self.logger.debug('_cache_check(%s) : [%s]'
247 %(str(attrlist), str(e)))
248 pass
249 return False
250
251 def _cache_update(self, attrlist, value):
252 if ifupdownflags.flags.DRYRUN: return
253 try:
254 linkCache.set_attr(attrlist, value)
255 except:
256 pass
257
258 def _cache_delete(self, attrlist):
259 if ifupdownflags.flags.DRYRUN: return
260 try:
261 linkCache.del_attr(attrlist)
262 except:
263 pass
264
265 def _cache_invalidate(self):
266 linkCache.invalidate()
267 iproute2._cache_fill_done = False
268
269 def batch_start(self):
270 self.ipbatcbuf = ''
271 self.ipbatch = True
272 self.ipbatch_pause = False
273
274 def add_to_batch(self, cmd):
275 self.ipbatchbuf += cmd + '\n'
276
277 def batch_pause(self):
278 self.ipbatch_pause = True
279
280 def batch_resume(self):
281 self.ipbatch_pause = False
282
283 def batch_commit(self):
284 if not self.ipbatchbuf:
285 self.ipbatchbuf = ''
286 self.ipbatch = False
287 self.ipbatch_pause = False
288 return
289 try:
290 utils.exec_command('ip -force -batch -', stdin=self.ipbatchbuf)
291 except:
292 raise
293 finally:
294 self.ipbatchbuf = ''
295 self.ipbatch = False
296 self.ipbatch_pause = False
297
298 def bridge_batch_commit(self):
299 if not self.ipbatchbuf:
300 self.ipbatchbuf = ''
301 self.ipbatch = False
302 self.ipbatch_pause = False
303 return
304 try:
305 utils.exec_command('bridge -force -batch -', stdin=self.ipbatchbuf)
306 except:
307 raise
308 finally:
309 self.ipbatchbuf = ''
310 self.ipbatch = False
311 self.ipbatch_pause = False
312
313 def addr_show(self, ifacename=None):
314 if ifacename:
315 if not self.link_exists(ifacename):
316 return
317 return utils.exec_commandl(['ip', '-o', 'addr', 'show', 'dev',
318 ifacename])
319 else:
320 return utils.exec_commandl(['ip', '-o', 'addr', 'show'])
321
322 def link_show(self, ifacename=None):
323 if ifacename:
324 return utils.exec_commandl(['ip', '-o', '-d', 'link', 'show', 'dev',
325 ifacename])
326 else:
327 return utils.exec_commandl(['ip', '-o', '-d', 'link', 'show'])
328
329 def addr_add(self, ifacename, address, broadcast=None,
330 peer=None, scope=None, preferred_lifetime=None):
331 if not address:
332 return
333 cmd = 'addr add %s' %address
334 if broadcast:
335 cmd += ' broadcast %s' %broadcast
336 if peer:
337 cmd += ' peer %s' %peer
338 if scope:
339 cmd += ' scope %s' %scope
340 if preferred_lifetime:
341 cmd += ' preferred_lft %s' %preferred_lifetime
342 cmd += ' dev %s' %ifacename
343 if self.ipbatch and not self.ipbatch_pause:
344 self.add_to_batch(cmd)
345 else:
346 utils.exec_command('ip %s' % cmd)
347 self._cache_update([ifacename, 'addrs', address], {})
348
349 def addr_del(self, ifacename, address, broadcast=None,
350 peer=None, scope=None):
351 """ Delete ipv4 address """
352 if not address:
353 return
354 if not self._cache_get('addr', [ifacename, 'addrs', address]):
355 return
356 cmd = 'addr del %s' %address
357 if broadcast:
358 cmd += 'broadcast %s' %broadcast
359 if peer:
360 cmd += 'peer %s' %peer
361 if scope:
362 cmd += 'scope %s' %scope
363 cmd += ' dev %s' %ifacename
364 utils.exec_command('ip %s' % cmd)
365 self._cache_delete([ifacename, 'addrs', address])
366
367 def addr_flush(self, ifacename):
368 cmd = 'addr flush dev %s' %ifacename
369 if self.ipbatch and not self.ipbatch_pause:
370 self.add_to_batch(cmd)
371 else:
372 utils.exec_command('ip %s' % cmd)
373 self._cache_delete([ifacename, 'addrs'])
374
375 def del_addr_all(self, ifacename, skip_addrs=[]):
376 if not skip_addrs: skip_addrs = []
377 runningaddrsdict = self.addr_get(ifacename)
378 try:
379 # XXX: ignore errors. Fix this to delete secondary addresses
380 # first
381 [self.addr_del(ifacename, a) for a in
382 set(runningaddrsdict.keys()).difference(skip_addrs)]
383 except:
384 # ignore errors
385 pass
386
387 def addr_get(self, ifacename, details=True, refresh=False):
388 addrs = self._cache_get('addr', [ifacename, 'addrs'],
389 refresh=refresh)
390 if not addrs:
391 return None
392 if details:
393 return addrs
394 return addrs.keys()
395
396 def addr_add_multiple(self, ifacename, addrs, purge_existing=False):
397 # purges address
398 if purge_existing:
399 # if perfmode is not set and also if iface has no sibling
400 # objects, purge addresses that are not present in the new
401 # config
402 runningaddrs = self.addr_get(ifacename, details=False)
403 if addrs == runningaddrs:
404 return
405 try:
406 # if primary address is not same, there is no need to keep any.
407 # reset all addresses
408 if (addrs and runningaddrs and
409 (addrs[0] != runningaddrs[0])):
410 self.del_addr_all(ifacename)
411 else:
412 self.del_addr_all(ifacename, addrs)
413 except Exception, e:
414 self.log_warn(str(e))
415 for a in addrs:
416 try:
417 self.addr_add(ifacename, a)
418 except Exception, e:
419 self.logger.error(str(e))
420
421 def _link_set_ifflag(self, ifacename, value):
422 # Dont look at the cache, the cache may have stale value
423 # because link status can be changed by external
424 # entity (One such entity is ifupdown main program)
425 cmd = 'link set dev %s %s' %(ifacename, value.lower())
426 if self.ipbatch:
427 self.add_to_batch(cmd)
428 else:
429 utils.exec_command('ip %s' % cmd)
430
431 def link_up(self, ifacename):
432 self._link_set_ifflag(ifacename, 'UP')
433
434 def link_down(self, ifacename):
435 self._link_set_ifflag(ifacename, 'DOWN')
436
437 def link_set(self, ifacename, key, value=None,
438 force=False, type=None, state=None):
439 if not force:
440 if (key not in ['master', 'nomaster'] and
441 self._cache_check('link', [ifacename, key], value)):
442 return
443 cmd = 'link set dev %s' %ifacename
444 if type:
445 cmd += ' type %s' %type
446 cmd += ' %s' %key
447 if value:
448 cmd += ' %s' %value
449 if state:
450 cmd += ' %s' %state
451 if self.ipbatch:
452 self.add_to_batch(cmd)
453 else:
454 utils.exec_command('ip %s' % cmd)
455 if key not in ['master', 'nomaster']:
456 self._cache_update([ifacename, key], value)
457
458 def link_set_hwaddress(self, ifacename, hwaddress, force=False):
459 if not force:
460 if self._cache_check('link', [ifacename, 'hwaddress'], hwaddress):
461 return
462 self.link_down(ifacename)
463 cmd = 'link set dev %s address %s' %(ifacename, hwaddress)
464 if self.ipbatch:
465 self.add_to_batch(cmd)
466 else:
467 utils.exec_command('ip %s' % cmd)
468 self.link_up(ifacename)
469 self._cache_update([ifacename, 'hwaddress'], hwaddress)
470
471 def link_set_mtu(self, ifacename, mtu):
472 if ifupdownflags.flags.DRYRUN:
473 return True
474 if not mtu or not ifacename: return
475 with open('/sys/class/net/%s/mtu' % ifacename, 'w') as f:
476 f.write(mtu)
477 self._cache_update([ifacename, 'mtu'], mtu)
478
479 def link_set_alias(self, ifacename, alias):
480 if not alias:
481 utils.exec_user_command('echo "" > /sys/class/net/%s/ifalias'
482 % ifacename)
483 else:
484 self.write_file('/sys/class/net/%s/ifalias' % ifacename, alias)
485
486 def link_get_alias(self, ifacename):
487 return self.read_file_oneline('/sys/class/net/%s/ifalias'
488 %ifacename)
489
490 def link_isloopback(self, ifacename):
491 flags = self._cache_get('link', [ifacename, 'flags'])
492 if not flags:
493 return
494 if 'LOOPBACK' in flags:
495 return True
496 return False
497
498 def link_get_status(self, ifacename):
499 return self._cache_get('link', [ifacename, 'ifflag'], refresh=True)
500
501 def route_add_gateway(self, ifacename, gateway, vrf=None, metric=None):
502 if not gateway:
503 return
504 if not vrf:
505 cmd = 'ip route add default via %s' %gateway
506 else:
507 cmd = 'ip route add table %s default via %s' %(vrf, gateway)
508 # Add metric
509 if metric:
510 cmd += 'metric %s' %metric
511 cmd += ' dev %s' %ifacename
512 utils.exec_command(cmd)
513
514 def route_del_gateway(self, ifacename, gateway, vrf=None, metric=None):
515 # delete default gw
516 if not gateway:
517 return
518 if not vrf:
519 cmd = 'ip route del default via %s' %gateway
520 else:
521 cmd = 'ip route del table %s default via %s' %(vrf, gateway)
522 if metric:
523 cmd += ' metric %s' %metric
524 cmd += ' dev %s' %ifacename
525 utils.exec_command(cmd)
526
527 def route6_add_gateway(self, ifacename, gateway):
528 if not gateway:
529 return
530 return utils.exec_command('ip -6 route add default via %s dev %s' %
531 (gateway, ifacename))
532
533 def route6_del_gateway(self, ifacename, gateway):
534 if not gateway:
535 return
536 return utils.exec_command('ip -6 route del default via %s dev %s' %
537 (gateway, ifacename))
538
539 def link_create_vlan(self, vlan_device_name, vlan_raw_device, vlanid):
540 if self.link_exists(vlan_device_name):
541 return
542 utils.exec_command('ip link add link %s name %s type vlan id %d' %
543 (vlan_raw_device, vlan_device_name, vlanid))
544 self._cache_update([vlan_device_name], {})
545
546 def link_create_vlan_from_name(self, vlan_device_name):
547 v = vlan_device_name.split('.')
548 if len(v) != 2:
549 self.logger.warn('invalid vlan device name %s' %vlan_device_name)
550 return
551 self.link_create_vlan(vlan_device_name, v[0], v[1])
552
553 def link_create_macvlan(self, name, linkdev, mode='private'):
554 if self.link_exists(name):
555 return
556 cmd = ('link add link %s' %linkdev +
557 ' name %s' %name +
558 ' type macvlan mode %s' %mode)
559 if self.ipbatch and not self.ipbatch_pause:
560 self.add_to_batch(cmd)
561 else:
562 utils.exec_command('ip %s' % cmd)
563 self._cache_update([name], {})
564
565 def get_vxlan_peers(self, dev, svcnodeip):
566 cmd = 'bridge fdb show brport %s' % dev
567 cur_peers = []
568 try:
569 ps = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, close_fds=False)
570 utils.enable_subprocess_signal_forwarding(ps, signal.SIGINT)
571 output = subprocess.check_output(('grep', '00:00:00:00:00:00'), stdin=ps.stdout)
572 ps.wait()
573 utils.disable_subprocess_signal_forwarding(signal.SIGINT)
574 try:
575 ppat = re.compile('\s+dst\s+(\d+.\d+.\d+.\d+)\s+')
576 for l in output.split('\n'):
577 m = ppat.search(l)
578 if m and m.group(1) != svcnodeip:
579 cur_peers.append(m.group(1))
580 except:
581 self.logger.warn('error parsing ip link output')
582 pass
583 except subprocess.CalledProcessError as e:
584 if e.returncode != 1:
585 self.logger.error(str(e))
586 finally:
587 utils.disable_subprocess_signal_forwarding(signal.SIGINT)
588
589 return cur_peers
590
591 def link_create_vxlan(self, name, vxlanid,
592 localtunnelip=None,
593 svcnodeip=None,
594 remoteips=None,
595 learning='on',
596 ageing=None,
597 anycastip=None):
598 if svcnodeip and remoteips:
599 raise Exception("svcnodeip and remoteip is mutually exclusive")
600 args = ''
601 if svcnodeip:
602 args += ' remote %s' %svcnodeip
603 if ageing:
604 args += ' ageing %s' %ageing
605 if learning == 'off':
606 args += ' nolearning'
607
608 if self.link_exists(name):
609 cmd = 'link set dev %s type vxlan dstport %d' %(name, VXLAN_UDP_PORT)
610 vxlanattrs = self.get_vxlandev_attrs(name)
611 # on ifreload do not overwrite anycast_ip to individual ip if clagd
612 # has modified
613 if vxlanattrs:
614 running_localtunnelip = vxlanattrs.get('local')
615 if anycastip and running_localtunnelip and anycastip == running_localtunnelip:
616 localtunnelip = running_localtunnelip
617 running_svcnode = vxlanattrs.get('svcnode')
618 if running_svcnode and not svcnodeip:
619 args += ' noremote'
620 else:
621 cmd = 'link add dev %s type vxlan id %s dstport %d' %(name, vxlanid, VXLAN_UDP_PORT)
622
623 if localtunnelip:
624 args += ' local %s' %localtunnelip
625 cmd += args
626
627 if self.ipbatch and not self.ipbatch_pause:
628 self.add_to_batch(cmd)
629 else:
630 utils.exec_command('ip %s' % cmd)
631
632 # XXX: update linkinfo correctly
633 self._cache_update([name], {})
634
635 def link_exists(self, ifacename):
636 if ifupdownflags.flags.DRYRUN:
637 return True
638 return os.path.exists('/sys/class/net/%s' %ifacename)
639
640 def link_get_ifindex(self, ifacename):
641 if ifupdownflags.flags.DRYRUN:
642 return True
643 return self.read_file_oneline('/sys/class/net/%s/ifindex' %ifacename)
644
645 def is_vlan_device_by_name(self, ifacename):
646 if re.search(r'\.', ifacename):
647 return True
648 return False
649
650 def route_add(self, route):
651 utils.exec_command('ip route add %s' % route)
652
653 def route6_add(self, route):
654 utils.exec_command('ip -6 route add %s' % route)
655
656 def get_vlandev_attrs(self, ifacename):
657 return (self._cache_get('link', [ifacename, 'link']),
658 self._cache_get('link', [ifacename, 'linkinfo', 'vlanid']))
659
660 def get_vxlandev_attrs(self, ifacename):
661 return self._cache_get('link', [ifacename, 'linkinfo'])
662
663 def get_vxlandev_learning(self, ifacename):
664 return self._cache_get('link', [ifacename, 'linkinfo', 'learning'])
665
666 def set_vxlandev_learning(self, ifacename, learn):
667 if learn == 'on':
668 utils.exec_command('ip link set dev %s type vxlan learning' %ifacename)
669 self._cache_update([ifacename, 'linkinfo', 'learning'], 'on')
670 else:
671 utils.exec_command('ip link set dev %s type vxlan nolearning' %ifacename)
672 self._cache_update([ifacename, 'linkinfo', 'learning'], 'off')
673
674 def link_get_linkinfo_attrs(self, ifacename):
675 return self._cache_get('link', [ifacename, 'linkinfo'])
676
677 def link_get_mtu(self, ifacename, refresh=False):
678 return self._cache_get('link', [ifacename, 'mtu'], refresh=refresh)
679
680 def link_get_mtu_sysfs(self, ifacename):
681 return self.read_file_oneline('/sys/class/net/%s/mtu'
682 %ifacename)
683
684 def link_get_kind(self, ifacename):
685 return self._cache_get('link', [ifacename, 'kind'])
686
687 def link_get_hwaddress(self, ifacename):
688 address = self._cache_get('link', [ifacename, 'hwaddress'])
689 # newly created logical interface addresses dont end up in the cache
690 # read hwaddress from sysfs file for these interfaces
691 if not address:
692 address = self.read_file_oneline('/sys/class/net/%s/address'
693 %ifacename)
694 return address
695
696 def link_create(self, ifacename, type, attrs={}):
697 """ generic link_create function """
698 if self.link_exists(ifacename):
699 return
700 cmd = 'link add'
701 cmd += ' name %s type %s' %(ifacename, type)
702 if attrs:
703 for k, v in attrs.iteritems():
704 cmd += ' %s' %k
705 if v:
706 cmd += ' %s' %v
707 if self.ipbatch and not self.ipbatch_pause:
708 self.add_to_batch(cmd)
709 else:
710 utils.exec_command('ip %s' % cmd)
711 self._cache_update([ifacename], {})
712
713 def link_delete(self, ifacename):
714 if not self.link_exists(ifacename):
715 return
716 cmd = 'link del %s' %ifacename
717 if self.ipbatch and not self.ipbatch_pause:
718 self.add_to_batch(cmd)
719 else:
720 utils.exec_command('ip %s' % cmd)
721 self._cache_invalidate()
722
723 def link_get_master(self, ifacename):
724 sysfs_master_path = '/sys/class/net/%s/master' %ifacename
725 if os.path.exists(sysfs_master_path):
726 link_path = os.readlink(sysfs_master_path)
727 if link_path:
728 return os.path.basename(link_path)
729 else:
730 return None
731 else:
732 return self._cache_get('link', [ifacename, 'master'])
733
734 def bridge_port_vids_add(self, bridgeportname, vids):
735 [utils.exec_command('bridge vlan add vid %s dev %s' %
736 (v, bridgeportname)) for v in vids]
737
738 def bridge_port_vids_del(self, bridgeportname, vids):
739 if not vids:
740 return
741 [utils.exec_command('bridge vlan del vid %s dev %s' %
742 (v, bridgeportname)) for v in vids]
743
744 def bridge_port_vids_flush(self, bridgeportname, vid):
745 utils.exec_command('bridge vlan del vid %s dev %s' %
746 (vid, bridgeportname))
747
748 def bridge_port_vids_get(self, bridgeportname):
749 utils.exec_command('/sbin/bridge vlan show %s' % bridgeportname)
750 bridgeout = utils.exec_command('/sbin/bridge vlan show dev %s' %
751 bridgeportname)
752 if not bridgeout: return []
753 brvlanlines = bridgeout.readlines()[2:]
754 vids = [l.strip() for l in brvlanlines]
755 return [v for v in vids if v]
756
757 def bridge_port_vids_get_all(self):
758 brvlaninfo = {}
759 bridgeout = utils.exec_command('/sbin/bridge -c vlan show')
760 if not bridgeout: return brvlaninfo
761 brvlanlines = bridgeout.splitlines()
762 brportname=None
763 for l in brvlanlines[1:]:
764 if l and not l.startswith(' ') and not l.startswith('\t'):
765 attrs = l.split()
766 brportname = attrs[0].strip()
767 brvlaninfo[brportname] = {'pvid' : None, 'vlan' : []}
768 l = ' '.join(attrs[1:])
769 if not brportname or not l:
770 continue
771 l = l.strip()
772 if 'PVID' in l:
773 brvlaninfo[brportname]['pvid'] = l.split()[0]
774 elif 'Egress Untagged' not in l:
775 brvlaninfo[brportname]['vlan'].append(l)
776 return brvlaninfo
777
778 def bridge_port_vids_get_all_json(self):
779 if not self.supported_command['/sbin/bridge -c -json vlan show']:
780 return {}
781 brvlaninfo = {}
782 try:
783 bridgeout = utils.exec_command('/sbin/bridge -c -json vlan show')
784 except:
785 self.supported_command['/sbin/bridge -c -json vlan show'] = False
786 self.logger.info('/sbin/bridge -c -json vlan show: skipping unsupported command')
787 return {}
788 if not bridgeout: return brvlaninfo
789 try:
790 vlan_json_dict = json.loads(bridgeout, encoding="utf-8")
791 except Exception, e:
792 self.logger.info('json loads failed with (%s)' %str(e))
793 return {}
794 return vlan_json_dict
795
796 def bridge_port_pvid_add(self, bridgeportname, pvid):
797 if self.ipbatch and not self.ipbatch_pause:
798 self.add_to_batch('vlan add vid %s untagged pvid dev %s' %
799 (pvid, bridgeportname))
800 else:
801 utils.exec_command('bridge vlan add vid %s untagged pvid dev %s' %
802 (pvid, bridgeportname))
803
804 def bridge_port_pvid_del(self, bridgeportname, pvid):
805 if self.ipbatch and not self.ipbatch_pause:
806 self.add_to_batch('vlan del vid %s untagged pvid dev %s' %
807 (pvid, bridgeportname))
808 else:
809 utils.exec_command('bridge vlan del vid %s untagged pvid dev %s' %
810 (pvid, bridgeportname))
811
812 def bridge_port_pvids_get(self, bridgeportname):
813 return self.read_file_oneline('/sys/class/net/%s/brport/pvid'
814 %bridgeportname)
815
816 def bridge_vids_add(self, bridgeportname, vids, bridge=True):
817 target = 'self' if bridge else ''
818 if self.ipbatch and not self.ipbatch_pause:
819 [self.add_to_batch('vlan add vid %s dev %s %s' %
820 (v, bridgeportname, target)) for v in vids]
821 else:
822 [utils.exec_command('bridge vlan add vid %s dev %s %s' %
823 (v, bridgeportname, target)) for v in vids]
824
825 def bridge_vids_del(self, bridgeportname, vids, bridge=True):
826 target = 'self' if bridge else ''
827 if self.ipbatch and not self.ipbatch_pause:
828 [self.add_to_batch('vlan del vid %s dev %s %s' %
829 (v, bridgeportname, target)) for v in vids]
830 else:
831 [utils.exec_command('bridge vlan del vid %s dev %s %s' %
832 (v, bridgeportname, target)) for v in vids]
833
834 def bridge_fdb_add(self, dev, address, vlan=None, bridge=True, remote=None):
835 target = 'self' if bridge else ''
836 vlan_str = ''
837 if vlan:
838 vlan_str = 'vlan %s ' % vlan
839
840 dst_str = ''
841 if remote:
842 dst_str = 'dst %s ' % remote
843
844 utils.exec_command('bridge fdb replace %s dev %s %s %s %s' %
845 (address, dev, vlan_str, target, dst_str))
846
847 def bridge_fdb_append(self, dev, address, vlan=None, bridge=True, remote=None):
848 target = 'self' if bridge else ''
849 vlan_str = ''
850 if vlan:
851 vlan_str = 'vlan %s ' % vlan
852
853 dst_str = ''
854 if remote:
855 dst_str = 'dst %s ' % remote
856
857 utils.exec_command('bridge fdb append %s dev %s %s %s %s' %
858 (address, dev, vlan_str, target, dst_str))
859
860 def bridge_fdb_del(self, dev, address, vlan=None, bridge=True, remote=None):
861 target = 'self' if bridge else ''
862 vlan_str = ''
863 if vlan:
864 vlan_str = 'vlan %s ' % vlan
865
866 dst_str = ''
867 if remote:
868 dst_str = 'dst %s ' % remote
869 utils.exec_command('bridge fdb del %s dev %s %s %s %s' %
870 (address, dev, vlan_str, target, dst_str))
871
872 def bridge_is_vlan_aware(self, bridgename):
873 filename = '/sys/class/net/%s/bridge/vlan_filtering' %bridgename
874 if os.path.exists(filename) and self.read_file_oneline(filename) == '1':
875 return True
876 return False
877
878 def bridge_port_get_bridge_name(self, bridgeport):
879 filename = '/sys/class/net/%s/brport/bridge' %bridgeport
880 try:
881 return os.path.basename(os.readlink(filename))
882 except:
883 return None
884
885 def bridge_port_exists(self, bridge, bridgeportname):
886 try:
887 return os.path.exists('/sys/class/net/%s/brif/%s'
888 %(bridge, bridgeportname))
889 except Exception:
890 return False
891
892 def bridge_fdb_show_dev(self, dev):
893 try:
894 fdbs = {}
895 output = utils.exec_command('bridge fdb show dev %s' % dev)
896 if output:
897 for fdb_entry in output.splitlines():
898 try:
899 entries = fdb_entry.split()
900 fdbs.setdefault(entries[2], []).append(entries[0])
901 except:
902 self.logger.debug('%s: invalid fdb line \'%s\''
903 %(dev, fdb_entry))
904 pass
905 return fdbs
906 except Exception:
907 return None
908
909 def is_bridge(self, bridge):
910 return os.path.exists('/sys/class/net/%s/bridge' %bridge)
911
912 def is_link_up(self, ifacename):
913 ret = False
914 try:
915 flags = self.read_file_oneline('/sys/class/net/%s/flags' %ifacename)
916 iflags = int(flags, 16)
917 if (iflags & 0x0001):
918 ret = True
919 except:
920 ret = False
921 pass
922 return ret
923
924 def ip_route_get_dev(self, prefix):
925 try:
926 output = utils.exec_command('ip route get %s' % prefix)
927 if output:
928 rline = output.splitlines()[0]
929 if rline:
930 rattrs = rline.split()
931 return rattrs[rattrs.index('dev') + 1]
932 except Exception, e:
933 self.logger.debug('ip_route_get_dev: failed .. %s' %str(e))
934 pass
935 return None
936
937 def link_get_lowers(self, ifacename):
938 try:
939 lowers = glob.glob("/sys/class/net/%s/lower_*" %ifacename)
940 if not lowers:
941 return []
942 return [os.path.basename(l)[6:] for l in lowers]
943 except:
944 return []
945
946 def link_get_uppers(self, ifacename):
947 try:
948 uppers = glob.glob("/sys/class/net/%s/upper_*" %ifacename)
949 if not uppers:
950 return None
951 return [ os.path.basename(u)[6:] for u in uppers ]
952 except:
953 return None
954
955 def link_get_vrfs(self):
956 self._fill_cache()
957 return linkCache.vrfs
958
959 def get_brport_learning(self, ifacename):
960 learn = self.read_file_oneline('/sys/class/net/%s/brport/learning'
961 %ifacename)
962 if learn and learn == '1':
963 return 'on'
964 else:
965 return 'off'
966
967 def set_brport_learning(self, ifacename, learn):
968 if learn == 'off':
969 return self.write_file('/sys/class/net/%s/brport/learning'
970 %ifacename, '0')
971 else:
972 return self.write_file('/sys/class/net/%s/brport/learning'
973 %ifacename, '1')