acl: memory leak in acl_fa_session_cleaner_process
[vpp.git] / test / vpp_papi_provider.py
index dc90289..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 array
-from logging import error
+import time
+import queue
+from six import moves, iteritems
+from config import config
+from vpp_papi import VPPApiClient
 from hook import Hook
+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())
 
-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:
-    import vpp_papi
+class VppPapiProvider(object):
+    """VPP-api provider using vpp-papi
 
+    @property hook: hook object providing before and after api/cli hooks
+    """
 
-# from vnet/vnet/mpls/mpls_types.h
-MPLS_IETF_MAX_LABEL = 0xfffff
-MPLS_LABEL_INVALID = MPLS_IETF_MAX_LABEL + 1
+    _zero, _negative = range(2)
 
-class L2_VTR_OP:
-    L2_POP_1 = 3
+    def __init__(self, name, test_class, read_timeout):
+        self.hook = Hook(test_class)
+        self.name = name
+        self.test_class = test_class
+        self._expect_api_retval = self._zero
+        self._expect_stack = []
+
+        # install_dir is a class attribute. We need to set it before
+        # calling the constructor.
+        VPPApiClient.apidir = config.vpp_install_dir
+
+        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()
 
-need_swap = True if os.sys.byteorder == 'little' else False
+    def __enter__(self):
+        return self
 
-class VppPapiProvider(object):
-    """VPP-api provider using vpp-papi
+    def assert_negative_api_retval(self):
+        """Expect API failure - used with with, e.g.::
 
-    @property hook: hook object providing before and after api/cli hooks
+            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 assert_zero_api_retval(self):
+        """Expect API success - used with with, e.g.::
 
-    def __init__(self, name, shm_prefix):
-        self.hook = Hook("vpp-papi-provider")
-        self.name = name
-        self.shm_prefix = shm_prefix
+            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
+
+    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
@@ -45,16 +294,91 @@ class VppPapiProvider(object):
         """
         self.hook = hook
 
+    def collect_events(self):
+        """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 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."""
+        self.test_class.logger.debug("New event: %s: %s" % (name, 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"""
-        vpp_papi.connect(self.name, self.shm_prefix)
+        # 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"""
-        vpp_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
@@ -64,622 +388,768 @@ 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))
-            error(msg)
-            raise Exception(msg)
+        reply = api_fn(**api_args)
+        if self._expect_api_retval == self._negative:
+            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 UnexpectedApiReturnValueError(reply.retval, msg)
+        elif self._expect_api_retval == self._zero:
+            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 UnexpectedApiReturnValueError(reply.retval, 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
 
-    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 = vpp_papi.cli_inband(len(cli), cli)
+        cli += "\n"
+        r = self.papi.cli_inband(cmd=cli)
         self.hook.after_cli(cli)
-        if hasattr(r, 'reply'):
-            return r.reply[0].decode().rstrip('\x00')
+        return r
+
+    def cli(self, cli):
+        """Execute a CLI, calling the before/after hooks appropriately.
+
+        :param cli: CLI to execute
+        :returns: CLI output
 
-    def ppcli(self, cli):
         """
-        Helping method to print CLI command in case of info logging level.
+        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
+
+    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 cli + "\n" + str(self.cli(cli))
+        return cli + "\n" + self.cli(cli)
 
-    def _convert_mac(self, mac):
-        return int(mac.replace(":", ""), 16) << 16
+    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,
+            },
+        )
 
-    def show_version(self):
-        """ """
-        return vpp_papi.show_version()
+    def want_interface_events(self, enable_disable=1):
+        return self.api(
+            self.papi.want_interface_events,
+            {
+                "enable_disable": enable_disable,
+                "pid": os.getpid(),
+            },
+        )
 
-    def pg_create_interface(self, pg_index):
-        """
+    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},
+        )
 
-        :param pg_index:
+    def p2p_ethernet_add(self, sw_if_index, remote_mac, subif_id):
+        """Create p2p ethernet subinterface
 
-        """
-        return self.api(vpp_papi.pg_create_interface, (pg_index, ))
+        :param sw_if_index: main (parent) interface
+        :param remote_mac: client (remote) mac address
 
-    def sw_interface_dump(self, filter=None):
         """
+        return self.api(
+            self.papi.p2p_ethernet_add,
+            {
+                "parent_if_index": sw_if_index,
+                "remote_mac": remote_mac,
+                "subif_id": subif_id,
+            },
+        )
+
+    def p2p_ethernet_del(self, sw_if_index, remote_mac):
+        """Delete p2p ethernet subinterface
 
-        :param filter:  (Default value = None)
+        :param sw_if_index: main (parent) interface
+        :param remote_mac: client (remote) mac address
 
         """
