# 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 socket 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, }, "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): """VPP-api provider using vpp-papi @property hook: hook object providing before and after api/cli hooks """ _zero, _negative = range(2) def __init__(self, name, 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 = [] self.vpp = VPPApiClient( apidir=config.extern_apidir + [config.vpp_install_dir], 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 assert_negative_api_retval(self): """Expect API failure - used with with, e.g.:: with self.vapi.assert_negative_api_retval(): self.vapi. .. """ 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.:: with self.vapi.assert_negative_api_retval(): self.vapi. :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 :param hook: """ 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""" # 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.vpp.disconnect() def api(self, api_fn, api_args, expected_retval=0): """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 :param api_args: tuple of API function arguments :param expected_retval: Expected return value (Default value = 0) :returns: reply from the API """ 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 = ( "%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_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: response object """ self.hook.before_cli(cli) cli += "\n" r = self.papi.cli_inband(cmd=cli) self.hook.after_cli(cli) return r def cli(self, cli): """Execute a CLI, calling the before/after hooks appropriately. :param cli: CLI to execute :returns: CLI output """ 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" + self.cli(cli) 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 want_interface_events(self, enable_disable=1): return self.api( self.papi.want_interface_events, { "enable_disable": enable_disable, "pid": os.getpid(), }, ) 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 p2p_ethernet_add(self, sw_if_index, remote_mac, subif_id): """Create p2p ethernet subinterface :param sw_if_index: main (parent) interface :param remote_mac: client (remote) mac address """ 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 sw_if_index: main (parent) interface :param remote_mac: client (remote) mac address """ return self.api( self.papi.p2p_ethernet_del, {"parent_if_index": sw_if_index, "remote_mac": remote_mac}, ) def create_vlan_subif(self, sw_if_index, vlan): """ :param vlan: :param sw_if_index: """ return self.api( self.papi.create_vlan_subif, {"sw_if_index": sw_if_index, "vlan_id": vlan} ) def create_loopback(self, mac=""): """ :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 sw_if_index: :param mac_address: :param dst_address: :param is_add: (Default value = 1) :param flags: (Default value = 0/NONE) """ 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.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 table_id :param is_add: (Default value = 1) """ return self.api( self.papi.mpls_table_add_del, { "mt_table": { "mt_table_id": table_id, }, "mt_is_add": is_add, }, ) 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, ): """ :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.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, ): """ :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.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 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 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_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 ): """ :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) """ 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.sr_mpls_policy_add, { "bsid": bsid, "weight": weight, "is_spray": type, "n_segments": len(segments), "segments": segments, }, ) def sr_mpls_policy_del(self, bsid): return self.api(self.papi.sr_mpls_policy_del, {"bsid": bsid}) 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.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.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 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, }, ) def bier_imp_del(self, bi_index): """BIER Imposition del""" return self.api(self.papi.bier_imp_del, {"bi_index": bi_index}) 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.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.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.ipsec_spd_add_del, {"spd_id": spd_id, "is_add": is_add} ) 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( 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 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=socket.IPPROTO_RAW, 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_v2, { "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 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, }, ) 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( self.papi.punt_socket_register, {"header_version": header_version, "punt": reg, "pathname": pathname}, ) 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.igmp_enable_disable, {"enable": enable, "mode": host, "sw_if_index": sw_if_index}, ) def igmp_proxy_device_add_del(self, vrf_id, sw_if_index, add): """Add/del IGMP proxy device""" return self.api( 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.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.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()} )