-
Notifications
You must be signed in to change notification settings - Fork 117
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
Implement ipNetToMediaPhysAddress (ARP table) #19
Changes from 5 commits
4af72bd
406ac06
de9b237
859652a
8b3f88d
d5ffbca
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ | |
dependencies = [ | ||
'sswsdk>=2.0.1', | ||
'psutil>=4.0', | ||
'python_arptable>=0.0.1', | ||
] | ||
|
||
test_deps = [ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,11 @@ | ||
import python_arptable | ||
from enum import unique, Enum | ||
from bisect import bisect_right | ||
|
||
from sonic_ax_impl import mibs | ||
from ax_interface import MIBMeta, ValueType, MIBUpdater, MIBEntry, ContextualMIBEntry | ||
from ax_interface import MIBMeta, ValueType, MIBUpdater, MIBEntry, ContextualMIBEntry, SubtreeMIBEntry | ||
from ax_interface.encodings import ObjectIdentifier | ||
from ax_interface.util import mac_decimals, ip2tuple_v4 | ||
|
||
|
||
@unique | ||
|
@@ -41,6 +44,53 @@ class DbTables(int, Enum): | |
# ifOutQLen ::= { ifEntry 21 } | ||
SAI_PORT_STAT_IF_OUT_QLEN = 21 | ||
|
||
class ArpUpdater(MIBUpdater): | ||
def __init__(self): | ||
super().__init__() | ||
self.arp_dest_map = {} | ||
self.arp_dest_list = [] | ||
# call our update method once to "seed" data before the "Agent" starts accepting requests. | ||
self.update_data() | ||
|
||
def update_data(self): | ||
self.arp_dest_map = {} | ||
self.arp_dest_list = [] | ||
for entry in python_arptable.get_arp_table(): | ||
dev = entry['Device'] | ||
mac = entry['HW address'] | ||
ip = entry['IP address'] | ||
|
||
if_index = mibs.get_index_from_str(dev) | ||
if if_index is None: continue | ||
|
||
mactuple = mac_decimals(mac) | ||
machex = ''.join(chr(b) for b in mactuple) | ||
# if MAC is all zero | ||
#if not any(mac): continue | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we remove this line? What to do if the mac is 0? #Resolved There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The correct behavior of incomplete ARP entry (an IP without MAC) is not clear in the protocol. ref: http://cric.grenoble.cnrs.fr/Administrateurs/Outils/MIBS/?oid=1.3.6.1.2.1.4.22.1.2 In reply to: 108499363 [](ancestors = 108499363) |
||
|
||
iptuple = ip2tuple_v4(ip) | ||
|
||
subid = (if_index,) + iptuple | ||
self.arp_dest_map[subid] = machex | ||
self.arp_dest_list.append(subid) | ||
|
||
# print(subid, dev, mac, ip) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we remove it? #Resolved There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
self.arp_dest_list.sort() | ||
|
||
def arp_dest(self, sub_id): | ||
return self.arp_dest_map.get(sub_id, None) | ||
|
||
def get_next(self, sub_id): | ||
right = bisect_right(self.arp_dest_list, sub_id) | ||
if right >= len(self.arp_dest_list): | ||
return None | ||
return self.arp_dest_list[right] | ||
|
||
class IpMib(metaclass=MIBMeta, prefix='.1.3.6.1.2.1.4'): | ||
arp_updater = ArpUpdater() | ||
|
||
ipNetToMediaPhysAddress = \ | ||
SubtreeMIBEntry('22.1.2', arp_updater, ValueType.OCTET_STRING, arp_updater.arp_dest) | ||
|
||
class InterfacesUpdater(MIBUpdater): | ||
def __init__(self): | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
IP address HW type Flags HW address Mask Device | ||
10.3.146.86 0x1 0x2 00:a0:a5:75:35:8d * eth0 | ||
10.0.0.35 0x1 0x2 52:54:00:a5:70:47 * Ethernet68 | ||
10.0.0.19 0x1 0x2 52:54:00:04:52:5d * Ethernet36 | ||
10.0.0.57 0x1 0x2 52:54:00:b4:59:59 * Ethernet112 | ||
10.3.146.1 0x1 0x2 00:00:5e:00:01:64 * eth0 | ||
10.3.146.244 0x1 0x2 e4:d3:f1:51:3c:80 * eth0 | ||
10.3.147.97 0x1 0x2 3c:94:d5:69:b5:02 * eth0 | ||
10.0.0.25 0x1 0x2 52:54:00:55:2d:fe * Ethernet48 | ||
10.3.146.75 0x1 0x2 00:a0:a5:76:17:70 * eth0 | ||
10.3.146.131 0x1 0x2 00:15:c7:21:f7:40 * eth0 | ||
10.0.0.21 0x1 0x2 52:54:00:d0:a0:8c * Ethernet40 | ||
10.3.147.223 0x1 0x2 00:17:0f:ac:c4:40 * eth0 | ||
10.3.146.78 0x1 0x2 3c:94:d5:68:9d:82 * eth0 | ||
10.3.146.184 0x1 0x2 e4:d3:f1:51:38:60 * eth0 | ||
10.3.146.170 0x1 0x2 30:e4:db:a4:c9:3f * eth0 | ||
10.0.0.33 0x1 0x2 7c:fe:90:5e:6b:a6 * Ethernet64 | ||
10.3.146.134 0x1 0x2 00:23:04:18:8e:c0 * eth0 | ||
10.3.146.15 0x1 0x2 00:1e:f7:f7:0a:80 * eth0 | ||
10.3.146.85 0x1 0x2 00:a0:a5:80:38:22 * eth0 | ||
10.0.0.45 0x1 0x2 52:54:00:d0:23:2b * Ethernet88 | ||
10.3.147.40 0x1 0x2 3c:94:d5:68:4a:82 * eth0 | ||
10.0.0.59 0x1 0x2 52:54:00:ae:c8:01 * Ethernet116 | ||
10.3.146.74 0x1 0x2 00:a0:a5:7a:39:ea * eth0 | ||
10.0.0.5 0x1 0x2 52:54:00:fc:50:3c * Ethernet8 | ||
10.3.146.130 0x1 0x2 00:15:c7:21:dd:00 * eth0 | ||
10.3.146.81 0x1 0x2 5c:5e:ab:de:70:ff * eth0 | ||
10.0.0.55 0x1 0x2 52:54:00:1b:d6:95 * Ethernet108 | ||
10.0.0.11 0x1 0x0 00:00:00:00:00:00 * Ethernet20 | ||
10.3.146.14 0x1 0x2 00:1e:f7:f7:14:40 * eth0 | ||
10.0.0.61 0x1 0x0 00:00:00:00:00:00 * Ethernet120 | ||
10.0.0.3 0x1 0x0 00:00:00:00:00:00 * Ethernet4 | ||
10.3.146.70 0x1 0x2 00:a0:a5:77:ef:f1 * eth0 | ||
10.3.146.162 0x1 0x2 58:8d:09:8c:3c:bf * eth0 | ||
10.3.146.172 0x1 0x2 a4:93:4c:da:f7:bf * eth0 | ||
10.0.0.29 0x1 0x0 00:00:00:00:00:00 * Ethernet56 | ||
10.3.146.95 0x1 0x2 00:a0:a5:85:f8:98 * eth0 | ||
10.3.146.187 0x1 0x2 6c:20:56:cb:20:40 * eth0 | ||
10.0.0.31 0x1 0x0 00:00:00:00:00:00 * Ethernet60 | ||
10.3.146.10 0x1 0x2 4c:76:25:eb:52:42 * eth0 | ||
10.3.147.225 0x1 0x2 00:22:91:86:10:00 * eth0 | ||
10.0.0.53 0x1 0x2 52:54:00:c3:a1:2d * Ethernet104 | ||
10.0.0.41 0x1 0x2 52:54:00:08:de:c3 * Ethernet80 | ||
10.3.146.190 0x1 0x2 e4:d3:f1:51:33:20 * eth0 | ||
10.0.0.15 0x1 0x2 52:54:00:c6:31:42 * Ethernet28 | ||
10.0.0.43 0x1 0x2 52:54:00:44:73:a4 * Ethernet84 | ||
10.3.146.3 0x1 0x2 f4:b5:2f:72:bf:f0 * eth0 | ||
10.3.147.250 0x1 0x2 4c:76:25:f4:c6:02 * eth0 | ||
10.0.0.49 0x1 0x2 52:54:00:74:c5:38 * Ethernet96 | ||
10.3.146.91 0x1 0x2 54:e0:32:cf:6f:ff * eth0 | ||
10.0.0.63 0x1 0x0 00:00:00:00:00:00 * Ethernet124 | ||
10.0.0.27 0x1 0x2 52:54:00:1c:90:c4 * Ethernet52 | ||
10.0.0.9 0x1 0x2 52:54:00:71:ae:0e * Ethernet16 | ||
10.3.146.157 0x1 0x2 00:1e:be:38:44:ff * eth0 | ||
10.3.147.239 0x1 0x2 ec:f4:bb:fe:80:a1 * eth0 | ||
10.0.0.7 0x1 0x2 52:54:00:d1:75:b4 * Ethernet12 | ||
10.3.146.72 0x1 0x2 00:a0:a5:80:26:07 * eth0 | ||
10.3.146.164 0x1 0x2 00:15:c6:df:03:7f * eth0 | ||
10.3.146.150 0x1 0x2 00:05:9b:7e:61:00 * eth0 | ||
10.3.147.224 0x1 0x2 00:22:91:85:88:00 * eth0 | ||
10.3.146.87 0x1 0x2 00:a0:a5:80:2c:7a * eth0 | ||
10.0.0.37 0x1 0x2 52:54:00:30:a7:95 * Ethernet72 | ||
10.3.146.16 0x1 0x2 ec:bd:1d:f2:a6:00 * eth0 | ||
10.0.0.51 0x1 0x2 52:54:00:36:5b:05 * Ethernet100 | ||
10.3.146.2 0x1 0x2 f4:b5:2f:79:b3:f0 * eth0 | ||
10.0.0.1 0x1 0x2 7c:fe:90:5e:6b:a6 * Ethernet0 | ||
10.0.0.13 0x1 0x2 52:54:00:88:3c:5e * Ethernet24 | ||
10.3.146.90 0x1 0x2 54:e0:32:cf:76:ff * eth0 | ||
10.3.146.182 0x1 0x2 6c:20:56:ee:c0:80 * eth0 | ||
10.0.0.47 0x1 0x2 52:54:00:77:e3:91 * Ethernet92 | ||
10.3.146.156 0x1 0x2 00:18:73:b1:7d:bf * eth0 | ||
10.0.0.23 0x1 0x2 52:54:00:df:ec:bf * Ethernet44 | ||
10.3.146.83 0x1 0x2 00:a0:a5:87:1d:28 * eth0 | ||
10.3.146.93 0x1 0x2 54:e0:32:cf:77:ff * eth0 | ||
10.3.146.79 0x1 0x2 3c:94:d5:60:40:c2 * eth0 | ||
10.3.146.171 0x1 0x2 c8:9c:1d:ee:7f:7f * eth0 | ||
10.0.0.39 0x1 0x2 52:54:00:66:a7:29 * Ethernet76 | ||
10.0.0.17 0x1 0x2 52:54:00:e7:53:c2 * Ethernet32 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import os | ||
import csv | ||
import unittest | ||
from unittest import TestCase, mock | ||
from unittest.mock import patch, mock_open, MagicMock | ||
|
||
INPUT_DIR = os.path.dirname(os.path.abspath(__file__)) | ||
|
||
import python_arptable | ||
|
||
# Backup original function | ||
_get_arp_table = getattr(python_arptable, 'get_arp_table') | ||
|
||
# Monkey patch | ||
def get_arp_table(): | ||
with open(INPUT_DIR + '/arp.txt') as farp: | ||
file_content = mock_open(read_data = farp.read()) | ||
file_content.return_value.__iter__ = lambda self : iter(self.readline, '') | ||
# file_content = MagicMock(name = 'open', spec = open) | ||
# file_content.return_value = iter(farp.readlines()) | ||
with patch('builtins.open', file_content): | ||
return _get_arp_table() | ||
|
||
# Replace the function with mocked one | ||
python_arptable.get_arp_table = get_arp_table |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
import os | ||
import sys | ||
import mock | ||
|
||
modules_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | ||
sys.path.insert(0, os.path.join(modules_path, 'src')) | ||
|
||
from unittest import TestCase | ||
from unittest.mock import patch, mock_open | ||
|
||
# noinspection PyUnresolvedReferences | ||
import tests.mock_tables.dbconnector | ||
import tests.mock_tables.python_arptable | ||
from ax_interface.mib import MIBTable | ||
from ax_interface.pdu import PDUHeader | ||
from ax_interface.pdu_implementations import GetPDU, GetNextPDU | ||
from ax_interface import ValueType | ||
from ax_interface.encodings import ObjectIdentifier | ||
from ax_interface.constants import PduTypes | ||
from sonic_ax_impl.mibs.ietf import rfc4363 | ||
from sonic_ax_impl.main import SonicMIB | ||
|
||
class TestSonicMIB(TestCase): | ||
@classmethod | ||
def setUpClass(cls): | ||
cls.lut = MIBTable(SonicMIB) | ||
|
||
def test_getpdu(self): | ||
oid = ObjectIdentifier(20, 0, 0, 0, (1, 3, 6, 1, 2, 1, 4, 22, 1, 2, 37, 10, 0, 0, 19)) | ||
get_pdu = GetPDU( | ||
header=PDUHeader(1, PduTypes.GET, 16, 0, 42, 0, 0, 0), | ||
oids=[oid] | ||
) | ||
|
||
encoded = get_pdu.encode() | ||
response = get_pdu.make_response(self.lut) | ||
print(response) | ||
|
||
value0 = response.values[0] | ||
self.assertEqual(value0.type_, ValueType.OCTET_STRING) | ||
self.assertEqual(str(value0.name), str(oid)) | ||
self.assertEqual(value0.data.string, b'\x52\x54\x00\x04\x52\x5d') | ||
|
||
def test_getnextpdu(self): | ||
get_pdu = GetNextPDU( | ||
header=PDUHeader(1, PduTypes.GET, 16, 0, 42, 0, 0, 0), | ||
oids=( | ||
ObjectIdentifier(20, 0, 0, 0, (1, 3, 6, 1, 2, 1, 4, 22, 1, 2, 37, 10, 0, 0, 19)), | ||
) | ||
) | ||
|
||
encoded = get_pdu.encode() | ||
response = get_pdu.make_response(self.lut) | ||
print(response) | ||
|
||
n = len(response.values) | ||
value0 = response.values[0] | ||
self.assertEqual(value0.type_, ValueType.OCTET_STRING) | ||
self.assertEqual(value0.data.string, b'\x52\x54\x00\xd0\xa0\x8c') | ||
|
||
def test_getnextpdu_exactmatch(self): | ||
# oid.include = 1 | ||
oid = ObjectIdentifier(20, 0, 1, 0, (1, 3, 6, 1, 2, 1, 4, 22, 1, 2, 37, 10, 0, 0, 19)) | ||
get_pdu = GetNextPDU( | ||
header=PDUHeader(1, PduTypes.GET, 16, 0, 42, 0, 0, 0), | ||
oids=[oid] | ||
) | ||
|
||
encoded = get_pdu.encode() | ||
response = get_pdu.make_response(self.lut) | ||
print(response) | ||
|
||
n = len(response.values) | ||
value0 = response.values[0] | ||
self.assertEqual(value0.type_, ValueType.OCTET_STRING) | ||
print("test_getnextpdu_exactmatch: ", str(oid)) | ||
self.assertEqual(str(value0.name), str(oid)) | ||
self.assertEqual(value0.data.string, b'\x52\x54\x00\x04\x52\x5d') | ||
|
||
def test_getpdu_noinstance(self): | ||
get_pdu = GetPDU( | ||
header=PDUHeader(1, PduTypes.GET, 16, 0, 42, 0, 0, 0), | ||
oids=( | ||
ObjectIdentifier(20, 0, 0, 0, (1, 3, 6, 1, 2, 1, 4, 22, 1, 2, 39)), | ||
) | ||
) | ||
|
||
encoded = get_pdu.encode() | ||
response = get_pdu.make_response(self.lut) | ||
print(response) | ||
|
||
n = len(response.values) | ||
value0 = response.values[0] | ||
self.assertEqual(value0.type_, ValueType.NO_SUCH_INSTANCE) | ||
|
||
def test_getnextpdu_empty(self): | ||
get_pdu = GetNextPDU( | ||
header=PDUHeader(1, PduTypes.GET, 16, 0, 42, 0, 0, 0), | ||
oids=( | ||
ObjectIdentifier(20, 0, 0, 0, (1, 3, 6, 1, 2, 1, 4, 22, 1, 3)), | ||
) | ||
) | ||
|
||
encoded = get_pdu.encode() | ||
response = get_pdu.make_response(self.lut) | ||
print(response) | ||
|
||
n = len(response.values) | ||
value0 = response.values[0] | ||
self.assertEqual(value0.type_, ValueType.END_OF_MIB_VIEW) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably it's better to compile this regexp in init?
Also is it possible to extract this value from string using something like
if_name.replace('Ethernet', '') ? #Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's keep it for readability and optimize if we find it on critical path. re library has the opportunity to hide the optimization without users changing code.
In reply to: 108313222 [](ancestors = 108313222)