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