diff --git a/src/sonic_ax_impl/mibs/ietf/rfc1213.py b/src/sonic_ax_impl/mibs/ietf/rfc1213.py index 1a13c6f94..b5189083e 100644 --- a/src/sonic_ax_impl/mibs/ietf/rfc1213.py +++ b/src/sonic_ax_impl/mibs/ietf/rfc1213.py @@ -1,3 +1,5 @@ +import os +import re import ipaddress import python_arptable import socket @@ -179,9 +181,86 @@ def get_next(self, sub_id): return self.route_list[right] +class NetmaskUpdater(MIBUpdater): + def __init__(self): + super().__init__() + self.db_conn = Namespace.init_namespace_dbs() + self.netmask_map = {} + self.netmask_list = [] + + def _update_netmask_info(self, dev, ip): + if ip is None: return + + if_index = mibs.get_index_from_str(dev) + if if_index is None: return + + netip = ipaddress.ip_network(ip, False) + netip = str(netip) + + netmask = ip.split('/')[1] + netmask = int(netmask) + ip = ip.split('/')[0] + netip = netip.split('/')[0] + + netiptuple = ip2byte_tuple(netip) + iptuple = ip2byte_tuple(ip) + subid = (4,) + iptuple + + # Create map beteen subid and OID + oid_tuple = (1, 3, 6, 1, 2, 1, 4, 32, 1, 5) + self.netmask_map[subid] = oid_tuple + (if_index,) + (1, 4) + netiptuple + (netmask,) + self.netmask_list.append(subid) + + def update_data(self): + self.netmask_map = {} + self.netmask_list = [] + + interfaces = Namespace.dbs_keys(self.db_conn, mibs.APPL_DB, "INTF_TABLE:*") + for interface in interfaces: + ethTablePrefix = re.search(r"INTF_TABLE\:[A-Z][a-z0-9]+\:[0-9./]+", interface) + if ethTablePrefix is None: + continue + else: + dev = ethTablePrefix.group().split(':')[1] + ip = ethTablePrefix.group().split(':')[2] + + if ip.find(".") != -1: + self._update_netmask_info(dev, ip) + + process = os.popen('ip addr show eth0 | grep "\" | awk \'{ print $2 }\' | awk -F "/" \'{ print $1 }\'') + mgmt_ip = process.read().strip() + if (len(mgmt_ip) != 0): + self._update_netmask_info("eth0", mgmt_ip) + process.close() + + process = os.popen('ip addr show docker0 | grep "\" | awk \'{ print $2 }\' | awk -F "/" \'{ print $1 }\'') + docker_inet = process.read().strip() + if (len(docker_inet) != 0): + self._update_netmask_info("docker0", docker_inet) + process.close() + + process = os.popen('ip addr show docker0 | grep "\" | awk \'{ print $4 }\' | awk -F "/" \'{ print $1 }\'') + docker_brd = process.read().strip() + if (len(docker_brd) != 0): + self._update_netmask_info("docker0", docker_brd) + process.close() + + self.netmask_list.sort() + + def get_netmask_oid(self, sub_id): + return self.netmask_map.get(sub_id, None) + + def get_next(self, sub_id): + right = bisect_right(self.netmask_list, sub_id) + if right >= len(self.netmask_list): + return None + + return self.netmask_list[right] + class IpMib(metaclass=MIBMeta, prefix='.1.3.6.1.2.1.4'): arp_updater = ArpUpdater() nexthop_updater = NextHopUpdater() + netmask_updater = NetmaskUpdater() ipRouteNextHop = \ SubtreeMIBEntry('21.1.7', nexthop_updater, ValueType.IP_ADDRESS, nexthop_updater.nexthop) @@ -189,6 +268,9 @@ class IpMib(metaclass=MIBMeta, prefix='.1.3.6.1.2.1.4'): ipNetToMediaPhysAddress = \ SubtreeMIBEntry('22.1.2', arp_updater, ValueType.OCTET_STRING, arp_updater.arp_dest) + ipNetToNetMask = \ + SubtreeMIBEntry('34.1.5.1', netmask_updater, ValueType.OBJECT_IDENTIFIER, netmask_updater.get_netmask_oid) + class InterfacesUpdater(MIBUpdater): RFC1213_MAX_SPEED = 4294967295 @@ -398,6 +480,9 @@ def get_counter(self, sub_id, table_name): # TODO: mgmt counters not available through SNMP right now # COUNTERS DB does not have support for generic linux (mgmt) interface counters return 0 + elif oid in self.vlan_oid_name_map: + return 0 + elif oid in self.oid_lag_name_map: counter_value = 0 # Sum the values of this counter for all ports in the LAG. diff --git a/src/sonic_ax_impl/mibs/ietf/rfc2863.py b/src/sonic_ax_impl/mibs/ietf/rfc2863.py index 4074cdc61..d896258f2 100644 --- a/src/sonic_ax_impl/mibs/ietf/rfc2863.py +++ b/src/sonic_ax_impl/mibs/ietf/rfc2863.py @@ -246,6 +246,8 @@ def _get_counter(self, oid, table_name, mask): # TODO: mgmt counters not available through SNMP right now # COUNTERS DB does not have support for generic linux (mgmt) interface counters return 0 + if oid in self.vlan_oid_name_map: + return 0 if oid in self.oid_lag_name_map: counter_value = 0 diff --git a/tests/test_rfc1213.py b/tests/test_rfc1213.py index 8a4b2cee6..db135d363 100644 --- a/tests/test_rfc1213.py +++ b/tests/test_rfc1213.py @@ -3,6 +3,9 @@ import sonic_ax_impl import sys from unittest import TestCase +import pytest +from unittest.mock import MagicMock +from sonic_ax_impl.mibs.ietf.rfc1213 import NetmaskUpdater if sys.version_info.major == 3: from unittest import mock @@ -12,7 +15,7 @@ modules_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, os.path.join(modules_path, 'src')) -from sonic_ax_impl.mibs.ietf.rfc1213 import NextHopUpdater, InterfacesUpdater, DbTables +from sonic_ax_impl.mibs.ietf.rfc1213 import NextHopUpdater, InterfacesUpdater, DbTables, NetmaskUpdater class TestNextHopUpdater(TestCase): @@ -163,3 +166,53 @@ def mock_dbs_get_all(dbs, db_name, hash, *args, **kwargs): except TypeError: self.fail("Caught Type error") self.assertTrue(counter == None) + +class TestNetmaskUpdater(TestCase): + @mock.patch("sonic_ax_impl.mibs.Namespace.init_namespace_dbs", return_value="mock_db_conn") + @mock.patch('sonic_ax_impl.mibs.get_index_from_str', return_value=1) + @mock.patch('ax_interface.util.ip2byte_tuple', side_effect=lambda ip: tuple(map(int, ip.split('.')))) + def test_update_netmask_info(self, mock_ip2byte, mock_get_index, mock_namespace): + updater = NetmaskUpdater() + updater._update_netmask_info("eth0", "192.168.1.1/24") + + expected_key = (4, 192, 168, 1, 1) + self.assertIn(expected_key, updater.netmask_map) + self.assertIn(expected_key, updater.netmask_list) + + @mock.patch("ax_interface.util.ip2byte_tuple", side_effect=lambda ip: tuple(map(int, ip.split('.')))) + @mock.patch("sonic_ax_impl.mibs.get_index_from_str", return_value=2) + @mock.patch("sonic_ax_impl.mibs.ietf.rfc1213.Namespace.init_namespace_dbs", return_value="mock_db_conn") + @mock.patch("sonic_ax_impl.mibs.ietf.rfc1213.os.popen") + def test_update_data(self, mock_popen, mock_init_ns, mock_get_index, mock_ip2byte): + mock_dbs_keys = mock.MagicMock(return_value=[ + "INTF_TABLE:Eth0:192.168.1.1/24", + "INTF_TABLE:Docker0:10.0.0.1/8" + ]) + mock_init_ns.return_value = "mock_db_conn" + + with mock.patch("sonic_ax_impl.mibs.ietf.rfc1213.Namespace.dbs_keys", mock_dbs_keys): + def popen_side_effect(cmd): + mock_proc = MagicMock() + if "Eth0" in cmd and "print $2" in cmd: + mock_proc.read.return_value = "192.168.1.1/24\n" + elif "docker0" in cmd and "print $2" in cmd: + mock_proc.read.return_value = "172.17.0.1/24\n" + elif "docker0" in cmd and "print $4" in cmd: + mock_proc.read.return_value = "172.17.255.255/24\n" + else: + mock_proc.read.return_value = "192.168.1.1/24\n" + return mock_proc + + mock_popen.side_effect = popen_side_effect + + updater = NetmaskUpdater() + updater.update_data() + + self.assertGreater(len(updater.netmask_map), 0) + self.assertTrue(all(isinstance(k, tuple) for k in updater.netmask_list)) + + def test_get_next(self): + updater = NetmaskUpdater() + updater.netmask_list = [(4, 10, 0, 0, 1), (4, 192, 168, 1, 1), (4, 192, 168, 1, 2)] + self.assertEqual(updater.get_next((4, 10, 0, 0, 1)), (4, 192, 168, 1, 1)) + self.assertEqual(updater.get_next((4, 192, 168, 1, 2)), None) \ No newline at end of file