ipsec: change wildcard value for any protocol of spd policy
[vpp.git] / test / vpp_papi_provider.py
1 # NB NB NB NB NB NB NB NB NB NB NB
2 #
3 # NOTE: The API binary wrappers in this file are in the process of being
4 # deprecated. DO NOT ADD NEW WRAPPERS HERE. Call the functions using
5 # named arguments directly instead.
6 #
7
8 import os
9 import time
10 import queue
11 from six import moves, iteritems
12 from config import config
13 from vpp_papi import VPPApiClient
14 from hook import Hook
15 from vpp_papi_exceptions import (
16     CliFailedCommandError,
17     CliSyntaxError,
18     UnexpectedApiReturnValueError,
19 )
20
21 #
22 # Dictionary keyed on message name to override default values for
23 # named parameters
24 #
25 defaultmapping = {
26     "acl_interface_add_del": {"is_add": 1, "is_input": 1},
27     "bd_ip_mac_add_del": {
28         "is_add": 1,
29     },
30     "bfd_udp_add": {"is_authenticated": False, "bfd_key_id": None, "conf_key_id": None},
31     "bfd_udp_auth_activate": {
32         "bfd_key_id": None,
33         "conf_key_id": None,
34         "is_delayed": False,
35     },
36     "bier_disp_entry_add_del": {
37         "next_hop_rpf_id": -1,
38         "next_hop_is_ip4": 1,
39         "is_add": 1,
40     },
41     "bier_disp_table_add_del": {
42         "is_add": 1,
43     },
44     "bier_imp_add": {
45         "is_add": 1,
46     },
47     "bier_route_add_del": {
48         "is_add": 1,
49     },
50     "bier_table_add_del": {
51         "is_add": 1,
52     },
53     "bridge_domain_add_del": {
54         "flood": 1,
55         "uu_flood": 1,
56         "forward": 1,
57         "learn": 1,
58         "is_add": 1,
59     },
60     "bvi_delete": {},
61     "geneve_add_del_tunnel": {
62         "mcast_sw_if_index": 4294967295,
63         "is_add": 1,
64         "decap_next_index": 4294967295,
65     },
66     "input_acl_set_interface": {
67         "ip4_table_index": 4294967295,
68         "ip6_table_index": 4294967295,
69         "l2_table_index": 4294967295,
70     },
71     "ip6_add_del_address_using_prefix": {
72         "is_add": 1,
73     },
74     "ip6nd_send_router_solicitation": {
75         "irt": 1,
76         "mrt": 120,
77     },
78     "ip_add_del_route": {
79         "next_hop_sw_if_index": 4294967295,
80         "next_hop_weight": 1,
81         "next_hop_via_label": 1048576,
82         "classify_table_index": 4294967295,
83         "is_add": 1,
84     },
85     "ip_mroute_add_del": {
86         "is_add": 1,
87     },
88     "ip_neighbor_add_del": {
89         "is_add": 1,
90     },
91     "ipsec_interface_add_del_spd": {
92         "is_add": 1,
93     },
94     "ipsec_spd_add_del": {
95         "is_add": 1,
96     },
97     "ipsec_spd_dump": {
98         "sa_id": 4294967295,
99     },
100     "ipsec_spd_entry_add_del": {
101         "local_port_stop": 65535,
102         "remote_port_stop": 65535,
103         "priority": 100,
104         "is_outbound": 1,
105         "is_add": 1,
106     },
107     "ipsec_tunnel_if_add_del": {
108         "is_add": 1,
109         "anti_replay": 1,
110     },
111     "l2_emulation": {
112         "enable": 1,
113     },
114     "l2fib_add_del": {
115         "is_add": 1,
116     },
117     "lisp_add_del_adjacency": {
118         "is_add": 1,
119     },
120     "lisp_add_del_local_eid": {
121         "is_add": 1,
122     },
123     "lisp_add_del_locator": {
124         "priority": 1,
125         "weight": 1,
126         "is_add": 1,
127     },
128     "lisp_add_del_locator_set": {
129         "is_add": 1,
130     },
131     "lisp_add_del_remote_mapping": {
132         "is_add": 1,
133     },
134     "macip_acl_interface_add_del": {
135         "is_add": 1,
136     },
137     "mpls_ip_bind_unbind": {
138         "is_ip4": 1,
139         "is_bind": 1,
140     },
141     "mpls_route_add_del": {
142         "mr_next_hop_sw_if_index": 4294967295,
143         "mr_next_hop_weight": 1,
144         "mr_next_hop_via_label": 1048576,
145         "mr_is_add": 1,
146         "mr_classify_table_index": 4294967295,
147     },
148     "mpls_table_add_del": {
149         "is_add": 1,
150     },
151     "mpls_tunnel_add_del": {
152         "next_hop_sw_if_index": 4294967295,
153         "next_hop_weight": 1,
154         "next_hop_via_label": 1048576,
155         "is_add": 1,
156     },
157     "output_acl_set_interface": {
158         "ip4_table_index": 4294967295,
159         "ip6_table_index": 4294967295,
160         "l2_table_index": 4294967295,
161     },
162     "pppoe_add_del_session": {
163         "is_add": 1,
164     },
165     "policer_add_del": {
166         "is_add": 1,
167         "conform_action": {"type": 1},
168     },
169     "set_ipfix_exporter": {
170         "collector_port": 4739,
171     },
172     "sr_policy_add": {
173         "weight": 1,
174         "is_encap": 1,
175     },
176     "sw_interface_add_del_address": {
177         "is_add": 1,
178     },
179     "sw_interface_ip6nd_ra_prefix": {
180         "val_lifetime": 4294967295,
181         "pref_lifetime": 4294967295,
182     },
183     "sw_interface_set_ip_directed_broadcast": {
184         "enable": 1,
185     },
186     "sw_interface_set_l2_bridge": {
187         "enable": 1,
188     },
189     "sw_interface_set_mpls_enable": {
190         "enable": 1,
191     },
192     "sw_interface_set_mtu": {
193         "mtu": [0, 0, 0, 0],
194     },
195     "sw_interface_set_unnumbered": {
196         "is_add": 1,
197     },
198     "sw_interface_span_enable_disable": {
199         "state": 1,
200     },
201     "vxlan_add_del_tunnel": {
202         "mcast_sw_if_index": 4294967295,
203         "is_add": 1,
204         "decap_next_index": 4294967295,
205         "instance": 4294967295,
206     },
207     "want_bfd_events": {
208         "enable_disable": 1,
209     },
210     "want_igmp_events": {
211         "enable": 1,
212     },
213     "want_interface_events": {
214         "enable_disable": 1,
215     },
216     "want_l2_macs_events": {
217         "enable_disable": 1,
218         "pid": os.getpid(),
219     },
220     "want_l2_macs_events2": {
221         "enable_disable": 1,
222         "pid": os.getpid(),
223     },
224 }
225
226
227 def as_fn_signature(d):
228     return ", ".join(f"{k}={v}" for k, v in d.items())
229
230
231 class VppPapiProvider(object):
232     """VPP-api provider using vpp-papi
233
234     @property hook: hook object providing before and after api/cli hooks
235     """
236
237     _zero, _negative = range(2)
238
239     def __init__(self, name, test_class, read_timeout):
240         self.hook = Hook(test_class)
241         self.name = name
242         self.test_class = test_class
243         self._expect_api_retval = self._zero
244         self._expect_stack = []
245
246         # install_dir is a class attribute. We need to set it before
247         # calling the constructor.
248         VPPApiClient.apidir = config.vpp_install_dir
249
250         self.vpp = VPPApiClient(
251             logger=test_class.logger,
252             read_timeout=read_timeout,
253             use_socket=True,
254             server_address=test_class.get_api_sock_path(),
255         )
256         self._events = queue.Queue()
257
258     def __enter__(self):
259         return self
260
261     def assert_negative_api_retval(self):
262         """Expect API failure - used with with, e.g.::
263
264             with self.vapi.assert_negative_api_retval():
265                 self.vapi.<api call expected to fail>
266
267         ..
268         """
269         self._expect_stack.append(self._expect_api_retval)
270         self._expect_api_retval = self._negative
271         return self
272
273     def assert_zero_api_retval(self):
274         """Expect API success - used with with, e.g.::
275
276             with self.vapi.assert_negative_api_retval():
277                 self.vapi.<api call expected to succeed>
278
279         :note: this is useful only inside another with block
280              as success is the default expected value
281         """
282         self._expect_stack.append(self._expect_api_retval)
283         self._expect_api_retval = self._zero
284         return self
285
286     def __exit__(self, exc_type, exc_value, traceback):
287         self._expect_api_retval = self._expect_stack.pop()
288
289     def register_hook(self, hook):
290         """Replace hook registration with new hook
291
292         :param hook:
293
294         """
295         self.hook = hook
296
297     def collect_events(self):
298         """Collect all events from the internal queue and clear the queue."""
299         result = []
300         while True:
301             try:
302                 e = self._events.get(block=False)
303                 result.append(e)
304             except queue.Empty:
305                 return result
306         return result
307
308     def wait_for_event(self, timeout, name=None):
309         """Wait for and return next event."""
310         if name:
311             self.test_class.logger.debug(
312                 "Expecting event '%s' within %ss", name, timeout
313             )
314         else:
315             self.test_class.logger.debug("Expecting event within %ss", timeout)
316         try:
317             e = self._events.get(timeout=timeout)
318         except queue.Empty:
319             raise Exception("Event did not occur within timeout")
320         msgname = type(e).__name__
321         if name and msgname != name:
322             raise Exception("Unexpected event received: %s, expected: %s" % msgname)
323         self.test_class.logger.debug("Returning event %s:%s" % (name, e))
324         return e
325
326     def __call__(self, name, event):
327         """Enqueue event in the internal event queue."""
328         self.test_class.logger.debug("New event: %s: %s" % (name, event))
329         self._events.put(event)
330
331     def factory(self, name, apifn):
332         def f(*a, **ka):
333             fields = apifn._func.msg.fields
334
335             # add positional and kw arguments
336             d = ka
337             for i, o in enumerate(fields[3:]):
338                 try:
339                     d[o] = a[i]
340                 except BaseException:
341                     break
342
343             # Default override
344             if name in defaultmapping:
345                 for k, v in iteritems(defaultmapping[name]):
346                     if k in d:
347                         continue
348                     d[k] = v
349             return self.api(apifn, d)
350
351         return f
352
353     def __getattribute__(self, name):
354         try:
355             method = super(VppPapiProvider, self).__getattribute__(name)
356         except AttributeError:
357             method = self.factory(name, getattr(self.papi, name))
358             # lazily load the method so we don't need to call factory
359             # again for this name.
360             setattr(self, name, method)
361         return method
362
363     def connect(self):
364         """Connect the API to VPP"""
365         # This might be called before VPP is prepared to listen to the socket
366         retries = 0
367         while not os.path.exists(self.test_class.get_api_sock_path()):
368             time.sleep(0.5)
369             retries += 1
370             if retries > 120:
371                 break
372         self.vpp.connect(self.name[:63])
373         self.papi = self.vpp.api
374         self.vpp.register_event_callback(self)
375
376     def disconnect(self):
377         """Disconnect the API from VPP"""
378         self.vpp.disconnect()
379
380     def api(self, api_fn, api_args, expected_retval=0):
381         """Call API function and check it's return value.
382         Call the appropriate hooks before and after the API call
383
384         :param api_fn: API function to call
385         :param api_args: tuple of API function arguments
386         :param expected_retval: Expected return value (Default value = 0)
387         :returns: reply from the API
388
389         """
390         self.hook.before_api(api_fn.__name__, api_args)
391         reply = api_fn(**api_args)
392         if self._expect_api_retval == self._negative:
393             if hasattr(reply, "retval") and reply.retval >= 0:
394                 msg = (
395                     "%s(%s) passed unexpectedly: expected negative "
396                     "return value instead of %d in %s"
397                     % (
398                         api_fn.__name__,
399                         as_fn_signature(api_args),
400                         reply.retval,
401                         moves.reprlib.repr(reply),
402                     )
403                 )
404                 self.test_class.logger.info(msg)
405                 raise UnexpectedApiReturnValueError(reply.retval, msg)
406         elif self._expect_api_retval == self._zero:
407             if hasattr(reply, "retval") and reply.retval != expected_retval:
408                 msg = (
409                     "%s(%s) failed, expected %d return value instead "
410                     "of %d in %s"
411                     % (
412                         api_fn.__name__,
413                         as_fn_signature(api_args),
414                         expected_retval,
415                         reply.retval,
416                         repr(reply),
417                     )
418                 )
419                 self.test_class.logger.info(msg)
420                 raise UnexpectedApiReturnValueError(reply.retval, msg)
421         else:
422             raise Exception(
423                 "Internal error, unexpected value for "
424                 "self._expect_api_retval %s" % self._expect_api_retval
425             )
426         self.hook.after_api(api_fn.__name__, api_args)
427         return reply
428
429     def cli_return_response(self, cli):
430         """Execute a CLI, calling the before/after hooks appropriately.
431         Return the reply without examining it
432
433         :param cli: CLI to execute
434         :returns: response object
435
436         """
437         self.hook.before_cli(cli)
438         cli += "\n"
439         r = self.papi.cli_inband(cmd=cli)
440         self.hook.after_cli(cli)
441         return r
442
443     def cli(self, cli):
444         """Execute a CLI, calling the before/after hooks appropriately.
445
446         :param cli: CLI to execute
447         :returns: CLI output
448
449         """
450         r = self.cli_return_response(cli)
451         if r.retval == -156:
452             raise CliSyntaxError(r.reply)
453         if r.retval != 0:
454             raise CliFailedCommandError(r.reply)
455         if hasattr(r, "reply"):
456             return r.reply
457
458     def ppcli(self, cli):
459         """Helper method to print CLI command in case of info logging level.
460
461         :param cli: CLI to execute
462         :returns: CLI output
463         """
464         return cli + "\n" + self.cli(cli)
465
466     def ip6nd_send_router_solicitation(self, sw_if_index, irt=1, mrt=120, mrc=0, mrd=0):
467         return self.api(
468             self.papi.ip6nd_send_router_solicitation,
469             {
470                 "irt": irt,
471                 "mrt": mrt,
472                 "mrc": mrc,
473                 "mrd": mrd,
474                 "sw_if_index": sw_if_index,
475             },
476         )
477
478     def want_interface_events(self, enable_disable=1):
479         return self.api(
480             self.papi.want_interface_events,
481             {
482                 "enable_disable": enable_disable,
483                 "pid": os.getpid(),
484             },
485         )
486
487     def sw_interface_set_mac_address(self, sw_if_index, mac):
488         return self.api(
489             self.papi.sw_interface_set_mac_address,
490             {"sw_if_index": sw_if_index, "mac_address": mac},
491         )
492
493     def p2p_ethernet_add(self, sw_if_index, remote_mac, subif_id):
494         """Create p2p ethernet subinterface
495
496         :param sw_if_index: main (parent) interface
497         :param remote_mac: client (remote) mac address
498
499         """
500         return self.api(
501             self.papi.p2p_ethernet_add,
502             {
503                 "parent_if_index": sw_if_index,
504                 "remote_mac": remote_mac,
505                 "subif_id": subif_id,
506             },
507         )
508
509     def p2p_ethernet_del(self, sw_if_index, remote_mac):
510         """Delete p2p ethernet subinterface
511
512         :param sw_if_index: main (parent) interface
513         :param remote_mac: client (remote) mac address
514
515         """
516         return self.api(
517             self.papi.p2p_ethernet_del,
518             {"parent_if_index": sw_if_index, "remote_mac": remote_mac},
519         )
520
521     def create_vlan_subif(self, sw_if_index, vlan):
522         """
523
524         :param vlan:
525         :param sw_if_index:
526
527         """
528         return self.api(
529             self.papi.create_vlan_subif, {"sw_if_index": sw_if_index, "vlan_id": vlan}
530         )
531
532     def create_loopback(self, mac=""):
533         """
534
535         :param mac: (Optional)
536         """
537         return self.api(self.papi.create_loopback, {"mac_address": mac})
538
539     def ip_route_dump(self, table_id, is_ip6=False):
540         return self.api(
541             self.papi.ip_route_dump, {"table": {"table_id": table_id, "is_ip6": is_ip6}}
542         )
543
544     def ip_route_v2_dump(self, table_id, is_ip6=False, src=0):
545         return self.api(
546             self.papi.ip_route_v2_dump,
547             {"src": src, "table": {"table_id": table_id, "is_ip6": is_ip6}},
548         )
549
550     def ip_neighbor_add_del(
551         self, sw_if_index, mac_address, ip_address, is_add=1, flags=0
552     ):
553         """Add neighbor MAC to IPv4 or IPv6 address.
554
555         :param sw_if_index:
556         :param mac_address:
557         :param dst_address:
558         :param is_add:  (Default value = 1)
559         :param flags:  (Default value = 0/NONE)
560         """
561         return self.api(
562             self.papi.ip_neighbor_add_del,
563             {
564                 "is_add": is_add,
565                 "neighbor": {
566                     "sw_if_index": sw_if_index,
567                     "flags": flags,
568                     "mac_address": mac_address,
569                     "ip_address": ip_address,
570                 },
571             },
572         )
573
574     def udp_encap_add(self, src_ip, dst_ip, src_port, dst_port, table_id=0):
575         """Add a GRE tunnel
576         :param src_ip:
577         :param dst_ip:
578         :param src_port:
579         :param dst_port:
580         :param outer_fib_id:  (Default value = 0)
581         """
582
583         return self.api(
584             self.papi.udp_encap_add,
585             {
586                 "udp_encap": {
587                     "src_ip": src_ip,
588                     "dst_ip": dst_ip,
589                     "src_port": src_port,
590                     "dst_port": dst_port,
591                     "table_id": table_id,
592                 }
593             },
594         )
595
596     def udp_encap_del(self, id):
597         return self.api(self.papi.udp_encap_del, {"id": id})
598
599     def udp_encap_dump(self):
600         return self.api(self.papi.udp_encap_dump, {})
601
602     def want_udp_encap_stats(self, enable=1):
603         return self.api(
604             self.papi.want_udp_encap_stats, {"enable": enable, "pid": os.getpid()}
605         )
606
607     def mpls_route_dump(self, table_id):
608         return self.api(self.papi.mpls_route_dump, {"table": {"mt_table_id": table_id}})
609
610     def mpls_table_dump(self):
611         return self.api(self.papi.mpls_table_dump, {})
612
613     def mpls_table_add_del(self, table_id, is_add=1):
614         """
615
616         :param table_id
617         :param is_add:  (Default value = 1)
618
619         """
620
621         return self.api(
622             self.papi.mpls_table_add_del,
623             {
624                 "mt_table": {
625                     "mt_table_id": table_id,
626                 },
627                 "mt_is_add": is_add,
628             },
629         )
630
631     def mpls_route_add_del(
632         self, table_id, label, eos, eos_proto, is_multicast, paths, is_add, is_multipath
633     ):
634         """MPLS Route add/del"""
635         return self.api(
636             self.papi.mpls_route_add_del,
637             {
638                 "mr_route": {
639                     "mr_table_id": table_id,
640                     "mr_label": label,
641                     "mr_eos": eos,
642                     "mr_eos_proto": eos_proto,
643                     "mr_is_multicast": is_multicast,
644                     "mr_n_paths": len(paths),
645                     "mr_paths": paths,
646                 },
647                 "mr_is_add": is_add,
648                 "mr_is_multipath": is_multipath,
649             },
650         )
651
652     def mpls_ip_bind_unbind(self, label, prefix, table_id=0, ip_table_id=0, is_bind=1):
653         """ """
654         return self.api(
655             self.papi.mpls_ip_bind_unbind,
656             {
657                 "mb_mpls_table_id": table_id,
658                 "mb_label": label,
659                 "mb_ip_table_id": ip_table_id,
660                 "mb_is_bind": is_bind,
661                 "mb_prefix": prefix,
662             },
663         )
664
665     def mpls_tunnel_add_del(
666         self, tun_sw_if_index, paths, is_add=1, l2_only=0, is_multicast=0
667     ):
668         """ """
669         return self.api(
670             self.papi.mpls_tunnel_add_del,
671             {
672                 "mt_is_add": is_add,
673                 "mt_tunnel": {
674                     "mt_sw_if_index": tun_sw_if_index,
675                     "mt_l2_only": l2_only,
676                     "mt_is_multicast": is_multicast,
677                     "mt_n_paths": len(paths),
678                     "mt_paths": paths,
679                 },
680             },
681         )
682
683     def input_acl_set_interface(
684         self,
685         is_add,
686         sw_if_index,
687         ip4_table_index=0xFFFFFFFF,
688         ip6_table_index=0xFFFFFFFF,
689         l2_table_index=0xFFFFFFFF,
690     ):
691         """
692         :param is_add:
693         :param sw_if_index:
694         :param ip4_table_index:  (Default value = 0xFFFFFFFF)
695         :param ip6_table_index:  (Default value = 0xFFFFFFFF)
696         :param l2_table_index:  (Default value = 0xFFFFFFFF)
697         """
698
699         return self.api(
700             self.papi.input_acl_set_interface,
701             {
702                 "sw_if_index": sw_if_index,
703                 "ip4_table_index": ip4_table_index,
704                 "ip6_table_index": ip6_table_index,
705                 "l2_table_index": l2_table_index,
706                 "is_add": is_add,
707             },
708         )
709
710     def output_acl_set_interface(
711         self,
712         is_add,
713         sw_if_index,
714         ip4_table_index=0xFFFFFFFF,
715         ip6_table_index=0xFFFFFFFF,
716         l2_table_index=0xFFFFFFFF,
717     ):
718         """
719         :param is_add:
720         :param sw_if_index:
721         :param ip4_table_index:  (Default value = 0xFFFFFFFF)
722         :param ip6_table_index:  (Default value = 0xFFFFFFFF)
723         :param l2_table_index:  (Default value = 0xFFFFFFFF)
724         """
725
726         return self.api(
727             self.papi.output_acl_set_interface,
728             {
729                 "sw_if_index": sw_if_index,
730                 "ip4_table_index": ip4_table_index,
731                 "ip6_table_index": ip6_table_index,
732                 "l2_table_index": l2_table_index,
733                 "is_add": is_add,
734             },
735         )
736
737     def set_ipfix_exporter(
738         self,
739         collector_address,
740         src_address,
741         path_mtu,
742         template_interval,
743         vrf_id=0,
744         collector_port=4739,
745         udp_checksum=0,
746     ):
747         return self.api(
748             self.papi.set_ipfix_exporter,
749             {
750                 "collector_address": collector_address,
751                 "collector_port": collector_port,
752                 "src_address": src_address,
753                 "vrf_id": vrf_id,
754                 "path_mtu": path_mtu,
755                 "template_interval": template_interval,
756                 "udp_checksum": udp_checksum,
757             },
758         )
759
760     def mfib_signal_dump(self):
761         return self.api(self.papi.mfib_signal_dump, {})
762
763     def ip_mroute_dump(self, table_id, is_ip6=False):
764         return self.api(
765             self.papi.ip_mroute_dump,
766             {"table": {"table_id": table_id, "is_ip6": is_ip6}},
767         )
768
769     def pppoe_add_del_session(
770         self, client_ip, client_mac, session_id=0, is_add=1, decap_vrf_id=0
771     ):
772         """
773
774         :param is_add:  (Default value = 1)
775         :param is_ipv6:  (Default value = 0)
776         :param client_ip:
777         :param session_id:  (Default value = 0)
778         :param client_mac:
779         :param decap_vrf_id:  (Default value = 0)
780
781         """
782         return self.api(
783             self.papi.pppoe_add_del_session,
784             {
785                 "is_add": is_add,
786                 "session_id": session_id,
787                 "client_ip": client_ip,
788                 "decap_vrf_id": decap_vrf_id,
789                 "client_mac": client_mac,
790             },
791         )
792
793     def sr_mpls_policy_add(self, bsid, weight, type, segments):
794         return self.api(
795             self.papi.sr_mpls_policy_add,
796             {
797                 "bsid": bsid,
798                 "weight": weight,
799                 "is_spray": type,
800                 "n_segments": len(segments),
801                 "segments": segments,
802             },
803         )
804
805     def sr_mpls_policy_del(self, bsid):
806         return self.api(self.papi.sr_mpls_policy_del, {"bsid": bsid})
807
808     def bier_table_add_del(self, bti, mpls_label, is_add=1):
809         """BIER Table add/del"""
810         return self.api(
811             self.papi.bier_table_add_del,
812             {
813                 "bt_tbl_id": {
814                     "bt_set": bti.set_id,
815                     "bt_sub_domain": bti.sub_domain_id,
816                     "bt_hdr_len_id": bti.hdr_len_id,
817                 },
818                 "bt_label": mpls_label,
819                 "bt_is_add": is_add,
820             },
821         )
822
823     def bier_table_dump(self):
824         return self.api(self.papi.bier_table_dump, {})
825
826     def bier_route_add_del(self, bti, bp, paths, is_add=1, is_replace=0):
827         """BIER Route add/del"""
828         return self.api(
829             self.papi.bier_route_add_del,
830             {
831                 "br_route": {
832                     "br_tbl_id": {
833                         "bt_set": bti.set_id,
834                         "bt_sub_domain": bti.sub_domain_id,
835                         "bt_hdr_len_id": bti.hdr_len_id,
836                     },
837                     "br_bp": bp,
838                     "br_n_paths": len(paths),
839                     "br_paths": paths,
840                 },
841                 "br_is_add": is_add,
842                 "br_is_replace": is_replace,
843             },
844         )
845
846     def bier_route_dump(self, bti):
847         return self.api(
848             self.papi.bier_route_dump,
849             {
850                 "br_tbl_id": {
851                     "bt_set": bti.set_id,
852                     "bt_sub_domain": bti.sub_domain_id,
853                     "bt_hdr_len_id": bti.hdr_len_id,
854                 }
855             },
856         )
857
858     def bier_imp_add(self, bti, src, ibytes, is_add=1):
859         """BIER Imposition Add"""
860         return self.api(
861             self.papi.bier_imp_add,
862             {
863                 "bi_tbl_id": {
864                     "bt_set": bti.set_id,
865                     "bt_sub_domain": bti.sub_domain_id,
866                     "bt_hdr_len_id": bti.hdr_len_id,
867                 },
868                 "bi_src": src,
869                 "bi_n_bytes": len(ibytes),
870                 "bi_bytes": ibytes,
871             },
872         )
873
874     def bier_imp_del(self, bi_index):
875         """BIER Imposition del"""
876         return self.api(self.papi.bier_imp_del, {"bi_index": bi_index})
877
878     def bier_imp_dump(self):
879         return self.api(self.papi.bier_imp_dump, {})
880
881     def bier_disp_table_add_del(self, bdti, is_add=1):
882         """BIER Disposition Table add/del"""
883         return self.api(
884             self.papi.bier_disp_table_add_del,
885             {"bdt_tbl_id": bdti, "bdt_is_add": is_add},
886         )
887
888     def bier_disp_table_dump(self):
889         return self.api(self.papi.bier_disp_table_dump, {})
890
891     def bier_disp_entry_add_del(
892         self,
893         bdti,
894         bp,
895         payload_proto,
896         next_hop_afi,
897         next_hop,
898         next_hop_tbl_id=0,
899         next_hop_rpf_id=~0,
900         next_hop_is_ip4=1,
901         is_add=1,
902     ):
903         """BIER Route add/del"""
904         lstack = []
905         while len(lstack) < 16:
906             lstack.append({})
907         return self.api(
908             self.papi.bier_disp_entry_add_del,
909             {
910                 "bde_tbl_id": bdti,
911                 "bde_bp": bp,
912                 "bde_payload_proto": payload_proto,
913                 "bde_n_paths": 1,
914                 "bde_paths": [
915                     {
916                         "table_id": next_hop_tbl_id,
917                         "rpf_id": next_hop_rpf_id,
918                         "n_labels": 0,
919                         "label_stack": lstack,
920                     }
921                 ],
922                 "bde_is_add": is_add,
923             },
924         )
925
926     def bier_disp_entry_dump(self, bdti):
927         return self.api(self.papi.bier_disp_entry_dump, {"bde_tbl_id": bdti})
928
929     def ipsec_spd_add_del(self, spd_id, is_add=1):
930         """SPD add/del - Wrapper to add or del ipsec SPD
931         Sample CLI : 'ipsec spd add 1'
932
933         :param spd_id - SPD ID to be created in the vpp . mandatory
934         :param is_add - create (1) or delete(0) SPD (Default 1 - add) .
935         optional
936         :returns: reply from the API
937         """
938         return self.api(
939             self.papi.ipsec_spd_add_del, {"spd_id": spd_id, "is_add": is_add}
940         )
941
942     def ipsec_spds_dump(self):
943         return self.api(self.papi.ipsec_spds_dump, {})
944
945     def ipsec_interface_add_del_spd(self, spd_id, sw_if_index, is_add=1):
946         """ IPSEC interface SPD add/del - \
947              Wrapper to associate/disassociate SPD to interface in VPP
948         Sample CLI : 'set interface ipsec spd GigabitEthernet0/6/0 1'
949
950         :param spd_id - SPD ID to associate with the interface . mandatory
951         :param sw_if_index - Interface Index which needs to ipsec \
952             association mandatory
953         :param is_add - add(1) or del(0) association with interface \
954                 (Default 1 - add) . optional
955         :returns: reply from the API
956         """
957         return self.api(
958             self.papi.ipsec_interface_add_del_spd,
959             {"spd_id": spd_id, "sw_if_index": sw_if_index, "is_add": is_add},
960         )
961
962     def ipsec_spd_interface_dump(self, spd_index=None):
963         return self.api(
964             self.papi.ipsec_spd_interface_dump,
965             {
966                 "spd_index": spd_index if spd_index else 0,
967                 "spd_index_valid": 1 if spd_index else 0,
968             },
969         )
970
971     def ipsec_spd_entry_add_del(
972         self,
973         spd_id,
974         sa_id,
975         local_address_start,
976         local_address_stop,
977         remote_address_start,
978         remote_address_stop,
979         local_port_start=0,
980         local_port_stop=65535,
981         remote_port_start=0,
982         remote_port_stop=65535,
983         protocol=socket.IPPROTO_RAW,
984         policy=0,
985         priority=100,
986         is_outbound=1,
987         is_add=1,
988         is_ipv6=0,
989         is_ip_any=0,
990     ):
991         """IPSEC policy SPD add/del   -
992                     Wrapper to configure ipsec SPD policy entries in VPP
993
994         :param spd_id: SPD ID for the policy
995         :param local_address_start: local-ip-range start address
996         :param local_address_stop: local-ip-range stop address
997         :param remote_address_start: remote-ip-range start address
998         :param remote_address_stop: remote-ip-range stop address
999         :param local_port_start: (Default value = 0)
1000         :param local_port_stop: (Default value = 65535)
1001         :param remote_port_start: (Default value = 0)
1002         :param remote_port_stop: (Default value = 65535)
1003         :param protocol: Any(0), AH(51) & ESP(50) protocol (Default value = 0)
1004         :param sa_id: Security Association ID for mapping it to SPD
1005         :param policy: bypass(0), discard(1), resolve(2) or protect(3) action
1006             (Default value = 0)
1007         :param priority: value for the spd action (Default value = 100)
1008         :param is_outbound: flag for inbound(0) or outbound(1)
1009             (Default value = 1)
1010         :param is_add: (Default value = 1)
1011         """
1012         return self.api(
1013             self.papi.ipsec_spd_entry_add_del_v2,
1014             {
1015                 "is_add": is_add,
1016                 "entry": {
1017                     "spd_id": spd_id,
1018                     "sa_id": sa_id,
1019                     "local_address_start": local_address_start,
1020                     "local_address_stop": local_address_stop,
1021                     "remote_address_start": remote_address_start,
1022                     "remote_address_stop": remote_address_stop,
1023                     "local_port_start": local_port_start,
1024                     "local_port_stop": local_port_stop,
1025                     "remote_port_start": remote_port_start,
1026                     "remote_port_stop": remote_port_stop,
1027                     "protocol": protocol,
1028                     "policy": policy,
1029                     "priority": priority,
1030                     "is_outbound": is_outbound,
1031                 },
1032             },
1033         )
1034
1035     def ipsec_spd_dump(self, spd_id, sa_id=0xFFFFFFFF):
1036         return self.api(self.papi.ipsec_spd_dump, {"spd_id": spd_id, "sa_id": sa_id})
1037
1038     def ipsec_tunnel_if_add_del(
1039         self,
1040         local_ip,
1041         remote_ip,
1042         local_spi,
1043         remote_spi,
1044         crypto_alg,
1045         local_crypto_key,
1046         remote_crypto_key,
1047         integ_alg,
1048         local_integ_key,
1049         remote_integ_key,
1050         is_add=1,
1051         esn=0,
1052         salt=0,
1053         anti_replay=1,
1054         renumber=0,
1055         udp_encap=0,
1056         show_instance=0xFFFFFFFF,
1057     ):
1058         return self.api(
1059             self.papi.ipsec_tunnel_if_add_del,
1060             {
1061                 "local_ip": local_ip,
1062                 "remote_ip": remote_ip,
1063                 "local_spi": local_spi,
1064                 "remote_spi": remote_spi,
1065                 "crypto_alg": crypto_alg,
1066                 "local_crypto_key_len": len(local_crypto_key),
1067                 "local_crypto_key": local_crypto_key,
1068                 "remote_crypto_key_len": len(remote_crypto_key),
1069                 "remote_crypto_key": remote_crypto_key,
1070                 "integ_alg": integ_alg,
1071                 "local_integ_key_len": len(local_integ_key),
1072                 "local_integ_key": local_integ_key,
1073                 "remote_integ_key_len": len(remote_integ_key),
1074                 "remote_integ_key": remote_integ_key,
1075                 "is_add": is_add,
1076                 "esn": esn,
1077                 "anti_replay": anti_replay,
1078                 "renumber": renumber,
1079                 "show_instance": show_instance,
1080                 "udp_encap": udp_encap,
1081                 "salt": salt,
1082             },
1083         )
1084
1085     def ipsec_select_backend(self, protocol, index):
1086         return self.api(
1087             self.papi.ipsec_select_backend, {"protocol": protocol, "index": index}
1088         )
1089
1090     def ipsec_backend_dump(self):
1091         return self.api(self.papi.ipsec_backend_dump, {})
1092
1093     def punt_socket_register(self, reg, pathname, header_version=1):
1094         """Register punt socket"""
1095         return self.api(
1096             self.papi.punt_socket_register,
1097             {"header_version": header_version, "punt": reg, "pathname": pathname},
1098         )
1099
1100     def punt_socket_deregister(self, reg):
1101         """Unregister punt socket"""
1102         return self.api(self.papi.punt_socket_deregister, {"punt": reg})
1103
1104     def igmp_enable_disable(self, sw_if_index, enable, host):
1105         """Enable/disable IGMP on a given interface"""
1106         return self.api(
1107             self.papi.igmp_enable_disable,
1108             {"enable": enable, "mode": host, "sw_if_index": sw_if_index},
1109         )
1110
1111     def igmp_proxy_device_add_del(self, vrf_id, sw_if_index, add):
1112         """Add/del IGMP proxy device"""
1113         return self.api(
1114             self.papi.igmp_proxy_device_add_del,
1115             {"vrf_id": vrf_id, "sw_if_index": sw_if_index, "add": add},
1116         )
1117
1118     def igmp_proxy_device_add_del_interface(self, vrf_id, sw_if_index, add):
1119         """Add/del interface to/from IGMP proxy device"""
1120         return self.api(
1121             self.papi.igmp_proxy_device_add_del_interface,
1122             {"vrf_id": vrf_id, "sw_if_index": sw_if_index, "add": add},
1123         )
1124
1125     def igmp_listen(self, filter, sw_if_index, saddrs, gaddr):
1126         """Listen for new (S,G) on specified interface
1127
1128         :param enable: add/delas
1129         :param sw_if_index: interface sw index
1130         :param saddr: source ip4 addr
1131         :param gaddr: group ip4 addr
1132         """
1133         return self.api(
1134             self.papi.igmp_listen,
1135             {
1136                 "group": {
1137                     "filter": filter,
1138                     "sw_if_index": sw_if_index,
1139                     "n_srcs": len(saddrs),
1140                     "saddrs": saddrs,
1141                     "gaddr": gaddr,
1142                 }
1143             },
1144         )
1145
1146     def igmp_clear_interface(self, sw_if_index):
1147         """Remove all (S,G)s from specified interface
1148         doesn't send IGMP report!
1149         """
1150         return self.api(self.papi.igmp_clear_interface, {"sw_if_index": sw_if_index})
1151
1152     def want_igmp_events(self, enable=1):
1153         return self.api(
1154             self.papi.want_igmp_events, {"enable": enable, "pid": os.getpid()}
1155         )