acl: memory leak in acl_fa_session_cleaner_process
[vpp.git] / test / vpp_papi_provider.py
index 1b2895e..a4a3799 100644 (file)
+# NB NB NB NB NB NB NB NB NB NB NB
+#
+# NOTE: The API binary wrappers in this file are in the process of being
+# deprecated. DO NOT ADD NEW WRAPPERS HERE. Call the functions using
+# named arguments directly instead.
+#
+
 import os
-import fnmatch
 import time
+import queue
+from six import moves, iteritems
+from config import config
+from vpp_papi import VPPApiClient
 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.
-do_import = True
-try:
-    no_vpp_papi = os.getenv("NO_VPP_PAPI")
-    if no_vpp_papi == "1":
-        do_import = False
-except:
-    pass
-
-if do_import:
-    from vpp_papi import VPP
-
-# from vnet/vnet/mpls/mpls_types.h
-MPLS_IETF_MAX_LABEL = 0xfffff
-MPLS_LABEL_INVALID = MPLS_IETF_MAX_LABEL + 1
-
-
-class L2_VTR_OP:
-    L2_POP_1 = 3
+from vpp_papi_exceptions import (
+    CliFailedCommandError,
+    CliSyntaxError,
+    UnexpectedApiReturnValueError,
+)
+
+#
+# Dictionary keyed on message name to override default values for
+# named parameters
+#
+defaultmapping = {
+    "acl_interface_add_del": {"is_add": 1, "is_input": 1},
+    "bd_ip_mac_add_del": {
+        "is_add": 1,
+    },
+    "bfd_udp_add": {"is_authenticated": False, "bfd_key_id": None, "conf_key_id": None},
+    "bfd_udp_auth_activate": {
+        "bfd_key_id": None,
+        "conf_key_id": None,
+        "is_delayed": False,
+    },
+    "bier_disp_entry_add_del": {
+        "next_hop_rpf_id": -1,
+        "next_hop_is_ip4": 1,
+        "is_add": 1,
+    },
+    "bier_disp_table_add_del": {
+        "is_add": 1,
+    },
+    "bier_imp_add": {
+        "is_add": 1,
+    },
+    "bier_route_add_del": {
+        "is_add": 1,
+    },
+    "bier_table_add_del": {
+        "is_add": 1,
+    },
+    "bridge_domain_add_del": {
+        "flood": 1,
+        "uu_flood": 1,
+        "forward": 1,
+        "learn": 1,
+        "is_add": 1,
+    },
+    "bvi_delete": {},
+    "geneve_add_del_tunnel": {
+        "mcast_sw_if_index": 4294967295,
+        "is_add": 1,
+        "decap_next_index": 4294967295,
+    },
+    "input_acl_set_interface": {
+        "ip4_table_index": 4294967295,
+        "ip6_table_index": 4294967295,
+        "l2_table_index": 4294967295,
+    },
+    "ip6_add_del_address_using_prefix": {
+        "is_add": 1,
+    },
+    "ip6nd_send_router_solicitation": {
+        "irt": 1,
+        "mrt": 120,
+    },
+    "ip_add_del_route": {
+        "next_hop_sw_if_index": 4294967295,
+        "next_hop_weight": 1,
+        "next_hop_via_label": 1048576,
+        "classify_table_index": 4294967295,
+        "is_add": 1,
+    },
+    "ip_mroute_add_del": {
+        "is_add": 1,
+    },
+    "ip_neighbor_add_del": {
+        "is_add": 1,
+    },
+    "ipsec_interface_add_del_spd": {
+        "is_add": 1,
+    },
+    "ipsec_spd_add_del": {
+        "is_add": 1,
+    },
+    "ipsec_spd_dump": {
+        "sa_id": 4294967295,
+    },
+    "ipsec_spd_entry_add_del": {
+        "local_port_stop": 65535,
+        "remote_port_stop": 65535,
+        "priority": 100,
+        "is_outbound": 1,
+        "is_add": 1,
+    },
+    "ipsec_tunnel_if_add_del": {
+        "is_add": 1,
+        "anti_replay": 1,
+    },
+    "l2_emulation": {
+        "enable": 1,
+    },
+    "l2fib_add_del": {
+        "is_add": 1,
+    },
+    "lisp_add_del_adjacency": {
+        "is_add": 1,
+    },
+    "lisp_add_del_local_eid": {
+        "is_add": 1,
+    },
+    "lisp_add_del_locator": {
+        "priority": 1,
+        "weight": 1,
+        "is_add": 1,
+    },
+    "lisp_add_del_locator_set": {
+        "is_add": 1,
+    },
+    "lisp_add_del_remote_mapping": {
+        "is_add": 1,
+    },
+    "macip_acl_interface_add_del": {
+        "is_add": 1,
+    },
+    "mpls_ip_bind_unbind": {
+        "is_ip4": 1,
+        "is_bind": 1,
+    },
+    "mpls_route_add_del": {
+        "mr_next_hop_sw_if_index": 4294967295,
+        "mr_next_hop_weight": 1,
+        "mr_next_hop_via_label": 1048576,
+        "mr_is_add": 1,
+        "mr_classify_table_index": 4294967295,
+    },
+    "mpls_table_add_del": {
+        "is_add": 1,
+    },
+    "mpls_tunnel_add_del": {
+        "next_hop_sw_if_index": 4294967295,
+        "next_hop_weight": 1,
+        "next_hop_via_label": 1048576,
+        "is_add": 1,
+    },
+    "output_acl_set_interface": {
+        "ip4_table_index": 4294967295,
+        "ip6_table_index": 4294967295,
+        "l2_table_index": 4294967295,
+    },
+    "pppoe_add_del_session": {
+        "is_add": 1,
+    },
+    "policer_add_del": {
+        "is_add": 1,
+        "conform_action": {"type": 1},
+    },
+    "set_ipfix_exporter": {
+        "collector_port": 4739,
+    },
+    "sr_policy_add": {
+        "weight": 1,
+        "is_encap": 1,
+    },
+    "sw_interface_add_del_address": {
+        "is_add": 1,
+    },
+    "sw_interface_ip6nd_ra_prefix": {
+        "val_lifetime": 4294967295,
+        "pref_lifetime": 4294967295,
+    },
+    "sw_interface_set_ip_directed_broadcast": {
+        "enable": 1,
+    },
+    "sw_interface_set_l2_bridge": {
+        "enable": 1,
+    },
+    "sw_interface_set_mpls_enable": {
+        "enable": 1,
+    },
+    "sw_interface_set_mtu": {
+        "mtu": [0, 0, 0, 0],
+    },
+    "sw_interface_set_unnumbered": {
+        "is_add": 1,
+    },
+    "sw_interface_span_enable_disable": {
+        "state": 1,
+    },
+    "vxlan_add_del_tunnel": {
+        "mcast_sw_if_index": 4294967295,
+        "is_add": 1,
+        "decap_next_index": 4294967295,
+        "instance": 4294967295,
+    },
+    "want_bfd_events": {
+        "enable_disable": 1,
+    },
+    "want_igmp_events": {
+        "enable": 1,
+    },
+    "want_interface_events": {
+        "enable_disable": 1,
+    },
+    "want_l2_macs_events": {
+        "enable_disable": 1,
+        "pid": os.getpid(),
+    },
+    "want_l2_macs_events2": {
+        "enable_disable": 1,
+        "pid": os.getpid(),
+    },
+}
+
+
+def as_fn_signature(d):
+    return ", ".join(f"{k}={v}" for k, v in d.items())
 
 
 class VppPapiProvider(object):
@@ -36,34 +236,49 @@ class VppPapiProvider(object):
 
     _zero, _negative = range(2)
 
-    def __init__(self, name, shm_prefix, test_class):
-        self.hook = Hook("vpp-papi-provider")
+    def __init__(self, name, test_class, read_timeout):
+        self.hook = Hook(test_class)
         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')
-        for root, dirnames, filenames in os.walk(install_dir):
-            for filename in fnmatch.filter(filenames, '*.api.json'):
-                jsonfiles.append(os.path.join(root, filename))
+        # install_dir is a class attribute. We need to set it before
+        # calling the constructor.
+        VPPApiClient.apidir = config.vpp_install_dir
 
-        self.papi = VPP(jsonfiles)
-        self._events = deque()
+        self.vpp = VPPApiClient(
+            logger=test_class.logger,
+            read_timeout=read_timeout,
+            use_socket=True,
+            server_address=test_class.get_api_sock_path(),
+        )
+        self._events = queue.Queue()
 
     def __enter__(self):
         return self
 
-    def expect_negative_api_retval(self):
-        """ Expect API failure """
+    def assert_negative_api_retval(self):
+        """Expect API failure - used with with, e.g.::
+
+            with self.vapi.assert_negative_api_retval():
+                self.vapi.<api call expected to fail>
+
+        ..
+        """
         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 """
+    def assert_zero_api_retval(self):
+        """Expect API success - used with with, e.g.::
+
+            with self.vapi.assert_negative_api_retval():
+                self.vapi.<api call expected to succeed>
+
+        :note: this is useful only inside another with block
+             as success is the default expected value
+        """
         self._expect_stack.append(self._expect_api_retval)
         self._expect_api_retval = self._zero
         return self
@@ -80,49 +295,90 @@ class VppPapiProvider(object):
         self.hook = hook
 
     def collect_events(self):
-        """ Collect all events from the internal queue and clear the queue. """
-        e = self._events
-        self._events = deque()
-        return e
+        """Collect all events from the internal queue and clear the queue."""
+        result = []
+        while True:
+            try:
+                e = self._events.get(block=False)
+                result.append(e)
+            except queue.Empty:
+                return result
+        return result
 
     def wait_for_event(self, timeout, name=None):
-        """ Wait for and return next event. """
-        if self._events:
-            self.test_class.logger.debug("Not waiting, event already queued")
-        limit = time.time() + timeout
-        while time.time() < limit:
-            if self._events:
-                e = self._events.popleft()
-                if name and type(e).__name__ != name:
-                    raise Exception(
-                        "Unexpected event received: %s, expected: %s" %
-                        (type(e).__name__, name))
-                self.test_class.logger.debug("Returning event %s:%s" %
-                                             (name, e))
-                return e
-            time.sleep(0)  # yield
-        if name is not None:
-            raise Exception("Event %s did not occur within timeout" % name)
-        raise Exception("Event did not occur within timeout")
+        """Wait for and return next event."""
+        if name:
+            self.test_class.logger.debug(
+                "Expecting event '%s' within %ss", name, timeout
+            )
+        else:
+            self.test_class.logger.debug("Expecting event within %ss", timeout)
+        try:
+            e = self._events.get(timeout=timeout)
+        except queue.Empty:
+            raise Exception("Event did not occur within timeout")
+        msgname = type(e).__name__
+        if name and msgname != name:
+            raise Exception("Unexpected event received: %s, expected: %s" % msgname)
+        self.test_class.logger.debug("Returning event %s:%s" % (name, e))
+        return e
 
     def __call__(self, name, event):
-        """ Enqueue event in the internal event queue. """
-        # FIXME use the name instead of relying on type(e).__name__ ?
-        # FIXME #2 if this throws, it is eaten silently, Ole?
+        """Enqueue event in the internal event queue."""
         self.test_class.logger.debug("New event: %s: %s" % (name, event))
-        self._events.append(event)
+        self._events.put(event)
+
+    def factory(self, name, apifn):
+        def f(*a, **ka):
+            fields = apifn._func.msg.fields
+
+            # add positional and kw arguments
+            d = ka
+            for i, o in enumerate(fields[3:]):
+                try:
+                    d[o] = a[i]
+                except BaseException:
+                    break
+
+            # Default override
+            if name in defaultmapping:
+                for k, v in iteritems(defaultmapping[name]):
+                    if k in d:
+                        continue
+                    d[k] = v
+            return self.api(apifn, d)
+
+        return f
+
+    def __getattribute__(self, name):
+        try:
+            method = super(VppPapiProvider, self).__getattribute__(name)
+        except AttributeError:
+            method = self.factory(name, getattr(self.papi, name))
+            # lazily load the method so we don't need to call factory
+            # again for this name.
+            setattr(self, name, method)
+        return method
 
     def connect(self):
         """Connect the API to VPP"""
-        self.papi.connect(self.name, self.shm_prefix)
-        self.papi.register_event_callback(self)
+        # This might be called before VPP is prepared to listen to the socket
+        retries = 0
+        while not os.path.exists(self.test_class.get_api_sock_path()):
+            time.sleep(0.5)
+            retries += 1
+            if retries > 120:
+                break
+        self.vpp.connect(self.name[:63])
+        self.papi = self.vpp.api
+        self.vpp.register_event_callback(self)
 
     def disconnect(self):
         """Disconnect the API from VPP"""
-        self.papi.disconnect()
+        self.vpp.disconnect()
 
     def api(self, api_fn, api_args, expected_retval=0):
-        """ Call API function and check it's return value.
+        """Call API function and check it's return value.
         Call the appropriate hooks before and after the API call
 
         :param api_fn: API function to call
@@ -134,1047 +390,766 @@ class VppPapiProvider(object):
         self.hook.before_api(api_fn.__name__, api_args)
         reply = api_fn(**api_args)
         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))
+            if hasattr(reply, "retval") and reply.retval >= 0:
+                msg = (
+                    "%s(%s) passed unexpectedly: expected negative "
+                    "return value instead of %d in %s"
+                    % (
+                        api_fn.__name__,
+                        as_fn_signature(api_args),
+                        reply.retval,
+                        moves.reprlib.repr(reply),
+                    )
+                )
                 self.test_class.logger.info(msg)
-                raise Exception(msg)
+                raise UnexpectedApiReturnValueError(reply.retval, 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))
+            if hasattr(reply, "retval") and reply.retval != expected_retval:
+                msg = (
+                    "%s(%s) failed, expected %d return value instead "
+                    "of %d in %s"
+                    % (
+                        api_fn.__name__,
+                        as_fn_signature(api_args),
+                        expected_retval,
+                        reply.retval,
+                        repr(reply),
+                    )
+                )
                 self.test_class.logger.info(msg)
-                raise Exception(msg)
+                raise UnexpectedApiReturnValueError(reply.retval, msg)
         else:
-            raise Exception("Internal error, unexpected value for "
-                            "self._expect_api_retval %s" %
-                            self._expect_api_retval)
+            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
 
-    def cli(self, cli):
-        """ Execute a CLI, calling the before/after hooks appropriately.
+    def cli_return_response(self, cli):
+        """Execute a CLI, calling the before/after hooks appropriately.
+        Return the reply without examining it
 
         :param cli: CLI to execute
-        :returns: CLI output
+        :returns: response object
 
         """
         self.hook.before_cli(cli)
-        cli += '\n'
-        r = self.papi.cli_inband(length=len(cli), cmd=cli)
+        cli += "\n"
+        r = self.papi.cli_inband(cmd=cli)
         self.hook.after_cli(cli)
-        if hasattr(r, 'reply'):
-            return r.reply.decode().rstrip('\x00')
+        return r
 
-    def ppcli(self, cli):
-        """ Helper method to print CLI command in case of info logging level.
+    def cli(self, cli):
+        """Execute a CLI, calling the before/after hooks appropriately.
 
         :param cli: CLI to execute
         :returns: CLI output
-        """
-        return cli + "\n" + str(self.cli(cli))
-
-    def _convert_mac(self, mac):
-        return int(mac.replace(":", ""), 16) << 16
-
-    def show_version(self):
-        """ """
-        return self.papi.show_version()
 
-    def pg_create_interface(self, pg_index):
         """
+        r = self.cli_return_response(cli)
+        if r.retval == -156:
+            raise CliSyntaxError(r.reply)
+        if r.retval != 0:
+            raise CliFailedCommandError(r.reply)
+        if hasattr(r, "reply"):
+            return r.reply
 
-        :param pg_index:
+    def ppcli(self, cli):
+        """Helper method to print CLI command in case of info logging level.
 
+        :param cli: CLI to execute
+        :returns: CLI output
         """
-        return self.api(self.papi.pg_create_interface,
-                        {"interface_id": pg_index})
+        return cli + "\n" + self.cli(cli)
 
-    def sw_interface_dump(self, filter=None):
-        """
+    def ip6nd_send_router_solicitation(self, sw_if_index, irt=1, mrt=120, mrc=0, mrd=0):
+        return self.api(
+            self.papi.ip6nd_send_router_solicitation,
+            {
+                "irt": irt,
+                "mrt": mrt,
+                "mrc": mrc,
+                "mrd": mrd,
+                "sw_if_index": sw_if_index,
+            },
+        )
 
-        :param filter:  (Default value = None)
+    def want_interface_events(self, enable_disable=1):
+        return self.api(
+            self.papi.want_interface_events,
+            {
+                "enable_disable": enable_disable,
+                "pid": os.getpid(),
+            },
+        )
 
-        """
-        if filter is not None:
-            args = {"name_filter_valid": 1, "name_filter": filter}
-        else:
-            args = {}
-        return self.api(self.papi.sw_interface_dump, args)
+    def sw_interface_set_mac_address(self, sw_if_index, mac):
+        return self.api(
+            self.papi.sw_interface_set_mac_address,
+            {"sw_if_index": sw_if_index, "mac_address": mac},
+        )
 
