IMplementation for option to not create a FIB table entry when adding a neighbor entry

Change-Id: I952039e101031ee6a06e63f4c73d8eb359423e1a
Signed-off-by: Neale Ranns <nranns@cisco.com>
diff --git a/test/test_ip6.py b/test/test_ip6.py
index b95809b..e57e034 100644
--- a/test/test_ip6.py
+++ b/test/test_ip6.py
@@ -6,8 +6,8 @@
 from framework import VppTestCase, VppTestRunner
 from vpp_sub_interface import VppSubInterface, VppDot1QSubint
 from vpp_pg_interface import is_ipv6_misc
-from vpp_neighbor import find_nbr
-from vpp_ip_route import VppIpRoute, VppRoutePath
+from vpp_ip_route import VppIpRoute, VppRoutePath, find_route
+from vpp_neighbor import find_nbr, VppNeighbor
 
 from scapy.packet import Raw
 from scapy.layers.l2 import Ether, Dot1Q
@@ -351,6 +351,30 @@
         self.send_and_assert_no_replies(self.pg0, pkts,
                                         "No response to NS for unknown target")
 
+        #
+        # A neighbor entry that has no associated FIB-entry
+        #
+        self.pg0.generate_remote_hosts(4)
+        nd_entry = VppNeighbor(self,
+                               self.pg0.sw_if_index,
+                               self.pg0.remote_hosts[2].mac,
+                               self.pg0.remote_hosts[2].ip6,
+                               af=AF_INET6,
+                               is_no_fib_entry=1)
+        nd_entry.add_vpp_config()
+
+        #
+        # check we have the neighbor, but no route
+        #
+        self.assertTrue(find_nbr(self,
+                                 self.pg0.sw_if_index,
+                                 self.pg0._remote_hosts[2].ip6,
+                                 inet=AF_INET6))
+        self.assertFalse(find_route(self,
+                                    self.pg0._remote_hosts[2].ip6,
+                                    128,
+                                    inet=AF_INET6))
+
     def validate_ra(self, intf, rx, dst_ip=None, mtu=9000, pi_opt=None):
         if not dst_ip:
             dst_ip = intf.remote_ip6
diff --git a/test/test_neighbor.py b/test/test_neighbor.py
index 2ce0a63..1dfae24 100644
--- a/test/test_neighbor.py
+++ b/test/test_neighbor.py
@@ -5,7 +5,7 @@
 
 from framework import VppTestCase, VppTestRunner
 from vpp_neighbor import VppNeighbor, find_nbr
-from vpp_ip_route import VppIpRoute, VppRoutePath
+from vpp_ip_route import VppIpRoute, VppRoutePath, find_route
 
 from scapy.packet import Raw
 from scapy.layers.l2 import Ether, ARP
@@ -115,7 +115,7 @@
         #
         # Generate some hosts on the LAN
         #
-        self.pg1.generate_remote_hosts(4)
+        self.pg1.generate_remote_hosts(5)
 
         #
         # Send IP traffic to one of these unresolved hosts.
@@ -301,6 +301,25 @@
                                         "ARP req for non-local source")
 
         #
+        # A neighbor entry that has no associated FIB-entry
+        #
+        arp_no_fib = VppNeighbor(self,
+                                 self.pg1.sw_if_index,
+                                 self.pg1.remote_hosts[4].mac,
+                                 self.pg1.remote_hosts[4].ip4,
+                                 is_no_fib_entry=1)
+        arp_no_fib.add_vpp_config()
+
+        #
+        # check we have the neighbor, but no route
+        #
+        self.assertTrue(find_nbr(self,
+                                 self.pg1.sw_if_index,
+                                 self.pg1._remote_hosts[4].ip4))
+        self.assertFalse(find_route(self,
+                                    self.pg1._remote_hosts[4].ip4,
+                                    32))
+        #
         # cleanup
         #
         dyn_arp.remove_vpp_config()