-        if filter is not None:
-            args = (1, filter)
-        else:
-            args = (0, b'')
-        return self.api(vpp_papi.sw_interface_dump, args)
+        return self.api(
+            self.papi.p2p_ethernet_del,
+            {"parent_if_index": sw_if_index, "remote_mac": remote_mac},
+        )
 
-    def sw_interface_set_table(self, sw_if_index, is_ipv6, table_id):
+    def create_vlan_subif(self, sw_if_index, vlan):
         """
-          Set the IPvX Table-id for the Interface
 
+        :param vlan:
         :param sw_if_index:
-        :param is_ipv6:
-        :param table_id:
 
         """
-        return self.api(vpp_papi.sw_interface_set_table,
-                        (sw_if_index, is_ipv6, table_id))
+        return self.api(
+            self.papi.create_vlan_subif, {"sw_if_index": sw_if_index, "vlan_id": vlan}
+        )
+
+    def create_loopback(self, mac=""):
+        """
 
-    def sw_interface_add_del_address(self, sw_if_index, addr, addr_len,
-                                     is_ipv6=0, is_add=1, del_all=0):
+        :param mac: (Optional)
         """
+        return self.api(self.papi.create_loopback, {"mac_address": mac})
+
+    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}}
+        )
+
+    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}},
+        )
+
+    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 addr: param is_ipv6:  (Default value = 0)
         :param sw_if_index:
-        :param addr_len:
-        :param is_ipv6:  (Default value = 0)
+        :param mac_address:
+        :param dst_address:
         :param is_add:  (Default value = 1)
-        :param del_all:  (Default value = 0)
-
+        :param flags:  (Default value = 0/NONE)
         """
-        return self.api(vpp_papi.sw_interface_add_del_address,
-                        (sw_if_index, is_add, is_ipv6, del_all, addr_len, addr))
+        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 sw_interface_enable_disable_mpls(self, sw_if_index,
-                                         is_enable=1):
+    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)
         """
-        Enable/Disable MPLS on the interface
-        :param sw_if_index:
-        :param is_enable:  (Default value = 1)
 
-        """
-        return self.api(vpp_papi.sw_interface_set_mpls_enable,
-                        (sw_if_index, is_enable))
-
-    def sw_interface_ra_suppress(self, sw_if_index):
-        suppress = 1
-        managed = 0
-        other = 0
-        ll_option = 0
-        send_unicast = 0
-        cease = 0
-        is_no = 0
-        default_router = 0
-        max_interval = 0
-        min_interval = 0
-        lifetime = 0
-        initial_count = 0
-        initial_interval = 0
-        async = False
-        return self.api(vpp_papi.sw_interface_ip6nd_ra_config,
-                        (sw_if_index, suppress, managed, other,
-                         ll_option, send_unicast, cease, is_no,
-                         default_router, max_interval, min_interval,
-                         lifetime, initial_count, initial_interval, async))
-
-    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):
+        return self.api(
+            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,
+                }
+            },
+        )
+
+    def udp_encap_del(self, id):
+        return self.api(self.papi.udp_encap_del, {"id": id})
+
+    def udp_encap_dump(self):
+        return self.api(self.papi.udp_encap_dump, {})
+
+    def want_udp_encap_stats(self, enable=1):
+        return self.api(
+            self.papi.want_udp_encap_stats, {"enable": enable, "pid": os.getpid()}
+        )
+
+    def mpls_route_dump(self, table_id):
+        return self.api(self.papi.mpls_route_dump, {"table": {"mt_table_id": table_id}})
+
+    def mpls_table_dump(self):
+        return self.api(self.papi.mpls_table_dump, {})
+
+    def mpls_table_add_del(self, table_id, is_add=1):
         """
 
-        :param dst_addr:
-        :param src_addr:
+        :param table_id
         :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)
 
         """
-        return self.api(vpp_papi.vxlan_add_del_tunnel,
-                        (is_add, is_ipv6, src_addr, dst_addr, mcast_sw_if_index,
-                        encap_vrf_id, decap_next_index, 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.
+        return self.api(
+            self.papi.mpls_table_add_del,
+            {
+                "mt_table": {
+                    "mt_table_id": table_id,
+                },
+                "mt_is_add": is_add,
+            },
+        )
 
-        :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)
+    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.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 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,
+                },
+            },
+        )
+
+    def input_acl_set_interface(
+        self,
+        is_add,
+        sw_if_index,
+        ip4_table_index=0xFFFFFFFF,
+        ip6_table_index=0xFFFFFFFF,
+        l2_table_index=0xFFFFFFFF,
+    ):
         """