-    def sw_interface_set_table(self, sw_if_index, is_ipv6, table_id):
-        """ Set the IPvX Table-id for the Interface
+    def p2p_ethernet_add(self, sw_if_index, remote_mac, subif_id):
+        """Create p2p ethernet subinterface
 
-        :param sw_if_index:
-        :param is_ipv6:
-        :param table_id:
+        :param sw_if_index: main (parent) interface
+        :param remote_mac: client (remote) mac address
 
         """
-        return self.api(self.papi.sw_interface_set_table,
-                        {'sw_if_index': sw_if_index, 'is_ipv6': is_ipv6,
-                         'vrf_id': table_id})
+        return self.api(
+            self.papi.p2p_ethernet_add,
+            {
+                "parent_if_index": sw_if_index,
+                "remote_mac": remote_mac,
+                "subif_id": subif_id,
+            },
+        )
 
-    def sw_interface_add_del_address(self, sw_if_index, addr, addr_len,
-                                     is_ipv6=0, is_add=1, del_all=0):
-        """
+    def p2p_ethernet_del(self, sw_if_index, remote_mac):
+        """Delete p2p ethernet subinterface
 
-        :param addr: param is_ipv6:  (Default value = 0)
-        :param sw_if_index:
-        :param addr_len:
-        :param is_ipv6:  (Default value = 0)
-        :param is_add:  (Default value = 1)
-        :param del_all:  (Default value = 0)
+        :param sw_if_index: main (parent) interface
+        :param remote_mac: client (remote) mac address
 
         """
