]>
Commit | Line | Data |
---|---|---|
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 | ||
7 | import os | |
768b4ec5 | 8 | import glob |
a4a53f4b JF |
9 | import shlex |
10 | import signal | |
a193d8d1 | 11 | import subprocess |
a4a53f4b JF |
12 | |
13 | from ifupdown.utils import utils | |
15ef32ea RP |
14 | from collections import OrderedDict |
15 | from utilsbase import * | |
dae9c5de | 16 | from systemutils import * |
15ef32ea | 17 | from cache import * |
fc5e1735 | 18 | import ifupdown.ifupdownflags as ifupdownflags |
15ef32ea | 19 | |
44533c72 WK |
20 | VXLAN_UDP_PORT = 4789 |
21 | ||
15ef32ea RP |
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) | |
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') |