Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improves route control script #710

Merged

Conversation

saltiyazan
Copy link
Contributor

@saltiyazan saltiyazan commented Aug 2, 2023

Improve the route_control.py script by adding logging, error handling, and threading.

This PR was motivated by the goal of improving logging and adding a thread that retries pinging endpoints that are not in the ARP table. (In case of packet loss for example when pinged for the first time). Other refactoring work has been done as well to improve the readability of the code and reduce complexity.

  1. Adds threading to ping IPs that don't have entries in the ARP table.
  2. Adds logging.
  3. Improves Error handling.
  4. Breaks the code into classes.

Breaks it into classes
Adds type hints and docstrings
Adds error handling
Adds logging
@omecproject
Copy link

Can one of the admins verify this patch?

@saltiyazan saltiyazan force-pushed the improves-route-control-script branch 7 times, most recently from 0f922e1 to 3ea8ee7 Compare August 3, 2023 11:23
@saltiyazan saltiyazan force-pushed the improves-route-control-script branch from 3ea8ee7 to dd0aa92 Compare August 3, 2023 11:38
Copy link

@gruyaume gruyaume left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall I feel like this code is pretty complex for what it's supposed to do. This PR increases the amount of lines of code by 50%. I understand that we have improved error handling but it also feels like we increased complexity

I understand why we want to go OOP, but the class selection and separation is "weird". I think we should spend a bit more time designing this. A class diagram could be useful.

I'm also yet unconvinced of the need for threads.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably should place tests in the project's test directory

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, we can move it no problem, but looking at the structure of the project and at some other test files being placed in many different locations, it becomes less clear to me which directory should hold these tests.

- name: Install dependencies
run: ./venv/bin/pip install -r conf/test_requirements.txt

- name: Lint with flake8
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we sure about introducing mypy/flake8 here? I'd have a different PR for this as there can be discussions on theses points alone independent of the code implementation below

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, this can and maybe should be part of different discussion :)
I removed flake8 and mypy for now.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(not related to this file)

In the PR description, please add context as to why we are making those changes in the first place.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

def tearDown(self):
self.ipdb.release()

def test_parse_valid_entry_and_dst_len_is_zero(self):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why drop the given/when/then test naming convention?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at tests in the projects, naming does not seem to follow a specific convention, tests seem to have descriptive names instead.
What do you think should use given/when/then? (Happy to do so)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went back to given/when/then ✅

Comment on lines 749 to 762
parser = argparse.ArgumentParser(
description='Basic IPv4 Routing Controller')
parser.add_argument('-i',
type=str,
nargs='+',
help='interface(s) to control')
parser.add_argument('--ip',
type=str,
default='localhost',
help='BESSD address')
parser.add_argument('--port', type=str, default='10514', help='BESSD port')

# for holding command-line arguments
global args
description="Basic IPv4 Routing Controller"
)
parser.add_argument(
"-i", type=str, nargs="+", help="interface(s) to control"
)
parser.add_argument(
"--ip", type=str, default="localhost", help="BESSD address"
)
parser.add_argument(
"--port", type=str, default="10514", help="BESSD port"
)

args = parser.parse_args()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whole block could have its own function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

self.ipdb = ipdb
self.bess_controller = bess_controller
self.route_parser = route_parser
self.ping_missing = Thread(target=self._ping_missing_entries, daemon=True) # noqa: E501
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this really need to be multi-threaded? It feels overkilled for what we really need

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable name is somewhat confusing, it's really a thread that we are talking about here.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It already is multi-threaded through ipdb and the event callback. I think this design is better than the alternative (the main thread looping and pinging missing entries), as the thread's job is really clear. Also, if in the future we need to react to other events, or execute other checks, we can start small threads with clear focus.


DESTINATION_IP = "NDA_DST"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"NDA_DST" is not an IP address. These variables are confusing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Improved the naming for these variables in general. ✅


def __init__(self, ipdb):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add typing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.