diff --git a/test/vpp_ip_route.py b/test/vpp_ip_route.py
index 247263a..7a62b23 100644
--- a/test/vpp_ip_route.py
+++ b/test/vpp_ip_route.py
@@ -4,14 +4,31 @@
   object abstractions for representing IP routes in VPP
 """
 
-import socket
 from vpp_object import *
+from socket import inet_pton, inet_ntop, AF_INET, AF_INET6
 
 # from vnet/vnet/mpls/mpls_types.h
 MPLS_IETF_MAX_LABEL = 0xfffff
 MPLS_LABEL_INVALID = MPLS_IETF_MAX_LABEL + 1
 
 
+def find_route(test, ip_addr, len, table_id=0, inet=AF_INET):
+    if inet == AF_INET:
+        s = 4
+        routes = test.vapi.ip_fib_dump()
+    else:
+        s = 16
+        routes = test.vapi.ip6_fib_dump()
+
+    route_addr = inet_pton(inet, ip_addr)
+    for e in routes:
+        if route_addr == e.address[:s] \
+           and len == e.address_length \
+           and table_id == e.table_id:
+            return True
+    return False
+
+
 class VppRoutePath(object):
 
     def __init__(
@@ -27,9 +44,9 @@
         self.nh_via_label = nh_via_label
         self.nh_labels = labels
         if is_ip6:
-            self.nh_addr = socket.inet_pton(socket.AF_INET6, nh_addr)
+            self.nh_addr = inet_pton(AF_INET6, nh_addr)
         else:
-            self.nh_addr = socket.inet_pton(socket.AF_INET, nh_addr)
+            self.nh_addr = inet_pton(AF_INET, nh_addr)
 
 
 class VppMRoutePath(VppRoutePath):
@@ -56,17 +73,18 @@
         self.is_local = is_local
         self.is_unreach = is_unreach
         self.is_prohibit = is_prohibit
+        self.dest_addr_p = dest_addr
         if is_ip6:
-            self.dest_addr = socket.inet_pton(socket.AF_INET6, dest_addr)
+            self.dest_addr = inet_pton(AF_INET6, dest_addr)
         else:
-            self.dest_addr = socket.inet_pton(socket.AF_INET, dest_addr)
+            self.dest_addr = inet_pton(AF_INET, dest_addr)
 
     def add_vpp_config(self):
         if self.is_local or self.is_unreach or self.is_prohibit:
             self._test.vapi.ip_add_del_route(
                 self.dest_addr,
                 self.dest_addr_len,
-                socket.inet_pton(socket.AF_INET6, "::"),
+                inet_pton(AF_INET6, "::"),
                 0xffffffff,
                 is_local=self.is_local,
                 is_unreach=self.is_unreach,
@@ -93,7 +111,7 @@
             self._test.vapi.ip_add_del_route(
                 self.dest_addr,
                 self.dest_addr_len,
-                socket.inet_pton(socket.AF_INET6, "::"),
+                inet_pton(AF_INET6, "::"),
                 0xffffffff,
                 is_local=self.is_local,
                 is_unreach=self.is_unreach,
@@ -111,28 +129,20 @@
                                                  is_add=0)
 
     def query_vpp_config(self):
-        dump = self._test.vapi.ip_fib_dump()
-        for e in dump:
-            if self.dest_addr == e.address \
-               and self.dest_addr_len == e.address_length \
-               and self.table_id == e.table_id:
-                return True
-        return False
+        return find_route(self._test,
+                          self.dest_addr_p,
+                          self.dest_addr_len,
+                          self.table_id,
+                          inet=AF_INET6 if self.is_ip6 == 1 else AF_INET)
 
     def __str__(self):
         return self.object_id()
 
     def object_id(self):
-        if self.is_ip6:
-            return ("%d:%s/%d"
-                    % (self.table_id,
-                       socket.inet_ntop(socket.AF_INET6, self.dest_addr),
-                       self.dest_addr_len))
-        else:
-            return ("%d:%s/%d"
-                    % (self.table_id,
-                       socket.inet_ntop(socket.AF_INET, self.dest_addr),
-                       self.dest_addr_len))
+        return ("%d:%s/%d"
+                % (self.table_id,
+                   self.dest_addr_p,
+                   self.dest_addr_len))
 
 
 class VppIpMRoute(VppObject):
@@ -150,11 +160,11 @@
         self.is_ip6 = is_ip6
 
         if is_ip6:
-            self.grp_addr = socket.inet_pton(socket.AF_INET6, grp_addr)
-            self.src_addr = socket.inet_pton(socket.AF_INET6, src_addr)
+            self.grp_addr = inet_pton(AF_INET6, grp_addr)
+            self.src_addr = inet_pton(AF_INET6, src_addr)
         else:
-            self.grp_addr = socket.inet_pton(socket.AF_INET, grp_addr)
-            self.src_addr = socket.inet_pton(socket.AF_INET, src_addr)
+            self.grp_addr = inet_pton(AF_INET, grp_addr)
+            self.src_addr = inet_pton(AF_INET, src_addr)
 
     def add_vpp_config(self):
         for path in self.paths:
@@ -221,14 +231,14 @@
         if self.is_ip6:
             return ("%d:(%s,%s/%d)"
                     % (self.table_id,
-                       socket.inet_ntop(socket.AF_INET6, self.src_addr),
-                       socket.inet_ntop(socket.AF_INET6, self.grp_addr),
+                       inet_ntop(AF_INET6, self.src_addr),
+                       inet_ntop(AF_INET6, self.grp_addr),
                        self.grp_addr_len))
         else:
             return ("%d:(%s,%s/%d)"
                     % (self.table_id,
-                       socket.inet_ntop(socket.AF_INET, self.src_addr),
-                       socket.inet_ntop(socket.AF_INET, self.grp_addr),
+                       inet_ntop(AF_INET, self.src_addr),
+                       inet_ntop(AF_INET, self.grp_addr),
                        self.grp_addr_len))
 
 
@@ -261,7 +271,7 @@
     def __init__(self, test, local_label, dest_addr, dest_addr_len,
                  table_id=0, ip_table_id=0):
         self._test = test
-        self.dest_addr = socket.inet_pton(socket.AF_INET, dest_addr)
+        self.dest_addr = inet_pton(AF_INET, dest_addr)
         self.dest_addr_len = dest_addr_len
         self.local_label = local_label
         self.table_id = table_id
@@ -298,7 +308,7 @@
                 % (self.table_id,
                    self.local_label,
                    self.ip_table_id,
-                   socket.inet_ntop(socket.AF_INET, self.dest_addr),
+                   inet_ntop(AF_INET, self.dest_addr),
                    self.dest_addr_len))
 
 
diff --git a/test/vpp_neighbor.py b/test/vpp_neighbor.py
index 5c2e347..6968b5f 100644
--- a/test/vpp_neighbor.py
+++ b/test/vpp_neighbor.py
@@ -31,12 +31,13 @@
     """
 
     def __init__(self, test, sw_if_index, mac_addr, nbr_addr,
-                 af=AF_INET, is_static=False):
+                 af=AF_INET, is_static=False, is_no_fib_entry=False):
         self._test = test
         self.sw_if_index = sw_if_index
         self.mac_addr = mactobinary(mac_addr)
         self.af = af
         self.is_static = is_static