-        return self.api(self.papi.sw_interface_add_del_address,
-                        {'sw_if_index': sw_if_index,
-                         'is_add': is_add,
-                         'is_ipv6': is_ipv6,
-                         'del_all': del_all,
-                         'address_length': addr_len,
-                         'address': addr})
-
-    def sw_interface_enable_disable_mpls(self, sw_if_index,
-                                         is_enable=1):
-        """
-        Enable/Disable MPLS on the interface
-        :param sw_if_index:
-        :param is_enable:  (Default value = 1)
+        return self.api(
+            self.papi.p2p_ethernet_del,
+            {"parent_if_index": sw_if_index, "remote_mac": remote_mac},
+        )
 
-        """
-        return self.api(self.papi.sw_interface_set_mpls_enable,
-                        {'sw_if_index': sw_if_index,
-                         'enable': is_enable})
-
-    def sw_interface_ra_suppress(self, sw_if_index):
-        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,
-                                   suppress,
-                                   send_unicast,):
-        return self.api(self.papi.sw_interface_ip6nd_ra_config,
-                        {'sw_if_index': sw_if_index,
-                         '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,
-            dst_addr,
-            mcast_sw_if_index=0xFFFFFFFF,
-            is_add=1,
-            is_ipv6=0,
-            encap_vrf_id=0,
-            decap_next_index=0xFFFFFFFF,
-            vni=0):
+    def create_vlan_subif(self, sw_if_index, vlan):
         """
 
-        :param dst_addr:
-        :param src_addr:
-        :param is_add:  (Default value = 1)
-        :param is_ipv6:  (Default value = 0)
-        :param encap_vrf_id:  (Default value = 0)
-        :param decap_next_index:  (Default value = 0xFFFFFFFF)
-        :param mcast_sw_if_index:  (Default value = 0xFFFFFFFF)
-        :param vni:  (Default value = 0)
+        :param vlan:
+        :param sw_if_index:
 
         """
-        return self.api(self.papi.vxlan_add_del_tunnel,
-                        {'is_add': is_add,
-                         'is_ipv6': is_ipv6,
-                         'src_address': src_addr,
-                         'dst_address': dst_addr,
-                         'mcast_sw_if_index': mcast_sw_if_index,
-                         'encap_vrf_id': encap_vrf_id,
-                         'decap_next_index': decap_next_index,
-                         'vni': vni})
-
-    def bridge_domain_add_del(self, bd_id, flood=1, uu_flood=1, forward=1,
-                              learn=1, arp_term=0, is_add=1):
-        """Create/delete bridge domain.
-
-        :param int bd_id: Bridge domain index.
-        :param int flood: Enable/disable bcast/mcast flooding in the BD.
-            (Default value = 1)
-        :param int uu_flood: Enable/disable unknown unicast flood in the BD.
-            (Default value = 1)
-        :param int forward: Enable/disable forwarding on all interfaces in
-            the BD. (Default value = 1)
-        :param int learn: Enable/disable learning on all interfaces in the BD.
-            (Default value = 1)
-        :param int arp_term: Enable/disable arp termination in the BD.
-            (Default value = 1)
-        :param int is_add: Add or delete flag. (Default value = 1)
-        """
-        return self.api(self.papi.bridge_domain_add_del,
-                        {'bd_id': bd_id,
-                         'flood': flood,
-                         'uu_flood': uu_flood,
-                         'forward': forward,
-                         'learn': learn,
-                         'arp_term': arp_term,
-                         'is_add': is_add})
-
-    def l2fib_add_del(self, mac, bd_id, sw_if_index, is_add=1, static_mac=0,
-                      filter_mac=0, bvi_mac=0):
-        """Create/delete L2 FIB entry.
-
-        :param str mac: MAC address to create FIB entry for.
-        :param int bd_id: Bridge domain index.
-        :param int sw_if_index: Software interface index of the interface.
-        :param int is_add: Add or delete flag. (Default value = 1)
-        :param int static_mac: Set to 1 to create static MAC entry.
-            (Default value = 0)
-        :param int filter_mac: Set to 1 to drop packet that's source or
-            destination MAC address contains defined MAC address.
-            (Default value = 0)
-        :param int bvi_mac: Set to 1 to create entry that points to BVI
-            interface. (Default value = 0)
-        """
-        return self.api(self.papi.l2fib_add_del,
-                        {'mac': self._convert_mac(mac),
-                         'bd_id': bd_id,
-                         'sw_if_index': sw_if_index,
-                         'is_add': is_add,
-                         'static_mac': static_mac,
-                         'filter_mac': filter_mac,
-                         'bvi_mac': bvi_mac})
-
-    def sw_interface_set_l2_bridge(self, sw_if_index, bd_id,
-                                   shg=0, bvi=0, enable=1):
-        """Add/remove interface to/from bridge domain.
-
-        :param int sw_if_index: Software interface index of the interface.
-        :param int bd_id: Bridge domain index.
-        :param int shg: Split-horizon group index. (Default value = 0)
-        :param int bvi: Set interface as a bridge group virtual interface.
-            (Default value = 0)
-        :param int enable: Add or remove interface. (Default value = 1)
-        """
-        return self.api(self.papi.sw_interface_set_l2_bridge,
-                        {'rx_sw_if_index': sw_if_index,
-                         'bd_id': bd_id,
-                         'shg': shg,
-                         'bvi': bvi,
-                         'enable': enable})
-
-    def bridge_flags(self, bd_id, is_set, feature_bitmap):
-        """Enable/disable required feature of the bridge domain with defined ID.
-
-        :param int bd_id: Bridge domain ID.
-        :param int is_set: Set to 1 to enable, set to 0 to disable the feature.
-        :param int feature_bitmap: Bitmap value of the feature to be set:
-            - learn (1 << 0),
-            - forward (1 << 1),
-            - flood (1 << 2),
-            - uu-flood (1 << 3) or
-            - arp-term (1 << 4).
-        """
-        return self.api(self.papi.bridge_flags,
-                        {'bd_id': bd_id,
-                         'is_set': is_set,
-                         'feature_bitmap': feature_bitmap})
+        return self.api(
+            self.papi.create_vlan_subif, {"sw_if_index": sw_if_index, "vlan_id": vlan}
+        )
 
-    def bridge_domain_dump(self, bd_id=0):
+    def create_loopback(self, mac=""):
         """
 
-        :param int bd_id: Bridge domain ID. (Default value = 0 => dump of all
-            existing bridge domains returned)
-        :return: Dictionary of bridge domain(s) data.
+        :param mac: (Optional)
         """
-        return self.api(self.papi.bridge_domain_dump,
-                        {'bd_id': bd_id})
+        return self.api(self.papi.create_loopback, {"mac_address": mac})
 
-    def sw_interface_set_l2_xconnect(self, rx_sw_if_index, tx_sw_if_index,
-                                     enable):
-        """Create or delete unidirectional cross-connect from Tx interface to
-        Rx interface.
-
-        :param int rx_sw_if_index: Software interface index of Rx interface.
-        :param int tx_sw_if_index: Software interface index of Tx interface.
-        :param int enable: Create cross-connect if equal to 1, delete
-            cross-connect if equal to 0.
+    def ip_route_dump(self, table_id, is_ip6=False):
+        return self.api(
+            self.papi.ip_route_dump, {"table": {"table_id": table_id, "is_ip6": is_ip6}}
+        )
 
-        """
-        return self.api(self.papi.sw_interface_set_l2_xconnect,
-                        {'rx_sw_if_index': rx_sw_if_index,
-                         'tx_sw_if_index': tx_sw_if_index,
-                         'enable': enable})
-
-    def sw_interface_set_l2_tag_rewrite(
-            self,
-            sw_if_index,
-            vtr_oper,
-            push=0,
-            tag1=0,
-            tag2=0):
-        """L2 interface vlan tag rewrite configure request
-        :param client_index - opaque cookie to identify the sender
-        :param context - sender context, to match reply w/ request
-        :param sw_if_index - interface the operation is applied to
-        :param vtr_op - Choose from l2_vtr_op_t enum values
-        :param push_dot1q - first pushed flag dot1q id set, else dot1ad
-        :param tag1 - Needed for any push or translate vtr op
-        :param tag2 - Needed for any push 2 or translate x-2 vtr ops
+    def ip_route_v2_dump(self, table_id, is_ip6=False, src=0):
+        return self.api(
+            self.papi.ip_route_v2_dump,
+            {"src": src, "table": {"table_id": table_id, "is_ip6": is_ip6}},
+        )
 
-        """
-        return self.api(self.papi.l2_interface_vlan_tag_rewrite,
-                        {'sw_if_index': sw_if_index,
-                         'vtr_op': vtr_oper,
-                         'push_dot1q': push,
-                         'tag1': tag1,
-                         'tag2': tag2})
-
-    def sw_interface_set_flags(self, sw_if_index, admin_up_down,
-                               link_up_down=0, deleted=0):
-        """
+    def ip_neighbor_add_del(
+        self, sw_if_index, mac_address, ip_address, is_add=1, flags=0
+    ):
+        """Add neighbor MAC to IPv4 or IPv6 address.
 
-        :param admin_up_down:
         :param sw_if_index:
-        :param link_up_down:  (Default value = 0)
-        :param deleted:  (Default value = 0)
-
+        :param mac_address:
+        :param dst_address:
+        :param is_add:  (Default value = 1)
+        :param flags:  (Default value = 0/NONE)
         """
-        return self.api(self.papi.sw_interface_set_flags,
-                        {'sw_if_index': sw_if_index,
-                         'admin_up_down': admin_up_down,
-                         'link_up_down': link_up_down,
-                         'deleted': deleted})
-
-    def create_subif(self, sw_if_index, sub_id, outer_vlan, inner_vlan,
-                     no_tags=0, one_tag=0, two_tags=0, dot1ad=0, exact_match=0,
-                     default_sub=0, outer_vlan_id_any=0, inner_vlan_id_any=0):
-        """Create subinterface
-        from vpe.api: set dot1ad = 0 for dot1q, set dot1ad = 1 for dot1ad
-
-        :param sub_id: param inner_vlan:
-        :param sw_if_index:
-        :param outer_vlan:
-        :param inner_vlan:
-        :param no_tags:  (Default value = 0)
-        :param one_tag:  (Default value = 0)
-        :param two_tags:  (Default value = 0)
-        :param dot1ad:  (Default value = 0)
-        :param exact_match:  (Default value = 0)
-        :param default_sub:  (Default value = 0)
-        :param outer_vlan_id_any:  (Default value = 0)
-        :param inner_vlan_id_any:  (Default value = 0)
+        return self.api(
+            self.papi.ip_neighbor_add_del,
+            {
+                "is_add": is_add,
+                "neighbor": {
+                    "sw_if_index": sw_if_index,
+                    "flags": flags,
+                    "mac_address": mac_address,
+                    "ip_address": ip_address,
+                },
+            },
+        )
 
+    def udp_encap_add(self, src_ip, dst_ip, src_port, dst_port, table_id=0):
+        """Add a GRE tunnel
+        :param src_ip:
+        :param dst_ip:
+        :param src_port:
+        :param dst_port:
+        :param outer_fib_id:  (Default value = 0)
         """
+
         return self.api(
-            self.papi.create_subif,
-            {'sw_if_index': sw_if_index,
-             'sub_id': sub_id,
-             'no_tags': no_tags,
-             'one_tag': one_tag,
-             'two_tags': two_tags,
-             'dot1ad': dot1ad,
-             'exact_match': exact_match,
-             'default_sub': default_sub,
-             'outer_vlan_id_any': outer_vlan_id_any,
-             'inner_vlan_id_any': inner_vlan_id_any,
-             'outer_vlan_id': outer_vlan,
-             'inner_vlan_id': inner_vlan})
-
-    def delete_subif(self, sw_if_index):
-        """Delete subinterface
+            self.papi.udp_encap_add,
+            {
+                "udp_encap": {
+                    "src_ip": src_ip,
+                    "dst_ip": dst_ip,
+                    "src_port": src_port,
+                    "dst_port": dst_port,
+                    "table_id": table_id,
+                }
+            },
+        )
 
-        :param sw_if_index:
-        """
-        return self.api(self.papi.delete_subif,
-                        {'sw_if_index': sw_if_index})
+    def udp_encap_del(self, id):
+        return self.api(self.papi.udp_encap_del, {"id": id})
 
-    def create_vlan_subif(self, sw_if_index, vlan):
-        """
+    def udp_encap_dump(self):
+        return self.api(self.papi.udp_encap_dump, {})
 
-        :param vlan:
-        :param sw_if_index:
+    def want_udp_encap_stats(self, enable=1):
+        return self.api(
+            self.papi.want_udp_encap_stats, {"enable": enable, "pid": os.getpid()}
+        )
 
-        """
-        return self.api(self.papi.create_vlan_subif,
-                        {'sw_if_index': sw_if_index,
-                         'vlan_id': vlan})
+    def mpls_route_dump(self, table_id):
+        return self.api(self.papi.mpls_route_dump, {"table": {"mt_table_id": table_id}})
 
-    def create_loopback(self, mac=''):
-        """
+    def mpls_table_dump(self):
+        return self.api(self.papi.mpls_table_dump, {})
 
-        :param mac: (Optional)
-        """
-        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,
-            dst_address_length,
-            next_hop_address,
-            next_hop_sw_if_index=0xFFFFFFFF,
-            table_id=0,
-            next_hop_table_id=0,
-            next_hop_weight=1,
-            next_hop_n_out_labels=0,
-            next_hop_out_label_stack=[],
-            next_hop_via_label=MPLS_LABEL_INVALID,
-            create_vrf_if_needed=0,
-            is_resolve_host=0,
-            is_resolve_attached=0,
-            classify_table_index=0xFFFFFFFF,
-            is_add=1,
-            is_drop=0,
-            is_unreach=0,
-            is_prohibit=0,
-            is_ipv6=0,
-            is_local=0,
-            is_classify=0,
-            is_multipath=0,
-            not_last=0):
+    def mpls_table_add_del(self, table_id, is_add=1):
         """
 
-        :param dst_address_length:
-        :param next_hop_sw_if_index:  (Default value = 0xFFFFFFFF)
-        :param dst_address:
-        :param next_hop_address:
-        :param next_hop_sw_if_index:  (Default value = 0xFFFFFFFF)
-        :param vrf_id:  (Default value = 0)
-        :param lookup_in_vrf:  (Default value = 0)
-        :param classify_table_index:  (Default value = 0xFFFFFFFF)
-        :param create_vrf_if_needed:  (Default value = 0)
+        :param table_id
         :param is_add:  (Default value = 1)
-        :param is_drop:  (Default value = 0)
-        :param is_ipv6:  (Default value = 0)
-        :param is_local:  (Default value = 0)
-        :param is_classify:  (Default value = 0)
-        :param is_multipath:  (Default value = 0)
-        :param is_resolve_host:  (Default value = 0)
-        :param is_resolve_attached:  (Default value = 0)
-        :param not_last:  (Default value = 0)
-        :param next_hop_weight:  (Default value = 1)
 
         """
 
         return self.api(
-            self.papi.ip_add_del_route,
-            {'next_hop_sw_if_index': next_hop_sw_if_index,
-             'table_id': table_id,
-             'classify_table_index': classify_table_index,
-             'next_hop_table_id': next_hop_table_id,
-             'create_vrf_if_needed': create_vrf_if_needed,
-             'is_add': is_add,
-             'is_drop': is_drop,
-             'is_unreach': is_unreach,
-             'is_prohibit': is_prohibit,
-             'is_ipv6': is_ipv6,
-             'is_local': is_local,
-             'is_classify': is_classify,
-             'is_multipath': is_multipath,
-             'is_resolve_host': is_resolve_host,
-             'is_resolve_attached': is_resolve_attached,
-             'not_last': not_last,
-             'next_hop_weight': next_hop_weight,
-             'dst_address_length': dst_address_length,
-             'dst_address': dst_address,
-             'next_hop_address': next_hop_address,
-             'next_hop_n_out_labels': next_hop_n_out_labels,
-             'next_hop_via_label': next_hop_via_label,
-             'next_hop_out_label_stack': next_hop_out_label_stack})
-
-    def ip_fib_dump(self):
-        return self.api(self.papi.ip_fib_dump, {})
-
-    def ip_neighbor_add_del(self,
-                            sw_if_index,
-                            mac_address,
-                            dst_address,
-                            vrf_id=0,
-                            is_add=1,
-                            is_ipv6=0,
-                            is_static=0,
-                            ):
-        """ Add neighbor MAC to IPv4 or IPv6 address.
+            self.papi.mpls_table_add_del,
+            {
+                "mt_table": {
+                    "mt_table_id": table_id,
+                },
+                "mt_is_add": is_add,
+            },
+        )
 
-        :param sw_if_index:
-        :param mac_address:
-        :param dst_address:
-        :param vrf_id:  (Default value = 0)
-        :param is_add:  (Default value = 1)
-        :param is_ipv6:  (Default value = 0)
-        :param is_static:  (Default value = 0)
-        """
+    def mpls_route_add_del(
+        self, table_id, label, eos, eos_proto, is_multicast, paths, is_add, is_multipath
+    ):
+        """MPLS Route add/del"""
+        return self.api(
+            self.papi.mpls_route_add_del,
+            {
+                "mr_route": {
+                    "mr_table_id": table_id,
+                    "mr_label": label,
+                    "mr_eos": eos,
+                    "mr_eos_proto": eos_proto,
+                    "mr_is_multicast": is_multicast,
+                    "mr_n_paths": len(paths),
+                    "mr_paths": paths,
+                },
+                "mr_is_add": is_add,
+                "mr_is_multipath": is_multipath,
+            },
+        )
 
