From 9e51fa4ad6c2edd25c57d17e520a5b5c83a4f5b8 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Sat, 2 May 2020 15:02:44 +0200 Subject: interface: T2367: fix add_addr and del_addr address tracking in cache Correctly track addresses in cache _addr variable --- python/vyos/ifconfig/interface.py | 77 +++++++++++++++++++++++++-------------- 1 file changed, 50 insertions(+), 27 deletions(-) (limited to 'python/vyos/ifconfig/interface.py') diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index a156eddd9..8bcfda13c 100644 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -219,7 +219,7 @@ class Interface(Control): else: raise Exception('interface "{}" not found'.format(self.config['ifname'])) - # list of assigned IP addresses + # temporary list of assigned IP addresses self._addr = [] self.operational = self.OperationalClass(ifname) @@ -621,7 +621,8 @@ class Interface(Control): def add_addr(self, addr): """ Add IP(v6) address to interface. Address is only added if it is not - already assigned to that interface. + already assigned to that interface. Address format must be validated + and compressed/normalized before calling this function. addr: can be an IPv4 address, IPv6 address, dhcp or dhcpv6! IPv4: add IPv4 address to interface @@ -629,6 +630,7 @@ class Interface(Control): dhcp: start dhclient (IPv4) on interface dhcpv6: start dhclient (IPv6) on interface + Returns False if address is already assigned and wasn't re-added. Example: >>> from vyos.ifconfig import Interface >>> j = Interface('eth0') @@ -637,32 +639,42 @@ class Interface(Control): >>> j.get_addr() ['192.0.2.1/24', '2001:db8::ffff/64'] """ - - # cache new IP address which is assigned to interface - self._addr.append(addr) - - # we can not have both DHCP and static IPv4 addresses assigned to an interface - if 'dhcp' in self._addr: - for addr in self._addr: - # do not change below 'if' ordering esle you will get an exception as: - # ValueError: 'dhcp' does not appear to be an IPv4 or IPv6 address - if addr != 'dhcp' and is_ipv4(addr): - raise ConfigError( - "Can't configure both static IPv4 and DHCP address on the same interface") - - if addr == 'dhcp': - self.dhcp.v4.set() - elif addr == 'dhcpv6': - self.dhcp.v6.set() + # XXX: normalize/compress with ipaddress if calling functions don't? + # is subnet mask always passed, and in the same way? + ret = True + + # we can't have both DHCP and static IPv4 addresses assigned + for a in self._addr: + if ( ( addr == 'dhcp' and a != 'dhcpv6' and is_ipv4(a) ) or + ( a == 'dhcp' and addr != 'dhcpv6' and is_ipv4(addr) ) ): + raise ConfigError(( + "Can't configure both static IPv4 and DHCP address " + "on the same interface")) + + # do not add same address twice + if addr not in self._addr: + # add to interface + if addr == 'dhcp': + self.dhcp.v4.set() + elif addr == 'dhcpv6': + self.dhcp.v6.set() + else: + if not is_intf_addr_assigned(self.ifname, addr): + ret = self._cmd(f'ip addr add "{addr}" dev "{self.ifname}"') + else: + return False + # add to cache + self._addr.append(addr) else: - if not is_intf_addr_assigned(self.config['ifname'], addr): - cmd = 'ip addr add "{}" dev "{}"'.format(addr, self.config['ifname']) - return self._cmd(cmd) + return False + + return ret def del_addr(self, addr): """ - Delete IP(v6) address to interface. Address is only added if it is - assigned to that interface. + Delete IP(v6) address from interface. Address is only deleted if it is + assigned to that interface. Address format must be exactly the same as + was used when adding the address. addr: can be an IPv4 address, IPv6 address, dhcp or dhcpv6! IPv4: delete IPv4 address from interface @@ -670,6 +682,7 @@ class Interface(Control): dhcp: stop dhclient (IPv4) on interface dhcpv6: stop dhclient (IPv6) on interface + Returns False if address isn't already assigned and wasn't deleted. Example: >>> from vyos.ifconfig import Interface >>> j = Interface('eth0') @@ -681,11 +694,21 @@ class Interface(Control): >>> j.get_addr() ['2001:db8::ffff/64'] """ + ret = True + + # remove from interface if addr == 'dhcp': self.dhcp.v4.delete() elif addr == 'dhcpv6': self.dhcp.v6.delete() else: - if is_intf_addr_assigned(self.config['ifname'], addr): - cmd = 'ip addr del "{}" dev "{}"'.format(addr, self.config['ifname']) - return self._cmd(cmd) + if is_intf_addr_assigned(self.ifname, addr): + ret = self._cmd(f'ip addr del "{addr}" dev "{self.ifname}"') + else: + return False + + if addr in self._addr: + # remove from cache + self._addr.remove(addr) + + return ret -- cgit v1.2.3