+        self.is_no_fib_entry = is_no_fib_entry
         self.nbr_addr = inet_pton(af, nbr_addr)
 
     def add_vpp_config(self):
@@ -46,7 +47,8 @@
             self.nbr_addr,
             is_add=1,
             is_ipv6=1 if AF_INET6 == self.af else 0,
-            is_static=self.is_static)
+            is_static=self.is_static,
+            is_no_adj_fib=self.is_no_fib_entry)
         self._test.registry.register(self, self._test.logger)
 
     def remove_vpp_config(self):
diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py
index 9207042..2d683dc 100644
--- a/test/vpp_papi_provider.py
+++ b/test/vpp_papi_provider.py
@@ -663,6 +663,7 @@
                             is_add=1,
                             is_ipv6=0,
                             is_static=0,
+                            is_no_adj_fib=0,
                             ):
         """ Add neighbor MAC to IPv4 or IPv6 address.
 
@@ -672,6 +673,7 @@
         :param is_add:  (Default value = 1)
         :param is_ipv6:  (Default value = 0)
         :param is_static:  (Default value = 0)
+        :param is_no_adj_fib:  (Default value = 0)
         """
 
         return self.api(
@@ -680,6 +682,7 @@
              'is_add': is_add,
              'is_ipv6': is_ipv6,
              'is_static': is_static,
+             'is_no_adj_fib': is_no_adj_fib,
              'mac_address': mac_address,
              'dst_address': dst_address
              }