-        return self.api(vpp_papi.bridge_domain_add_del,
-                        (bd_id, flood, uu_flood, forward, learn, arp_term,
-                         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)
+        :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(vpp_papi.l2fib_add_del,
-                        (self._convert_mac(mac), bd_id, sw_if_index, is_add,
-                         static_mac, filter_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.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 output_acl_set_interface(
+        self,
+        is_add,
+        sw_if_index,
+        ip4_table_index=0xFFFFFFFF,
+        ip6_table_index=0xFFFFFFFF,
+        l2_table_index=0xFFFFFFFF,
+    ):
         """
-        return self.api(vpp_papi.sw_interface_set_l2_bridge,
-                        (sw_if_index, bd_id, shg, bvi, 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).
+        :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(vpp_papi.bridge_flags, (bd_id, is_set, feature_bitmap))
 
-    def bridge_domain_dump(self, bd_id=0):
-        """
+        return self.api(
+            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,
+            },
+        )
 
-        :param int bd_id: Bridge domain ID. (Default value = 0 => dump of all
-            existing bridge domains returned)
-        :return: Dictionary of bridge domain(s) data.
-        """
-        return self.api(vpp_papi.bridge_domain_dump, (bd_id, ))
+    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,
+            },
+        )
 
-    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.
+    def mfib_signal_dump(self):
+        return self.api(self.papi.mfib_signal_dump, {})
 
-        :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_mroute_dump(self, table_id, is_ip6=False):
+        return self.api(
+            self.papi.ip_mroute_dump,
+            {"table": {"table_id": table_id, "is_ip6": is_ip6}},
+        )
 
+    def pppoe_add_del_session(
+        self, client_ip, client_mac, session_id=0, is_add=1, decap_vrf_id=0
+    ):
         """
-        return self.api(vpp_papi.sw_interface_set_l2_xconnect,
-                        (rx_sw_if_index, tx_sw_if_index, 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
 
-        """
-        return self.api(vpp_papi.l2_interface_vlan_tag_rewrite,
-                        (sw_if_index, vtr_oper, push, tag1, tag2))
+        :param is_add:  (Default value = 1)
+        :param is_ipv6:  (Default value = 0)
+        :param client_ip:
+        :param session_id:  (Default value = 0)
+        :param client_mac:
+        :param decap_vrf_id:  (Default value = 0)
 
-    def sw_interface_set_flags(self, sw_if_index, admin_up_down,
-                               link_up_down=0, deleted=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,
+            },
+        )
 
-        :param admin_up_down:
-        :param sw_if_index:
-        :param link_up_down:  (Default value = 0)
-        :param deleted:  (Default value = 0)
+    def sr_mpls_policy_add(self, bsid, weight, type, segments):
+        return self.api(
+            self.papi.sr_mpls_policy_add,
+            {
+                "bsid": bsid,
+                "weight": weight,
+                "is_spray": type,
+                "n_segments": len(segments),
+                "segments": segments,
+            },
+        )
 
-        """
-        return self.api(vpp_papi.sw_interface_set_flags,
-                        (sw_if_index, admin_up_down, link_up_down, deleted))
+    def sr_mpls_policy_del(self, bsid):
+        return self.api(self.papi.sr_mpls_policy_del, {"bsid": bsid})
 
-    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
+    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,
+            },
+        )
 
-        :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)
+    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(
-            vpp_papi.create_subif,
-            (sw_if_index,
-             sub_id,
-             no_tags,
-             one_tag,
-             two_tags,
-             dot1ad,
-             exact_match,
-             default_sub,
-             outer_vlan_id_any,
-             inner_vlan_id_any,
-             outer_vlan,
-             inner_vlan))
-
-    def delete_subif(self, sw_if_index):
-        """Delete subinterface
+            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,
+            },
+        )
 
-        :param sw_if_index:
-        """
-        return self.api(vpp_papi.delete_subif, ([sw_if_index]))
+    def bier_route_dump(self, bti):
+        return self.api(
+            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 create_vlan_subif(self, sw_if_index, vlan):
-        """
+    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 vlan:
-        :param sw_if_index:
+    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(vpp_papi.create_vlan_subif, (sw_if_index, vlan))
+    def bier_imp_dump(self):
+        return self.api(self.papi.bier_imp_dump, {})
 
-    def create_loopback(self, mac=''):
-        """
+    def bier_disp_table_add_del(self, bdti, is_add=1):
+        """BIER Disposition Table add/del"""
+        return self.api(
+            self.papi.bier_disp_table_add_del,
+            {"bdt_tbl_id": bdti, "bdt_is_add": is_add},
+        )
 
-        :param mac: (Optional)
-        """
-        return self.api(vpp_papi.create_loopback, (mac,))
-
-    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 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.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,
+            },
+        )
 
-        :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_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
         """
-        stack = array.array('I', next_hop_out_label_stack)
-        if need_swap:
-            stack.byteswap()
-        stack = stack.tostring()
-
-        return self.api(
-            vpp_papi.ip_add_del_route,
-            (next_hop_sw_if_index,
-             table_id,
-             classify_table_index,
-             next_hop_table_id,
-             create_vrf_if_needed,
-             is_add,
-             is_drop,
-             is_unreach,
-             is_prohibit,
-             is_ipv6,
-             is_local,
-             is_classify,
-             is_multipath,
-             is_resolve_host,
-             is_resolve_attached,
-             not_last,
-             next_hop_weight,
-             dst_address_length,
-             dst_address,
-             next_hop_address,
-             next_hop_n_out_labels,
-             next_hop_via_label,
-             stack))
-
-    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.
+        return self.api(
+            self.papi.ipsec_spd_add_del, {"spd_id": spd_id, "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 ipsec_spds_dump(self):
+        return self.api(self.papi.ipsec_spds_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'
+
+        :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.ipsec_interface_add_del_spd,
+            {"spd_id": spd_id, "sw_if_index": sw_if_index, "is_add": is_add},
+        )
 
+    def ipsec_spd_interface_dump(self, spd_index=None):
         return self.api(
-            vpp_papi.ip_neighbor_add_del,
-            (vrf_id,
-             sw_if_index,
-             is_add,
-             is_ipv6,
-             is_static,
-             mac_address,
-             dst_address
-             )
+            self.papi.ipsec_spd_interface_dump,
+            {
+                "spd_index": spd_index if spd_index else 0,
+                "spd_index_valid": 1 if spd_index else 0,
+            },
         )
 
-    def sw_interface_span_enable_disable(self, sw_if_index_from, sw_if_index_to, enable=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.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,
+                },
+            },
+        )
 
-        :param sw_if_index_from:
-        :param sw_if_index_to:
-        :param enable
+    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.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,
+            },
+        )
 
