IP Multicast FIB (mfib)
[vpp.git] / test / vpp_papi_provider.py
index bdbcc3d..90c954d 100644 (file)
@@ -5,9 +5,9 @@ from hook import Hook
 from collections import deque
 
 # Sphinx creates auto-generated documentation by importing the python source
-# files and collecting the docstrings from them. The NO_VPP_PAPI flag allows the
-# vpp_papi_provider.py file to be importable without having to build the whole
-# vpp api if the user only wishes to generate the test documentation.
+# files and collecting the docstrings from them. The NO_VPP_PAPI flag allows
+# the vpp_papi_provider.py file to be importable without having to build
+# the whole vpp api if the user only wishes to generate the test documentation.
 do_import = True
 try:
     no_vpp_papi = os.getenv("NO_VPP_PAPI")
@@ -32,15 +32,17 @@ class VppPapiProvider(object):
     """VPP-api provider using vpp-papi
 
     @property hook: hook object providing before and after api/cli hooks
-
-
     """
 
+    _zero, _negative = range(2)
+
     def __init__(self, name, shm_prefix, test_class):
         self.hook = Hook("vpp-papi-provider")
         self.name = name
         self.shm_prefix = shm_prefix
         self.test_class = test_class
+        self._expect_api_retval = self._zero
+        self._expect_stack = []
         jsonfiles = []
 
         install_dir = os.getenv('VPP_TEST_INSTALL_PATH')
@@ -51,6 +53,24 @@ class VppPapiProvider(object):
         self.papi = VPP(jsonfiles)
         self._events = deque()
 
+    def __enter__(self):
+        return self
+
+    def expect_negative_api_retval(self):
+        """ Expect API failure """
+        self._expect_stack.append(self._expect_api_retval)
+        self._expect_api_retval = self._negative
+        return self
+
+    def expect_zero_api_retval(self):
+        """ Expect API success """
+        self._expect_stack.append(self._expect_api_retval)
+        self._expect_api_retval = self._zero
+        return self
+
+    def __exit__(self, exc_type, exc_value, traceback):
+        self._expect_api_retval = self._expect_stack.pop()
+
     def register_hook(self, hook):
         """Replace hook registration with new hook
 
@@ -113,11 +133,23 @@ class VppPapiProvider(object):
         """
         self.hook.before_api(api_fn.__name__, api_args)
         reply = api_fn(**api_args)
-        if hasattr(reply, 'retval') and reply.retval != expected_retval:
-            msg = "API call failed, expected retval == %d, got %s" % (
-                expected_retval, repr(reply))
-            self.test_class.logger.info(msg)
-            raise Exception(msg)
+        if self._expect_api_retval == self._negative:
+            if hasattr(reply, 'retval') and reply.retval >= 0:
+                msg = "API call passed unexpectedly: expected negative "\
+                    "return value instead of %d in %s" % \
+                    (reply.retval, repr(reply))
+                self.test_class.logger.info(msg)
+                raise Exception(msg)
+        elif self._expect_api_retval == self._zero:
+            if hasattr(reply, 'retval') and reply.retval != expected_retval:
+                msg = "API call failed, expected zero return value instead "\
+                    "of %d in %s" % (expected_retval, repr(reply))
+                self.test_class.logger.info(msg)
+                raise Exception(msg)
+        else:
+            raise Exception("Internal error, unexpected value for "
+                            "self._expect_api_retval %s" %
+                            self._expect_api_retval)
         self.hook.after_api(api_fn.__name__, api_args)
         return reply
 
@@ -219,6 +251,24 @@ class VppPapiProvider(object):
         return self.api(self.papi.sw_interface_ip6nd_ra_config,
                         {'sw_if_index': sw_if_index})
 
+    def ip6_sw_interface_ra_config(self, sw_if_index,
+                                   no,
+                                   suppress,
+                                   send_unicast):
+        return self.api(self.papi.sw_interface_ip6nd_ra_config,
+                        {'sw_if_index': sw_if_index,
+                         'is_no': no,
+                         'suppress': suppress,
+                         'send_unicast': send_unicast})
+
+    def ip6_sw_interface_enable_disable(self, sw_if_index, enable):
+        """
+        Enable/Disable An interface for IPv6
+        """
+        return self.api(self.papi.sw_interface_ip6_enable_disable,
+                        {'sw_if_index': sw_if_index,
+                         'enable': enable})
+
     def vxlan_add_del_tunnel(
             self,
             src_addr,
@@ -465,6 +515,10 @@ class VppPapiProvider(object):
         return self.api(self.papi.create_loopback,
                         {'mac_address': mac})
 
+    def delete_loopback(self, sw_if_index):
+        return self.api(self.papi.delete_loopback,
+                        {'sw_if_index': sw_if_index, })
+
     def ip_add_del_route(
             self,
             dst_address,
@@ -575,6 +629,54 @@ class VppPapiProvider(object):
              }
         )
 
+    def reset_vrf(self,
+                  vrf_id,
+                  is_ipv6=0,
+                  ):
+        """ Reset VRF (remove all routes etc.) request.
+
+        :param int vrf_id: ID of the FIB table / VRF to reset.
+        :param int is_ipv6: 1 for IPv6 neighbor, 0 for IPv4. (Default = 0)
+        """
+
+        return self.api(
+            self.papi.reset_vrf,
+            {'vrf_id': vrf_id,
+             'is_ipv6': is_ipv6,
+             }
+        )
+
+    def reset_fib(self,
+                  vrf_id,
+                  is_ipv6=0,
+                  ):
+        """ Reset VRF (remove all routes etc.) request.
+
+        :param int vrf_id: ID of the FIB table / VRF to reset.
+        :param int is_ipv6: 1 for IPv6 neighbor, 0 for IPv4. (Default = 0)
+        """
+
+        return self.api(
+            self.papi.reset_fib,
+            {'vrf_id': vrf_id,
+             'is_ipv6': is_ipv6,
+             }
+        )
+
+    def ip_dump(self,
+                is_ipv6=0,
+                ):
+        """ Return IP dump.
+
+        :param int is_ipv6: 1 for IPv6 neighbor, 0 for IPv4. (Default = 0)
+        """
+
+        return self.api(
+            self.papi.ip_dump,
+            {'is_ipv6': is_ipv6,
+             }
+        )
+
     def sw_interface_span_enable_disable(
             self, sw_if_index_from, sw_if_index_to, state=1):
         """
@@ -775,7 +877,8 @@ class VppPapiProvider(object):
     def snat_add_static_mapping(
             self,
             local_ip,
-            external_ip,
+            external_ip=0,
+            external_sw_if_index=0xFFFFFFFF,
             local_port=0,
             external_port=0,
             addr_only=1,
@@ -786,6 +889,7 @@ class VppPapiProvider(object):
 
         :param local_ip: Local IP address
         :param external_ip: External IP address
+        :param external_sw_if_index: External interface instead of IP address
         :param local_port: Local port number (Default value = 0)
         :param external_port: External port number (Default value = 0)
         :param addr_only: 1 if address only mapping, 0 if address and port
@@ -802,6 +906,7 @@ class VppPapiProvider(object):
              'external_ip_address': external_ip,
              'local_port': local_port,
              'external_port': external_port,
+             'external_sw_if_index': external_sw_if_index,
              'vrf_id': vrf_id})
 
     def snat_add_address_range(
@@ -848,6 +953,41 @@ class VppPapiProvider(object):
         """
         return self.api(self.papi.snat_show_config, {})
 
