summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--python/vyos/ifconfig/interface.py47
1 files changed, 45 insertions, 2 deletions
diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py
index 85de0947a..baa45f5bd 100644
--- a/python/vyos/ifconfig/interface.py
+++ b/python/vyos/ifconfig/interface.py
@@ -22,6 +22,7 @@ from copy import deepcopy
from glob import glob
from ipaddress import IPv4Network
+from ipaddress import IPv6Interface
from netifaces import ifaddresses
# this is not the same as socket.AF_INET/INET6
from netifaces import AF_INET
@@ -911,7 +912,8 @@ class Interface(Control):
return None
rc = self.set_interface('ipv6_autoconf', autoconf)
if autoconf == '0':
- self.flush_ipv6_slaac_addrs()
+ flushed = self.flush_ipv6_slaac_addrs()
+ self.flush_ipv6_slaac_routes(flushed)
return rc
def add_ipv6_eui64_address(self, prefix):
@@ -1313,12 +1315,13 @@ class Interface(Control):
# flush all addresses
self._cmd(cmd)
- def flush_ipv6_slaac_addrs(self):
+ def flush_ipv6_slaac_addrs(self) -> list:
"""
Flush all IPv6 addresses installed in response to router advertisement
messages from this interface.
Will raise an exception on error.
+ Will return a list of flushed IPv6 addresses.
"""
netns = get_interface_namespace(self.ifname)
netns_cmd = f'ip netns exec {netns}' if netns else ''
@@ -1331,6 +1334,7 @@ class Interface(Control):
# 'prefixlen': 64, 'scope': 'global', 'dynamic': True,
# 'mngtmpaddr': True, 'protocol': 'kernel_ra',
# 'valid_life_time': 2591987, 'preferred_life_time': 14387}
+ flushed = []
for addr_info in tmp['addr_info']:
if 'protocol' not in addr_info:
continue
@@ -1338,8 +1342,47 @@ class Interface(Control):
addr_info['scope'] == 'global'):
# Flush IPv6 addresses installed by router advertisement
ra_addr = f"{addr_info['local']}/{addr_info['prefixlen']}"
+ flushed.append(ra_addr)
cmd = f'{netns_cmd} ip -6 addr del dev {self.ifname} {ra_addr}'
self._cmd(cmd)
+ return flushed
+
+ def flush_ipv6_slaac_routes(self, ra_addrs: list=[]) -> None:
+ """
+ Flush IPv6 default routes installed in response to router advertisement
+ messages from this interface.
+
+ Will raise an exception on error.
+ """
+ # Do not flush default route if interface uses DHCPv6 in addition to SLAAC
+ if 'address' in self.config and 'dhcpv6' in self.config['address']:
+ return None
+
+ # Find IPv6 connected prefixes for flushed SLAAC addresses
+ connected = []
+ for addr in ra_addrs:
+ connected.append(str(IPv6Interface(addr).network))
+
+ netns = get_interface_namespace(self.ifname)
+ netns_cmd = f'ip netns exec {netns}' if netns else ''
+
+ tmp = self._cmd(f'{netns_cmd} ip -j -6 route show dev {self.ifname}')
+ tmp = json.loads(tmp)
+ # Parse interface routes. Example data:
+ # {'dst': 'default', 'gateway': 'fe80::250:56ff:feb3:cdba',
+ # 'protocol': 'ra', 'metric': 1024, 'flags': [], 'expires': 1398,
+ # 'metrics': [{'hoplimit': 64}], 'pref': 'medium'}
+ for route in tmp:
+ # If it's a default route received from RA, delete it
+ if (dict_search('dst', route) == 'default' and
+ dict_search('protocol', route) == 'ra'):
+ self._cmd(f'{netns_cmd} ip -6 route del default via {route["gateway"]} dev {self.ifname}')
+ # Remove connected prefixes received from RA
+ if dict_search('dst', route) in connected:
+ # If it's a connected prefix, delete it
+ self._cmd(f'{netns_cmd} ip -6 route del {route["dst"]} dev {self.ifname}')
+
+ return None
def add_to_bridge(self, bridge_dict):
"""