-        """
-        return self.api(vpp_papi.sw_interface_span_enable_disable, (sw_if_index_from, sw_if_index_to, enable ))
-
-    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)
-        """
+    def ipsec_select_backend(self, protocol, index):
+        return self.api(
+            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(
-            vpp_papi.gre_add_del_tunnel,
-            (is_add,
-             is_ip6,
-             is_teb,
-             src_address,
-             dst_address,
-             outer_fib_id)
+            self.papi.punt_socket_register,
+            {"header_version": header_version, "punt": reg, "pathname": pathname},
         )
 
-    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 punt_socket_deregister(self, reg):
+        """Unregister punt socket"""
+        return self.api(self.papi.punt_socket_deregister, {"punt": reg})
 
-        :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 igmp_enable_disable(self, sw_if_index, enable, host):
+        """Enable/disable IGMP on a given interface"""
+        return self.api(
+            self.papi.igmp_enable_disable,
+            {"enable": enable, "mode": host, "sw_if_index": sw_if_index},
+        )
 
-        """
-        stack = array.array('I', next_hop_out_label_stack)
-        if need_swap:
-            stack.byteswap()
-        stack = stack.tostring()
-
-        return self.api(
-            vpp_papi.mpls_route_add_del,
-            (label,
-             eos,
-             table_id,
-             classify_table_index,
-             create_vrf_if_needed,
-             is_add,
-             is_classify,
-             is_multipath,
-             is_resolve_host,
-             is_resolve_attached,
-             next_hop_proto_is_ip4,
-             next_hop_weight,
-             next_hop_address,
-             next_hop_n_out_labels,
-             next_hop_sw_if_index,
-             next_hop_table_id,
-             next_hop_via_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):
-        """
-        """
+    def igmp_proxy_device_add_del(self, vrf_id, sw_if_index, add):
+        """Add/del IGMP proxy device"""
         return self.api(
-            vpp_papi.mpls_ip_bind_unbind,
-            (table_id,
-             label,
-             ip_table_id,
-             create_vrf_if_needed,
-             is_bind,
-             is_ip4,
-             dst_address_length,
-             dst_address))
+            self.papi.igmp_proxy_device_add_del,
+            {"vrf_id": vrf_id, "sw_if_index": sw_if_index, "add": add},
+        )
 
-    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 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.igmp_proxy_device_add_del_interface,
+            {"vrf_id": vrf_id, "sw_if_index": sw_if_index, "add": add},
+        )
 
-        :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 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
         """
-        stack = array.array('I', next_hop_out_label_stack)
-        if need_swap:
-            stack.byteswap()
-        stack = stack.tostring()
-
-        return self.api(
-            vpp_papi.mpls_tunnel_add_del,
-            (tun_sw_if_index,
-             is_add,
-             l2_only,
-             next_hop_proto_is_ip4,
-             next_hop_weight,
-             next_hop_address,
-             next_hop_n_out_labels,
-             next_hop_sw_if_index,
-             next_hop_table_id,
-             stack))
+        return self.api(
+            self.papi.igmp_listen,
+            {
+                "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()}
+        )