def mac2hex(mac):
return int(mac.replace(':', ''), 16)
class RouteEntryParser:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is more a function than an object.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, moved.

class RouteController:
def __init__(
self,
bess_controller: BessController,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does a RouteController have a bess_controller as an attribute?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RouteController uses the interface of BessController to add the routes in BESS.

Copy link

@ghislainbourgeois ghislainbourgeois left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work, added some comments.

Args:
update_module (str): The name of the module to delete.
"""
for i in range(MAX_RETRIES):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for i in range(MAX_RETRIES):
for _ in range(MAX_RETRIES):

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

self.ipdb = ipdb
self.bess_controller = bess_controller
self.route_parser = route_parser
self.ping_missing = Thread(target=self._ping_missing_entries, daemon=True) # noqa: E501

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It already is multi-threaded through ipdb and the event callback. I think this design is better than the alternative (the main thread looping and pinging missing entries), as the thread's job is really clear. Also, if in the future we need to react to other events, or execute other checks, we can start small threads with clear focus.

Comment on lines 522 to 526
unresolved_next_hop = self.unresolved_arp_queries_cache.get(
attr_dict[DESTINATION_IP]
)
gateway_mac = attr_dict[LINK_LAYER_ADDRESS]
if unresolved_next_hop:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
unresolved_next_hop = self.unresolved_arp_queries_cache.get(
attr_dict[DESTINATION_IP]
)
gateway_mac = attr_dict[LINK_LAYER_ADDRESS]
if unresolved_next_hop:
route_entry = self.unresolved_arp_queries_cache.get(
attr_dict[DESTINATION_IP]
)
gateway_mac = attr_dict[LINK_LAYER_ADDRESS]
if route_entry:

If we find the entry in the cache, it is not an unresolved next hop, since we just received the MAC address.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Optional[str]: The MAC address of the target IP.
"""
neighbors = ipr.get_neighbours(dst=target_ip)
for i in range(len(neighbors)):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for i in range(len(neighbors)):
for neighbor in neighbors:

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@saltiyazan saltiyazan force-pushed the improves-route-control-script branch from 77e6668 to 2d1c0d7 Compare August 9, 2023 15:58
Renames constants
Small changes in the design
Extracts arg parsing
@saltiyazan saltiyazan force-pushed the improves-route-control-script branch from 2d1c0d7 to d8c96b7 Compare August 9, 2023 16:02
@gab-arrobo
Copy link
Collaborator

Hi @saltiyazan, this is the ONF bot 🤖 I'm glad you want to contribute to our projects! However, before accepting your contribution, we need to ask you to sign a Contributor License Agreement (CLA). You can do it online, it will take only a few minutes:

✒️ 👉 https://cla.opennetworking.org

After signing, make sure to add your Github user ID saltiyazan to the agreement.

For more information or help:" https://wiki.opennetworking.org/x/BgCUI

@saltiyazan, you need to sign the CLA. So, the GitHub Actions can run

DELETE_ROUTE_ACTION = "RTM_DELROUTE"
NEW_ROUTE_ACTION = "RTM_NEWROUTE"
INTERFACE = "RTA_OIF"
DESTINATION_IP = "RTA_DST"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure of this variable name, it suggests it's an IP address.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same applies to a bunch of variables here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with you that it is a bit confusing.
For now I added a "KEY_" prefix, that might make it clearer that these variables hold key literals and not actual values.
Happy to hear any suggestion you might have.

@@ -0,0 +1,5 @@
pyroute2
scapy
flake8

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need flake8/mypy to run the tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, removed


# for retrieving neighbor info
from pyroute2 import IPDB, IPRoute
from pybess.bess import * # type: ignore[import]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd remove those "# type: ignore[import]" if we're not implementing mypy here

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This applies at a couple of places

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

ipr = IPRoute()
ipdb = IPDB()
bess_controller = BessController(ip_arg, port_arg)
controller = RouteController(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

route_controller may be a better variable name

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

"""
self.bess = self.get_bess(ip=bess_ip, port=bess_port)

def get_bess(self, ip: str, port: str) -> "BESS": # type: ignore[name-defined]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method should probably be private

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

"""Connects to the BESS daemon."""
bess = BESS() # type: ignore[name-defined]
logger.info("Connecting to BESS daemon...")
for _ in range(MAX_RETRIES):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAX_RETRIES should probably be specific to the BessController class and not be global. I'd suggest either changing the name or placing it under the BessController class

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved, same for SLEEP_S

gate_idx (int): Gate of the module used in the route.
module_name (str): The name of the module.
"""
logger.info(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to have the logging both before and after the action was completed. I think we're good with the other logs (errors or success)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This applies at a couple of places

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did some improvements. ✅

)
)

def del_module(self, module_name) -> None:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use "create", "link", "update", why not use "delete" (instead of "del")

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

)
)

