Skip to content

Commit

Permalink
Implement ipRouteTable.ipRouteNextHop in MIB-2 (only default routes) (s…
Browse files Browse the repository at this point in the history
…onic-net#26)

* Implement ipRouteTable.ipRouteNextHop in MIB-2 (only default routes)

* Fix bug: crash if no default route
  • Loading branch information
qiluo-msft authored May 24, 2017
1 parent 2a1dd2f commit 46ab9d9
Show file tree
Hide file tree
Showing 2 changed files with 163 additions and 0 deletions.
50 changes: 50 additions & 0 deletions src/sonic_ax_impl/mibs/ietf/rfc1213.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import ipaddress
import python_arptable
from enum import unique, Enum
from bisect import bisect_right
Expand Down Expand Up @@ -84,8 +85,57 @@ def get_next(self, sub_id):
return None
return self.arp_dest_list[right]

class NextHopUpdater(MIBUpdater):
def __init__(self):
super().__init__()
self.db_conn = mibs.init_db()
self.update_data()

def update_data(self):
"""
Update redis (caches config)
Pulls the table references for each interface.
"""
self.nexthop_map = {}
self.route_list = []

self.db_conn.connect(mibs.APPL_DB)
route_entries = self.db_conn.keys(mibs.APPL_DB, "ROUTE_TABLE:*")
if not route_entries:
return

for route_entry in route_entries:
routestr = route_entry.decode()
ipnstr = routestr[len("ROUTE_TABLE:"):]
if ipnstr == "0.0.0.0/0":
ipn = ipaddress.ip_network(ipnstr)
ent = self.db_conn.get_all(mibs.APPL_DB, routestr, blocking=True)
nexthops = ent[b"nexthop"].decode()
for nh in nexthops.split(','):
# TODO: if ipn contains IP range, create more sub_id here
sub_id = ip2tuple_v4(ipn.network_address)
self.route_list.append(sub_id)
self.nexthop_map[sub_id] = ipaddress.ip_address(nh).packed
break # Just need the first nexthop

self.route_list.sort()

def nexthop(self, sub_id):
return self.nexthop_map.get(sub_id, None)

def get_next(self, sub_id):
right = bisect_right(self.route_list, sub_id)
if right >= len(self.route_list):
return None

return self.route_list[right]

class IpMib(metaclass=MIBMeta, prefix='.1.3.6.1.2.1.4'):
arp_updater = ArpUpdater()
nexthop_updater = NextHopUpdater()

ipRouteNextHop = \
SubtreeMIBEntry('21.1.7', nexthop_updater, ValueType.IP_ADDRESS, nexthop_updater.nexthop)

ipNetToMediaPhysAddress = \
SubtreeMIBEntry('22.1.2', arp_updater, ValueType.OCTET_STRING, arp_updater.arp_dest)
Expand Down
113 changes: 113 additions & 0 deletions tests/test_nexthop.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import os
import sys
import ipaddress

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

import tests.mock_tables.dbconnector

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 TestForwardMIB(TestCase):
@classmethod
def setUpClass(cls):
cls.lut = MIBTable(SonicMIB)

def test_network_order(self):
ip = ipaddress.ip_address("0.1.2.3")
ipb = ip.packed
ips = ".".join(str(int(x)) for x in list(ipb))
self.assertEqual(ips, "0.1.2.3")

def test_getpdu(self):
oid = ObjectIdentifier(14, 0, 1, 0, (1, 3, 6, 1, 2, 1, 4, 21, 1, 7, 0, 0, 0, 0))
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.IP_ADDRESS)
self.assertEqual(str(value0.name), str(oid))
self.assertEqual(str(value0.data), ipaddress.ip_address("10.0.0.1").packed.decode())

def test_getnextpdu(self):
get_pdu = GetNextPDU(
header=PDUHeader(1, PduTypes.GET, 16, 0, 42, 0, 0, 0),
oids=(
ObjectIdentifier(10, 0, 0, 0, (1, 3, 6, 1, 2, 1, 4, 21, 1, 7)),
)
)

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.IP_ADDRESS)
self.assertEqual(str(value0.data), ipaddress.ip_address("10.0.0.1").packed.decode())

def test_getnextpdu_exactmatch(self):
oid = ObjectIdentifier(14, 0, 1, 0, (1, 3, 6, 1, 2, 1, 4, 21, 1, 7, 0, 0, 0, 0))
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.IP_ADDRESS)
print("test_getnextpdu_exactmatch: ", str(oid))
self.assertEqual(str(value0.name), str(oid))
self.assertEqual(str(value0.data), ipaddress.ip_address("10.0.0.1").packed.decode())

def test_getpdu_noinstance(self):
get_pdu = GetPDU(
header=PDUHeader(1, PduTypes.GET, 16, 0, 42, 0, 0, 0),
oids=(
ObjectIdentifier(14, 0, 1, 0, (1, 3, 6, 1, 2, 1, 4, 21, 1, 7, 0, 0, 0, 1)),
)
)

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(14, 0, 1, 0, (1, 3, 6, 1, 2, 1, 4, 21, 1, 7, 0, 0, 0, 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)

0 comments on commit 46ab9d9

Please sign in to comment.