diff --git a/kuryr_kubernetes/cni/binding/nested.py b/kuryr_kubernetes/cni/binding/nested.py index db1231616..fafe65e80 100644 --- a/kuryr_kubernetes/cni/binding/nested.py +++ b/kuryr_kubernetes/cni/binding/nested.py @@ -110,9 +110,13 @@ class NestedDriver(health.HealthHandler, b_base.BaseBindingDriver, iface.up() def disconnect(self, vif, ifname, netns, container_id): - # NOTE(vikasc): device will get deleted with container namespace, so - # nothing to be done here. - pass + # NOTE(dulek): Interfaces should get deleted with the netns, but it may + # happen that kubelet or crio will call new CNI ADD before + # the old netns is deleted. This might result in VLAN ID + # conflict. In oder to protect from that let's remove the + # netns ifaces here anyway. + with b_base.get_ipdb(netns) as c_ipdb: + self._remove_ifaces(c_ipdb, (vif.vif_name, ifname), netns) class VlanDriver(NestedDriver): diff --git a/kuryr_kubernetes/tests/unit/cni/test_binding.py b/kuryr_kubernetes/tests/unit/cni/test_binding.py index ba5a49fc7..da19af45e 100644 --- a/kuryr_kubernetes/tests/unit/cni/test_binding.py +++ b/kuryr_kubernetes/tests/unit/cni/test_binding.py @@ -97,8 +97,13 @@ class TestDriverMixin(test_base.TestCase): if report: report.assert_called_once() + @mock.patch('kuryr_kubernetes.cni.binding.base.get_ipdb') @mock.patch('os_vif.unplug') - def _test_disconnect(self, m_vif_unplug, report=None): + def _test_disconnect(self, m_vif_unplug, m_get_ipdb, report=None): + def get_ipdb(netns=None): + return self.ipdbs[netns] + m_get_ipdb.side_effect = get_ipdb + base.disconnect(self.vif, self.instance_info, self.ifname, self.netns, report) m_vif_unplug.assert_called_once_with(self.vif, self.instance_info)