def del_module(self, module_name) -> None:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing typing for module name

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed


link_route_module(bess, gateway_mac, item)
logger.info("Module %s destroyed", module_name)
logger.info("BESS resume all")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This log doesn't match with what has been done

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved

@saltiyazan saltiyazan force-pushed the improves-route-control-script branch 2 times, most recently from e917a36 to e5616f0 Compare August 28, 2023 12:35
Moves and renames constatns
@saltiyazan saltiyazan force-pushed the improves-route-control-script branch from e5616f0 to 1189218 Compare August 28, 2023 15:22
Fixes mac_to_hex function
Removes unnecessary int conversion
@gab-arrobo
Copy link
Collaborator

@saltiyazan, I am going to try to review your PR over the weekend. I am pretty busy until Thursday.

Copy link

@gruyaume gruyaume left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good but the unit tests could be improved. Our current implementation prevents future refactoring.

Comment on lines 53 to 55
def test_given_valid_ip_when_validate_ipv4_then_returns_true(self):
self.assertTrue(validate_ipv4("192.168.1.1"))
self.assertFalse(validate_ipv4("192.168.300.1"))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be 2 different tests, here we validate both the positive and negative outcomes

)
self.assertIsNone(result)

@patch.object(RouteController, "_handle_new_route_entry")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not patch private methods. With the state of the tests right now (we patch a _parse_route_entry_msg, _parse_route_entry_msg, _probe_addr and more), we can't refactor the code and expect the unit tests to still pass.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, I improved the tests.
Now we don't patch anything private.

Removes patches of private functions
Uses MAX_GATES-1 as gate index for default routes
@gab-arrobo
Copy link
Collaborator

ok to test

@saltiyazan
Copy link
Contributor Author

ok to test

Awesome @gab-arrobo , should I run some tests manually that are not ran by the CI? could you please tell me which ones? reading through the testing section I see that "PTF tests for BESS-UPF" might be the one not ran by the CI.

@gab-arrobo
Copy link
Collaborator

retest this please

Copy link
Collaborator

@gab-arrobo gab-arrobo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @saltiyazan, thanks for your contribution and sorry for the time it took me to review it.
There is an issue with your modifications because for some reason the output of the pipeline for the N6 interface (in my case, ens801f1) is not getting properly built/assembled. Attached are two files showing the pipeline. The one named current-routectl.svg shows the UPF pipeline using the current route-control.py script, while the other figure (new-routectl.svg) shows the UPF pipeline using your modified/improved route-control.py script and as you can see in the new-routectl.svg, the ens801f1Routes, ens801f1DstMACCB.... and ens801f1Merge are not getting connected and the route-control.py script is "responsible" for that connection. Please take a look at the issue and properly address it. Thanks!
new-routectl
current-routectl

@gab-arrobo gab-arrobo self-requested a review October 18, 2023 02:56
Copy link
Collaborator

@gab-arrobo gab-arrobo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue with connecting the modules for the output of the N6 interface is that the ens801f1Routes is trying to connect to the ens801f1DstMAC... using ogate 8191 which is already used by the ens801f1bad_route module. The correct ogate should be 0
image