+    def mpls_ip_bind_unbind(self, label, prefix, table_id=0, ip_table_id=0, is_bind=1):
+        """ """
         return self.api(
-            self.papi.ip_neighbor_add_del,
-            {'vrf_id': vrf_id,
-             'sw_if_index': sw_if_index,
-             'is_add': is_add,
-             'is_ipv6': is_ipv6,
-             'is_static': is_static,
-             'mac_address': mac_address,
-             'dst_address': dst_address
-             }
+            self.papi.mpls_ip_bind_unbind,
+            {
+                "mb_mpls_table_id": table_id,
+                "mb_label": label,
+                "mb_ip_table_id": ip_table_id,
+                "mb_is_bind": is_bind,
+                "mb_prefix": prefix,
+            },
         )
 
-    def reset_vrf(self,
-                  vrf_id,
-                  is_ipv6=0,
-                  ):
-        """ Reset VRF (remove all routes etc.) request.
+    def mpls_tunnel_add_del(
+        self, tun_sw_if_index, paths, is_add=1, l2_only=0, is_multicast=0
+    ):
+        """ """
+        return self.api(
+            self.papi.mpls_tunnel_add_del,
+            {
+                "mt_is_add": is_add,
+                "mt_tunnel": {
+                    "mt_sw_if_index": tun_sw_if_index,
+                    "mt_l2_only": l2_only,
+                    "mt_is_multicast": is_multicast,
+                    "mt_n_paths": len(paths),
+                    "mt_paths": paths,
+                },
+            },
+        )
 
-        :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)
+    def input_acl_set_interface(
+        self,
+        is_add,
+        sw_if_index,
+        ip4_table_index=0xFFFFFFFF,
+        ip6_table_index=0xFFFFFFFF,
+        l2_table_index=0xFFFFFFFF,
+    ):
+        """
+        :param is_add:
+        :param sw_if_index:
+        :param ip4_table_index:  (Default value = 0xFFFFFFFF)
+        :param ip6_table_index:  (Default value = 0xFFFFFFFF)
+        :param l2_table_index:  (Default value = 0xFFFFFFFF)
         """
 
         return self.api(
-            self.papi.reset_vrf,
-            {'vrf_id': vrf_id,
-             'is_ipv6': is_ipv6,
-             }
+            self.papi.input_acl_set_interface,
+            {
+                "sw_if_index": sw_if_index,
+                "ip4_table_index": ip4_table_index,
+                "ip6_table_index": ip6_table_index,
+                "l2_table_index": l2_table_index,
+                "is_add": is_add,
+            },
         )
 
-    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)
+    def output_acl_set_interface(
+        self,
+        is_add,
+        sw_if_index,
+        ip4_table_index=0xFFFFFFFF,
+        ip6_table_index=0xFFFFFFFF,
+        l2_table_index=0xFFFFFFFF,
+    ):
+        """
+        :param is_add:
+        :param sw_if_index:
+        :param ip4_table_index:  (Default value = 0xFFFFFFFF)
+        :param ip6_table_index:  (Default value = 0xFFFFFFFF)
+        :param l2_table_index:  (Default value = 0xFFFFFFFF)
         """
 
         return self.api(
-            self.papi.reset_fib,
-            {'vrf_id': vrf_id,
-             'is_ipv6': is_ipv6,
-             }
+            self.papi.output_acl_set_interface,
+            {
+                "sw_if_index": sw_if_index,
+                "ip4_table_index": ip4_table_index,
+                "ip6_table_index": ip6_table_index,
+                "l2_table_index": l2_table_index,
+                "is_add": is_add,
+            },
         )
 
-    def ip_dump(self,
-                is_ipv6=0,
-                ):
-        """ Return IP dump.
+    def set_ipfix_exporter(
+        self,
+        collector_address,
+        src_address,
+        path_mtu,
+        template_interval,
+        vrf_id=0,
+        collector_port=4739,
+        udp_checksum=0,
+    ):
+        return self.api(
+            self.papi.set_ipfix_exporter,
+            {
+                "collector_address": collector_address,
+                "collector_port": collector_port,
+                "src_address": src_address,
+                "vrf_id": vrf_id,
+                "path_mtu": path_mtu,
+                "template_interval": template_interval,
+                "udp_checksum": udp_checksum,
+            },
+        )
 
-        :param int is_ipv6: 1 for IPv6 neighbor, 0 for IPv4. (Default = 0)
-        """
+    def mfib_signal_dump(self):
+        return self.api(self.papi.mfib_signal_dump, {})
 
+    def ip_mroute_dump(self, table_id, is_ip6=False):
         return self.api(
-            self.papi.ip_dump,
-            {'is_ipv6': is_ipv6,
-             }
+            self.papi.ip_mroute_dump,
+            {"table": {"table_id": table_id, "is_ip6": is_ip6}},
         )
 
-    def sw_interface_span_enable_disable(
-            self, sw_if_index_from, sw_if_index_to, state=1):
+    def pppoe_add_del_session(
+        self, client_ip, client_mac, session_id=0, is_add=1, decap_vrf_id=0
+    ):
         """
 
-        :param sw_if_index_from:
-        :param sw_if_index_to:
-        :param state:
-        """
-        return self.api(self.papi.sw_interface_span_enable_disable,
-                        {'sw_if_index_from': sw_if_index_from,
-                         'sw_if_index_to': sw_if_index_to,
-                         'state': state})
-
-    def gre_tunnel_add_del(self,
-                           src_address,
-                           dst_address,
-                           outer_fib_id=0,
-                           is_teb=0,
-                           is_add=1,
-                           is_ip6=0):
-        """ Add a GRE tunnel
-
-        :param src_address:
-        :param dst_address:
-        :param outer_fib_id:  (Default value = 0)
         :param is_add:  (Default value = 1)
         :param is_ipv6:  (Default value = 0)
-        :param is_teb:  (Default value = 0)
+        :param client_ip:
+        :param session_id:  (Default value = 0)
+        :param client_mac:
+        :param decap_vrf_id:  (Default value = 0)
+
         """
+        return self.api(
+            self.papi.pppoe_add_del_session,
+            {
+                "is_add": is_add,
+                "session_id": session_id,
+                "client_ip": client_ip,
+                "decap_vrf_id": decap_vrf_id,
+                "client_mac": client_mac,
+            },
+        )
 
+    def sr_mpls_policy_add(self, bsid, weight, type, segments):
         return self.api(
-            self.papi.gre_add_del_tunnel,
-            {'is_add': is_add,
-             'is_ipv6': is_ip6,
-             'teb': is_teb,
-             'src_address': src_address,
-             'dst_address': dst_address,
-             'outer_fib_id': outer_fib_id}
+            self.papi.sr_mpls_policy_add,
+            {
+                "bsid": bsid,
+                "weight": weight,
+                "is_spray": type,
+                "n_segments": len(segments),
+                "segments": segments,
+            },
         )
 
-    def mpls_route_add_del(
-            self,
-            label,
-            eos,
-            next_hop_proto_is_ip4,
-            next_hop_address,
-            next_hop_sw_if_index=0xFFFFFFFF,
-            table_id=0,
-            next_hop_table_id=0,
-            next_hop_weight=1,
-            next_hop_n_out_labels=0,
-            next_hop_out_label_stack=[],
-            next_hop_via_label=MPLS_LABEL_INVALID,
-            create_vrf_if_needed=0,
-            is_resolve_host=0,
-            is_resolve_attached=0,
-            is_add=1,
-            is_drop=0,
-            is_multipath=0,
-            classify_table_index=0xFFFFFFFF,
-            is_classify=0,
-            not_last=0):
-        """
+    def sr_mpls_policy_del(self, bsid):
+        return self.api(self.papi.sr_mpls_policy_del, {"bsid": bsid})
 
-        :param dst_address_length:
-        :param next_hop_sw_if_index:  (Default value = 0xFFFFFFFF)
-        :param dst_address:
-        :param next_hop_address:
-        :param next_hop_sw_if_index:  (Default value = 0xFFFFFFFF)
-        :param vrf_id:  (Default value = 0)
-        :param lookup_in_vrf:  (Default value = 0)
-        :param classify_table_index:  (Default value = 0xFFFFFFFF)
-        :param create_vrf_if_needed:  (Default value = 0)
-        :param is_add:  (Default value = 1)
-        :param is_drop:  (Default value = 0)
-        :param is_ipv6:  (Default value = 0)
-        :param is_local:  (Default value = 0)
-        :param is_classify:  (Default value = 0)
-        :param is_multipath:  (Default value = 0)
-        :param is_resolve_host:  (Default value = 0)
-        :param is_resolve_attached:  (Default value = 0)
-        :param not_last:  (Default value = 0)
-        :param next_hop_weight:  (Default value = 1)
+    def bier_table_add_del(self, bti, mpls_label, is_add=1):
+        """BIER Table add/del"""
+        return self.api(
+            self.papi.bier_table_add_del,
+            {
+                "bt_tbl_id": {
+                    "bt_set": bti.set_id,
+                    "bt_sub_domain": bti.sub_domain_id,
+                    "bt_hdr_len_id": bti.hdr_len_id,
+                },
+                "bt_label": mpls_label,
+                "bt_is_add": is_add,
+            },
+        )
 
-        """
+    def bier_table_dump(self):
+        return self.api(self.papi.bier_table_dump, {})
 
+    def bier_route_add_del(self, bti, bp, paths, is_add=1, is_replace=0):
+        """BIER Route add/del"""
         return self.api(
-            self.papi.mpls_route_add_del,
-            {'mr_label': label,
-             'mr_eos': eos,
-             'mr_table_id': table_id,
-             'mr_classify_table_index': classify_table_index,
-             'mr_create_table_if_needed': create_vrf_if_needed,
-             'mr_is_add': is_add,
-             'mr_is_classify': is_classify,
-             'mr_is_multipath': is_multipath,
-             'mr_is_resolve_host': is_resolve_host,
-             'mr_is_resolve_attached': is_resolve_attached,
-             'mr_next_hop_proto_is_ip4': next_hop_proto_is_ip4,
-             'mr_next_hop_weight': next_hop_weight,
-             'mr_next_hop': next_hop_address,
-             'mr_next_hop_n_out_labels': next_hop_n_out_labels,
-             'mr_next_hop_sw_if_index': next_hop_sw_if_index,
-             'mr_next_hop_table_id': next_hop_table_id,
-             'mr_next_hop_via_label': next_hop_via_label,
-             'mr_next_hop_out_label_stack': next_hop_out_label_stack})
-
-    def mpls_ip_bind_unbind(
-            self,
-            label,
-            dst_address,
-            dst_address_length,
-            table_id=0,
-            ip_table_id=0,
-            is_ip4=1,
-            create_vrf_if_needed=0,
-            is_bind=1):
-        """
-        """
+            self.papi.bier_route_add_del,
+            {
+                "br_route": {
+                    "br_tbl_id": {
+                        "bt_set": bti.set_id,
+                        "bt_sub_domain": bti.sub_domain_id,
+                        "bt_hdr_len_id": bti.hdr_len_id,
+                    },
+                    "br_bp": bp,
+                    "br_n_paths": len(paths),
+                    "br_paths": paths,
+                },
+                "br_is_add": is_add,
+                "br_is_replace": is_replace,
+            },
+        )
+
+    def bier_route_dump(self, bti):
         return self.api(
-            self.papi.mpls_ip_bind_unbind,
-            {'mb_mpls_table_id': table_id,
-             'mb_label': label,
-             'mb_ip_table_id': ip_table_id,
-             'mb_create_table_if_needed': create_vrf_if_needed,
-             'mb_is_bind': is_bind,
-             'mb_is_ip4': is_ip4,
-             'mb_address_length': dst_address_length,
-             'mb_address': dst_address})
+            self.papi.bier_route_dump,
+            {
+                "br_tbl_id": {
+                    "bt_set": bti.set_id,
+                    "bt_sub_domain": bti.sub_domain_id,
+                    "bt_hdr_len_id": bti.hdr_len_id,
+                }
+            },
+        )
 
-    def mpls_tunnel_add_del(
-            self,
-            tun_sw_if_index,
-            next_hop_proto_is_ip4,
-            next_hop_address,
-            next_hop_sw_if_index=0xFFFFFFFF,
-            next_hop_table_id=0,
-            next_hop_weight=1,
-            next_hop_n_out_labels=0,
-            next_hop_out_label_stack=[],
-            next_hop_via_label=MPLS_LABEL_INVALID,
-            create_vrf_if_needed=0,
-            is_add=1,
-            l2_only=0):
-        """
+    def bier_imp_add(self, bti, src, ibytes, is_add=1):
+        """BIER Imposition Add"""
+        return self.api(
+            self.papi.bier_imp_add,
+            {
+                "bi_tbl_id": {
+                    "bt_set": bti.set_id,
+                    "bt_sub_domain": bti.sub_domain_id,
+                    "bt_hdr_len_id": bti.hdr_len_id,
+                },
+                "bi_src": src,
+                "bi_n_bytes": len(ibytes),
+                "bi_bytes": ibytes,
+            },
+        )
 
-        :param dst_address_length:
-        :param next_hop_sw_if_index:  (Default value = 0xFFFFFFFF)
-        :param dst_address:
-        :param next_hop_address:
-        :param next_hop_sw_if_index:  (Default value = 0xFFFFFFFF)
-        :param vrf_id:  (Default value = 0)
-        :param lookup_in_vrf:  (Default value = 0)
-        :param classify_table_index:  (Default value = 0xFFFFFFFF)
-        :param create_vrf_if_needed:  (Default value = 0)
-        :param is_add:  (Default value = 1)
-        :param is_drop:  (Default value = 0)
-        :param is_ipv6:  (Default value = 0)
-        :param is_local:  (Default value = 0)
-        :param is_classify:  (Default value = 0)
-        :param is_multipath:  (Default value = 0)
-        :param is_resolve_host:  (Default value = 0)
-        :param is_resolve_attached:  (Default value = 0)
-        :param not_last:  (Default value = 0)
-        :param next_hop_weight:  (Default value = 1)
+    def bier_imp_del(self, bi_index):
+        """BIER Imposition del"""
+        return self.api(self.papi.bier_imp_del, {"bi_index": bi_index})
 
