API Reference Manual  1.46.0
example/ipsec_api/odp_ipsec.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2013-2018 Linaro Limited
3  */
4 
13 /* enable strtok */
14 #ifndef _GNU_SOURCE
15 #define _GNU_SOURCE
16 #endif
17 
18 #include <stdlib.h>
19 #include <getopt.h>
20 #include <signal.h>
21 #include <unistd.h>
22 #include <inttypes.h>
23 
24 #include <odp_api.h>
25 
26 #include <odp/helper/odph_api.h>
27 
28 #include <stdbool.h>
29 #include <sys/socket.h>
30 #include <net/if.h>
31 #include <sys/ioctl.h>
32 
33 #include <sys/socket.h>
34 #include <netpacket/packet.h>
35 #include <net/ethernet.h>
36 #include <arpa/inet.h>
37 
38 #include <odp_ipsec_misc.h>
39 #include <odp_ipsec_sa_db.h>
40 #include <odp_ipsec_sp_db.h>
41 #include <odp_ipsec_fwd_db.h>
42 #include <odp_ipsec_cache.h>
43 
44 #ifndef NO_OPENSSL
45 #include <odp_ipsec_stream.h>
46 #else
47 static void init_stream_db(void) {}
48 static void deinit_stream_db(void) {}
49 static void resolve_stream_db(void) {}
50 static int create_stream_db_inputs(void)
51 {
52  return 0;
53 }
54 
55 static odp_bool_t verify_stream_db_outputs(void)
56 {
57  return true;
58 }
59 
60 static int create_stream_db_entry(char *input ODP_UNUSED)
61 {
62  return -1;
63 }
64 #endif
65 
66 /* maximum number of worker threads */
67 #define MAX_WORKERS (ODP_THREAD_COUNT_MAX - 1)
68 
69 #define MAX_POLL_QUEUES 256
70 
74 typedef struct {
75  unsigned int cpu_count;
76  int if_count;
77  char **if_names;
78  odp_ipsec_op_mode_t mode;
79  odp_pool_t pool;
80  char *if_str;
81  odp_bool_t lookup;
82 } appl_args_t;
83 
87 typedef struct {
89  appl_args_t appl;
90  odp_shm_t shm;
91  odp_pool_t ctx_pool;
92  odp_pool_t pkt_pool;
94  odp_queue_t completionq;
96  odp_barrier_t sync_barrier;
97  odp_queue_t poll_queues[MAX_POLL_QUEUES];
98  int num_polled_queues;
99  /* Stop workers if set to 1 */
100  odp_atomic_u32_t exit_threads;
101 } global_data_t;
102 
103 /* helper funcs */
104 static void parse_args(int argc, char *argv[], appl_args_t *appl_args);
105 static void print_info(char *progname, appl_args_t *appl_args);
106 static void usage(char *progname);
107 
111 #define SHM_PKT_POOL_BUF_COUNT 1024
112 #define SHM_PKT_POOL_BUF_SIZE 4096
113 #define SHM_PKT_POOL_SIZE (SHM_PKT_POOL_BUF_COUNT * SHM_PKT_POOL_BUF_SIZE)
114 
118 typedef enum {
119  PKT_STATE_INPUT_VERIFY,
120  PKT_STATE_IPSEC_IN_CLASSIFY,
121  PKT_STATE_ROUTE_LOOKUP,
122  PKT_STATE_IPSEC_OUT_CLASSIFY,
123  PKT_STATE_TRANSMIT,
124 } pkt_state_e;
125 
129 typedef enum {
130  PKT_CONTINUE,
131  PKT_POSTED,
132  PKT_DROP,
133  PKT_DONE
134 } pkt_disposition_e;
135 
139 typedef struct {
140  odp_buffer_t buffer;
141  pkt_state_e state;
142  odp_pktout_queue_t pktout;
143  odp_pktio_t pktio;
144  odph_ethhdr_t eth;
145 } pkt_ctx_t;
146 
147 #define SHM_CTX_POOL_BUF_SIZE (sizeof(pkt_ctx_t))
148 #define SHM_CTX_POOL_BUF_COUNT (SHM_PKT_POOL_BUF_COUNT)
149 #define SHM_CTX_POOL_SIZE (SHM_CTX_POOL_BUF_COUNT * SHM_CTX_POOL_BUF_SIZE)
150 
151 static global_data_t *global;
152 
153 static void sig_handler(int signo ODP_UNUSED)
154 {
155  if (global == NULL)
156  return;
157  odp_atomic_store_u32(&global->exit_threads, 1);
158 }
159 
168 static
169 pkt_ctx_t *alloc_pkt_ctx(odp_packet_t pkt)
170 {
171  odp_buffer_t ctx_buf = odp_buffer_alloc(global->ctx_pool);
172  pkt_ctx_t *ctx;
173 
174  if (odp_unlikely(ODP_BUFFER_INVALID == ctx_buf))
175  return NULL;
176 
177  ctx = odp_buffer_addr(ctx_buf);
178  memset(ctx, 0, sizeof(*ctx));
179  ctx->buffer = ctx_buf;
180  odp_packet_user_ptr_set(pkt, ctx);
181 
182  return ctx;
183 }
184 
190 static
191 void free_pkt_ctx(pkt_ctx_t *ctx)
192 {
193  odp_buffer_free(ctx->buffer);
194 }
195 
199 typedef odp_queue_t (*queue_create_func_t)
200  (const char *, const odp_queue_param_t *);
201 typedef odp_event_t (*schedule_func_t) (odp_queue_t *);
202 
203 static queue_create_func_t queue_create;
204 static schedule_func_t schedule_fn;
205 
209 static
210 odp_queue_t polled_odp_queue_create(const char *name,
211  const odp_queue_param_t *param)
212 {
213  odp_queue_t my_queue;
215  odp_queue_type_t type;
216 
218  if (param)
219  memcpy(&qp, param, sizeof(odp_queue_param_t));
220 
221  type = qp.type;
222 
223  if (ODP_QUEUE_TYPE_SCHED == type) {
224  printf("%s: change %s to PLAIN\n", __func__, name);
226  }
227 
228  my_queue = odp_queue_create(name, &qp);
229 
230  if (ODP_QUEUE_TYPE_SCHED == type) {
231  global->poll_queues[global->num_polled_queues++] = my_queue;
232  printf("%s: adding %" PRIu64 "\n", __func__,
233  odp_queue_to_u64(my_queue));
234  }
235 
236  return my_queue;
237 }
238 
239 static inline
240 odp_event_t odp_schedule_cb(odp_queue_t *from)
241 {
242  return odp_schedule(from, ODP_SCHED_NO_WAIT);
243 }
244 
248 static
249 odp_event_t polled_odp_schedule_cb(odp_queue_t *from)
250 {
251  int idx = 0;
252 
253  while (idx < global->num_polled_queues) {
254  odp_queue_t queue = global->poll_queues[idx++];
255  odp_event_t ev;
256 
257  ev = odp_queue_deq(queue);
258 
259  if (ODP_EVENT_INVALID != ev) {
260  if (from)
261  *from = queue;
262 
263  return ev;
264  }
265  }
266 
267  if (from)
268  *from = ODP_QUEUE_INVALID;
269 
270  return ODP_EVENT_INVALID;
271 }
272 
276 static
277 void ipsec_init_pre(void)
278 {
279  odp_queue_param_t qparam;
280 
281  /*
282  * Create queues
283  *
284  * - completion queue (should eventually be ORDERED)
285  * - sequence number queue (must be ATOMIC)
286  */
287  odp_queue_param_init(&qparam);
288  qparam.type = ODP_QUEUE_TYPE_SCHED;
289  qparam.sched.prio = odp_schedule_max_prio();
292 
293  global->completionq = queue_create("completion", &qparam);
294  if (ODP_QUEUE_INVALID == global->completionq) {
295  ODPH_ERR("Error: completion queue creation failed\n");
296  exit(EXIT_FAILURE);
297  }
298 
299  qparam.type = ODP_QUEUE_TYPE_SCHED;
300  qparam.sched.prio = odp_schedule_max_prio();
303 
304  /* Initialize our data bases */
305  init_sp_db();
306  init_sa_db();
307  init_tun_db();
308  init_ipsec_cache();
309 }
310 
318 static
319 void ipsec_init_post(odp_ipsec_op_mode_t api_mode)
320 {
321  sp_db_entry_t *entry;
322  odp_ipsec_config_t ipsec_config;
323  odp_ipsec_capability_t ipsec_cap;
324 
325  if (odp_ipsec_capability(&ipsec_cap) != ODP_IPSEC_OK) {
326  ODPH_ERR("Error: failure getting IPSec caps\n");
327  exit(EXIT_FAILURE);
328  }
329 
330  odp_ipsec_config_init(&ipsec_config);
331  ipsec_config.inbound.parse_level = ODP_PROTO_LAYER_ALL;
332  ipsec_config.inbound_mode = api_mode;
333  ipsec_config.outbound_mode = api_mode;
334  ipsec_config.inbound.default_queue = global->completionq;
335  if (odp_ipsec_config(&ipsec_config) != ODP_IPSEC_OK) {
336  ODPH_ERR("Error: failure setting IPSec config\n");
337  exit(EXIT_FAILURE);
338  }
339 
340  /* Attempt to find appropriate SA for each SP */
341  for (entry = sp_db->list; NULL != entry; entry = entry->next) {
342  sa_db_entry_t *cipher_sa = NULL;
343  sa_db_entry_t *auth_sa = NULL;
344  tun_db_entry_t *tun = NULL;
345 
346  if (entry->esp) {
347  cipher_sa = find_sa_db_entry(&entry->src_subnet,
348  &entry->dst_subnet,
349  1);
350  tun = find_tun_db_entry(cipher_sa->src_ip,
351  cipher_sa->dst_ip);
352  }
353  if (entry->ah) {
354  auth_sa = find_sa_db_entry(&entry->src_subnet,
355  &entry->dst_subnet,
356  0);
357  tun = find_tun_db_entry(auth_sa->src_ip,
358  auth_sa->dst_ip);
359  }
360 
361  if (cipher_sa || auth_sa) {
362  if (create_ipsec_cache_entry(cipher_sa,
363  auth_sa,
364  tun,
365  entry->input,
366  global->completionq)) {
367  ODPH_ERR("Error: IPSec cache entry failed.\n"
368  );
369  exit(EXIT_FAILURE);
370  }
371  } else {
372  printf(" WARNING: SA not found for SP\n");
373  dump_sp_db_entry(entry);
374  }
375  }
376 }
377 
378 #ifndef NO_OPENSSL
379 static
380 int check_stream_db_in(const char *intf)
381 {
382  stream_db_entry_t *stream = NULL;
383 
384  /* For each stream look for input and output IPsec entries */
385  for (stream = stream_db->list; NULL != stream; stream = stream->next) {
386  if (!strcmp(stream->input.intf, intf))
387  return 1;
388  }
389 
390  return 0;
391 }
392 
393 static
394 int check_stream_db_out(const char *intf)
395 {
396  stream_db_entry_t *stream = NULL;
397 
398  /* For each stream look for input and output IPsec entries */
399  for (stream = stream_db->list; NULL != stream; stream = stream->next) {
400  if (!strcmp(stream->output.intf, intf))
401  return 1;
402  }
403 
404  return 0;
405 }
406 #else
407 static
408 int check_stream_db_in(const char *intf ODP_UNUSED)
409 {
410  return 0;
411 }
412 
413 static
414 int check_stream_db_out(const char *intf ODP_UNUSED)
415 {
416  return 0;
417 }
418 #endif
419 
428 static
429 void initialize_intf(char *intf)
430 {
431  odp_pktio_t pktio;
432  odp_pktout_queue_t pktout;
433  odp_queue_t inq;
434  int ret;
435  uint8_t src_mac[ODPH_ETHADDR_LEN];
436  char src_mac_str[MAX_STRING];
437  odp_pktio_param_t pktio_param;
438  odp_pktin_queue_param_t pktin_param;
440  odp_pktio_config_t config;
441 
442  odp_pktio_param_init(&pktio_param);
443 
444  if (getenv("ODP_IPSEC_USE_POLL_QUEUES") ||
445  check_stream_db_out(intf))
446  pktio_param.in_mode = ODP_PKTIN_MODE_QUEUE;
447  else
448  pktio_param.in_mode = ODP_PKTIN_MODE_SCHED;
449 
450  /*
451  * Open a packet IO instance for thread and get default output queue
452  */
453  pktio = odp_pktio_open(intf, global->pkt_pool, &pktio_param);
454  if (ODP_PKTIO_INVALID == pktio) {
455  ODPH_ERR("Error: pktio create failed for %s\n", intf);
456  exit(EXIT_FAILURE);
457  }
458 
459  odp_pktin_queue_param_init(&pktin_param);
461 
462  if (odp_pktin_queue_config(pktio, &pktin_param)) {
463  ODPH_ERR("Error: pktin config failed for %s\n", intf);
464  exit(EXIT_FAILURE);
465  }
466 
467  if (odp_pktout_queue_config(pktio, NULL)) {
468  ODPH_ERR("Error: pktout config failed for %s\n", intf);
469  exit(EXIT_FAILURE);
470  }
471 
472  if (odp_pktin_event_queue(pktio, &inq, 1) != 1) {
473  ODPH_ERR("Error: failed to get input queue for %s\n", intf);
474  exit(EXIT_FAILURE);
475  }
476 
477  if (odp_pktout_queue(pktio, &pktout, 1) != 1) {
478  ODPH_ERR("Error: failed to get pktout queue for %s\n", intf);
479  exit(EXIT_FAILURE);
480  }
481 
482  if (odp_pktio_capability(pktio, &capa) != 0) {
483  ODPH_ERR("Error: failed to get capabilities for %s\n", intf);
484  exit(EXIT_FAILURE);
485  }
486 
487  odp_pktio_config_init(&config);
488  if (check_stream_db_in(intf) &&
489  global->appl.mode == ODP_IPSEC_OP_MODE_INLINE)
490  config.inbound_ipsec = capa.config.inbound_ipsec;
491  if (check_stream_db_out(intf) &&
492  global->appl.mode == ODP_IPSEC_OP_MODE_INLINE)
493  config.outbound_ipsec = capa.config.outbound_ipsec;
494 
495  if (odp_pktio_config(pktio, &config) != 0) {
496  ODPH_ERR("Error: failed to set config for %s\n", intf);
497  exit(EXIT_FAILURE);
498  }
499 
500  ret = odp_pktio_start(pktio);
501  if (ret) {
502  ODPH_ERR("Error: unable to start %s\n", intf);
503  exit(EXIT_FAILURE);
504  }
505 
506  /* Read the source MAC address for this interface */
507  ret = odp_pktio_mac_addr(pktio, src_mac, sizeof(src_mac));
508  if (ret <= 0) {
509  ODPH_ERR("Error: failed during MAC address get for %s\n", intf);
510  exit(EXIT_FAILURE);
511  }
512 
513  printf("Created pktio:%02" PRIu64 ", queue mode (ATOMIC queues)\n"
514  " default pktio%02" PRIu64 "-INPUT queue:%" PRIu64 "\n"
515  " source mac address %s\n",
516  odp_pktio_to_u64(pktio), odp_pktio_to_u64(pktio),
517  odp_queue_to_u64(inq),
518  mac_addr_str(src_mac_str, src_mac));
519 
520  /* Resolve any routes using this interface for output */
521  resolve_fwd_db(intf, pktio, pktout, src_mac);
522 }
523 
532 static
533 pkt_disposition_e do_input_verify(odp_packet_t pkt,
534  pkt_ctx_t *ctx ODP_UNUSED)
535 {
537  return PKT_DROP;
538 
539  if (!odp_packet_has_eth(pkt))
540  return PKT_DROP;
541 
542  if (!odp_packet_has_ipv4(pkt))
543  return PKT_DROP;
544 
545  return PKT_CONTINUE;
546 }
547 
556 static
557 pkt_disposition_e do_route_fwd_db(odp_packet_t pkt, pkt_ctx_t *ctx)
558 {
559  odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL);
560  fwd_db_entry_t *entry;
561 
562  entry = find_fwd_db_entry(odp_be_to_cpu_32(ip->dst_addr));
563 
564  if (entry) {
565  uint32_t l3_offset = odp_packet_l3_offset(pkt);
566 
567  if (l3_offset > sizeof(odph_ethhdr_t))
569  l3_offset - sizeof(odph_ethhdr_t));
570  else
572  sizeof(odph_ethhdr_t) - l3_offset);
573 
574  memcpy(&ctx->eth.dst, entry->dst_mac, ODPH_ETHADDR_LEN);
575  memcpy(&ctx->eth.src, entry->src_mac, ODPH_ETHADDR_LEN);
576  ctx->eth.type = odp_cpu_to_be_16(ODPH_ETHTYPE_IPV4);
577 
578  if (global->appl.mode != ODP_IPSEC_OP_MODE_INLINE) {
579  odp_packet_l2_offset_set(pkt, 0);
580  odp_packet_copy_from_mem(pkt, 0, ODPH_ETHHDR_LEN,
581  &ctx->eth);
582  }
583 
584  ctx->pktio = entry->pktio;
585  ctx->pktout = entry->pktout;
586 
587  return PKT_CONTINUE;
588  }
589 
590  return PKT_DROP;
591 }
592 
605 static
606 pkt_disposition_e do_ipsec_in_classify(odp_packet_t *ppkt)
607 {
608  odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(*ppkt, NULL);
609  odph_ahhdr_t *ah = NULL;
610  odph_esphdr_t *esp = NULL;
611  ipsec_cache_entry_t *entry;
612  odp_ipsec_in_param_t in_param;
613  int rc;
614 
615  /* Check IP header for IPSec protocols and look it up */
616  locate_ipsec_headers(ip, &ah, &esp);
617  if (!ah && !esp)
618  return PKT_CONTINUE;
619  entry = find_ipsec_cache_entry_in(odp_be_to_cpu_32(ip->src_addr),
620  odp_be_to_cpu_32(ip->dst_addr),
621  ah,
622  esp);
623  if (!entry)
624  return PKT_CONTINUE;
625 
626  memset(&in_param, 0, sizeof(in_param));
627  if (global->appl.lookup) {
628  in_param.num_sa = 0;
629  in_param.sa = NULL;
630  } else {
631  in_param.num_sa = 1;
632  in_param.sa = &entry->ipsec_sa;
633  }
634 
635  /* Issue crypto request */
636  if (global->appl.mode != ODP_IPSEC_OP_MODE_SYNC) {
637  rc = odp_ipsec_in_enq(ppkt, 1, &in_param);
638  if (rc <= 0)
639  return PKT_DROP;
640 
641  return PKT_POSTED;
642  } else {
643  int out = 1;
645 
646  rc = odp_ipsec_in(ppkt, 1, ppkt, &out, &in_param);
647  if (rc <= 0)
648  return PKT_DROP;
649 
650  if (odp_ipsec_result(&result, *ppkt) < 0) {
651  ODPH_DBG("odp_ipsec_result() failed\n");
652  return PKT_DROP;
653  }
654  if (result.status.error.all != 0) {
655  ODPH_DBG("Error in inbound IPsec processing\n");
656  return PKT_DROP;
657  }
658  return PKT_CONTINUE;
659  }
660 }
661 
676 static
677 pkt_disposition_e do_ipsec_out_classify(odp_packet_t *ppkt, pkt_ctx_t *ctx)
678 {
679  odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(*ppkt, NULL);
680  ipsec_cache_entry_t *entry;
681  odp_ipsec_out_param_t out_param;
682  int rc;
683 
684  /* Find record */
685  entry = find_ipsec_cache_entry_out(odp_be_to_cpu_32(ip->src_addr),
686  odp_be_to_cpu_32(ip->dst_addr),
687  ip->proto);
688  if (!entry)
689  return PKT_CONTINUE;
690 
691  memset(&out_param, 0, sizeof(out_param));
692  out_param.num_sa = 1;
693  out_param.num_opt = 0;
694  out_param.sa = &entry->ipsec_sa;
695  out_param.opt = NULL;
696 
697  /* Issue crypto request */
698  if (global->appl.mode == ODP_IPSEC_OP_MODE_INLINE) {
699  odp_ipsec_out_inline_param_t inline_param;
700 
701  inline_param.pktio = ctx->pktio;
702  inline_param.outer_hdr.ptr = (void *)&ctx->eth;
703  inline_param.outer_hdr.len = ODPH_ETHHDR_LEN;
704  rc = odp_ipsec_out_inline(ppkt, 1, &out_param, &inline_param);
705  if (rc <= 0)
706  return PKT_DROP;
707 
708  return PKT_DONE;
709  } else if (global->appl.mode != ODP_IPSEC_OP_MODE_SYNC) {
710  rc = odp_ipsec_out_enq(ppkt, 1, &out_param);
711  if (rc <= 0)
712  return PKT_DROP;
713 
714  return PKT_POSTED;
715  } else {
716  int out = 1;
718 
719  rc = odp_ipsec_out(ppkt, 1, ppkt, &out, &out_param);
720  if (rc <= 0)
721  return PKT_DROP;
722 
723  if (odp_ipsec_result(&result, *ppkt) < 0) {
724  ODPH_DBG("odp_ipsec_result() failed\n");
725  return PKT_DROP;
726  }
727  if (result.status.error.all != 0) {
728  ODPH_DBG("Error in outbound IPsec processing\n");
729  return PKT_DROP;
730  }
731  return PKT_CONTINUE;
732  }
733 }
734 
750 static
751 int pktio_thread(void *arg ODP_UNUSED)
752 {
753  int thr;
754  odp_packet_t pkt;
755  odp_event_t ev;
756  unsigned long pkt_cnt = 0;
757 
758  thr = odp_thread_id();
759 
760  printf("Pktio thread [%02i] starts\n", thr);
761 
762  odp_barrier_wait(&global->sync_barrier);
763 
764  /* Loop packets */
765  while (!odp_atomic_load_u32(&global->exit_threads)) {
766  pkt_disposition_e rc = PKT_CONTINUE;
767  pkt_ctx_t *ctx;
768  odp_queue_t dispatchq;
769  odp_event_subtype_t subtype;
770 
771  /* Use schedule to get event from any input queue */
772  ev = schedule_fn(&dispatchq);
773 
774  if (ev == ODP_EVENT_INVALID)
775  continue;
776 
777  /* Determine new work versus completion or sequence number */
778  if (ODP_EVENT_PACKET == odp_event_types(ev, &subtype)) {
779  pkt = odp_packet_from_event(ev);
780  if (ODP_EVENT_PACKET_BASIC == subtype) {
781  ctx = alloc_pkt_ctx(pkt);
782  if (!ctx) {
783  odp_packet_free(pkt);
784  continue;
785  }
786  ctx->state = PKT_STATE_INPUT_VERIFY;
787  } else if (ODP_EVENT_PACKET_IPSEC == subtype) {
789 
790  if (odp_unlikely(odp_ipsec_result(&result,
791  pkt) < 0)) {
792  ODPH_DBG("Error Event\n");
793  odp_event_free(ev);
794  continue;
795  }
796 
797  if (result.status.error.all != 0) {
798  ODPH_DBG("Error in IPsec\n");
799  rc = PKT_DROP;
800  }
801 
802  if (result.flag.inline_mode) {
803  ctx = alloc_pkt_ctx(pkt);
804  if (!ctx) {
805  odp_packet_free(pkt);
806  continue;
807  }
808  if (odp_unlikely(
809  odp_packet_has_error(pkt) ||
810  !odp_packet_has_ipv4(pkt)))
811  rc = PKT_DROP;
812  ctx->state = PKT_STATE_ROUTE_LOOKUP;
813  } else {
814  ctx = odp_packet_user_ptr(pkt);
815  }
816  } else {
817  ODPH_DBG("Unsupported Packet\n");
818  odp_event_free(ev);
819  continue;
820  }
821  } else if (ODP_EVENT_IPSEC_STATUS == odp_event_type(ev)) {
822  odp_ipsec_status_t status;
823 
824  if (odp_unlikely(odp_ipsec_status(&status, ev) < 0)) {
825  ODPH_DBG("Error Event\n");
826  odp_event_free(ev);
827  continue;
828  }
829 
830  printf("IPsec status %d result %d for SA %" PRIx64 "\n",
831  status.id, status.result,
832  odp_ipsec_sa_to_u64(status.sa));
833 
834  odp_event_free(ev);
835  continue;
836  } else {
837  abort();
838  }
839 
840  /*
841  * We now have a packet and its associated context. Loop here
842  * executing processing based on the current state value stored
843  * in the context as long as the processing return code
844  * indicates PKT_CONTINUE.
845  *
846  * For other return codes:
847  *
848  * o PKT_DONE - finished with the packet
849  * o PKT_DROP - something incorrect about the packet, drop it
850  * o PKT_POSTED - packet/event has been queued for later
851  */
852  while (rc == PKT_CONTINUE) {
853  switch (ctx->state) {
854  case PKT_STATE_INPUT_VERIFY:
855 
856  rc = do_input_verify(pkt, ctx);
857  ctx->state = PKT_STATE_IPSEC_IN_CLASSIFY;
858  break;
859 
860  case PKT_STATE_IPSEC_IN_CLASSIFY:
861 
862  ctx->state = PKT_STATE_ROUTE_LOOKUP;
863  rc = do_ipsec_in_classify(&pkt);
864  break;
865 
866  case PKT_STATE_ROUTE_LOOKUP:
867 
868  rc = do_route_fwd_db(pkt, ctx);
869  ctx->state = PKT_STATE_IPSEC_OUT_CLASSIFY;
870  break;
871 
872  case PKT_STATE_IPSEC_OUT_CLASSIFY:
873  ctx->state = PKT_STATE_TRANSMIT;
874  rc = do_ipsec_out_classify(&pkt, ctx);
875  break;
876 
877  case PKT_STATE_TRANSMIT:
878 
879  if (odp_pktout_send(ctx->pktout, &pkt, 1) < 1)
880  rc = PKT_DROP;
881  else
882  rc = PKT_DONE;
883  break;
884 
885  default:
886  rc = PKT_DROP;
887  break;
888  }
889  }
890 
891  /* Free context on drop or transmit */
892  if ((PKT_DROP == rc) || (PKT_DONE == rc))
893  free_pkt_ctx(ctx);
894 
895  /* Check for drop */
896  if (PKT_DROP == rc)
897  odp_packet_free(pkt);
898 
899  /* Print packet counts every once in a while */
900  if (PKT_DONE == rc) {
901  if (odp_unlikely(pkt_cnt++ % 1000 == 0)) {
902  printf(" [%02i] pkt_cnt:%lu\n", thr, pkt_cnt);
903  fflush(NULL);
904  }
905  }
906  }
907 
908  return 0;
909 }
910 
914 int
915 main(int argc, char *argv[])
916 {
917  odph_helper_options_t helper_options;
918  odph_thread_t thread_tbl[MAX_WORKERS];
919  odph_thread_common_param_t thr_common;
920  odph_thread_param_t thr_param;
921  int num_workers;
922  int i;
923  int stream_count;
924  odp_shm_t shm;
925  odp_cpumask_t cpumask;
926  char cpumaskstr[ODP_CPUMASK_STR_SIZE];
927  odp_ipsec_capability_t ipsec_capa;
928  odp_pool_param_t params;
929  odp_instance_t instance;
930  odp_init_t init_param;
931  odp_event_t ev;
932 
933  /* create by default scheduled queues */
934  queue_create = odp_queue_create;
935  schedule_fn = odp_schedule_cb;
936 
937  /* check for using poll queues */
938  if (getenv("ODP_IPSEC_USE_POLL_QUEUES")) {
939  queue_create = polled_odp_queue_create;
940  schedule_fn = polled_odp_schedule_cb;
941  }
942 
943  /* Let helper collect its own arguments (e.g. --odph_proc) */
944  argc = odph_parse_options(argc, argv);
945  if (odph_options(&helper_options)) {
946  ODPH_ERR("Error: reading ODP helper options failed.\n");
947  exit(EXIT_FAILURE);
948  }
949 
950  /* Signal handler has to be registered before global init in case ODP
951  * implementation creates internal threads/processes. */
952  signal(SIGINT, sig_handler);
953 
954  odp_init_param_init(&init_param);
955  init_param.mem_model = helper_options.mem_model;
956 
957  /* Init ODP before calling anything else */
958  if (odp_init_global(&instance, &init_param, NULL)) {
959  ODPH_ERR("Error: ODP global init failed.\n");
960  exit(EXIT_FAILURE);
961  }
962 
963  /* Init this thread */
964  if (odp_init_local(instance, ODP_THREAD_CONTROL)) {
965  ODPH_ERR("Error: ODP local init failed.\n");
966  exit(EXIT_FAILURE);
967  }
968 
969  if (odp_ipsec_capability(&ipsec_capa)) {
970  ODPH_ERR("Error: IPsec capability request failed.\n");
971  exit(EXIT_FAILURE);
972  }
973 
974  if (queue_create == polled_odp_queue_create) {
975  if (!ipsec_capa.queue_type_plain) {
976  ODPH_ERR("Error: Plain type dest queue not supported.\n");
977  exit(EXIT_FAILURE);
978  }
979  } else {
980  if (!ipsec_capa.queue_type_sched) {
981  ODPH_ERR("Error: scheduled type dest queue not supported.\n");
982  exit(EXIT_FAILURE);
983  }
984  }
985 
986  /* Reserve memory for args from shared mem */
987  shm = odp_shm_reserve("shm_args", sizeof(global_data_t),
988  ODP_CACHE_LINE_SIZE, 0);
989 
990  if (shm == ODP_SHM_INVALID) {
991  ODPH_ERR("Error: shared mem reserve failed.\n");
992  exit(EXIT_FAILURE);
993  }
994 
995  global = odp_shm_addr(shm);
996 
997  if (NULL == global) {
998  ODPH_ERR("Error: shared mem alloc failed.\n");
999  exit(EXIT_FAILURE);
1000  }
1001  memset(global, 0, sizeof(global_data_t));
1002  global->shm = shm;
1003  odp_atomic_init_u32(&global->exit_threads, 0);
1004 
1005  /* Configure scheduler */
1006  odp_schedule_config(NULL);
1007 
1008  /* Must init our databases before parsing args */
1009  ipsec_init_pre();
1010  init_fwd_db();
1011  init_stream_db();
1012 
1013  /* Parse and store the application arguments */
1014  parse_args(argc, argv, &global->appl);
1015 
1016  /* Print both system and application information */
1017  print_info(NO_PATH(argv[0]), &global->appl);
1018 
1019  num_workers = MAX_WORKERS;
1020  if (global->appl.cpu_count && global->appl.cpu_count < MAX_WORKERS)
1021  num_workers = global->appl.cpu_count;
1022 
1023  /* Get default worker cpumask */
1024  num_workers = odp_cpumask_default_worker(&cpumask, num_workers);
1025  (void)odp_cpumask_to_str(&cpumask, cpumaskstr, sizeof(cpumaskstr));
1026 
1027  printf("num worker threads: %i\n", num_workers);
1028  printf("first CPU: %i\n", odp_cpumask_first(&cpumask));
1029  printf("cpu mask: %s\n", cpumaskstr);
1030 
1031  /* Create a barrier to synchronize thread startup */
1032  odp_barrier_init(&global->sync_barrier, num_workers);
1033 
1034  /* Create packet buffer pool */
1035  odp_pool_param_init(&params);
1036  params.pkt.seg_len = SHM_PKT_POOL_BUF_SIZE;
1037  params.pkt.len = SHM_PKT_POOL_BUF_SIZE;
1038  params.pkt.num = SHM_PKT_POOL_BUF_COUNT;
1039  params.type = ODP_POOL_PACKET;
1040 
1041  global->pkt_pool = odp_pool_create("packet_pool", &params);
1042 
1043  if (ODP_POOL_INVALID == global->pkt_pool) {
1044  ODPH_ERR("Error: packet pool create failed.\n");
1045  exit(EXIT_FAILURE);
1046  }
1047 
1048  /* Create context buffer pool */
1049  params.buf.size = SHM_CTX_POOL_BUF_SIZE;
1050  params.buf.align = 0;
1051  params.buf.num = SHM_CTX_POOL_BUF_COUNT;
1052  params.type = ODP_POOL_BUFFER;
1053 
1054  global->ctx_pool = odp_pool_create("ctx_pool", &params);
1055 
1056  if (ODP_POOL_INVALID == global->ctx_pool) {
1057  ODPH_ERR("Error: context pool create failed.\n");
1058  exit(EXIT_FAILURE);
1059  }
1060 
1061  /* Populate our IPsec cache */
1062  printf("Using %s mode for IPsec API\n\n",
1063  (ODP_IPSEC_OP_MODE_SYNC == global->appl.mode) ? "SYNC" :
1064  (ODP_IPSEC_OP_MODE_ASYNC == global->appl.mode) ? "ASYNC" :
1065  "INLINE");
1066  ipsec_init_post(global->appl.mode);
1067 
1068  /* Initialize interfaces (which resolves FWD DB entries */
1069  for (i = 0; i < global->appl.if_count; i++)
1070  initialize_intf(global->appl.if_names[i]);
1071 
1072  /* If we have test streams build them before starting workers */
1073  resolve_stream_db();
1074  stream_count = create_stream_db_inputs();
1075  if (stream_count < 0) {
1076  ODPH_ERR("Error: creating input packets failed\n");
1077  exit(EXIT_FAILURE);
1078  }
1079 
1080  /*
1081  * Create and init worker threads
1082  */
1083  odph_thread_common_param_init(&thr_common);
1084  thr_common.instance = instance;
1085  thr_common.cpumask = &cpumask;
1086  thr_common.share_param = 1;
1087 
1088  odph_thread_param_init(&thr_param);
1089  thr_param.start = pktio_thread;
1090  thr_param.arg = NULL;
1091  thr_param.thr_type = ODP_THREAD_WORKER;
1092 
1093  memset(thread_tbl, 0, sizeof(thread_tbl));
1094  odph_thread_create(thread_tbl, &thr_common, &thr_param, num_workers);
1095 
1096  /* If there are streams attempt to verify them. Otherwise, run until
1097  * SIGINT is received. */
1098  if (stream_count) {
1099  odp_bool_t done;
1100 
1101  do {
1102  done = verify_stream_db_outputs();
1103  usleep(100000);
1104  } while (!done);
1105  printf("All received\n");
1106  odp_atomic_store_u32(&global->exit_threads, 1);
1107  }
1108  odph_thread_join(thread_tbl, num_workers);
1109 
1110  /* Stop and close used pktio devices */
1111  for (i = 0; i < global->appl.if_count; i++) {
1112  odp_pktio_t pktio = odp_pktio_lookup(global->appl.if_names[i]);
1113 
1114  if (pktio == ODP_PKTIO_INVALID)
1115  continue;
1116 
1117  if (odp_pktio_stop(pktio) || odp_pktio_close(pktio)) {
1118  ODPH_ERR("Error: failed to close pktio %s\n",
1119  global->appl.if_names[i]);
1120  exit(EXIT_FAILURE);
1121  }
1122  }
1123 
1124  free(global->appl.if_names);
1125  free(global->appl.if_str);
1126 
1127  if (destroy_ipsec_cache())
1128  ODPH_ERR("Error: crypto session destroy failed\n");
1129 
1130  /* Drop any remaining events. ipsec_sa_disable sends status event in
1131  * async mode */
1132  while ((ev = schedule_fn(NULL)) != ODP_EVENT_INVALID)
1133  odp_event_free(ev);
1134 
1135  if (odp_queue_destroy(global->completionq))
1136  ODPH_ERR("Error: queue destroy failed\n");
1137 
1138  if (odp_pool_destroy(global->pkt_pool))
1139  ODPH_ERR("Error: pool destroy failed\n");
1140  if (odp_pool_destroy(global->ctx_pool))
1141  ODPH_ERR("Error: pool destroy failed\n");
1142 
1143  shm = odp_shm_lookup("shm_ipsec_cache");
1144  if (odp_shm_free(shm) != 0)
1145  ODPH_ERR("Error: shm free shm_ipsec_cache failed\n");
1146  shm = odp_shm_lookup("shm_fwd_db");
1147  if (odp_shm_free(shm) != 0)
1148  ODPH_ERR("Error: shm free shm_fwd_db failed\n");
1149  shm = odp_shm_lookup("shm_sa_db");
1150  if (odp_shm_free(shm) != 0)
1151  ODPH_ERR("Error: shm free shm_sa_db failed\n");
1152  shm = odp_shm_lookup("shm_tun_db");
1153  if (odp_shm_free(shm) != 0)
1154  ODPH_ERR("Error: shm free shm_tun_db failed\n");
1155  shm = odp_shm_lookup("shm_sp_db");
1156  if (odp_shm_free(shm) != 0)
1157  ODPH_ERR("Error: shm free shm_sp_db failed\n");
1158 
1159  deinit_stream_db();
1160 
1161  if (odp_shm_free(global->shm)) {
1162  ODPH_ERR("Error: shm free global data failed\n");
1163  exit(EXIT_FAILURE);
1164  }
1165 
1166  if (odp_term_local()) {
1167  ODPH_ERR("Error: term local failed\n");
1168  exit(EXIT_FAILURE);
1169  }
1170 
1171  if (odp_term_global(instance)) {
1172  ODPH_ERR("Error: term global failed\n");
1173  exit(EXIT_FAILURE);
1174  }
1175 
1176  printf("Exit\n\n");
1177 
1178  return 0;
1179 }
1180 
1188 static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
1189 {
1190  int opt;
1191  char *token;
1192  size_t len;
1193  int rc = 0;
1194  int i;
1195 
1196  static const struct option longopts[] = {
1197  {"count", required_argument, NULL, 'c'},
1198  {"interface", required_argument, NULL, 'i'}, /* return 'i' */
1199  {"lookup", no_argument, NULL, 'l'},
1200  {"mode", required_argument, NULL, 'm'}, /* return 'm' */
1201  {"route", required_argument, NULL, 'r'}, /* return 'r' */
1202  {"policy", required_argument, NULL, 'p'}, /* return 'p' */
1203  {"ah", required_argument, NULL, 'a'}, /* return 'a' */
1204  {"esp", required_argument, NULL, 'e'}, /* return 'e' */
1205  {"tunnel", required_argument, NULL, 't'}, /* return 't' */
1206  {"stream", required_argument, NULL, 's'}, /* return 's' */
1207  {"help", no_argument, NULL, 'h'}, /* return 'h' */
1208  {NULL, 0, NULL, 0}
1209  };
1210 
1211  static const char *shortopts = "+c:i:m:r:p:a:e:t:s:lh";
1212 
1213  appl_args->cpu_count = 1; /* use one worker by default */
1214 
1215  printf("\nParsing command line options\n");
1216 
1217  while (!rc) {
1218  opt = getopt_long(argc, argv, shortopts, longopts, NULL);
1219 
1220  if (-1 == opt)
1221  break; /* No more options */
1222 
1223  switch (opt) {
1224  case 'c':
1225  appl_args->cpu_count = atoi(optarg);
1226  break;
1227  /* parse packet-io interface names */
1228  case 'i':
1229  len = strlen(optarg);
1230  if (0 == len) {
1231  usage(argv[0]);
1232  exit(EXIT_FAILURE);
1233  }
1234  len += 1; /* add room for '\0' */
1235 
1236  appl_args->if_str = malloc(len);
1237  if (appl_args->if_str == NULL) {
1238  usage(argv[0]);
1239  exit(EXIT_FAILURE);
1240  }
1241 
1242  /* count the number of tokens separated by ',' */
1243  strcpy(appl_args->if_str, optarg);
1244  for (token = strtok(appl_args->if_str, ","), i = 0;
1245  token != NULL;
1246  token = strtok(NULL, ","), i++)
1247  ;
1248 
1249  appl_args->if_count = i;
1250 
1251  if (0 == appl_args->if_count) {
1252  usage(argv[0]);
1253  exit(EXIT_FAILURE);
1254  }
1255 
1256  /* allocate storage for the if names */
1257  appl_args->if_names =
1258  calloc(appl_args->if_count, sizeof(char *));
1259 
1260  /* store the if names (reset names string) */
1261  strcpy(appl_args->if_str, optarg);
1262  for (token = strtok(appl_args->if_str, ","), i = 0;
1263  token != NULL; token = strtok(NULL, ","), i++) {
1264  appl_args->if_names[i] = token;
1265  }
1266  break;
1267 
1268  case 'l':
1269  appl_args->lookup = true;
1270  break;
1271 
1272  case 'm':
1273  appl_args->mode = atoi(optarg);
1274  break;
1275 
1276  case 'r':
1277  rc = create_fwd_db_entry(optarg, appl_args->if_names,
1278  appl_args->if_count);
1279  break;
1280 
1281  case 'p':
1282  rc = create_sp_db_entry(optarg, FALSE);
1283  break;
1284 
1285  case 'a':
1286  rc = create_sa_db_entry(optarg, FALSE);
1287  break;
1288 
1289  case 'e':
1290  rc = create_sa_db_entry(optarg, TRUE);
1291  break;
1292 
1293  case 't':
1294  rc = create_tun_db_entry(optarg);
1295  break;
1296 
1297  case 's':
1298  rc = create_stream_db_entry(optarg);
1299  break;
1300 
1301  case 'h':
1302  usage(argv[0]);
1303  exit(EXIT_SUCCESS);
1304  break;
1305 
1306  default:
1307  break;
1308  }
1309  }
1310 
1311  if (rc) {
1312  printf("ERROR: failed parsing -%c option\n", opt);
1313  usage(argv[0]);
1314  exit(EXIT_FAILURE);
1315  }
1316 
1317  if (0 == appl_args->if_count) {
1318  usage(argv[0]);
1319  exit(EXIT_FAILURE);
1320  }
1321 
1322  optind = 1; /* reset 'extern optind' from the getopt lib */
1323 }
1324 
1328 static void print_info(char *progname, appl_args_t *appl_args)
1329 {
1330  int i;
1331 
1333 
1334  printf("Running ODP appl: \"%s\"\n"
1335  "-----------------\n"
1336  "IF-count: %i\n"
1337  "Using IFs: ",
1338  progname, appl_args->if_count);
1339  for (i = 0; i < appl_args->if_count; ++i)
1340  printf(" %s", appl_args->if_names[i]);
1341 
1342  printf("\n");
1343 
1344  dump_fwd_db();
1345  dump_sp_db();
1346  dump_sa_db();
1347  dump_tun_db();
1348  printf("\n\n");
1349  fflush(NULL);
1350 }
1351 
1355 static void usage(char *progname)
1356 {
1357  printf("\n"
1358  "Usage: %s OPTIONS\n"
1359  " E.g. %s -i eth1,eth2,eth3 -m 0\n"
1360  "\n"
1361  "OpenDataPlane example application.\n"
1362  "\n"
1363  "Mandatory OPTIONS:\n"
1364  " -i, --interface Eth interfaces (comma-separated, no spaces)\n"
1365  " -m, --mode 0: SYNC\n"
1366  " 1: ASYNC\n"
1367  " Default: 1: ASYNC api mode\n"
1368  "\n"
1369  "Routing / IPSec OPTIONS:\n"
1370  " -r, --route SubNet,Intf,NextHopMAC\n"
1371  " -p, --policy SrcSubNet,DstSubNet,(in|out),(ah|esp)\n"
1372  " -e, --esp SrcIP,DstIP,(3des|null),SPI,Key192\n"
1373  " -a, --ah SrcIP,DstIP,(sha256|sha1|md5|null),SPI,Key(256|160|128)\n"
1374  "\n"
1375  " Where: NextHopMAC is raw hex/colon notation, i.e. 03:BA:44:9A:CE:02\n"
1376  " IP is decimal/dot notation, i.e. 192.168.1.1\n"
1377  " SubNet is decimal/dot/slash notation, i.e 192.168.0.0/16\n"
1378  " SPI is raw hex, 32 bits\n"
1379  " KeyXXX is raw hex, XXX bits long\n"
1380  "\n"
1381  " Examples:\n"
1382  " -r 192.168.222.0/24,p8p1,08:00:27:F5:8B:DB\n"
1383  " -p 192.168.111.0/24,192.168.222.0/24,out,esp\n"
1384  " -e 192.168.111.2,192.168.222.2,3des,201,656c8523255ccc23a66c1917aa0cf30991fce83532a4b224\n"
1385  " -a 192.168.111.2,192.168.222.2,md5,201,a731649644c5dee92cbd9c2e7e188ee6\n"
1386  "\n"
1387  "Optional OPTIONS\n"
1388  " -c, --count <number> CPU count, 0=all available, default=1\n"
1389  " -s, --stream SrcIP,DstIP,InIntf,OutIntf,Count,Length\n"
1390  " -h, --help Display help and exit.\n"
1391  " environment variables: ODP_IPSEC_USE_POLL_QUEUES\n"
1392  " to enable use of poll queues instead of scheduled (default)\n"
1393  " ODP_IPSEC_STREAM_VERIFY_MDEQ\n"
1394  " to enable use of multiple dequeue for queue draining during\n"
1395  " stream verification instead of single dequeue (default)\n"
1396  "\n", NO_PATH(progname), NO_PATH(progname)
1397  );
1398 }
1399 
1400 odp_bool_t sa_config_supported(const sa_db_entry_t *sa_entry, int *sa_flags);
1401 
1402 odp_bool_t sa_config_supported(const sa_db_entry_t *sa_entry ODP_UNUSED, int *sa_flags ODP_UNUSED)
1403 {
1404  return true;
1405 }
void odp_atomic_init_u32(odp_atomic_u32_t *atom, uint32_t val)
Initialize atomic uint32 variable.
uint32_t odp_atomic_load_u32(odp_atomic_u32_t *atom)
Load value of atomic uint32 variable.
void odp_atomic_store_u32(odp_atomic_u32_t *atom, uint32_t val)
Store value to atomic uint32 variable.
void odp_barrier_init(odp_barrier_t *barr, int count)
Initialize barrier with thread count.
void odp_barrier_wait(odp_barrier_t *barr)
Synchronize thread execution on barrier.
odp_buffer_t odp_buffer_alloc(odp_pool_t pool)
Buffer alloc.
void odp_buffer_free(odp_buffer_t buf)
Buffer free.
void * odp_buffer_addr(odp_buffer_t buf)
Buffer start address.
#define ODP_BUFFER_INVALID
Invalid buffer.
#define odp_unlikely(x)
Branch unlikely taken.
Definition: spec/hints.h:64
odp_u16be_t odp_cpu_to_be_16(uint16_t cpu16)
Convert cpu native uint16_t to 16bit big endian.
#define ODP_UNUSED
Intentionally unused variables of functions.
Definition: spec/hints.h:54
uint32_t odp_be_to_cpu_32(odp_u32be_t be32)
Convert 32bit big endian to cpu native uint32_t.
int odp_cpumask_default_worker(odp_cpumask_t *mask, int num)
Default CPU mask for worker threads.
int odp_cpumask_first(const odp_cpumask_t *mask)
Find first set CPU in mask.
int32_t odp_cpumask_to_str(const odp_cpumask_t *mask, char *str, int32_t size)
Format a string from CPU mask.
#define ODP_CPUMASK_STR_SIZE
The maximum number of characters needed to record any CPU mask as a string (output of odp_cpumask_to_...
void odp_event_free(odp_event_t event)
Free event.
odp_event_type_t odp_event_type(odp_event_t event)
Event type of an event.
_odp_abi_event_t * odp_event_t
ODP event.
odp_event_subtype_t
Event subtype.
odp_event_type_t odp_event_types(odp_event_t event, odp_event_subtype_t *subtype)
Event type and subtype of an event.
#define ODP_EVENT_INVALID
Invalid event.
void odp_init_param_init(odp_init_t *param)
Initialize the odp_init_t to default values for all fields.
int odp_init_local(odp_instance_t instance, odp_thread_type_t thr_type)
Thread local ODP initialization.
int odp_init_global(odp_instance_t *instance, const odp_init_t *params, const odp_platform_init_t *platform_params)
Global ODP initialization.
int odp_term_local(void)
Thread local ODP termination.
int odp_term_global(odp_instance_t instance)
Global ODP termination.
uint64_t odp_instance_t
ODP instance ID.
int odp_ipsec_in_enq(const odp_packet_t pkt[], int num, const odp_ipsec_in_param_t *param)
Inbound asynchronous IPSEC operation.
int odp_ipsec_in(const odp_packet_t pkt_in[], int num_in, odp_packet_t pkt_out[], int *num_out, const odp_ipsec_in_param_t *param)
Inbound synchronous IPSEC operation.
#define ODP_IPSEC_OK
IPSEC operation status has no errors.
int odp_ipsec_capability(odp_ipsec_capability_t *capa)
Query IPSEC capabilities.
int odp_ipsec_out(const odp_packet_t pkt_in[], int num_in, odp_packet_t pkt_out[], int *num_out, const odp_ipsec_out_param_t *param)
Outbound synchronous IPSEC operation.
uint64_t odp_ipsec_sa_to_u64(odp_ipsec_sa_t sa)
Printable format of odp_ipsec_sa_t.
odp_ipsec_op_mode_t
IPSEC operation mode.
void odp_ipsec_config_init(odp_ipsec_config_t *config)
Initialize IPSEC configuration options.
int odp_ipsec_config(const odp_ipsec_config_t *config)
Global IPSEC configuration.
int odp_ipsec_out_inline(const odp_packet_t pkt[], int num, const odp_ipsec_out_param_t *param, const odp_ipsec_out_inline_param_t *inline_param)
Outbound inline IPSEC operation.
int odp_ipsec_out_enq(const odp_packet_t pkt[], int num, const odp_ipsec_out_param_t *param)
Outbound asynchronous IPSEC operation.
int odp_ipsec_status(odp_ipsec_status_t *status, odp_event_t event)
Get IPSEC status information from an ODP_EVENT_IPSEC_STATUS event.
int odp_ipsec_result(odp_ipsec_packet_result_t *result, odp_packet_t packet)
Get IPSEC operation results from an IPSEC processed packet.
@ ODP_IPSEC_OP_MODE_INLINE
Inline IPSEC operation.
@ ODP_IPSEC_OP_MODE_SYNC
Synchronous IPSEC operation.
@ ODP_IPSEC_OP_MODE_ASYNC
Asynchronous IPSEC operation.
int odp_pktio_mac_addr(odp_pktio_t pktio, void *mac_addr, int size)
Get the default MAC address of a packet IO interface.
void odp_pktin_queue_param_init(odp_pktin_queue_param_t *param)
Initialize packet input queue parameters.
void odp_pktio_param_init(odp_pktio_param_t *param)
Initialize pktio params.
int odp_pktio_close(odp_pktio_t pktio)
Close a packet IO interface.
odp_pktio_t odp_pktio_lookup(const char *name)
Return a packet IO handle for an already open device.
int odp_pktout_queue(odp_pktio_t pktio, odp_pktout_queue_t queues[], int num)
Direct packet output queues.
void odp_pktio_config_init(odp_pktio_config_t *config)
Initialize packet IO configuration options.
int odp_pktin_event_queue(odp_pktio_t pktio, odp_queue_t queues[], int num)
Event queues for packet input.
odp_pktio_t odp_pktio_open(const char *name, odp_pool_t pool, const odp_pktio_param_t *param)
Open a packet IO interface.
int odp_pktio_config(odp_pktio_t pktio, const odp_pktio_config_t *config)
Configure packet IO interface options.
int odp_pktio_start(odp_pktio_t pktio)
Start packet receive and transmit.
#define ODP_PKTIO_INVALID
Invalid packet IO handle.
int odp_pktio_stop(odp_pktio_t pktio)
Stop packet receive and transmit.
int odp_pktio_capability(odp_pktio_t pktio, odp_pktio_capability_t *capa)
Query packet IO interface capabilities.
int odp_pktout_send(odp_pktout_queue_t queue, const odp_packet_t packets[], int num)
Send packets directly to an interface output queue.
uint64_t odp_pktio_to_u64(odp_pktio_t pktio)
Get printable value for an odp_pktio_t.
int odp_pktin_queue_config(odp_pktio_t pktio, const odp_pktin_queue_param_t *param)
Configure packet input queues.
int odp_pktout_queue_config(odp_pktio_t pktio, const odp_pktout_queue_param_t *param)
Configure packet output queues.
@ ODP_PKTIN_MODE_QUEUE
Packet input through plain event queues.
@ ODP_PKTIN_MODE_SCHED
Packet input through scheduler and scheduled event queues.
void * odp_packet_pull_head(odp_packet_t pkt, uint32_t len)
Pull in packet head.
void * odp_packet_user_ptr(odp_packet_t pkt)
User context pointer.
void * odp_packet_push_head(odp_packet_t pkt, uint32_t len)
Push out packet head.
int odp_packet_has_ipv4(odp_packet_t pkt)
Check for IPv4.
int odp_packet_has_eth(odp_packet_t pkt)
Check for Ethernet header.
int odp_packet_has_error(odp_packet_t pkt)
Check for all parse errors in packet.
int odp_packet_l2_offset_set(odp_packet_t pkt, uint32_t offset)
Set layer 2 start offset.
odp_packet_t odp_packet_from_event(odp_event_t ev)
Get packet handle from event.
void odp_packet_free(odp_packet_t pkt)
Free packet.
uint32_t odp_packet_l3_offset(odp_packet_t pkt)
Layer 3 start offset.
int odp_packet_copy_from_mem(odp_packet_t pkt, uint32_t offset, uint32_t len, const void *src)
Copy data from memory to packet.
void odp_packet_user_ptr_set(odp_packet_t pkt, const void *user_ptr)
Set user context pointer.
void * odp_packet_l3_ptr(odp_packet_t pkt, uint32_t *len)
Layer 3 start pointer.
@ ODP_PROTO_LAYER_ALL
All layers.
odp_pool_t odp_pool_create(const char *name, const odp_pool_param_t *param)
Create a pool.
void odp_pool_param_init(odp_pool_param_t *param)
Initialize pool params.
int odp_pool_destroy(odp_pool_t pool)
Destroy a pool previously created by odp_pool_create()
#define ODP_POOL_INVALID
Invalid pool.
@ ODP_POOL_BUFFER
Buffer pool.
@ ODP_POOL_PACKET
Packet pool.
_odp_abi_queue_t * odp_queue_t
ODP queue.
void odp_queue_param_init(odp_queue_param_t *param)
Initialize queue params.
#define ODP_QUEUE_INVALID
Invalid queue.
odp_event_t odp_queue_deq(odp_queue_t queue)
Dequeue an event from a queue.
odp_queue_type_t
Queue type.
odp_queue_t odp_queue_create(const char *name, const odp_queue_param_t *param)
Queue create.
int odp_queue_destroy(odp_queue_t queue)
Destroy ODP queue.
uint64_t odp_queue_to_u64(odp_queue_t hdl)
Get printable value for an odp_queue_t.
@ ODP_QUEUE_TYPE_SCHED
Scheduled queue.
@ ODP_QUEUE_TYPE_PLAIN
Plain queue.
#define ODP_SCHED_SYNC_ATOMIC
Atomic queue synchronization.
#define ODP_SCHED_NO_WAIT
Do not wait.
int odp_schedule_max_prio(void)
Maximum scheduling priority level.
int odp_schedule_config(const odp_schedule_config_t *config)
Global schedule configuration.
odp_event_t odp_schedule(odp_queue_t *from, uint64_t wait)
Schedule an event.
#define ODP_SCHED_GROUP_ALL
Group of all threads.
odp_shm_t odp_shm_lookup(const char *name)
Lookup for a block of shared memory.
int odp_shm_free(odp_shm_t shm)
Free a contiguous block of shared memory.
#define ODP_SHM_INVALID
Invalid shared memory block.
void * odp_shm_addr(odp_shm_t shm)
Shared memory block address.
odp_shm_t odp_shm_reserve(const char *name, uint64_t size, uint64_t align, uint32_t flags)
Reserve a contiguous block of shared memory.
bool odp_bool_t
Boolean type.
void odp_sys_info_print(void)
Print system info.
int odp_thread_id(void)
Get thread identifier.
@ ODP_THREAD_WORKER
Worker thread.
@ ODP_THREAD_CONTROL
Control thread.
The OpenDataPlane API.
Global initialization parameters.
odp_mem_model_t mem_model
Application memory model.
odp_bool_t queue_type_sched
Scheduled queue support.
odp_bool_t queue_type_plain
Plain queue support.
IPSEC configuration options.
odp_ipsec_op_mode_t outbound_mode
Outbound IPSEC operation mode.
odp_ipsec_inbound_config_t inbound
IPSEC inbound processing configuration.
odp_ipsec_op_mode_t inbound_mode
Inbound IPSEC operation mode.
uint32_t all
All error bits.
IPSEC inbound operation parameters.
const odp_ipsec_sa_t * sa
Pointer to an array of IPSEC SAs.
odp_queue_t default_queue
Default destination queue for IPSEC events.
odp_proto_layer_t parse_level
Parse packet headers after IPSEC transformation.
uint32_t inline_mode
Packet was processed in inline mode.
odp_ipsec_error_t error
IPSEC errors.
Outbound inline IPSEC operation parameters.
odp_pktio_t pktio
Packet output interface for inline outbound operation without TM.
uint32_t len
Outer header length in bytes.
const uint8_t * ptr
Points to first byte of outer headers to be copied in front of the outgoing IPSEC packet.
struct odp_ipsec_out_inline_param_t::@81 outer_hdr
Outer headers for inline output operation.
IPSEC outbound operation parameters.
int num_opt
Number of outbound operation options.
const odp_ipsec_sa_t * sa
Pointer to an array of IPSEC SAs.
const odp_ipsec_out_opt_t * opt
Pointer to an array of outbound operation options.
IPSEC operation result for a packet.
odp_ipsec_op_status_t status
IPSEC operation status.
odp_ipsec_op_flag_t flag
IPSEC operation flags.
IPSEC status content.
int result
Result of the operation.
odp_ipsec_sa_t sa
IPSEC SA that was target of the operation.
odp_ipsec_status_id_t id
IPSEC status ID.
Packet input queue parameters.
odp_queue_param_t queue_param
Queue parameters.
odp_pktio_config_t config
Supported pktio configuration options.
Packet IO configuration options.
odp_bool_t outbound_ipsec
Outbound IPSEC inlined with packet output.
odp_bool_t inbound_ipsec
Inbound IPSEC inlined with packet input.
Packet IO parameters.
odp_pktin_mode_t in_mode
Packet input mode.
Pool parameters.
uint32_t num
Number of buffers in the pool.
uint32_t align
Minimum buffer alignment in bytes.
uint32_t size
Minimum buffer size in bytes.
odp_pool_type_t type
Pool type.
uint32_t len
Minimum length of 'num' packets.
uint32_t seg_len
Minimum number of packet data bytes that can be stored in the first segment of a newly allocated pack...
struct odp_pool_param_t::@126 pkt
Parameters for packet pools.
struct odp_pool_param_t::@125 buf
Parameters for buffer pools.
ODP Queue parameters.
odp_schedule_param_t sched
Scheduler parameters.
odp_queue_type_t type
Queue type.
odp_schedule_group_t group
Thread group.
odp_schedule_prio_t prio
Priority level.
odp_schedule_sync_t sync
Synchronization method.