@gab-arrobo gab-arrobo self-requested a review October 18, 2023 03:12
Comment on lines 397 to 398
if route_entry.prefix_len == 0 and route_entry.dest_prefix == "0.0.0.0":
gate_idx = self.MAX_GATES - 1
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue with the pipeline for the output of the N6 interface is due to this if statement. This route 0.0.0.0/0 is/was already added to the routes module and connected to the bad_route module using routes ogate 8191 in the ports.py. So, you cannot use it again the same ogate and this is why the output of the N6 pipeline does not get properly connected/linked.

@gab-arrobo gab-arrobo self-requested a review October 18, 2023 03:37
Comment on lines 397 to 400
if route_entry.prefix_len == 0 and route_entry.dest_prefix == "0.0.0.0":
gate_idx = self.MAX_GATES - 1
else:
print("The IP address {} is valid ipv6 address. Ignore ".format(ipb))
return
except:
print("The IP address {} is invalid".format(item.neighbor_ip))
return
# Probe ARP request by sending ping
send_ping(item.neighbor_ip)

# Probe ARP request
##send_arp(neighbor_ip, src_mac, item.iface)


def parse_new_route(msg):
item = NeighborEntry()
# Fetch prefix_len
item.prefix_len = msg['dst_len']
# Default route
if item.prefix_len == 0:
item.iprange = '0.0.0.0'

for att in msg['attrs']:
if 'RTA_DST' in att:
# Fetch IP range
# ('RTA_DST', iprange)
item.iprange = att[1]
if 'RTA_GATEWAY' in att:
# Fetch gateway MAC address
# ('RTA_GATEWAY', neighbor_ip)
item.neighbor_ip = att[1]
_mac = fetch_mac(att[1])
if not _mac:
gateway_mac = 0
else:
gateway_mac = mac2hex(_mac)
if 'RTA_OIF' in att:
# Fetch interface name
# ('RTA_OIF', iface)
item.iface = ipdb.interfaces[int(att[1])].ifname

if not item.iface in args.i or not item.iprange or not item.neighbor_ip:
# Neighbor info is invalid
del item
return

# if mac is 0, send ARP request
if gateway_mac == 0:
print('Adding entry {} in arp probe table. Neighbor: {}'.format(item.iface,item.neighbor_ip))
probe_addr(item, ipdb.interfaces[item.iface].address)

else: # if gateway_mac is set
print('Linking module {}Routes with {}Merge (Dest MAC: {})'.format(
item.iface, item.iface, _mac))

link_route_module(bess, gateway_mac, item)


def parse_new_neighbor(msg):
for att in msg['attrs']:
if 'NDA_DST' in att:
# ('NDA_DST', neighbor_ip)
neighbor_ip = att[1]
if 'NDA_LLADDR' in att:
# ('NDA_LLADDR', neighbor_mac)
gateway_mac = att[1]

item = arpcache.get(neighbor_ip)
if item:
print('Linking module {}Routes with {}Merge (Dest MAC: {})'.format(
item.iface, item.iface, gateway_mac))

# Add route entry, and add item in the registered neighbor cache
link_route_module(bess, mac2hex(gateway_mac), item)

# Remove entry from unresolved arp cache
del arpcache[neighbor_ip]


def parse_del_route(msg):
item = NeighborEntry()
for att in msg['attrs']:
if 'RTA_DST' in att:
# Fetch IP range
# ('RTA_DST', iprange)
item.iprange = att[1]
if 'RTA_GATEWAY' in att:
# Fetch gateway MAC address
# ('RTA_GATEWAY', neighbor_ip)
item.neighbor_ip = att[1]
if 'RTA_OIF' in att:
# Fetch interface name
# ('RTA_OIF', iface)
item.iface = ipdb.interfaces[int(att[1])].ifname
gate_idx = self._get_gate_idx(route_entry, route_module_name)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that the route for 0.0.0.0/0 is already set in the ports.py, a simple solution for the pipeline to be fully built/assembled would be to replace the following:

        if route_entry.prefix_len == 0 and route_entry.dest_prefix == "0.0.0.0":
            gate_idx = self.MAX_GATES - 1
        else:
            gate_idx = self._get_gate_idx(route_entry, route_module_name)