+    def snat_add_interface_addr(
+            self,
+            sw_if_index,
+            is_add=1):
+        """Add/del S-NAT address from interface
+
+        :param sw_if_index: Software index of the interface
+        :param is_add: 1 if add, 0 if delete (Default value = 1)
+        """
+        return self.api(self.papi.snat_add_del_interface_addr,
+                        {'is_add': is_add, 'sw_if_index': sw_if_index})
+
+    def snat_interface_addr_dump(self):
+        """Dump S-NAT addresses interfaces
+        :return: Dictionary of S-NAT addresses interfaces
+        """
+        return self.api(self.papi.snat_interface_addr_dump, {})
+
+    def snat_ipfix(
+            self,
+            domain_id=1,
+            src_port=4739,
+            enable=1):
+        """Enable/disable S-NAT IPFIX logging
+
+        :param domain_id: Observation domain ID (Default value = 1)
+        :param src_port: Source port number (Default value = 4739)
+        :param enable: 1 if enable, 0 if disable (Default value = 1)
+        """
+        return self.api(
+            self.papi.snat_ipfix_enable_disable,
+            {'domain_id': domain_id,
+             'src_port': src_port,
+             'enable': enable})
+
     def control_ping(self):
         self.api(self.papi.control_ping)
 
@@ -904,8 +1044,8 @@ class VppPapiProvider(object):
         """
         :param is_add:
         :param mask:
-        :param match_n_vectors (Default value = 1):
-        :param table_index (Default value = 0xFFFFFFFF)
+        :param match_n_vectors: (Default value = 1)
+        :param table_index: (Default value = 0xFFFFFFFF)
         :param nbuckets:  (Default value = 2)
         :param memory_size:  (Default value = 2097152)
         :param skip_n_vectors:  (Default value = 0)
@@ -1004,3 +1144,69 @@ class VppPapiProvider(object):
                 'template_interval': template_interval,
                 'udp_checksum': udp_checksum,
             })
+
+    def dhcp_proxy_config(self,
+                          dhcp_server,
+                          dhcp_src_address,
+                          rx_table_id=0,
+                          server_table_id=0,
+                          is_add=1,
+                          is_ipv6=0,
+                          insert_circuit_id=0):
+        return self.api(
+            self.papi.dhcp_proxy_config_2,
+            {
+                'rx_vrf_id': rx_table_id,
+                'server_vrf_id': server_table_id,
+                'is_ipv6': is_ipv6,
+                'is_add': is_add,
+                'insert_circuit_id': insert_circuit_id,
+                'dhcp_server': dhcp_server,
+                'dhcp_src_address': dhcp_src_address,
+            })
+
+    def dhcp_proxy_set_vss(self,
+                           table_id,
+                           fib_id,
+                           oui,
+                           is_add=1,
+                           is_ip6=0):
+        return self.api(
+            self.papi.dhcp_proxy_set_vss,
+            {
+                'tbl_id': table_id,
+                'fib_id': fib_id,
+                'is_ipv6': is_ip6,
+                'is_add': is_add,
+                'oui': oui,
+            })
+
+    def ip_mroute_add_del(self,
+                          src_address,
+                          grp_address,
+                          grp_address_length,
+                          e_flags,
+                          next_hop_sw_if_index,
+                          i_flags,
+                          table_id=0,
+                          create_vrf_if_needed=0,
+                          is_add=1,
+                          is_ipv6=0,
+                          is_local=0):
+        """
+        """
+        return self.api(
+            self.papi.ip_mroute_add_del,
+            {'next_hop_sw_if_index': next_hop_sw_if_index,
+             'entry_flags': e_flags,
+             'itf_flags': i_flags,
+             'create_vrf_if_needed': create_vrf_if_needed,
+             'is_add': is_add,
+             'is_ipv6': is_ipv6,
+             'is_local': is_local,
+             'grp_address_length': grp_address_length,
+             'grp_address': grp_address,
+             'src_address': src_address})
+
+    def mfib_signal_dump(self):
+        return self.api(self.papi.mfib_signal_dump, {})