From c68088b811b90ebf46d86fa22f3ef7b5d4a7d914 Mon Sep 17 00:00:00 2001 From: gatici Date: Wed, 10 Jul 2024 23:22:53 +0300 Subject: [PATCH 1/5] Make the interfaces up after configuration Signed-off-by: gatici --- src/upf_network.py | 25 ++++++++++++++++++++++++- tests/unit/test_upf_network.py | 26 ++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/upf_network.py b/src/upf_network.py index 0e43c72..2c6c882 100644 --- a/src/upf_network.py +++ b/src/upf_network.py @@ -68,6 +68,21 @@ def addresses_are_set(self) -> bool: logger.warning("Interface %s not found in the network database", self.name) return False + def interface_is_up(self) -> bool: + """Check if the given network interface is up.""" + interfaces = self.network_db.interfaces # type: ignore[reportAttributeAccessIssue] + if iface_record := interfaces.get(self.name): + return iface_record.state == "up" + logger.warning("Interface %s not found in the network database", self.name) + return False + + def bring_up_interface(self) -> None: + """Set the network interface status to up.""" + interfaces = self.network_db.interfaces # type: ignore[reportAttributeAccessIssue] + if iface_record := interfaces.get(self.name): + iface_record.up() + logger.warning("Interface %s not found in the network database", self.name) + def set_ip_address(self) -> None: """Clean all unrequired IPs and set the IP address for the given network interface.""" interfaces = self.network_db.interfaces # type: ignore[reportAttributeAccessIssue] @@ -296,10 +311,14 @@ def configure(self) -> None: self.access_interface.set_ip_address() if not self.access_interface.mtu_size_is_set(): self.access_interface.set_mtu_size() + if not self.access_interface.interface_is_up(): + self.access_interface.bring_up_interface() if not self.core_interface.addresses_are_set(): self.core_interface.set_ip_address() if not self.core_interface.mtu_size_is_set(): self.core_interface.set_mtu_size() + if not self.core_interface.interface_is_up(): + self.core_interface.bring_up_interface() if not self.default_route.exists(): logger.info("Default route does not exist") self.default_route.create() @@ -321,7 +340,11 @@ def is_configured(self) -> bool: and self.ran_route.exists() and self.ip_tables_rule.exists() ) - return ifaces_are_configured and routes_are_configured + interfaces_are_up = ( + self.access_interface.interface_is_up() + and self.core_interface.interface_is_up() + ) + return ifaces_are_configured and routes_are_configured and interfaces_are_up def clean_configuration(self) -> None: """Remove the configured IPs/routes from the networking.""" diff --git a/tests/unit/test_upf_network.py b/tests/unit/test_upf_network.py index 89795d7..79afead 100644 --- a/tests/unit/test_upf_network.py +++ b/tests/unit/test_upf_network.py @@ -23,11 +23,17 @@ def __init__(self, ipv4_address: str = "", ipv6_address: str = ""): class MockInterface: def __init__( - self, name: str, ipv4_address: str = "", ipv6_address: str = "", mtu_size: int = 1500 + self, + name: str, + ipv4_address: str = "", + ipv6_address: str = "", + mtu_size: int = 1500, + state: str = "down", ): self.name = name self.ipaddr = [MockIPAddr(ipv4_address=ipv4_address, ipv6_address=ipv6_address)] self.mtu = mtu_size + self.state = state def get(self, key): return getattr(self, key) @@ -151,6 +157,18 @@ def test_given_interface_has_ipv4_address_when_get_interface_ip_address_ip_is_re assert address == self.interface_ipv4_address + def test_given_interface_status_is_up_when_get_interface_status_then_state_is_up(self): + self.network_interface.network_db.interfaces = MockInterfaces( + interfaces=[ + MockInterface( + ipv4_address=self.interface_ipv4_address, + name=self.network_interface_name, + state="up", + ) + ] + ) + assert self.network_interface.interface_is_up() + def test_given_interface_doesnt_exist_when_get_interface_ip_address_then_empty_string_is_returned(self): # noqa: E501 self.network_interface.network_db.interfaces = MockInterfaces(interfaces=[]) @@ -158,6 +176,11 @@ def test_given_interface_doesnt_exist_when_get_interface_ip_address_then_empty_s assert address == "" + def test_given_interface_doesnt_exist_when_check_interface_states_then_false_is_returned(self): # noqa: E501 + self.network_interface.network_db.interfaces = MockInterfaces(interfaces=[]) + + assert self.network_interface.interface_is_up() is False + def test_given_interface_doesnt_have_ipv4_address_when_get_interface_ip_address_then_empty_string_is_returned(self): # noqa: E501 self.network_interface.network_db.interfaces = MockInterfaces( interfaces=[ @@ -1163,5 +1186,4 @@ def test_given_core_mtu_set_when_configure_then_set_mtu_size_is_not_called(self) ) upf_network.configure() - mock_core_interface_instance.set_mtu_size.assert_not_called() From 8f37e70926acc8e99a568ea7ad4caa29b7b6d414 Mon Sep 17 00:00:00 2001 From: gatici Date: Thu, 11 Jul 2024 12:26:44 +0300 Subject: [PATCH 2/5] Rearrange the code and tests Signed-off-by: gatici --- src/upf_network.py | 5 ++- tests/unit/test_upf_network.py | 68 ++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/src/upf_network.py b/src/upf_network.py index 2c6c882..f172e6f 100644 --- a/src/upf_network.py +++ b/src/upf_network.py @@ -72,7 +72,7 @@ def interface_is_up(self) -> bool: """Check if the given network interface is up.""" interfaces = self.network_db.interfaces # type: ignore[reportAttributeAccessIssue] if iface_record := interfaces.get(self.name): - return iface_record.state == "up" + return iface_record["state"] == "up" logger.warning("Interface %s not found in the network database", self.name) return False @@ -80,7 +80,8 @@ def bring_up_interface(self) -> None: """Set the network interface status to up.""" interfaces = self.network_db.interfaces # type: ignore[reportAttributeAccessIssue] if iface_record := interfaces.get(self.name): - iface_record.up() + iface_record.set(state="up") + iface_record.commit() logger.warning("Interface %s not found in the network database", self.name) def set_ip_address(self) -> None: diff --git a/tests/unit/test_upf_network.py b/tests/unit/test_upf_network.py index 79afead..17bde88 100644 --- a/tests/unit/test_upf_network.py +++ b/tests/unit/test_upf_network.py @@ -36,6 +36,10 @@ def __init__( self.state = state def get(self, key): + return self.__getitem__(key) + + def __getitem__(self, key): + """Return the given attribute from the interface.""" return getattr(self, key) @@ -1187,3 +1191,67 @@ def test_given_core_mtu_set_when_configure_then_set_mtu_size_is_not_called(self) upf_network.configure() mock_core_interface_instance.set_mtu_size.assert_not_called() + + def test_given_interfaces_are_down_when_configure_then_bring_up_interface_is_called_for_both_interfaces(self): # noqa: E501 + mock_access_interface_instance = MagicMock() + mock_access_interface_instance.is_valid.return_value = True + mock_access_interface_instance.addresses_are_set.return_value = True + mock_access_interface_instance.mtu_size_is_set.return_value = True + mock_access_interface_instance.interface_is_up.return_value = False + mock_core_interface_instance = MagicMock() + mock_core_interface_instance.is_valid.return_value = True + mock_core_interface_instance.addresses_are_set.return_value = True + mock_core_interface_instance.mtu_size_is_set.return_value = True + mock_core_interface_instance.interface_is_up.return_value = False + self.mock_network_interface.side_effect = [ + mock_access_interface_instance, + mock_core_interface_instance, + ] + upf_network = UPFNetwork( + access_interface_name=self.access_interface_name, + access_ip=self.access_ip, + access_gateway_ip=self.access_gateway_ip, + access_mtu_size=self.access_interface_mtu_size, + core_interface_name=self.core_interface_name, + core_ip=self.core_ip, + core_gateway_ip=self.core_gateway_ip, + core_mtu_size=self.core_interface_mtu_size, + gnb_subnet=self.gnb_subnet, + ) + + upf_network.configure() + + mock_access_interface_instance.bring_up_interface.assert_called_once() + mock_core_interface_instance.bring_up_interface.assert_called_once() + + def test_given_interfaces_are_up_when_configure_then_bring_up_interface_is_not_called(self): + mock_access_interface_instance = MagicMock() + mock_access_interface_instance.is_valid.return_value = True + mock_access_interface_instance.addresses_are_set.return_value = True + mock_access_interface_instance.mtu_size_is_set.return_value = True + mock_access_interface_instance.interface_is_up.return_value = True + mock_core_interface_instance = MagicMock() + mock_core_interface_instance.is_valid.return_value = True + mock_core_interface_instance.addresses_are_set.return_value = True + mock_core_interface_instance.mtu_size_is_set.return_value = True + mock_core_interface_instance.interface_is_up.return_value = True + self.mock_network_interface.side_effect = [ + mock_access_interface_instance, + mock_core_interface_instance, + ] + upf_network = UPFNetwork( + access_interface_name=self.access_interface_name, + access_ip=self.access_ip, + access_gateway_ip=self.access_gateway_ip, + access_mtu_size=self.access_interface_mtu_size, + core_interface_name=self.core_interface_name, + core_ip=self.core_ip, + core_gateway_ip=self.core_gateway_ip, + core_mtu_size=self.core_interface_mtu_size, + gnb_subnet=self.gnb_subnet, + ) + + upf_network.configure() + + mock_access_interface_instance.bring_up_interface.assert_not_called() + mock_core_interface_instance.bring_up_interface.assert_not_called() From 8384cff90800c5c9ecbea2472dc8b99ae730f5da Mon Sep 17 00:00:00 2001 From: gatici Date: Thu, 11 Jul 2024 15:10:11 +0300 Subject: [PATCH 3/5] Change the log messages Signed-off-by: gatici --- src/upf_network.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/upf_network.py b/src/upf_network.py index f172e6f..16bd94f 100644 --- a/src/upf_network.py +++ b/src/upf_network.py @@ -73,16 +73,21 @@ def interface_is_up(self) -> bool: interfaces = self.network_db.interfaces # type: ignore[reportAttributeAccessIssue] if iface_record := interfaces.get(self.name): return iface_record["state"] == "up" - logger.warning("Interface %s not found in the network database", self.name) + logger.warning( + "Checking the state of network interface is failed: Interface %s not found in the network database", + self.name, + ) return False def bring_up_interface(self) -> None: """Set the network interface status to up.""" interfaces = self.network_db.interfaces # type: ignore[reportAttributeAccessIssue] if iface_record := interfaces.get(self.name): - iface_record.set(state="up") - iface_record.commit() - logger.warning("Interface %s not found in the network database", self.name) + iface_record.set(state="up").commit() + logger.warning( + "Setting the interface state to up is failed: Interface %s not found in the network database", + self.name, + ) def set_ip_address(self) -> None: """Clean all unrequired IPs and set the IP address for the given network interface.""" From f1b9f54eb0fc8745dbf1d0cbec91541eb17e4da1 Mon Sep 17 00:00:00 2001 From: gatici Date: Thu, 11 Jul 2024 15:28:14 +0300 Subject: [PATCH 4/5] Fix linting issue Signed-off-by: gatici --- src/upf_network.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/upf_network.py b/src/upf_network.py index 16bd94f..70a95e1 100644 --- a/src/upf_network.py +++ b/src/upf_network.py @@ -74,7 +74,7 @@ def interface_is_up(self) -> bool: if iface_record := interfaces.get(self.name): return iface_record["state"] == "up" logger.warning( - "Checking the state of network interface is failed: Interface %s not found in the network database", + "Checking the state of network interface is failed: Interface %s not found in the network database", # noqa: E501 self.name, ) return False @@ -85,7 +85,7 @@ def bring_up_interface(self) -> None: if iface_record := interfaces.get(self.name): iface_record.set(state="up").commit() logger.warning( - "Setting the interface state to up is failed: Interface %s not found in the network database", + "Setting the interface state to up is failed: Interface %s not found in the network database", # noqa: E501 self.name, ) From 8d91ba8975fd973c65598e2c4453ef41b8e7c432 Mon Sep 17 00:00:00 2001 From: gatici Date: Thu, 11 Jul 2024 18:05:10 +0300 Subject: [PATCH 5/5] Add the missing return Signed-off-by: gatici --- src/upf_network.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/upf_network.py b/src/upf_network.py index 70a95e1..fea18f0 100644 --- a/src/upf_network.py +++ b/src/upf_network.py @@ -84,6 +84,7 @@ def bring_up_interface(self) -> None: interfaces = self.network_db.interfaces # type: ignore[reportAttributeAccessIssue] if iface_record := interfaces.get(self.name): iface_record.set(state="up").commit() + return logger.warning( "Setting the interface state to up is failed: Interface %s not found in the network database", # noqa: E501 self.name,