by this:

        gate_idx = self._get_gate_idx(route_entry, route_module_name)

image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @gab-arrobo
Thanks for looking into it. I made the suggested change :) Let me know if it's all good now.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks good. I am planning to approve and merge it later tonight. Again, thanks for your contribution.

Copy link
Collaborator

@gab-arrobo gab-arrobo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested and works as expected.

@gab-arrobo gab-arrobo merged commit 7018518 into omec-project:master Oct 19, 2023
10 checks passed
@gab-arrobo
Copy link
Collaborator

Hi @saltiyazan, quick question. I just noticed the message below in the GHA. Is it expected?

2023-10-19 17:39:35,954 ERROR Error parsing route entry message
Traceback (most recent call last):
  File "/home/runner/work/upf/upf/conf/route_control.py", line 679, in _parse_route_entry_msg
    attr_dict = dict(route_entry["attrs"])
                     ~~~~~~~~~~~^^^^^^^^^
TypeError: string indices must be integers, not 'str'

@saltiyazan
Copy link
Contributor Author

GHA

Yes, it is expected, this is logged by

try:
            attr_dict = dict(route_entry["attrs"])
        except Exception:
            logger.exception("Error parsing route entry message")
            return None

logger.exception logs the trace I think, and test_given_invalid_route_message_when_parse_message_then_returns_none is expected to run into the error, therefore the log messages.

@gab-arrobo
Copy link
Collaborator

GHA

Yes, it is expected, this is logged by

try:
            attr_dict = dict(route_entry["attrs"])
        except Exception:
            logger.exception("Error parsing route entry message")
            return None

logger.exception logs the trace I think, and test_given_invalid_route_message_when_parse_message_then_returns_none is expected to run into the error, therefore the log messages.

Ok, thanks for the clarification.

@gab-arrobo
Copy link
Collaborator

gab-arrobo commented Oct 19, 2023

@saltiyazan, any comments/thoughts about the deprecation of IPDB shown in the route-control-tests GHA? Is this something you can help to address?

..2023-10-19 18:16:04,892 WARNING Deprecation warning https://docs.pyroute2.org/ipdb_toc.html
2023-10-19 18:16:04,892 WARNING To remove this DeprecationWarning exception, start IPDB(deprecation_warning=False, ...)
/home/runner/work/upf/upf/venv/lib/python3.11/site-packages/pyroute2/ipdb/main.py:841: DeprecationWarning: IPDB module is deprecated and will be removed in 0.7.1
  warnings.warn(
2023-10-19 18:16:04,893 INFO Mac address found for 192.168.1.1, Mac: 00:1a:2b:3c:4d:5e
.2023-10-19 18:16:04,893 WARNING Deprecation warning https://docs.pyroute2.org/ipdb_toc.html
2023-10-19 18:16:04,893 WARNING To remove this DeprecationWarning exception, start IPDB(deprecation_warning=False, ...)

@saltiyazan
Copy link
Contributor Author

Chore: Use upstream project for UPF configurations canonical/sdcore-upf-bess-rock#10

@gab-arrobo I added it to the list of possible improvements our team could contribute to.

def test_given_invalid_ip_when_validate_ipv4_then_returns_false(self):
self.assertFalse(validate_ipv4("192.168.300.1"))

def test_given_invalid_ip_when_validate_ipv4_then_returns_false(self):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @saltiyazan, I am working on replacing the IPDB for the NDB and while doing so, I noticed that this test has the exact same name as the previous definition/function. Should it be IPv6 instead of IPv4?

-    def test_given_invalid_ip_when_validate_ipv4_then_returns_false(self):
+    def test_given_invalid_ip_when_validate_ipv6_then_returns_false(self):

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @gab-arrobo
It seems like this should have been one test case asserting on different values.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants