Commit 56668000 authored by Léo-Paul Géneau's avatar Léo-Paul Géneau 👾

Fix: properly remove interfaces on stop command

On stop command call Main.stop() runs
`remove_interface("*", pim=True, membership=True, ipv4=True, ipv6=True)`.

Therefore if a PIM interface was added for network interface eth0, the call
`remove_interface('eth0', True, True)` will evaluate the condition
`membership and not membership_interface` as True and the PIM interface will
never be removed.

Furthermore
`remove_interface("*", pim=True, membership=True, ipv4=True, ipv6=True)` will
do calls like `remove_interface('lo', True, True)` then calling
`remove_virtual_interface('lo')` and the line
`index = self.vif_name_to_index_dic.pop(interface_name, None)` will cause a
KeyError when running
`del self.vif_name_to_index_dic[self.vif_index_to_name_dic[index]]` or
`mif_index = self.vif_name_to_index_dic.pop(interface_name)`.
parent efbb7b0c
...@@ -85,7 +85,7 @@ class Kernel(metaclass=ABCMeta): ...@@ -85,7 +85,7 @@ class Kernel(metaclass=ABCMeta):
elif membership_interface: elif membership_interface:
index = membership_interface.vif_index index = membership_interface.vif_index
else: else:
index = list(range(0, self.MAXVIFS) - self.vif_index_to_name_dic.keys())[0] index = (range(0, self.MAXVIFS) - self.vif_index_to_name_dic.keys()).pop()
ip_interface = None ip_interface = None
if interface_name not in self.pim_interface: if interface_name not in self.pim_interface:
...@@ -111,7 +111,7 @@ class Kernel(metaclass=ABCMeta): ...@@ -111,7 +111,7 @@ class Kernel(metaclass=ABCMeta):
elif pim_interface: elif pim_interface:
index = pim_interface.vif_index index = pim_interface.vif_index
else: else:
index = list(range(0, self.MAXVIFS) - self.vif_index_to_name_dic.keys())[0] index = (range(0, self.MAXVIFS) - self.vif_index_to_name_dic.keys()).pop()
if interface_name not in self.membership_interface: if interface_name not in self.membership_interface:
membership_interface = self._create_membership_interface_object(interface_name, index) membership_interface = self._create_membership_interface_object(interface_name, index)
...@@ -128,24 +128,39 @@ class Kernel(metaclass=ABCMeta): ...@@ -128,24 +128,39 @@ class Kernel(metaclass=ABCMeta):
def remove_interface(self, interface_name, membership: bool = False, pim: bool = False): def remove_interface(self, interface_name, membership: bool = False, pim: bool = False):
with self.interface_lock: with self.interface_lock:
pim_interface = self.pim_interface.get(interface_name) if pim and interface_name in self.pim_interface:
membership_interface = self.membership_interface.get(interface_name) self.pim_interface.pop(interface_name).remove()
if (membership and not membership_interface) or (pim and not pim_interface) or (not membership and not pim): if membership and interface_name in self.membership_interface:
return self.membership_interface.pop(interface_name).remove()
if pim:
pim_interface = self.pim_interface.pop(interface_name) if ((pim and not interface_name in self.membership_interface) or
pim_interface.remove() (membership and not interface_name in self.pim_interface)):
elif membership:
membership_interface = self.membership_interface.pop(interface_name)
membership_interface.remove()
if not self.membership_interface.get(interface_name) and not self.pim_interface.get(interface_name):
self.remove_virtual_interface(interface_name) self.remove_virtual_interface(interface_name)
@abstractmethod @abstractmethod
def remove_virtual_interface(self, interface_name): def remove_virtual_interface(self, interface_name):
raise NotImplementedError raise NotImplementedError
def start_forwarding(self, index):
for new_interface in (kernel_entry.new_interface
for source_dict in self.routing.values()
for kernel_entry in source_dict.values()
):
new_interface(index)
def stop_forwarding(self, index):
# change MFC's to not forward traffic by this interface (set OIL to 0 for this interface)
with self.rwlock.genWlock():
for remove_interface in (kernel_entry.remove_interface
for source_dict in self.routing.values()
for kernel_entry in source_dict.values()
):
remove_interface(index)
interface_name = self.vif_index_to_name_dic.pop(index)
self.interface_logger.debug('Remove virtual interface: %s -> %d', interface_name, index)
############################################# #############################################
# Manipulate multicast routing table # Manipulate multicast routing table
############################################# #############################################
...@@ -199,12 +214,12 @@ class Kernel(metaclass=ABCMeta): ...@@ -199,12 +214,12 @@ class Kernel(metaclass=ABCMeta):
# notify KernelEntries about changes at the unicast routing table # notify KernelEntries about changes at the unicast routing table
def notify_unicast_changes(self, subnet): def notify_unicast_changes(self, subnet):
with self.rwlock.genWlock(): with self.rwlock.genWlock():
for source_ip in list(self.routing.keys()): for network_update in (kernel_entry.network_update
source_ip_obj = ipaddress.ip_address(source_ip) for kernel_entry in group_ip_dict
if source_ip_obj not in subnet: for source_ip, group_ip_dict in self.routing.items()
continue if ipaddress.ip_address(source_ip) in subnet
for group_ip in list(self.routing[source_ip].keys()): ):
self.routing[source_ip][group_ip].network_update() network_update()
# notify about changes at the interface (IP) # notify about changes at the interface (IP)
...@@ -324,33 +339,22 @@ class Kernel4(Kernel): ...@@ -324,33 +339,22 @@ class Kernel4(Kernel):
self.vif_index_to_name_dic[index] = interface_name self.vif_index_to_name_dic[index] = interface_name
self.vif_name_to_index_dic[interface_name] = index self.vif_name_to_index_dic[interface_name] = index
for source_dict in list(self.routing.values()): self.start_forwarding(index)
for kernel_entry in list(source_dict.values()):
kernel_entry.new_interface(index)
self.interface_logger.debug('Create virtual interface: %s -> %d', interface_name, index) self.interface_logger.debug('Create virtual interface: %s -> %d', interface_name, index)
return index return index
def remove_virtual_interface(self, interface_name): def remove_virtual_interface(self, interface_name):
#with self.interface_lock: #with self.interface_lock:
index = self.vif_name_to_index_dic.pop(interface_name, None) if interface_name in self.vif_name_to_index_dic:
index = self.vif_name_to_index_dic.pop(interface_name)
struct_vifctl = struct.pack("HBBI 4s 4s", index, 0, 0, 0, socket.inet_aton("0.0.0.0"), socket.inet_aton("0.0.0.0")) struct_vifctl = struct.pack("HBBI 4s 4s", index, 0, 0, 0, socket.inet_aton("0.0.0.0"), socket.inet_aton("0.0.0.0"))
os.system("ip mrule del iif {}".format(interface_name)) os.system("ip mrule del iif {}".format(interface_name))
os.system("ip mrule del oif {}".format(interface_name)) os.system("ip mrule del oif {}".format(interface_name))
self.socket.setsockopt(socket.IPPROTO_IP, self.MRT_DEL_VIF, struct_vifctl) self.socket.setsockopt(socket.IPPROTO_IP, self.MRT_DEL_VIF, struct_vifctl)
del self.vif_name_to_index_dic[self.vif_index_to_name_dic[index]] self.stop_forwarding(index)
interface_name = self.vif_index_to_name_dic.pop(index)
# change MFC's to not forward traffic by this interface (set OIL to 0 for this interface)
with self.rwlock.genWlock():
for source_dict in list(self.routing.values()):
for kernel_entry in list(source_dict.values()):
kernel_entry.remove_interface(index)
self.interface_logger.debug('Remove virtual interface: %s -> %d', interface_name, index)
''' '''
...@@ -570,32 +574,24 @@ class Kernel6(Kernel): ...@@ -570,32 +574,24 @@ class Kernel6(Kernel):
self.vif_index_to_name_dic[index] = interface_name self.vif_index_to_name_dic[index] = interface_name
self.vif_name_to_index_dic[interface_name] = index self.vif_name_to_index_dic[interface_name] = index
for source_dict in list(self.routing.values()): self.start_forwarding(index)
for kernel_entry in list(source_dict.values()):
kernel_entry.new_interface(index)
self.interface_logger.debug('Create virtual interface: %s -> %d', interface_name, index) self.interface_logger.debug('Create virtual interface: %s -> %d', interface_name, index)
return index return index
def remove_virtual_interface(self, interface_name): def remove_virtual_interface(self, interface_name):
# with self.interface_lock: # with self.interface_lock:
mif_index = self.vif_name_to_index_dic.pop(interface_name, None) if interface_name in self.vif_name_to_index_dic:
interface_name = self.vif_index_to_name_dic.pop(mif_index) mif_index = self.vif_name_to_index_dic.pop(interface_name)
physical_if_index = if_nametoindex(interface_name) physical_if_index = if_nametoindex(interface_name)
struct_vifctl = struct.pack("HBBHI", mif_index, 0, 0, physical_if_index, 0) struct_vifctl = struct.pack("HBBHI", mif_index, 0, 0, physical_if_index, 0)
self.socket.setsockopt(socket.IPPROTO_IPV6, self.MRT6_DEL_MIF, struct_vifctl) self.socket.setsockopt(socket.IPPROTO_IPV6, self.MRT6_DEL_MIF, struct_vifctl)
os.system("ip -6 mrule del iif {}".format(interface_name)) os.system("ip -6 mrule del iif {}".format(interface_name))
os.system("ip -6 mrule del oif {}".format(interface_name)) os.system("ip -6 mrule del oif {}".format(interface_name))
# alterar MFC's para colocar a 0 esta interface self.stop_forwarding(mif_index)
with self.rwlock.genWlock():
for source_dict in list(self.routing.values()):
for kernel_entry in list(source_dict.values()):
kernel_entry.remove_interface(mif_index)
self.interface_logger.debug('Remove virtual interface: %s -> %d', interface_name, mif_index)
''' '''
/* Cache manipulation structures for mrouted and PIMd */ /* Cache manipulation structures for mrouted and PIMd */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment