]> git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdown2/lib/iproute2.py
12d14f54fb2d5342755943cb445eef39f5e10360
[mirror_ifupdown2.git] / ifupdown2 / lib / iproute2.py
1 # Copyright (C) 2017, 2018, 2019 Cumulus Networks, Inc. all rights reserved
2 #
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License as
5 # published by the Free Software Foundation; version 2.
6 #
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 # General Public License for more details.
11 #
12 # You should have received a copy of the GNU General Public License
13 # along with this program; if not, write to the Free Software
14 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 # 02110-1301, USA.
16 #
17 # https://www.gnu.org/licenses/gpl-2.0-standalone.html
18 #
19 # Author:
20 # Julien Fortin, julien@cumulusnetworks.com
21 #
22 # iproute2 -- contains all iproute2 related operation
23 #
24
25 import re
26 import shlex
27 import signal
28 import ipaddress
29 import subprocess
30
31
32 try:
33 from ifupdown2.lib.sysfs import Sysfs
34 from ifupdown2.lib.base_objects import Cache, Requirements
35
36 import ifupdown2.nlmanager.ipnetwork as ipnetwork
37
38 from ifupdown2.ifupdown.utils import utils
39 from ifupdown2.ifupdown.iface import ifaceLinkPrivFlags
40 from ifupdown2.nlmanager.nlpacket import Link
41 except (ImportError, ModuleNotFoundError):
42 from lib.sysfs import Sysfs
43 from lib.base_objects import Cache, Requirements
44
45 import nlmanager.ipnetwork as ipnetwork
46
47 from ifupdown.utils import utils
48 from ifupdown.iface import ifaceLinkPrivFlags
49 from nlmanager.nlpacket import Link
50
51 # WORK AROUND - Tunnel creation should be done via netlink and not iproute2 ####
52 import struct #
53 import socket #
54 #
55 try: #
56 import ifupdown2.nlmanager.nlpacket as nlpacket #
57 except: #
58 import nlmanager.nlpacket as nlpacket #
59 ################################################################################
60
61
62 class IPRoute2(Cache, Requirements):
63
64 VXLAN_UDP_PORT = 4789
65 VXLAN_PEER_REGEX_PATTERN = re.compile("\s+dst\s+(\d+.\d+.\d+.\d+)\s+")
66
67 def __init__(self):
68 Cache.__init__(self)
69 Requirements.__init__(self)
70
71 self.sysfs = Sysfs
72
73 self.__batch = {}
74 self.__batch_mode = False
75
76 # if bridge utils is not installed overrrides specific functions to
77 # avoid constantly checking bridge_utils_is_installed
78 if not Requirements.bridge_utils_is_installed:
79 self.bridge_set_stp = lambda _, __: None
80 self.bridge_del_mcqv4src = lambda _, __: None
81 self.bridge_set_mcqv4src = lambda _, __, ___: None
82
83 ############################################################################
84 # WORK-AROUND
85 ############################################################################
86
87 def __update_cache_after_link_creation(self, ifname, kind):
88 """
89 WORK AROUND - when creating tunnel via iproute2 we still need to fill
90 our internal cache to keep track of this interface until we receive the
91 NEWLINK notification. This code is a copy-paste from:
92 nlcache.tx_nlpacket_get_response_with_error_and_cache_on_ack
93
94 :param ifname:
95 :param kind:
96 :return:
97 """
98 packet = nlpacket.Link(nlpacket.RTM_NEWLINK, False, use_color=False)
99 packet.flags = nlpacket.NLM_F_CREATE | nlpacket.NLM_F_REQUEST | nlpacket.NLM_F_ACK
100 packet.body = struct.pack('Bxxxiii', socket.AF_UNSPEC, 0, 0, 0)
101 packet.add_attribute(nlpacket.Link.IFLA_IFNAME, ifname)
102 packet.add_attribute(nlpacket.Link.IFLA_LINKINFO, {
103 nlpacket.Link.IFLA_INFO_KIND: kind,
104 nlpacket.Link.IFLA_INFO_DATA: {}
105 })
106 packet.build_message(0, 0)
107 # When creating a new link via netlink, we don't always wait for the kernel
108 # NEWLINK notification to be cached to continue. If our request is ACKed by
109 # the OS we assume that the link was successfully created. Since we aren't
110 # waiting for the kernel notification to continue we need to manually fill
111 # our cache with the packet we just TX'ed. Once the NEWLINK notification
112 # is received it will simply override the previous entry.
113 # We need to keep track of those manually cached packets. We set a private
114 # flag on the objects via the attribute priv_flags
115 packet.priv_flags |= nlpacket.NLM_F_REQUEST
116 try:
117 # we need to decode the service header so all the attribute are properly
118 # filled in the packet object that we are about to store in cache.
119 # i.e.: packet.flags shouldn't contain NLM_F_* values but IFF_* (in case of Link object)
120 # otherwise call to cache.link_is_up() will probably return True
121 packet.decode_service_header()
122 except:
123 # we can ignore all errors
124 pass
125
126 # Then we can use our normal "add_link" API call to cache the packet
127 # and fill up our additional internal data structures.
128 self.cache.add_link(packet)
129
130 ############################################################################
131 # BATCH
132 ############################################################################
133
134 def __add_to_batch(self, prefix, cmd):
135 if prefix in self.__batch:
136 self.__batch[prefix].append(cmd)
137 else:
138 self.__batch[prefix] = [cmd]
139
140 def __execute_or_batch(self, prefix, cmd):
141 if self.__batch_mode:
142 self.__add_to_batch(prefix, cmd)
143 else:
144 utils.exec_command("%s %s" % (prefix, cmd))
145
146 def __execute_or_batch_dry_run(self, prefix, cmd):
147 """
148 The batch function has it's own dryrun handler so we only handle
149 dryrun for non-batch mode. Which will be removed once the "utils"
150 module has it's own dryrun handlers
151 """
152 if self.__batch_mode:
153 self.__add_to_batch(prefix, cmd)
154 else:
155 self.log_info_dry_run("executing: %s %s" % (prefix, cmd))
156
157 def batch_start(self):
158 if not self.__batch_mode:
159 self.__batch_mode = True
160 self.__batch = {}
161
162 def batch_commit(self):
163 try:
164 if not self.__batch_mode or not self.__batch:
165 return
166 for prefix, commands in self.__batch.items():
167 utils.exec_command(
168 "%s -force -batch -" % prefix,
169 stdin="\n".join(commands)
170 )
171 except:
172 raise
173 finally:
174 self.__batch_mode = False
175 del self.__batch
176 self.__batch = None
177
178 ############################################################################
179 # LINK
180 ############################################################################
181
182 def link_up(self, ifname):
183 if not self.cache.link_is_up(ifname):
184 self.link_up_force(ifname)
185
186 def link_down(self, ifname):
187 if self.cache.link_is_up(ifname):
188 self.link_down_force(ifname)
189
190 def link_up_dry_run(self, ifname):
191 self.link_up_force(ifname)
192
193 def link_down_dry_run(self, ifname):
194 self.link_down_force(ifname)
195
196 def link_up_force(self, ifname):
197 self.__execute_or_batch(utils.ip_cmd, "link set dev %s up" % ifname)
198
199 def link_down_force(self, ifname):
200 self.__execute_or_batch(utils.ip_cmd, "link set dev %s down" % ifname)
201
202 ###
203
204 def link_set_master(self, ifname, master):
205 if master != self.cache.get_master(ifname):
206 self.__execute_or_batch(
207 utils.ip_cmd,
208 "link set dev %s master %s" % (ifname, master)
209 )
210
211 def link_set_master_dry_run(self, ifname, master):
212 self.__execute_or_batch(
213 utils.ip_cmd,
214 "link set dev %s master %s" % (ifname, master)
215 )
216
217 ###
218
219 def link_set_address(self, ifname, address):
220 if utils.mac_str_to_int(address) != self.cache.get_link_address_raw(ifname):
221 self.link_down(ifname)
222 self.__execute_or_batch(
223 utils.ip_cmd,
224 "link set dev %s address %s" % (ifname, address)
225 )
226 self.link_up(ifname)
227
228 def link_set_address_dry_run(self, ifname, address):
229 self.link_down(ifname)
230 self.__execute_or_batch(
231 utils.ip_cmd,
232 "link set dev %s address %s" % (ifname, address)
233 )
234 self.link_up(ifname)
235
236 def link_set_address_and_keep_down(self, ifname, address, keep_down=False):
237 if utils.mac_str_to_int(address) != self.cache.get_link_address_raw(ifname):
238 self.link_down(ifname)
239 self.__execute_or_batch(
240 utils.ip_cmd,
241 "link set dev %s address %s" % (ifname, address)
242 )
243 if not keep_down:
244 self.link_up(ifname)
245
246 def link_set_address_and_keep_down_dry_run(self, ifname, address, keep_down=False):
247 self.link_down(ifname)
248 self.__execute_or_batch(
249 utils.ip_cmd,
250 "link set dev %s address %s" % (ifname, address)
251 )
252 if not keep_down:
253 self.link_up(ifname)
254
255 ###
256
257 def link_add_macvlan(self, ifname, macvlan_ifname, macvlan_mode):
258 utils.exec_command(
259 "%s link add link %s name %s type macvlan mode %s"
260 % (utils.ip_cmd, ifname, macvlan_ifname, macvlan_mode)
261 )
262
263 def link_add_macvlan_dry_run(self, ifname, macvlan_ifname, macvlan_mode):
264 # this dryrun method can be removed once dryrun handlers
265 # are added to the utils module
266 self.log_info_ifname_dry_run(ifname, "executing %s link add link %s name %s type macvlan mode %s"
267 % (utils.ip_cmd, ifname, macvlan_ifname, macvlan_mode)
268 )
269
270 ###
271
272 def link_create_vxlan(self, name, vxlanid, localtunnelip=None, svcnodeip=None,
273 remoteips=None, learning='on', ageing=None, ttl=None, physdev=None):
274 if svcnodeip and remoteips:
275 raise Exception("svcnodeip and remoteip are mutually exclusive")
276
277 if self.cache.link_exists(name):
278 cmd = [
279 "link set dev %s type vxlan dstport %d"
280 % (name, self.VXLAN_UDP_PORT)
281 ]
282 else:
283 cmd = [
284 "link add dev %s type vxlan id %s dstport %d"
285 % (name, vxlanid, self.VXLAN_UDP_PORT)
286 ]
287
288 if svcnodeip:
289 if svcnodeip.ip.is_multicast:
290 cmd.append("group %s" % svcnodeip)
291 else:
292 cmd.append("remote %s" % svcnodeip)
293
294 if ageing:
295 cmd.append("ageing %s" % ageing)
296
297 if learning == 'off':
298 cmd.append("nolearning")
299
300 if ttl is not None:
301 cmd.append("ttl %s" % ttl)
302
303 if physdev:
304 cmd.append("dev %s" % physdev)
305
306 if localtunnelip:
307 cmd.append("local %s" % localtunnelip)
308
309 self.__execute_or_batch(utils.ip_cmd, " ".join(cmd))
310
311 def get_vxlan_peers(self, dev, svcnodeip):
312 cmd = "%s fdb show brport %s" % (utils.bridge_cmd, dev)
313 cur_peers = []
314 try:
315 ps = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, close_fds=False)
316 utils.enable_subprocess_signal_forwarding(ps, signal.SIGINT)
317 output = subprocess.check_output(("grep", "00:00:00:00:00:00"), stdin=ps.stdout).decode()
318 ps.wait()
319 utils.disable_subprocess_signal_forwarding(signal.SIGINT)
320 try:
321 for l in output.split('\n'):
322 m = self.VXLAN_PEER_REGEX_PATTERN.search(l)
323 if m and m.group(1) != svcnodeip:
324 cur_peers.append(m.group(1))
325 except:
326 self.logger.warning('error parsing ip link output')
327 except subprocess.CalledProcessError as e:
328 if e.returncode != 1:
329 self.logger.error(str(e))
330 finally:
331 utils.disable_subprocess_signal_forwarding(signal.SIGINT)
332 return cur_peers
333
334 ###
335
336 def link_add_xfrm(self, ifname, xfrm_name, xfrm_id):
337 utils.exec_commandl(['ip', 'link', 'add', xfrm_name, 'type', 'xfrm', 'dev', ifname, 'if_id', xfrm_id])
338 self.__update_cache_after_link_creation(xfrm_name, "xfrm")
339
340 ############################################################################
341 # TUNNEL
342 ############################################################################
343
344 def tunnel_create(self, tunnelname, mode, attrs=None):
345 if self.cache.link_exists(tunnelname):
346 return
347
348 cmd = []
349 if "6" in mode:
350 cmd.append("-6")
351
352 if mode in ["gretap"]:
353 cmd.append("link add %s type %s" % (tunnelname, mode))
354 else:
355 cmd.append("tunnel add %s mode %s" % (tunnelname, mode))
356
357 if attrs:
358 for k, v in attrs.items():
359 cmd.append(k)
360 if v:
361 cmd.append(v)
362
363 utils.exec_command("%s %s" % (utils.ip_cmd, " ".join(cmd)))
364 self.__update_cache_after_link_creation(tunnelname, mode)
365
366 def tunnel_change(self, tunnelname, attrs=None):
367 """ tunnel change function """
368 if not self.cache.link_exists(tunnelname):
369 return
370 cmd = ["tunnel change %s" % tunnelname]
371 if attrs:
372 for k, v in attrs.items():
373 cmd.append(k)
374 if v:
375 cmd.append(v)
376 self.__execute_or_batch(utils.ip_cmd, " ".join(cmd))
377
378 ############################################################################
379 # ADDRESS
380 ############################################################################
381
382 def addr_flush(self, ifname):
383 if self.cache.link_has_ip(ifname):
384 self.__execute_or_batch(utils.ip_cmd, "addr flush dev %s" % ifname)
385
386 def link_set_ipv6_addrgen_dry_run(self, ifname, addrgen, link_created):
387 addrgen_str = "none" if addrgen else "eui64"
388 self.link_down(ifname)
389 self.__execute_or_batch(utils.ip_cmd, "link set dev %s addrgenmode %s" % (ifname, addrgen_str))
390 self.link_up(ifname)
391
392 def link_set_ipv6_addrgen(self, ifname, addrgen, link_created):
393 """
394 IFLA_INET6_ADDR_GEN_MODE values:
395 0 = eui64
396 1 = none
397
398 :param ifname:
399 :param addrgen:
400 :param link_created:
401 :return:
402 """
403 cached_ipv6_addr_gen_mode = self.cache.get_link_ipv6_addrgen_mode(ifname)
404
405 if cached_ipv6_addr_gen_mode == addrgen:
406 return True
407
408 disabled_ipv6 = self.sysfs.get_ipv6_conf_disable_ipv6(ifname)
409
410 if disabled_ipv6:
411 self.logger.info("%s: cannot set addrgen: ipv6 is disabled on this device" % ifname)
412 return False
413
414 if link_created:
415 link_mtu = self.sysfs.link_get_mtu(ifname)
416 else:
417 link_mtu = self.cache.get_link_mtu(ifname)
418
419 if link_mtu < 1280:
420 self.logger.info("%s: ipv6 addrgen is disabled on device with MTU "
421 "lower than 1280 (current mtu %s): cannot set addrgen %s"
422 % (ifname, link_mtu, "off" if addrgen else "on"))
423 return False
424
425 if not link_created:
426 # When setting addrgenmode it is necessary to flap the macvlan
427 # device. After flapping the device we also need to re-add all
428 # the user configuration. The best way to add the user config
429 # is to flush our internal address cache
430 self.cache.address_flush_link(ifname)
431
432 is_link_up = self.cache.link_is_up(ifname)
433
434 if is_link_up:
435 self.link_down_force(ifname)
436
437 self.__execute_or_batch(
438 utils.ip_cmd,
439 "link set dev %s addrgenmode %s" % (ifname, Link.ifla_inet6_addr_gen_mode_dict.get(addrgen))
440 )
441
442 if is_link_up:
443 self.link_up_force(ifname)
444
445 return True
446
447 @staticmethod
448 def __compare_user_config_vs_running_state(running_addrs, user_addrs):
449 ip4 = []
450 ip6 = []
451
452 for ip in user_addrs or []:
453 if ip.version == 6:
454 ip6.append(ip)
455 else:
456 ip4.append(ip)
457
458 running_ipobj = []
459 for ip in running_addrs or []:
460 running_ipobj.append(ip)
461
462 return running_ipobj == (ip4 + ip6)
463
464 def add_addresses(self, ifacobj, ifname, address_list, purge_existing=False, metric=None, with_address_virtual=False):
465 if purge_existing:
466 running_address_list = self.cache.get_managed_ip_addresses(
467 ifname,
468 [ifacobj],
469 with_address_virtual=with_address_virtual
470 )
471
472 if self.__compare_user_config_vs_running_state(running_address_list, address_list):
473 return
474
475 try:
476 self.__execute_or_batch(utils.ip_cmd, "addr flush dev %s" % ifname)
477 except Exception as e:
478 self.logger.warning("%s: flushing all ip address failed: %s" % (ifname, str(e)))
479 for addr in address_list:
480 try:
481 if metric:
482 self.__execute_or_batch(utils.ip_cmd, "addr add %s dev %s metric %s" % (addr, ifname, metric))
483 else:
484 self.__execute_or_batch(utils.ip_cmd, "addr add %s dev %s" % (addr, ifname))
485 except Exception as e:
486 self.logger.error("%s: add_address: %s" % (ifname, str(e)))
487
488 ############################################################################
489 # BRIDGE
490 ############################################################################
491
492 @staticmethod
493 def bridge_set_stp(bridge, stp_state):
494 utils.exec_command("%s stp %s %s" % (utils.brctl_cmd, bridge, stp_state))
495
496 @staticmethod
497 def bridge_fdb_show_dev(dev):
498 try:
499 fdbs = {}
500 output = utils.exec_command("%s fdb show dev %s" % (utils.bridge_cmd, dev))
501 if output:
502 for fdb_entry in output.splitlines():
503 try:
504 entries = fdb_entry.split()
505 fdbs.setdefault(entries[2], []).append(entries[0])
506 except:
507 pass
508 return fdbs
509 except Exception:
510 return None
511
512 @staticmethod
513 def bridge_fdb_add(dev, address, vlan=None, bridge=True, remote=None):
514 target = "self" if bridge else ""
515 vlan_str = "vlan %s " % vlan if vlan else ""
516 dst_str = "dst %s " % remote if remote else ""
517
518 utils.exec_command(
519 "%s fdb replace %s dev %s %s %s %s"
520 % (
521 utils.bridge_cmd,
522 address,
523 dev,
524 vlan_str,
525 target,
526 dst_str
527 )
528 )
529
530 @staticmethod
531 def bridge_fdb_append(dev, address, vlan=None, bridge=True, remote=None):
532 target = "self" if bridge else ""
533 vlan_str = "vlan %s " % vlan if vlan else ""
534 dst_str = "dst %s " % remote if remote else ""
535
536 utils.exec_command(
537 "%s fdb append %s dev %s %s %s %s"
538 % (
539 utils.bridge_cmd,
540 address,
541 dev,
542 vlan_str,
543 target,
544 dst_str
545 )
546 )
547
548 @staticmethod
549 def bridge_fdb_del(dev, address, vlan=None, bridge=True, remote=None):
550 target = "self" if bridge else ""
551 vlan_str = "vlan %s " % vlan if vlan else ""
552 dst_str = "dst %s " % remote if remote else ""
553
554 utils.exec_command(
555 "%s fdb del %s dev %s %s %s %s"
556 % (
557 utils.bridge_cmd,
558 address,
559 dev,
560 vlan_str,
561 target,
562 dst_str
563 )
564 )
565
566 @staticmethod
567 def bridge_vlan_del_vid_list(ifname, vids):
568 if not vids:
569 return
570 for v in vids:
571 utils.exec_command(
572 "%s vlan del vid %s dev %s" % (utils.bridge_cmd, v, ifname)
573 )
574
575 def bridge_vlan_del_vid_list_self(self, ifname, vids, is_bridge=True):
576 target = "self" if is_bridge else ""
577 for v in vids:
578 self.__execute_or_batch(
579 utils.bridge_cmd,
580 "vlan del vid %s dev %s %s" % (v, ifname, target)
581 )
582
583 @staticmethod
584 def bridge_vlan_add_vid_list(ifname, vids):
585 for v in vids:
586 utils.exec_command(
587 "%s vlan add vid %s dev %s" % (utils.bridge_cmd, v, ifname)
588 )
589
590 def bridge_vlan_add_vid_list_self(self, ifname, vids, is_bridge=True):
591 target = "self" if is_bridge else ""
592 for v in vids:
593 self.__execute_or_batch(
594 utils.bridge_cmd,
595 "vlan add vid %s dev %s %s" % (v, ifname, target)
596 )
597
598 def bridge_vlan_del_pvid(self, ifname, pvid):
599 self.__execute_or_batch(
600 utils.bridge_cmd,
601 "vlan del vid %s untagged pvid dev %s" % (pvid, ifname)
602 )
603
604 def bridge_vlan_add_pvid(self, ifname, pvid):
605 self.__execute_or_batch(
606 utils.bridge_cmd,
607 "vlan add vid %s untagged pvid dev %s" % (pvid, ifname)
608 )
609
610 def bridge_del_mcqv4src(self, bridge, vlan):
611 try:
612 vlan = int(vlan)
613 except Exception as e:
614 self.logger.info("%s: del mcqv4src vlan: invalid parameter %s: %s"
615 % (bridge, vlan, str(e)))
616 return
617 utils.exec_command("%s delmcqv4src %s %d" % (utils.brctl_cmd, bridge, vlan))
618
619 def bridge_set_mcqv4src(self, bridge, vlan, mcquerier):
620 try:
621 vlan = int(vlan)
622 except Exception as e:
623 self.logger.info("%s: set mcqv4src vlan: invalid parameter %s: %s" % (bridge, vlan, str(e)))
624 return
625 if vlan == 0 or vlan > 4095:
626 self.logger.warning("mcqv4src vlan '%d' invalid range" % vlan)
627 return
628
629 ip = mcquerier.split(".")
630 if len(ip) != 4:
631 self.logger.warning("mcqv4src '%s' invalid IPv4 address" % mcquerier)
632 return
633 for k in ip:
634 if not k.isdigit() or int(k, 10) < 0 or int(k, 10) > 255:
635 self.logger.warning("mcqv4src '%s' invalid IPv4 address" % mcquerier)
636 return
637
638 utils.exec_command("%s setmcqv4src %s %d %s" % (utils.brctl_cmd, bridge, vlan, mcquerier))
639
640 ############################################################################
641 # ROUTE
642 ############################################################################
643
644 @staticmethod
645 def route_add_gateway(ifname, gateway, vrf=None, metric=None, onlink=True):
646 if not gateway:
647 return
648
649 if not vrf:
650 cmd = "%s route add default via %s proto kernel" % (utils.ip_cmd, gateway)
651 else:
652 cmd = "%s route add table %s default via %s proto kernel" % (utils.ip_cmd, vrf, gateway)
653
654 if metric:
655 cmd += " metric %s" % metric
656
657 cmd += " dev %s" % ifname
658
659 if onlink:
660 cmd += " onlink"
661
662 utils.exec_command(cmd)
663
664 @staticmethod
665 def route_del_gateway(ifname, gateway, vrf=None, metric=None):
666 """
667 delete default gw
668 we don't need a DRYRUN handler here as utils.exec_command should have one
669 """
670 if not gateway:
671 return
672
673 if not vrf:
674 cmd = "%s route del default via %s proto kernel" % (utils.ip_cmd, gateway)
675 else:
676 cmd = "%s route del table %s default via %s proto kernel" % (utils.ip_cmd, vrf, gateway)
677
678 if metric:
679 cmd += " metric %s" % metric
680
681 cmd += " dev %s" % ifname
682 utils.exec_command(cmd)
683
684 def fix_ipv6_route_metric(self, ifaceobj, macvlan_ifacename, ips):
685 vrf_table = None
686
687 if ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE:
688 try:
689 for upper_iface in ifaceobj.upperifaces:
690 vrf_table = self.cache.get_vrf_table(upper_iface)
691 if vrf_table:
692 break
693 except:
694 pass
695
696 ip_route_del = []
697 for ip in ips:
698 ip_network_obj = ipaddress.ip_network(ip)
699
700 if ip_network_obj.version == 6:
701 route_prefix = '%s/%d' % (ip_network_obj.network, ip_network_obj.prefixlen)
702
703 if vrf_table:
704 self.__execute_or_batch(
705 utils.ip_cmd,
706 "route del %s table %s dev %s" % (route_prefix, vrf_table, macvlan_ifacename)
707 )
708 else:
709 self.__execute_or_batch(
710 utils.ip_cmd,
711 "route del %s dev %s" % (route_prefix, macvlan_ifacename)
712 )
713
714 ip_route_del.append((route_prefix, vrf_table))
715
716 for ip, vrf_table in ip_route_del:
717 if vrf_table:
718 self.__execute_or_batch(
719 utils.ip_cmd,
720 "route add %s table %s dev %s proto kernel metric 9999" % (ip, vrf_table, macvlan_ifacename)
721 )
722 else:
723 self.__execute_or_batch(
724 utils.ip_cmd,
725 "route add %s dev %s proto kernel metric 9999" % (ip, macvlan_ifacename)
726 )
727
728 def ip_route_get_dev(self, prefix, vrf_master=None):
729 try:
730 if vrf_master:
731 cmd = "%s route get %s vrf %s" % (utils.ip_cmd, prefix, vrf_master)
732 else:
733 cmd = "%s route get %s" % (utils.ip_cmd, prefix)
734
735 output = utils.exec_command(cmd)
736 if output:
737 rline = output.splitlines()[0]
738 if rline:
739 rattrs = rline.split()
740 return rattrs[rattrs.index("dev") + 1]
741 except Exception as e:
742 self.logger.debug("ip_route_get_dev: failed .. %s" % str(e))
743 return None