tests: handle removed interface
[vpp.git] / test / vpp_ip_route.py
index cd70b38..f5e5a88 100644 (file)
@@ -5,10 +5,10 @@
 """
 
 from vpp_object import VppObject
-from socket import inet_pton, inet_ntop, AF_INET, AF_INET6
 from vpp_ip import DpoProto, INVALID_INDEX, VppIpAddressUnion, \
     VppIpMPrefix
 from ipaddress import ip_network, ip_address, IPv4Network, IPv6Network
+from vpp_papi_exceptions import UnexpectedApiReturnValueError
 
 # from vnet/vnet/mpls/mpls_types.h
 MPLS_IETF_MAX_LABEL = 0xfffff
@@ -20,23 +20,6 @@ except NameError:
     text_type = str
 
 
-class MRouteItfFlags:
-    MFIB_ITF_FLAG_NONE = 0
-    MFIB_ITF_FLAG_NEGATE_SIGNAL = 1
-    MFIB_ITF_FLAG_ACCEPT = 2
-    MFIB_ITF_FLAG_FORWARD = 4
-    MFIB_ITF_FLAG_SIGNAL_PRESENT = 8
-    MFIB_ITF_FLAG_INTERNAL_COPY = 16
-
-
-class MRouteEntryFlags:
-    MFIB_ENTRY_FLAG_NONE = 0
-    MFIB_ENTRY_FLAG_SIGNAL = 1
-    MFIB_ENTRY_FLAG_DROP = 2
-    MFIB_ENTRY_FLAG_CONNECTED = 4
-    MFIB_ENTRY_FLAG_INHERIT_ACCEPT = 8
-
-
 class FibPathProto:
     FIB_PATH_NH_PROTO_IP4 = 0
     FIB_PATH_NH_PROTO_IP6 = 1
@@ -188,16 +171,19 @@ class VppIpTable(VppObject):
     def __init__(self,
                  test,
                  table_id,
-                 is_ip6=0):
+                 is_ip6=0,
+                 register=True):
         self._test = test
         self.table_id = table_id
         self.is_ip6 = is_ip6
+        self.register = register
 
     def add_vpp_config(self):
         self._test.vapi.ip_table_add_del(is_add=1,
                                          table={'is_ip6': self.is_ip6,
                                                 'table_id': self.table_id})
-        self._test.registry.register(self, self._test.logger)
+        if self.register:
+            self._test.registry.register(self, self._test.logger)
         return self
 
     def remove_vpp_config(self):
@@ -354,15 +340,20 @@ class VppIpInterfaceBind(VppObject):
     def query_vpp_config(self):
         if 0 == self.table.table_id:
             return False
-        return self._test.vapi.sw_interface_get_table(
-            self.intf.sw_if_index,
-            self.table.is_ip6).vrf_id == self.table.table_id
+        try:
+            return self._test.vapi.sw_interface_get_table(
+                self.intf.sw_if_index,
+                self.table.is_ip6).vrf_id == self.table.table_id
+        except UnexpectedApiReturnValueError as e:
+            if e.retval == -2:  # INVALID_SW_IF_INDEX
+                return False
+            raise
 
     def object_id(self):
         return "interface-bind-%s-%s" % (self.intf, self.table)
 
 
-class VppMplsLabel(object):
+class VppMplsLabel:
     def __init__(self, value, mode=MplsLspMode.PIPE, ttl=64, exp=0):
         self.value = value
         self.mode = mode
@@ -394,7 +385,7 @@ class VppMplsLabel(object):
         return not (self == other)
 
 
-class VppFibPathNextHop(object):
+class VppFibPathNextHop:
     def __init__(self, addr,
                  via_label=MPLS_LABEL_INVALID,
                  next_hop_id=INVALID_INDEX):
@@ -425,7 +416,7 @@ class VppFibPathNextHop(object):
                 self.obj_id == other.obj_id)
 
 
-class VppRoutePath(object):
+class VppRoutePath:
 
     def __init__(
             self,
@@ -620,6 +611,110 @@ class VppIpRoute(VppObject):
         return c[0][self.stats_index]
 
 
+class VppIpRouteV2(VppObject):
+    """
+    IP Route V2
+    """
+
+    def __init__(self, test, dest_addr,
+                 dest_addr_len, paths, table_id=0,
+                 register=True, src=0):
+        self._test = test
+        self.paths = paths
+        self.table_id = table_id
+        self.prefix = mk_network(dest_addr, dest_addr_len)
+        self.register = register
+        self.stats_index = None
+        self.modified = False
+        self.src = src
+
+        self.encoded_paths = []
+        for path in self.paths:
+            self.encoded_paths.append(path.encode())
+
+    def __eq__(self, other):
+        if self.table_id == other.table_id and \
+           self.prefix == other.prefix:
+            return True
+        return False
+
+    def modify(self, paths):
+        self.paths = paths
+        self.encoded_paths = []
+        for path in self.paths:
+            self.encoded_paths.append(path.encode())
+        self.modified = True
+
+        self._test.vapi.ip_route_add_del_v2(route={'table_id': self.table_id,
+                                                   'prefix': self.prefix,
+                                                   'src': self.src,
+                                                   'n_paths': len(
+                                                       self.encoded_paths),
+                                                   'paths': self.encoded_paths,
+                                                   },
+                                            is_add=1,
+                                            is_multipath=0)
+
+    def add_vpp_config(self):
+        r = self._test.vapi.ip_route_add_del_v2(
+            route={'table_id': self.table_id,
+                   'prefix': self.prefix,
+                   'n_paths': len(self.encoded_paths),
+                   'paths': self.encoded_paths,
+                   'src': self.src,
+                   },
+            is_add=1,
+            is_multipath=0)
+        self.stats_index = r.stats_index
+        if self.register:
+            self._test.registry.register(self, self._test.logger)
+        return self
+
+    def remove_vpp_config(self):
+        # there's no need to issue different deletes for modified routes
+        # we do this only to test the two different ways to delete routes
+        # eiter by passing all the paths to remove and mutlipath=1 or
+        # passing no paths and multipath=0
+        if self.modified:
+            self._test.vapi.ip_route_add_del_v2(
+                route={'table_id': self.table_id,
+                       'prefix': self.prefix,
+                       'src': self.src,
+                       'n_paths': len(
+                           self.encoded_paths),
+                       'paths': self.encoded_paths},
+                is_add=0,
+                is_multipath=1)
+        else:
+            self._test.vapi.ip_route_add_del_v2(
+                route={'table_id': self.table_id,
+                       'prefix': self.prefix,
+                       'src': self.src,
+                       'n_paths': 0},
+                is_add=0,
+                is_multipath=0)
+
+    def query_vpp_config(self):
+        return find_route(self._test,
+                          self.prefix.network_address,
+                          self.prefix.prefixlen,
+                          self.table_id)
+
+    def object_id(self):
+        return ("%s:table-%d-%s" % (
+            'ip6-route' if self.prefix.version == 6 else 'ip-route',
+                self.table_id,
+                self.prefix))
+
+    def get_stats_to(self):
+        c = self._test.statistics.get_counter("/net/route/to")
+        return c[0][self.stats_index]
+
+    def get_stats_via(self):
+        c = self._test.statistics.get_counter("/net/route/via")
+        return c[0][self.stats_index]
+
+
 class VppIpMRoute(VppObject):
     """
     IP Multicast Route
@@ -705,7 +800,7 @@ class VppIpMRoute(VppObject):
         return c[0][self.stats_index]
 
 
-class VppMFibSignal(object):
+class VppMFibSignal:
     def __init__(self, test, route, interface, packet):
         self.route = route
         self.interface = interface