From 5d94687c84d1fc655916bb8f9b924820479f30cb Mon Sep 17 00:00:00 2001 From: Christian Breunig Date: Sat, 13 Sep 2025 11:01:39 +0200 Subject: ethernet: T7813: remove VLAN interfaces first on deletion When an Ethernet interface is deleted from the configuration, its associated VLAN subinterfaces must be removed first. This ordering allows VLAN interfaces to gracefully release any active DHCP or DHCPv6 leases before the parent interface disappears, ensuring proper cleanup and avoiding potential lease retention issues. --- python/vyos/ifconfig/ethernet.py | 14 ++++++-------- python/vyos/ifconfig/section.py | 10 +++++++++- 2 files changed, 15 insertions(+), 9 deletions(-) (limited to 'python') diff --git a/python/vyos/ifconfig/ethernet.py b/python/vyos/ifconfig/ethernet.py index 864a9d0bc..6c7b230ca 100644 --- a/python/vyos/ifconfig/ethernet.py +++ b/python/vyos/ifconfig/ethernet.py @@ -131,19 +131,17 @@ class EthernetIf(Interface): >>> i.remove() """ + # T7813: we do need to remove the VLAN subinterfaces first so we can + # properly stop the DHCP client and inform the DHCP server that we are + # returning the lease. + for vlan in Section.sub_interfaces(self.ifname): + Interface(vlan).remove() + if self.exists(self.ifname): # interface is placed in A/D state when removed from config! It # will remain visible for the operating system. self.set_admin_state('down') - # Remove all VLAN subinterfaces - filter with the VLAN dot - for vlan in [ - x - for x in Section.interfaces('ethernet') - if x.startswith(f'{self.ifname}.') - ]: - Interface(vlan).remove() - super().remove() def set_flow_control(self, enable): diff --git a/python/vyos/ifconfig/section.py b/python/vyos/ifconfig/section.py index 4ea606495..201494736 100644 --- a/python/vyos/ifconfig/section.py +++ b/python/vyos/ifconfig/section.py @@ -144,9 +144,17 @@ class Section: if no section is provided, then it returns all configured interfaces. If vlan is True, also Vlan subinterfaces will be returned """ - return cls._sort_interfaces(cls._intf_under_section(section, vlan)) + @classmethod + def sub_interfaces(cls, interface : str) -> list: + """ + return a list of subinterfaces (e.g. VLAN) derived from a given interface + """ + if_type = cls.section(interface) + res = [x for x in cls.interfaces(if_type) if x.startswith(f'{interface}.')] + return res + @classmethod def _intf_with_feature(cls, feature=''): """ -- cgit v1.2.3