-        """
-        return self.api(
-            self.papi.mpls_tunnel_add_del,
-            {'mt_sw_if_index': tun_sw_if_index,
-             'mt_is_add': is_add,
-             'mt_l2_only': l2_only,
-             'mt_next_hop_proto_is_ip4': next_hop_proto_is_ip4,
-             'mt_next_hop_weight': next_hop_weight,
-             'mt_next_hop': next_hop_address,
-             'mt_next_hop_n_out_labels': next_hop_n_out_labels,
-             'mt_next_hop_sw_if_index': next_hop_sw_if_index,
-             'mt_next_hop_table_id': next_hop_table_id,
-             'mt_next_hop_out_label_stack': next_hop_out_label_stack})
-
-    def snat_interface_add_del_feature(
-            self,
-            sw_if_index,
-            is_inside=1,
-            is_add=1):
-        """Enable/disable S-NAT feature on the interface
-
-        :param sw_if_index: Software index of the interface
-        :param is_inside: 1 if inside, 0 if outside (Default value = 1)
-        :param is_add: 1 if add, 0 if delete (Default value = 1)
-        """
+    def bier_imp_dump(self):
+        return self.api(self.papi.bier_imp_dump, {})
+
+    def bier_disp_table_add_del(self, bdti, is_add=1):
+        """BIER Disposition Table add/del"""
         return self.api(
-            self.papi.snat_interface_add_del_feature,
-            {'is_add': is_add,
-             'is_inside': is_inside,
-             'sw_if_index': sw_if_index})
-
-    def snat_add_static_mapping(
-            self,
-            local_ip,
-            external_ip=0,
-            external_sw_if_index=0xFFFFFFFF,
-            local_port=0,
-            external_port=0,
-            addr_only=1,
-            vrf_id=0,
-            is_add=1,
-            is_ip4=1):
-        """Add/delete S-NAT static mapping
-
-        :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
-        :param vrf_id: VRF ID
-        :param is_add: 1 if add, 0 if delete (Default value = 1)
-        :param is_ip4: 1 if address type is IPv4 (Default value = 1)
-        """
+            self.papi.bier_disp_table_add_del,
+            {"bdt_tbl_id": bdti, "bdt_is_add": is_add},
+        )
+
+    def bier_disp_table_dump(self):
+        return self.api(self.papi.bier_disp_table_dump, {})
+
+    def bier_disp_entry_add_del(
+        self,
+        bdti,
+        bp,
+        payload_proto,
+        next_hop_afi,
+        next_hop,
+        next_hop_tbl_id=0,
+        next_hop_rpf_id=~0,
+        next_hop_is_ip4=1,
+        is_add=1,
+    ):
+        """BIER Route add/del"""
+        lstack = []
+        while len(lstack) < 16:
+            lstack.append({})
         return self.api(
-            self.papi.snat_add_static_mapping,
-            {'is_add': is_add,
-             'is_ip4': is_ip4,
-             'addr_only': addr_only,
-             'local_ip_address': local_ip,
-             '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(
-            self,
-            first_ip_address,
-            last_ip_address,
-            is_add=1,
-            is_ip4=1):
-        """Add/del S-NAT address range
-
-        :param first_ip_address: First IP address
-        :param last_ip_address: Last IP address
-        :param is_add: 1 if add, 0 if delete (Default value = 1)
-        :param is_ip4: 1 if address type is IPv4 (Default value = 1)
+            self.papi.bier_disp_entry_add_del,
+            {
+                "bde_tbl_id": bdti,
+                "bde_bp": bp,
+                "bde_payload_proto": payload_proto,
+                "bde_n_paths": 1,
+                "bde_paths": [
+                    {
+                        "table_id": next_hop_tbl_id,
+                        "rpf_id": next_hop_rpf_id,
+                        "n_labels": 0,
+                        "label_stack": lstack,
+                    }
+                ],
+                "bde_is_add": is_add,
+            },
+        )
+
+    def bier_disp_entry_dump(self, bdti):
+        return self.api(self.papi.bier_disp_entry_dump, {"bde_tbl_id": bdti})
+
+    def ipsec_spd_add_del(self, spd_id, is_add=1):
+        """SPD add/del - Wrapper to add or del ipsec SPD
+        Sample CLI : 'ipsec spd add 1'
+
+        :param spd_id - SPD ID to be created in the vpp . mandatory
+        :param is_add - create (1) or delete(0) SPD (Default 1 - add) .
+        optional
+        :returns: reply from the API
         """
         return self.api(
-            self.papi.snat_add_address_range,
-            {'is_ip4': is_ip4,
-             'first_ip_address': first_ip_address,
-             'last_ip_address': last_ip_address,
-             'is_add': is_add})
-
-    def snat_address_dump(self):
-        """Dump S-NAT addresses
-        :return: Dictionary of S-NAT addresses
-        """
-        return self.api(self.papi.snat_address_dump, {})
+            self.papi.ipsec_spd_add_del, {"spd_id": spd_id, "is_add": is_add}
+        )
 
-    def snat_interface_dump(self):
-        """Dump interfaces with S-NAT feature
-        :return: Dictionary of interfaces with S-NAT feature
-        """
-        return self.api(self.papi.snat_interface_dump, {})
+    def ipsec_spds_dump(self):
+        return self.api(self.papi.ipsec_spds_dump, {})
 
-    def snat_static_mapping_dump(self):
-        """Dump S-NAT static mappings
-        :return: Dictionary of S-NAT static mappings
-        """
-        return self.api(self.papi.snat_static_mapping_dump, {})
+    def ipsec_interface_add_del_spd(self, spd_id, sw_if_index, is_add=1):
+        """ IPSEC interface SPD add/del - \
+             Wrapper to associate/disassociate SPD to interface in VPP
+        Sample CLI : 'set interface ipsec spd GigabitEthernet0/6/0 1'
 
-    def snat_show_config(self):
-        """Show S-NAT config
-        :return: S-NAT config parameters
+        :param spd_id - SPD ID to associate with the interface . mandatory
+        :param sw_if_index - Interface Index which needs to ipsec \
+            association mandatory
+        :param is_add - add(1) or del(0) association with interface \
+                (Default 1 - add) . optional
+        :returns: reply from the API
         """
-        return self.api(self.papi.snat_show_config, {})
+        return self.api(
+            self.papi.ipsec_interface_add_del_spd,
+            {"spd_id": spd_id, "sw_if_index": sw_if_index, "is_add": is_add},
+        )
 
-    def snat_add_interface_addr(
-            self,
-            sw_if_index,
-            is_add=1):
-        """Add/del S-NAT address from interface
+    def ipsec_spd_interface_dump(self, spd_index=None):
+        return self.api(
+            self.papi.ipsec_spd_interface_dump,
+            {
+                "spd_index": spd_index if spd_index else 0,
+                "spd_index_valid": 1 if spd_index else 0,
+            },
+        )
 
-        :param sw_if_index: Software index of the interface
-        :param is_add: 1 if add, 0 if delete (Default value = 1)
+    def ipsec_spd_entry_add_del(
+        self,
+        spd_id,
+        sa_id,
+        local_address_start,
+        local_address_stop,
+        remote_address_start,
+        remote_address_stop,
+        local_port_start=0,
+        local_port_stop=65535,
+        remote_port_start=0,
+        remote_port_stop=65535,
+        protocol=0,
+        policy=0,
+        priority=100,
+        is_outbound=1,
+        is_add=1,
+        is_ipv6=0,
+        is_ip_any=0,
+    ):
+        """IPSEC policy SPD add/del   -
+                    Wrapper to configure ipsec SPD policy entries in VPP
+
+        :param spd_id: SPD ID for the policy
+        :param local_address_start: local-ip-range start address
+        :param local_address_stop: local-ip-range stop address
+        :param remote_address_start: remote-ip-range start address
+        :param remote_address_stop: remote-ip-range stop address
+        :param local_port_start: (Default value = 0)
+        :param local_port_stop: (Default value = 65535)
+        :param remote_port_start: (Default value = 0)
+        :param remote_port_stop: (Default value = 65535)
+        :param protocol: Any(0), AH(51) & ESP(50) protocol (Default value = 0)
+        :param sa_id: Security Association ID for mapping it to SPD
+        :param policy: bypass(0), discard(1), resolve(2) or protect(3) action
+            (Default value = 0)
+        :param priority: value for the spd action (Default value = 100)
+        :param is_outbound: flag for inbound(0) or outbound(1)
+            (Default value = 1)
+        :param is_add: (Default value = 1)
         """
-        return self.api(self.papi.snat_add_del_interface_addr,
-                        {'is_add': is_add, 'sw_if_index': sw_if_index})
+        return self.api(
+            self.papi.ipsec_spd_entry_add_del,
+            {
+                "is_add": is_add,
+                "entry": {
+                    "spd_id": spd_id,
+                    "sa_id": sa_id,
+                    "local_address_start": local_address_start,
+                    "local_address_stop": local_address_stop,
+                    "remote_address_start": remote_address_start,
+                    "remote_address_stop": remote_address_stop,
+                    "local_port_start": local_port_start,
+                    "local_port_stop": local_port_stop,
+                    "remote_port_start": remote_port_start,
+                    "remote_port_stop": remote_port_stop,
+                    "protocol": protocol,
+                    "policy": policy,
+                    "priority": priority,
+                    "is_outbound": is_outbound,
+                },
+            },
+        )
 
-    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)
-        """
+    def ipsec_spd_dump(self, spd_id, sa_id=0xFFFFFFFF):
+        return self.api(self.papi.ipsec_spd_dump, {"spd_id": spd_id, "sa_id": sa_id})
+
+    def ipsec_tunnel_if_add_del(
+        self,
+        local_ip,
+        remote_ip,
+        local_spi,
+        remote_spi,
+        crypto_alg,
+        local_crypto_key,
+        remote_crypto_key,
+        integ_alg,
+        local_integ_key,
+        remote_integ_key,
+        is_add=1,
+        esn=0,
+        salt=0,
+        anti_replay=1,
+        renumber=0,
+        udp_encap=0,
+        show_instance=0xFFFFFFFF,
+    ):
         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)
-
-    def bfd_udp_add(self, sw_if_index, desired_min_tx, required_min_rx,
-                    detect_mult, local_addr, peer_addr, is_ipv6=0):
-        return self.api(self.papi.bfd_udp_add,
-                        {
-                            'sw_if_index': sw_if_index,
-                            'desired_min_tx': desired_min_tx,
-                            'required_min_rx': required_min_rx,
-                            'local_addr': local_addr,
-                            'peer_addr': peer_addr,
-                            'is_ipv6': is_ipv6,
-                            'detect_mult': detect_mult,
-                        })
-
-    def bfd_udp_del(self, sw_if_index, local_addr, peer_addr, is_ipv6=0):
-        return self.api(self.papi.bfd_udp_del,
-                        {
-                            'sw_if_index': sw_if_index,
-                            'local_addr': local_addr,
-                            'peer_addr': peer_addr,
-                            'is_ipv6': is_ipv6,
-                        })
-
-    def bfd_udp_session_dump(self):
-        return self.api(self.papi.bfd_udp_session_dump, {})
-
-    def bfd_session_set_flags(self, bs_idx, admin_up_down):
-        return self.api(self.papi.bfd_session_set_flags, {
-            'bs_index': bs_idx,
-            'admin_up_down': admin_up_down,
-        })
-
-    def want_bfd_events(self, enable_disable=1):
-        return self.api(self.papi.want_bfd_events, {
-            'enable_disable': enable_disable,
-            'pid': os.getpid(),
-        })
-
-    def classify_add_del_table(
-            self,
-            is_add,
-            mask,
-            match_n_vectors=1,
-            table_index=0xFFFFFFFF,
-            nbuckets=2,
-            memory_size=2097152,
-            skip_n_vectors=0,
-            next_table_index=0xFFFFFFFF,
-            miss_next_index=0xFFFFFFFF,
-            current_data_flag=0,
-            current_data_offset=0):
-        """
-        :param is_add:
-        :param mask:
-        :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)
-        :param next_table_index:  (Default value = 0xFFFFFFFF)
-        :param miss_next_index:  (Default value = 0xFFFFFFFF)
-        :param current_data_flag:  (Default value = 0)
-        :param current_data_offset:  (Default value = 0)
-        """
+            self.papi.ipsec_tunnel_if_add_del,
+            {
+                "local_ip": local_ip,
+                "remote_ip": remote_ip,
+                "local_spi": local_spi,
+                "remote_spi": remote_spi,
+                "crypto_alg": crypto_alg,
+                "local_crypto_key_len": len(local_crypto_key),
+                "local_crypto_key": local_crypto_key,
+                "remote_crypto_key_len": len(remote_crypto_key),
+                "remote_crypto_key": remote_crypto_key,
+                "integ_alg": integ_alg,
+                "local_integ_key_len": len(local_integ_key),
+                "local_integ_key": local_integ_key,
+                "remote_integ_key_len": len(remote_integ_key),
+                "remote_integ_key": remote_integ_key,
+                "is_add": is_add,
+                "esn": esn,
+                "anti_replay": anti_replay,
+                "renumber": renumber,
+                "show_instance": show_instance,
+                "udp_encap": udp_encap,
+                "salt": salt,
+            },
+        )
 
+    def ipsec_select_backend(self, protocol, index):
         return self.api(
-            self.papi.classify_add_del_table,
-            {'is_add': is_add,
-             'table_index': table_index,
-             'nbuckets': nbuckets,
-             'memory_size': memory_size,
-             'skip_n_vectors': skip_n_vectors,
-             'match_n_vectors': match_n_vectors,
-             'next_table_index': next_table_index,
-             'miss_next_index': miss_next_index,
-             'current_data_flag': current_data_flag,
-             'current_data_offset': current_data_offset,
-             'mask': mask})
-
-    def classify_add_del_session(
-            self,
-            is_add,
-            table_index,
-            match,
-            opaque_index=0xFFFFFFFF,
-            hit_next_index=0xFFFFFFFF,
-            advance=0,
-            action=0,
-            metadata=0):
-        """
-        :param is_add:
-        :param table_index:
-        :param match:
-        :param opaque_index:  (Default value = 0xFFFFFFFF)
-        :param hit_next_index:  (Default value = 0xFFFFFFFF)
-        :param advance:  (Default value = 0)
-        :param action:  (Default value = 0)
-        :param metadata:  (Default value = 0)
-        """
+            self.papi.ipsec_select_backend, {"protocol": protocol, "index": index}
+        )
+
+    def ipsec_backend_dump(self):
+        return self.api(self.papi.ipsec_backend_dump, {})
 
+    def punt_socket_register(self, reg, pathname, header_version=1):
+        """Register punt socket"""
         return self.api(
-            self.papi.classify_add_del_session,
-            {'is_add': is_add,
-             'table_index': table_index,
-             'hit_next_index': hit_next_index,
-             'opaque_index': opaque_index,
-             'advance': advance,
-             'action': action,
-             'metadata': metadata,
-             'match': match})
+            self.papi.punt_socket_register,
+            {"header_version": header_version, "punt": reg, "pathname": pathname},
+        )
 
-    def input_acl_set_interface(
-            self,
-            is_add,
-            sw_if_index,
-            ip4_table_index=0xFFFFFFFF,
-            ip6_table_index=0xFFFFFFFF,
-            l2_table_index=0xFFFFFFFF):
-        """
-        :param is_add:
-        :param sw_if_index:
-        :param ip4_table_index:  (Default value = 0xFFFFFFFF)
-        :param ip6_table_index:  (Default value = 0xFFFFFFFF)
-        :param l2_table_index:  (Default value = 0xFFFFFFFF)
-        """
+    def punt_socket_deregister(self, reg):
+        """Unregister punt socket"""
+        return self.api(self.papi.punt_socket_deregister, {"punt": reg})
 
+    def igmp_enable_disable(self, sw_if_index, enable, host):
+        """Enable/disable IGMP on a given interface"""
         return self.api(
-            self.papi.input_acl_set_interface,
-            {'sw_if_index': sw_if_index,
-             'ip4_table_index': ip4_table_index,
-             'ip6_table_index': ip6_table_index,
-             'l2_table_index': l2_table_index,
-             'is_add': is_add})
+            self.papi.igmp_enable_disable,
+            {"enable": enable, "mode": host, "sw_if_index": sw_if_index},
+        )
 
-    def set_ipfix_exporter(
-            self,
-            collector_address,
-            src_address,
-            path_mtu,
-            template_interval,
-            vrf_id=0,
-            collector_port=4739,
-            udp_checksum=0):
+    def igmp_proxy_device_add_del(self, vrf_id, sw_if_index, add):
+        """Add/del IGMP proxy device"""
         return self.api(
-            self.papi.set_ipfix_exporter,
-            {
-                'collector_address': collector_address,
-                'collector_port': collector_port,
-                'src_address': src_address,
-                'vrf_id': vrf_id,
-                'path_mtu': path_mtu,
-                '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):
+            self.papi.igmp_proxy_device_add_del,
+            {"vrf_id": vrf_id, "sw_if_index": sw_if_index, "add": add},
+        )
+
+    def igmp_proxy_device_add_del_interface(self, vrf_id, sw_if_index, add):
+        """Add/del interface to/from IGMP proxy device"""
         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):
+            self.papi.igmp_proxy_device_add_del_interface,
+            {"vrf_id": vrf_id, "sw_if_index": sw_if_index, "add": add},
+        )
+
+    def igmp_listen(self, filter, sw_if_index, saddrs, gaddr):
+        """Listen for new (S,G) on specified interface
+
+        :param enable: add/delas
+        :param sw_if_index: interface sw index
+        :param saddr: source ip4 addr
+        :param gaddr: group ip4 addr
+        """
         return self.api(
-            self.papi.dhcp_proxy_set_vss,
+            self.papi.igmp_listen,
             {
-                'tbl_id': table_id,
-                'fib_id': fib_id,
-                'is_ipv6': is_ip6,
-                'is_add': is_add,
-                'oui': oui,
-            })
+                "group": {
+                    "filter": filter,
+                    "sw_if_index": sw_if_index,
+                    "n_srcs": len(saddrs),
+                    "saddrs": saddrs,
+                    "gaddr": gaddr,
+                }
+            },
+        )
+
+    def igmp_clear_interface(self, sw_if_index):
+        """Remove all (S,G)s from specified interface
+        doesn't send IGMP report!
+        """
+        return self.api(self.papi.igmp_clear_interface, {"sw_if_index": sw_if_index})
+
+    def want_igmp_events(self, enable=1):
+        return self.api(
+            self.papi.want_igmp_events, {"enable": enable, "pid": os.getpid()}
+        )