API Reference Manual  1.46.0
example/ipsec_crypto/odp_ipsec.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2013-2018 Linaro Limited
3  * Copyright (c) 2021-2022 Nokia
4  */
5 
14 /* enable strtok */
15 #ifndef _GNU_SOURCE
16 #define _GNU_SOURCE
17 #endif
18 
19 #include <stdlib.h>
20 #include <getopt.h>
21 #include <signal.h>
22 #include <unistd.h>
23 #include <inttypes.h>
24 
25 #include <odp_api.h>
26 
27 #include <odp/helper/odph_api.h>
28 
29 #include <stdbool.h>
30 #include <sys/socket.h>
31 #include <net/if.h>
32 #include <sys/ioctl.h>
33 
34 #include <sys/socket.h>
35 #include <netpacket/packet.h>
36 #include <net/ethernet.h>
37 #include <arpa/inet.h>
38 
39 #include <odp_ipsec_misc.h>
40 #include <odp_ipsec_sa_db.h>
41 #include <odp_ipsec_sp_db.h>
42 #include <odp_ipsec_fwd_db.h>
43 #include <odp_ipsec_cache.h>
44 
45 #ifndef NO_OPENSSL
46 #include <odp_ipsec_stream.h>
47 #else
48 static void init_stream_db(void) {}
49 static void deinit_stream_db(void) {}
50 static void resolve_stream_db(void) {}
51 static int create_stream_db_inputs(void)
52 {
53  return 0;
54 }
55 
56 static odp_bool_t verify_stream_db_outputs(void)
57 {
58  return true;
59 }
60 
61 static int create_stream_db_entry(char *input ODP_UNUSED)
62 {
63  return -1;
64 }
65 #endif
66 
67 /* maximum number of worker threads */
68 #define MAX_WORKERS (ODP_THREAD_COUNT_MAX - 1)
69 
70 #define MAX_POLL_QUEUES 256
71 
75 typedef struct {
76  unsigned int cpu_count;
77  int if_count;
78  char **if_names;
79  crypto_api_mode_e mode;
80  odp_pool_t pool;
81  char *if_str;
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 out_pool;
93  odp_pool_t pkt_pool;
95  odp_queue_t seqnumq;
97  odp_queue_t completionq;
99  odp_barrier_t sync_barrier;
100  odp_queue_t poll_queues[MAX_POLL_QUEUES];
101  int num_polled_queues;
102  /* Stop workers if set to 1 */
103  odp_atomic_u32_t exit_threads;
104  odp_crypto_capability_t crypto_capa;
105 } global_data_t;
106 
107 /* helper funcs */
108 static void parse_args(int argc, char *argv[], appl_args_t *appl_args);
109 static void print_info(char *progname, appl_args_t *appl_args);
110 static void usage(char *progname);
111 
115 #define SHM_PKT_POOL_BUF_COUNT 1024
116 #define SHM_PKT_POOL_BUF_SIZE 4096
117 #define SHM_PKT_POOL_SIZE (SHM_PKT_POOL_BUF_COUNT * SHM_PKT_POOL_BUF_SIZE)
118 
122 #define SHM_OUT_POOL_BUF_COUNT 1024
123 #define SHM_OUT_POOL_BUF_SIZE 4096
124 #define SHM_OUT_POOL_SIZE (SHM_OUT_POOL_BUF_COUNT * SHM_OUT_POOL_BUF_SIZE)
125 
129 typedef enum {
130  PKT_STATE_INPUT_VERIFY,
131  PKT_STATE_IPSEC_IN_CLASSIFY,
132  PKT_STATE_IPSEC_IN_FINISH,
133  PKT_STATE_ROUTE_LOOKUP,
134  PKT_STATE_IPSEC_OUT_CLASSIFY,
135  PKT_STATE_IPSEC_OUT_SEQ,
136  PKT_STATE_IPSEC_OUT_FINISH,
137  PKT_STATE_TRANSMIT,
138 } pkt_state_e;
139 
143 typedef enum {
144  PKT_CONTINUE,
145  PKT_POSTED,
146  PKT_DROP,
147  PKT_DONE
148 } pkt_disposition_e;
149 
153 typedef struct {
154  uint8_t ip_tos;
155  uint16_t ip_frag_offset;
156  uint8_t ip_ttl;
157  int hdr_len;
158  int trl_len;
159  uint16_t tun_hdr_offset;
161  uint16_t ah_offset;
162  uint16_t esp_offset;
164  /* Input only */
165  uint32_t src_ip;
166  uint32_t dst_ip;
168  /* Output only */
170  uint32_t *ah_seq;
171  uint32_t *esp_seq;
172  uint16_t *tun_hdr_id;
173 } ipsec_ctx_t;
174 
178 typedef struct {
179  odp_buffer_t buffer;
180  pkt_state_e state;
181  ipsec_ctx_t ipsec;
182  odp_pktout_queue_t pktout;
183 } pkt_ctx_t;
184 
185 #define SHM_CTX_POOL_BUF_SIZE (sizeof(pkt_ctx_t))
186 #define SHM_CTX_POOL_BUF_COUNT (SHM_PKT_POOL_BUF_COUNT + SHM_OUT_POOL_BUF_COUNT)
187 #define SHM_CTX_POOL_SIZE (SHM_CTX_POOL_BUF_COUNT * SHM_CTX_POOL_BUF_SIZE)
188 
189 static global_data_t *global;
190 
191 static void sig_handler(int signo ODP_UNUSED)
192 {
193  if (global == NULL)
194  return;
195  odp_atomic_store_u32(&global->exit_threads, 1);
196 }
197 
205 static
206 pkt_ctx_t *get_pkt_ctx_from_pkt(odp_packet_t pkt)
207 {
208  return (pkt_ctx_t *)odp_packet_user_ptr(pkt);
209 }
210 
219 static
220 pkt_ctx_t *alloc_pkt_ctx(odp_packet_t pkt)
221 {
222  odp_buffer_t ctx_buf = odp_buffer_alloc(global->ctx_pool);
223  pkt_ctx_t *ctx;
224 
225  if (odp_unlikely(ODP_BUFFER_INVALID == ctx_buf))
226  return NULL;
227 
228  ctx = odp_buffer_addr(ctx_buf);
229  memset(ctx, 0, sizeof(*ctx));
230  ctx->buffer = ctx_buf;
231  odp_packet_user_ptr_set(pkt, ctx);
232 
233  return ctx;
234 }
235 
241 static
242 void free_pkt_ctx(pkt_ctx_t *ctx)
243 {
244  odp_buffer_free(ctx->buffer);
245 }
246 
250 typedef odp_queue_t (*queue_create_func_t)
251  (const char *, const odp_queue_param_t *);
252 typedef odp_event_t (*schedule_func_t) (odp_queue_t *);
253 
254 static queue_create_func_t queue_create;
255 static schedule_func_t schedule_fn;
256 
260 static
261 odp_queue_t polled_odp_queue_create(const char *name,
262  const odp_queue_param_t *param)
263 {
264  odp_queue_t my_queue;
266  odp_queue_type_t type;
267 
269  if (param)
270  memcpy(&qp, param, sizeof(odp_queue_param_t));
271 
272  type = qp.type;
273 
274  if (ODP_QUEUE_TYPE_SCHED == type) {
275  printf("%s: change %s to PLAIN\n", __func__, name);
277  }
278 
279  my_queue = odp_queue_create(name, &qp);
280 
281  if (ODP_QUEUE_TYPE_SCHED == type) {
282  global->poll_queues[global->num_polled_queues++] = my_queue;
283  printf("%s: adding %"PRIu64"\n", __func__,
284  odp_queue_to_u64(my_queue));
285  }
286 
287  return my_queue;
288 }
289 
290 static inline
291 odp_event_t odp_schedule_cb(odp_queue_t *from)
292 {
293  return odp_schedule(from, ODP_SCHED_NO_WAIT);
294 }
295 
299 static
300 odp_event_t polled_odp_schedule_cb(odp_queue_t *from)
301 {
302  int idx = 0;
303 
304  while (idx < global->num_polled_queues) {
305  odp_queue_t queue = global->poll_queues[idx++];
306  odp_event_t ev;
307 
308  ev = odp_queue_deq(queue);
309 
310  if (ODP_EVENT_INVALID != ev) {
311  *from = queue;
312  return ev;
313  }
314  }
315 
316  *from = ODP_QUEUE_INVALID;
317  return ODP_EVENT_INVALID;
318 }
319 
323 static
324 void ipsec_init_pre(void)
325 {
326  odp_queue_param_t qparam;
327  odp_pool_param_t params;
328 
329  /*
330  * Create queues
331  *
332  * - completion queue (should eventually be ORDERED)
333  * - sequence number queue (must be ATOMIC)
334  */
335  odp_queue_param_init(&qparam);
336  qparam.type = ODP_QUEUE_TYPE_SCHED;
337  qparam.sched.prio = odp_schedule_max_prio();
340 
341  global->completionq = queue_create("completion", &qparam);
342  if (ODP_QUEUE_INVALID == global->completionq) {
343  ODPH_ERR("Error: completion queue creation failed\n");
344  exit(EXIT_FAILURE);
345  }
346 
347  qparam.type = ODP_QUEUE_TYPE_SCHED;
348  qparam.sched.prio = odp_schedule_max_prio();
351 
352  global->seqnumq = queue_create("seqnum", &qparam);
353  if (ODP_QUEUE_INVALID == global->seqnumq) {
354  ODPH_ERR("Error: sequence number queue creation failed\n");
355  exit(EXIT_FAILURE);
356  }
357 
358  /* Create output buffer pool */
359  odp_pool_param_init(&params);
360  params.pkt.seg_len = SHM_OUT_POOL_BUF_SIZE;
361  params.pkt.len = SHM_OUT_POOL_BUF_SIZE;
362  params.pkt.num = SHM_PKT_POOL_BUF_COUNT;
363  params.type = ODP_POOL_PACKET;
364 
365  global->out_pool = odp_pool_create("out_pool", &params);
366 
367  if (ODP_POOL_INVALID == global->out_pool) {
368  ODPH_ERR("Error: message pool create failed.\n");
369  exit(EXIT_FAILURE);
370  }
371 
372  /* Initialize our data bases */
373  init_sp_db();
374  init_sa_db();
375  init_tun_db();
376  init_ipsec_cache();
377 }
378 
386 static
387 void ipsec_init_post(crypto_api_mode_e api_mode)
388 {
389  sp_db_entry_t *entry;
390 
391  /* Attempt to find appropriate SA for each SP */
392  for (entry = sp_db->list; NULL != entry; entry = entry->next) {
393  sa_db_entry_t *cipher_sa = NULL;
394  sa_db_entry_t *auth_sa = NULL;
395  tun_db_entry_t *tun = NULL;
396 
397  if (entry->esp) {
398  cipher_sa = find_sa_db_entry(&entry->src_subnet,
399  &entry->dst_subnet,
400  1);
401  tun = find_tun_db_entry(cipher_sa->src_ip,
402  cipher_sa->dst_ip);
403  }
404  if (entry->ah) {
405  auth_sa = find_sa_db_entry(&entry->src_subnet,
406  &entry->dst_subnet,
407  0);
408  tun = find_tun_db_entry(auth_sa->src_ip,
409  auth_sa->dst_ip);
410  }
411 
412  if (cipher_sa || auth_sa) {
413  if (create_ipsec_cache_entry(cipher_sa,
414  auth_sa,
415  tun,
416  api_mode,
417  entry->input,
418  global->completionq,
419  global->out_pool)) {
420  ODPH_ERR("Error: IPSec cache entry failed.\n"
421  );
422  exit(EXIT_FAILURE);
423  }
424  } else {
425  printf(" WARNING: SA not found for SP\n");
426  dump_sp_db_entry(entry);
427  }
428  }
429 }
430 
431 #ifndef NO_OPENSSL
432 static
433 int check_stream_db_out(const char *intf)
434 {
435  stream_db_entry_t *stream = NULL;
436 
437  /* For each stream look for input and output IPsec entries */
438  for (stream = stream_db->list; NULL != stream; stream = stream->next) {
439  if (!strcmp(stream->output.intf, intf))
440  return 1;
441  }
442 
443  return 0;
444 }
445 #else
446 static
447 int check_stream_db_out(const char *intf ODP_UNUSED)
448 {
449  return 0;
450 }
451 #endif
452 
461 static
462 void initialize_intf(char *intf)
463 {
464  odp_pktio_t pktio;
465  odp_pktout_queue_t pktout;
466  odp_queue_t inq;
467  int ret;
468  uint8_t src_mac[ODPH_ETHADDR_LEN];
469  char src_mac_str[MAX_STRING];
470  odp_pktio_param_t pktio_param;
471  odp_pktin_queue_param_t pktin_param;
472 
473  odp_pktio_param_init(&pktio_param);
474 
475  if (getenv("ODP_IPSEC_USE_POLL_QUEUES") ||
476  check_stream_db_out(intf))
477  pktio_param.in_mode = ODP_PKTIN_MODE_QUEUE;
478  else
479  pktio_param.in_mode = ODP_PKTIN_MODE_SCHED;
480 
481  /*
482  * Open a packet IO instance for thread and get default output queue
483  */
484  pktio = odp_pktio_open(intf, global->pkt_pool, &pktio_param);
485  if (ODP_PKTIO_INVALID == pktio) {
486  ODPH_ERR("Error: pktio create failed for %s\n", intf);
487  exit(EXIT_FAILURE);
488  }
489 
490  odp_pktin_queue_param_init(&pktin_param);
492 
493  if (odp_pktin_queue_config(pktio, &pktin_param)) {
494  ODPH_ERR("Error: pktin config failed for %s\n", intf);
495  exit(EXIT_FAILURE);
496  }
497 
498  if (odp_pktout_queue_config(pktio, NULL)) {
499  ODPH_ERR("Error: pktout config failed for %s\n", intf);
500  exit(EXIT_FAILURE);
501  }
502 
503  if (odp_pktin_event_queue(pktio, &inq, 1) != 1) {
504  ODPH_ERR("Error: failed to get input queue for %s\n", intf);
505  exit(EXIT_FAILURE);
506  }
507 
508  if (odp_pktout_queue(pktio, &pktout, 1) != 1) {
509  ODPH_ERR("Error: failed to get pktout queue for %s\n", intf);
510  exit(EXIT_FAILURE);
511  }
512 
513  ret = odp_pktio_start(pktio);
514  if (ret) {
515  ODPH_ERR("Error: unable to start %s\n", intf);
516  exit(EXIT_FAILURE);
517  }
518 
519  /* Read the source MAC address for this interface */
520  ret = odp_pktio_mac_addr(pktio, src_mac, sizeof(src_mac));
521  if (ret <= 0) {
522  ODPH_ERR("Error: failed during MAC address get for %s\n", intf);
523  exit(EXIT_FAILURE);
524  }
525 
526  printf("Created pktio:%02" PRIu64 ", queue mode (ATOMIC queues)\n"
527  " default pktio%02" PRIu64 "-INPUT queue:%" PRIu64 "\n"
528  " source mac address %s\n",
529  odp_pktio_to_u64(pktio), odp_pktio_to_u64(pktio),
530  odp_queue_to_u64(inq),
531  mac_addr_str(src_mac_str, src_mac));
532 
533  /* Resolve any routes using this interface for output */
534  resolve_fwd_db(intf, pktio, pktout, src_mac);
535 }
536 
545 static
546 pkt_disposition_e do_input_verify(odp_packet_t pkt,
547  pkt_ctx_t *ctx ODP_UNUSED)
548 {
550  return PKT_DROP;
551 
552  if (!odp_packet_has_eth(pkt))
553  return PKT_DROP;
554 
555  if (!odp_packet_has_ipv4(pkt))
556  return PKT_DROP;
557 
558  return PKT_CONTINUE;
559 }
560 
569 static
570 pkt_disposition_e do_route_fwd_db(odp_packet_t pkt, pkt_ctx_t *ctx)
571 {
572  odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL);
573  fwd_db_entry_t *entry;
574 
575  entry = find_fwd_db_entry(odp_be_to_cpu_32(ip->dst_addr));
576 
577  if (entry) {
578  odph_ethhdr_t *eth =
579  (odph_ethhdr_t *)odp_packet_l2_ptr(pkt, NULL);
580 
581  memcpy(&eth->dst, entry->dst_mac, ODPH_ETHADDR_LEN);
582  memcpy(&eth->src, entry->src_mac, ODPH_ETHADDR_LEN);
583  ctx->pktout = entry->pktout;
584 
585  return PKT_CONTINUE;
586  }
587 
588  return PKT_DROP;
589 }
590 
604 static
605 pkt_disposition_e do_ipsec_in_classify(odp_packet_t *pkt,
606  pkt_ctx_t *ctx,
607  odp_bool_t *skip)
608 {
609  uint8_t *buf = odp_packet_data(*pkt);
610  odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(*pkt, NULL);
611  int hdr_len;
612  odph_ahhdr_t *ah = NULL;
613  odph_esphdr_t *esp = NULL;
614  ipsec_cache_entry_t *entry;
616  odp_packet_t out_pkt;
617 
618  /* Default to skip IPsec */
619  *skip = TRUE;
620 
621  /* Check IP header for IPSec protocols and look it up */
622  hdr_len = locate_ipsec_headers(ip, &ah, &esp);
623  if (!ah && !esp)
624  return PKT_CONTINUE;
625  entry = find_ipsec_cache_entry_in(odp_be_to_cpu_32(ip->src_addr),
626  odp_be_to_cpu_32(ip->dst_addr),
627  ah,
628  esp);
629  if (!entry)
630  return PKT_CONTINUE;
631 
632  /* Account for configured ESP IV length in packet */
633  hdr_len += entry->esp.iv_len;
634 
635  /* Initialize parameters block */
636  memset(&params, 0, sizeof(params));
637  params.session = entry->state.session;
638 
639  /*Save everything to context */
640  ctx->ipsec.ip_tos = ip->tos;
641  ctx->ipsec.ip_frag_offset = odp_be_to_cpu_16(ip->frag_offset);
642  ctx->ipsec.ip_ttl = ip->ttl;
643  ctx->ipsec.ah_offset = ah ? ((uint8_t *)ah) - buf : 0;
644  ctx->ipsec.esp_offset = esp ? ((uint8_t *)esp) - buf : 0;
645  ctx->ipsec.hdr_len = hdr_len;
646  ctx->ipsec.trl_len = 0;
647  ctx->ipsec.src_ip = entry->src_ip;
648  ctx->ipsec.dst_ip = entry->dst_ip;
649 
650  /*If authenticating, zero the mutable fields build the request */
651  if (ah) {
652  ip->chksum = 0;
653  ip->tos = 0;
654  ip->frag_offset = 0;
655  ip->ttl = 0;
656 
657  params.auth_range.offset = ((uint8_t *)ip) - buf;
658  params.auth_range.length = odp_be_to_cpu_16(ip->tot_len);
659  params.hash_result_offset = ah->icv - buf;
660  }
661 
662  /* If deciphering build request */
663  if (esp) {
664  params.cipher_range.offset = ipv4_data_p(ip) + hdr_len - buf;
665  params.cipher_range.length = ipv4_data_len(ip) - hdr_len;
666  params.cipher_iv_ptr = esp->iv;
667  }
668 
669  if (entry->sa_flags & BIT_MODE_CIPHER) {
670  params.cipher_range.offset *= 8;
671  params.cipher_range.length *= 8;
672  }
673  if (entry->sa_flags & BIT_MODE_AUTH) {
674  params.auth_range.offset *= 8;
675  params.auth_range.length *= 8;
676  }
677 
678  /* Issue crypto request */
679  *skip = FALSE;
680  ctx->state = PKT_STATE_IPSEC_IN_FINISH;
681  if (entry->async) {
682  if (odp_crypto_op_enq(pkt, NULL, &params, 1) != 1) {
683  ODPH_ERR("Error: odp_crypto_op_enq() failed\n");
684  exit(EXIT_FAILURE);
685  }
686  return PKT_POSTED;
687  }
688 
689  if (odp_crypto_op(pkt, &out_pkt, &params, 1) != 1) {
690  ODPH_ERR("Error: odp_crypto_op() failed\n");
691  exit(EXIT_FAILURE);
692  }
693  *pkt = out_pkt;
694 
695  return PKT_CONTINUE;
696 }
697 
706 static
707 pkt_disposition_e do_ipsec_in_finish(odp_packet_t pkt,
708  pkt_ctx_t *ctx)
709 {
710  odph_ipv4hdr_t *ip;
711  int hdr_len = ctx->ipsec.hdr_len;
712  int trl_len = 0;
713 
714  if (odp_crypto_result(NULL, pkt) != 0)
715  return PKT_DROP;
716 
717  ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL);
718 
719  /*
720  * Finish auth
721  */
722  if (ctx->ipsec.ah_offset) {
723  uint8_t *buf = odp_packet_data(pkt);
724  odph_ahhdr_t *ah;
725 
726  ah = (odph_ahhdr_t *)(ctx->ipsec.ah_offset + buf);
727  ip->proto = ah->next_header;
728  }
729 
730  /*
731  * Finish cipher by finding ESP trailer and processing
732  *
733  * NOTE: ESP authentication ICV not supported
734  */
735  if (ctx->ipsec.esp_offset) {
736  uint8_t *eop = (uint8_t *)(ip) + odp_be_to_cpu_16(ip->tot_len);
737  odph_esptrl_t *esp_t = (odph_esptrl_t *)(eop) - 1;
738 
739  ip->proto = esp_t->next_header;
740  trl_len += esp_t->pad_len + sizeof(*esp_t);
741  }
742 
743  /* We have a tunneled IPv4 packet */
744  if (ip->proto == ODPH_IPV4) {
745  odp_packet_pull_head(pkt, sizeof(*ip) + hdr_len);
746  odp_packet_pull_tail(pkt, trl_len);
747  odph_ethhdr_t *eth;
748 
749  eth = (odph_ethhdr_t *)odp_packet_l2_ptr(pkt, NULL);
750  eth->type = ODPH_ETHTYPE_IPV4;
751  ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL);
752 
753  /* Check inbound policy */
754  if ((ip->src_addr != ctx->ipsec.src_ip ||
755  ip->dst_addr != ctx->ipsec.dst_ip))
756  return PKT_DROP;
757 
758  return PKT_CONTINUE;
759  }
760 
761  /* Finalize the IPv4 header */
762  ipv4_adjust_len(ip, -(hdr_len + trl_len));
763  ip->ttl = ctx->ipsec.ip_ttl;
764  ip->tos = ctx->ipsec.ip_tos;
765  ip->frag_offset = odp_cpu_to_be_16(ctx->ipsec.ip_frag_offset);
766  ip->chksum = 0;
767  odph_ipv4_csum_update(pkt);
768 
769  /* Correct the packet length and move payload into position */
770  memmove(ipv4_data_p(ip),
771  ipv4_data_p(ip) + hdr_len,
772  odp_be_to_cpu_16(ip->tot_len));
773  odp_packet_pull_tail(pkt, hdr_len + trl_len);
774 
775  /* Fall through to next state */
776  return PKT_CONTINUE;
777 }
778 
779 static int generate_iv(uint8_t *buf, uint32_t size)
780 {
781  uint32_t n = 0;
782  int32_t ret;
783 
784  while (n < size) {
785  ret = odp_random_data(buf + n, size - n, ODP_RANDOM_CRYPTO);
786  if (ret < 0)
787  return 1;
788  n += ret;
789  }
790  return 0;
791 }
792 
808 static
809 pkt_disposition_e do_ipsec_out_classify(odp_packet_t pkt,
810  pkt_ctx_t *ctx,
811  odp_bool_t *skip)
812 {
813  uint8_t *buf = odp_packet_data(pkt);
814  odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL);
815  uint16_t ip_data_len = ipv4_data_len(ip);
816  uint8_t *ip_data = ipv4_data_p(ip);
817  ipsec_cache_entry_t *entry;
819  int hdr_len = 0;
820  int trl_len = 0;
821  odph_ahhdr_t *ah = NULL;
822  odph_esphdr_t *esp = NULL;
823 
824  /* Default to skip IPsec */
825  *skip = TRUE;
826 
827  /* Find record */
828  entry = find_ipsec_cache_entry_out(odp_be_to_cpu_32(ip->src_addr),
829  odp_be_to_cpu_32(ip->dst_addr),
830  ip->proto);
831  if (!entry)
832  return PKT_CONTINUE;
833 
834  /* Save IPv4 stuff */
835  ctx->ipsec.ip_tos = ip->tos;
836  ctx->ipsec.ip_frag_offset = odp_be_to_cpu_16(ip->frag_offset);
837  ctx->ipsec.ip_ttl = ip->ttl;
838 
839  /* Initialize parameters block */
840  memset(&params, 0, sizeof(params));
841  params.session = entry->state.session;
842 
843  if (entry->mode == IPSEC_SA_MODE_TUNNEL) {
844  hdr_len += sizeof(odph_ipv4hdr_t);
845  ip_data = (uint8_t *)ip;
846  ip_data_len += sizeof(odph_ipv4hdr_t);
847  }
848  /* Compute ah and esp, determine length of headers, move the data */
849  if (entry->ah.alg) {
850  ah = (odph_ahhdr_t *)(ip_data + hdr_len);
851  hdr_len += sizeof(odph_ahhdr_t);
852  hdr_len += entry->ah.icv_len;
853  }
854  if (entry->esp.alg) {
855  esp = (odph_esphdr_t *)(ip_data + hdr_len);
856  hdr_len += sizeof(odph_esphdr_t);
857  hdr_len += entry->esp.iv_len;
858  }
859  memmove(ip_data + hdr_len, ip_data, ip_data_len);
860  ip_data += hdr_len;
861 
862  /* update outer header in tunnel mode */
863  if (entry->mode == IPSEC_SA_MODE_TUNNEL) {
864  /* tunnel addresses */
865  ip->src_addr = odp_cpu_to_be_32(entry->tun_src_ip);
866  ip->dst_addr = odp_cpu_to_be_32(entry->tun_dst_ip);
867  }
868 
869  /* For cipher, compute encrypt length, build headers and request */
870  if (esp) {
871  uint32_t encrypt_len;
872  odph_esptrl_t *esp_t;
873 
874  encrypt_len = ESP_ENCODE_LEN(ip_data_len +
875  sizeof(*esp_t),
876  entry->esp.block_len);
877  trl_len = encrypt_len - ip_data_len;
878 
879  esp->spi = odp_cpu_to_be_32(entry->esp.spi);
880  if (generate_iv(esp->iv, entry->esp.iv_len))
881  return PKT_DROP;
882  params.cipher_iv_ptr = esp->iv;
883 
884  esp_t = (odph_esptrl_t *)(ip_data + encrypt_len) - 1;
885  esp_t->pad_len = trl_len - sizeof(*esp_t);
886  if (entry->mode == IPSEC_SA_MODE_TUNNEL)
887  esp_t->next_header = ODPH_IPV4;
888  else
889  esp_t->next_header = ip->proto;
890  ip->proto = ODPH_IPPROTO_ESP;
891 
892  params.cipher_range.offset = ip_data - buf;
893  params.cipher_range.length = encrypt_len;
894  }
895 
896  /* For authentication, build header clear mutables and build request */
897  if (ah) {
898  memset(ah, 0, sizeof(*ah) + entry->ah.icv_len);
899  ah->spi = odp_cpu_to_be_32(entry->ah.spi);
900  ah->ah_len = 1 + (entry->ah.icv_len / 4);
901  if (entry->mode == IPSEC_SA_MODE_TUNNEL && !esp)
902  ah->next_header = ODPH_IPV4;
903  else
904  ah->next_header = ip->proto;
905  ip->proto = ODPH_IPPROTO_AH;
906 
907  ip->chksum = 0;
908  ip->tos = 0;
909  ip->frag_offset = 0;
910  ip->ttl = 0;
911 
912  params.auth_range.offset = ((uint8_t *)ip) - buf;
913  params.auth_range.length =
914  odp_be_to_cpu_16(ip->tot_len) + (hdr_len + trl_len);
915  params.hash_result_offset = ah->icv - buf;
916  }
917 
918  /* Set IPv4 length before authentication */
919  ipv4_adjust_len(ip, hdr_len + trl_len);
920  if (!odp_packet_push_tail(pkt, hdr_len + trl_len))
921  return PKT_DROP;
922 
923  /* Save remaining context */
924  ctx->ipsec.hdr_len = hdr_len;
925  ctx->ipsec.trl_len = trl_len;
926  ctx->ipsec.ah_offset = ah ? ((uint8_t *)ah) - buf : 0;
927  ctx->ipsec.esp_offset = esp ? ((uint8_t *)esp) - buf : 0;
928  ctx->ipsec.tun_hdr_offset = (entry->mode == IPSEC_SA_MODE_TUNNEL) ?
929  ((uint8_t *)ip - buf) : 0;
930  ctx->ipsec.ah_seq = &entry->state.ah_seq;
931  ctx->ipsec.esp_seq = &entry->state.esp_seq;
932  ctx->ipsec.tun_hdr_id = &entry->state.tun_hdr_id;
933  memcpy(&ctx->ipsec.params, &params, sizeof(params));
934 
935  *skip = FALSE;
936 
937  return PKT_POSTED;
938 }
939 
950 static
951 pkt_disposition_e do_ipsec_out_seq(odp_packet_t *pkt,
952  pkt_ctx_t *ctx)
953 {
954  uint8_t *buf = odp_packet_data(*pkt);
955  odph_ipv4hdr_t *ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(*pkt, NULL);
956  odp_packet_t out_pkt;
957  ipsec_cache_entry_t *entry;
958 
959  entry = find_ipsec_cache_entry_out(odp_be_to_cpu_32(ip->src_addr),
960  odp_be_to_cpu_32(ip->dst_addr),
961  ip->proto);
962  if (!entry)
963  return PKT_DROP;
964 
965  /* We were dispatched from atomic queue, assign sequence numbers */
966  if (ctx->ipsec.ah_offset) {
967  odph_ahhdr_t *ah;
968 
969  ah = (odph_ahhdr_t *)(ctx->ipsec.ah_offset + buf);
970  ah->seq_no = odp_cpu_to_be_32((*ctx->ipsec.ah_seq)++);
971  }
972  if (ctx->ipsec.esp_offset) {
973  odph_esphdr_t *esp;
974 
975  esp = (odph_esphdr_t *)(ctx->ipsec.esp_offset + buf);
976  esp->seq_no = odp_cpu_to_be_32((*ctx->ipsec.esp_seq)++);
977  }
978  if (ctx->ipsec.tun_hdr_offset) {
979  odph_ipv4hdr_t *ip_tun;
980 
981  ip_tun = (odph_ipv4hdr_t *)(ctx->ipsec.tun_hdr_offset + buf);
982  ip_tun->id = odp_cpu_to_be_16((*ctx->ipsec.tun_hdr_id)++);
983  }
984 
985  /* Issue crypto request */
986  if (entry->async) {
987  if (odp_crypto_op_enq(pkt, NULL,
988  &ctx->ipsec.params, 1) != 1) {
989  ODPH_ERR("Error: odp_crypto_op_enq() failed\n");
990  exit(EXIT_FAILURE);
991  }
992  return PKT_POSTED;
993  }
994 
995  if (odp_crypto_op(pkt, &out_pkt, &ctx->ipsec.params, 1) != 1) {
996  ODPH_ERR("Error: odp_crypto_op() failed\n");
997  exit(EXIT_FAILURE);
998  }
999  *pkt = out_pkt;
1000 
1001  return PKT_CONTINUE;
1002 }
1003 
1012 static
1013 pkt_disposition_e do_ipsec_out_finish(odp_packet_t pkt,
1014  pkt_ctx_t *ctx)
1015 {
1016  odph_ipv4hdr_t *ip;
1017 
1018  if (odp_crypto_result(NULL, pkt) != 0)
1019  return PKT_DROP;
1020 
1021  ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL);
1022 
1023  /* Finalize the IPv4 header */
1024  ip->ttl = ctx->ipsec.ip_ttl;
1025  ip->tos = ctx->ipsec.ip_tos;
1026  ip->frag_offset = odp_cpu_to_be_16(ctx->ipsec.ip_frag_offset);
1027  ip->chksum = 0;
1028  odph_ipv4_csum_update(pkt);
1029 
1030  /* Fall through to next state */
1031  return PKT_CONTINUE;
1032 }
1033 
1049 static
1050 int pktio_thread(void *arg ODP_UNUSED)
1051 {
1052  int thr;
1053  odp_packet_t pkt;
1054  odp_event_t ev;
1055  unsigned long pkt_cnt = 0;
1056 
1057  thr = odp_thread_id();
1058 
1059  printf("Pktio thread [%02i] starts\n", thr);
1060 
1061  odp_barrier_wait(&global->sync_barrier);
1062 
1063  /* Loop packets */
1064  while (!odp_atomic_load_u32(&global->exit_threads)) {
1065  pkt_disposition_e rc;
1066  pkt_ctx_t *ctx;
1067  odp_queue_t dispatchq;
1068  odp_event_subtype_t subtype;
1069 
1070  /* Use schedule to get event from any input queue */
1071  ev = schedule_fn(&dispatchq);
1072 
1073  if (ev == ODP_EVENT_INVALID)
1074  continue;
1075 
1076  /* Determine new work versus completion or sequence number */
1077  if (ODP_EVENT_PACKET == odp_event_types(ev, &subtype)) {
1078  pkt = odp_packet_from_event(ev);
1079  if (global->seqnumq == dispatchq ||
1080  global->completionq == dispatchq) {
1081  ctx = get_pkt_ctx_from_pkt(pkt);
1082  } else {
1083  ctx = alloc_pkt_ctx(pkt);
1084  if (!ctx) {
1085  odp_packet_free(pkt);
1086  continue;
1087  }
1088  ctx->state = PKT_STATE_INPUT_VERIFY;
1089  }
1090  } else {
1091  ODPH_ERR("Error: Bad event type\n");
1092  exit(EXIT_FAILURE);
1093  }
1094 
1095  /*
1096  * We now have a packet and its associated context. Loop here
1097  * executing processing based on the current state value stored
1098  * in the context as long as the processing return code
1099  * indicates PKT_CONTINUE.
1100  *
1101  * For other return codes:
1102  *
1103  * o PKT_DONE - finished with the packet
1104  * o PKT_DROP - something incorrect about the packet, drop it
1105  * o PKT_POSTED - packet/event has been queued for later
1106  */
1107  do {
1108  odp_bool_t skip = FALSE;
1109 
1110  switch (ctx->state) {
1111  case PKT_STATE_INPUT_VERIFY:
1112 
1113  rc = do_input_verify(pkt, ctx);
1114  ctx->state = PKT_STATE_IPSEC_IN_CLASSIFY;
1115  break;
1116 
1117  case PKT_STATE_IPSEC_IN_CLASSIFY:
1118 
1119  ctx->state = PKT_STATE_ROUTE_LOOKUP;
1120  rc = do_ipsec_in_classify(&pkt,
1121  ctx,
1122  &skip);
1123  break;
1124 
1125  case PKT_STATE_IPSEC_IN_FINISH:
1126 
1127  rc = do_ipsec_in_finish(pkt, ctx);
1128  ctx->state = PKT_STATE_ROUTE_LOOKUP;
1129  break;
1130 
1131  case PKT_STATE_ROUTE_LOOKUP:
1132 
1133  rc = do_route_fwd_db(pkt, ctx);
1134  ctx->state = PKT_STATE_IPSEC_OUT_CLASSIFY;
1135  break;
1136 
1137  case PKT_STATE_IPSEC_OUT_CLASSIFY:
1138 
1139  rc = do_ipsec_out_classify(pkt,
1140  ctx,
1141  &skip);
1142  if (odp_unlikely(skip)) {
1143  ctx->state = PKT_STATE_TRANSMIT;
1144  } else {
1145  ctx->state = PKT_STATE_IPSEC_OUT_SEQ;
1146  if (odp_queue_enq(global->seqnumq, ev))
1147  rc = PKT_DROP;
1148  }
1149  break;
1150 
1151  case PKT_STATE_IPSEC_OUT_SEQ:
1152 
1153  ctx->state = PKT_STATE_IPSEC_OUT_FINISH;
1154  rc = do_ipsec_out_seq(&pkt, ctx);
1155  break;
1156 
1157  case PKT_STATE_IPSEC_OUT_FINISH:
1158 
1159  rc = do_ipsec_out_finish(pkt, ctx);
1160  ctx->state = PKT_STATE_TRANSMIT;
1161  break;
1162 
1163  case PKT_STATE_TRANSMIT:
1164 
1165  if (odp_pktout_send(ctx->pktout, &pkt, 1) < 1) {
1166  rc = PKT_DROP;
1167  } else {
1168  rc = PKT_DONE;
1169  }
1170  break;
1171 
1172  default:
1173  rc = PKT_DROP;
1174  break;
1175  }
1176  } while (PKT_CONTINUE == rc);
1177 
1178  /* Free context on drop or transmit */
1179  if ((PKT_DROP == rc) || (PKT_DONE == rc))
1180  free_pkt_ctx(ctx);
1181 
1182 
1183  /* Check for drop */
1184  if (PKT_DROP == rc)
1185  odp_packet_free(pkt);
1186 
1187  /* Print packet counts every once in a while */
1188  if (PKT_DONE == rc) {
1189  if (odp_unlikely(pkt_cnt++ % 1000 == 0)) {
1190  printf(" [%02i] pkt_cnt:%lu\n", thr, pkt_cnt);
1191  fflush(NULL);
1192  }
1193  }
1194  }
1195 
1196  return 0;
1197 }
1198 
1202 int
1203 main(int argc, char *argv[])
1204 {
1205  odph_helper_options_t helper_options;
1206  odph_thread_t thread_tbl[MAX_WORKERS];
1207  odph_thread_common_param_t thr_common;
1208  odph_thread_param_t thr_param;
1209  int num_workers;
1210  int i;
1211  int stream_count;
1212  odp_shm_t shm;
1213  odp_cpumask_t cpumask;
1214  char cpumaskstr[ODP_CPUMASK_STR_SIZE];
1215  odp_crypto_capability_t crypto_capa;
1216  odp_pool_param_t params;
1217  odp_instance_t instance;
1218  odp_init_t init_param;
1219 
1220  /* create by default scheduled queues */
1221  queue_create = odp_queue_create;
1222  schedule_fn = odp_schedule_cb;
1223 
1224  /* check for using poll queues */
1225  if (getenv("ODP_IPSEC_USE_POLL_QUEUES")) {
1226  queue_create = polled_odp_queue_create;
1227  schedule_fn = polled_odp_schedule_cb;
1228  }
1229 
1230  /* Let helper collect its own arguments (e.g. --odph_proc) */
1231  argc = odph_parse_options(argc, argv);
1232  if (odph_options(&helper_options)) {
1233  ODPH_ERR("Error: reading ODP helper options failed.\n");
1234  exit(EXIT_FAILURE);
1235  }
1236 
1237  /* Signal handler has to be registered before global init in case ODP
1238  * implementation creates internal threads/processes. */
1239  signal(SIGINT, sig_handler);
1240 
1241  odp_init_param_init(&init_param);
1242  init_param.mem_model = helper_options.mem_model;
1243 
1244  /* Init ODP before calling anything else */
1245  if (odp_init_global(&instance, &init_param, NULL)) {
1246  ODPH_ERR("Error: ODP global init failed.\n");
1247  exit(EXIT_FAILURE);
1248  }
1249 
1250  /* Init this thread */
1251  if (odp_init_local(instance, ODP_THREAD_CONTROL)) {
1252  ODPH_ERR("Error: ODP local init failed.\n");
1253  exit(EXIT_FAILURE);
1254  }
1255 
1256  if (odp_crypto_capability(&crypto_capa)) {
1257  ODPH_ERR("Error: Crypto capability request failed.\n");
1258  exit(EXIT_FAILURE);
1259  }
1260 
1261  if ((NULL == getenv("ODP_IPSEC_USE_POLL_QUEUES")) &&
1262  (crypto_capa.queue_type_sched == 0)) {
1263  ODPH_ERR("Error: scheduled type compl queue not supported.\n");
1264  exit(EXIT_FAILURE);
1265  } else if ((NULL != getenv("ODP_IPSEC_USE_POLL_QUEUES")) &&
1266  crypto_capa.queue_type_plain == 0) {
1267  ODPH_ERR("Error: Plain type compl queue not supported.\n");
1268  exit(EXIT_FAILURE);
1269  }
1270 
1271  /* Reserve memory for args from shared mem */
1272  shm = odp_shm_reserve("shm_args", sizeof(global_data_t),
1273  ODP_CACHE_LINE_SIZE, 0);
1274 
1275  if (shm == ODP_SHM_INVALID) {
1276  ODPH_ERR("Error: shared mem reserve failed.\n");
1277  exit(EXIT_FAILURE);
1278  }
1279 
1280  global = odp_shm_addr(shm);
1281 
1282  if (NULL == global) {
1283  ODPH_ERR("Error: shared mem alloc failed.\n");
1284  exit(EXIT_FAILURE);
1285  }
1286  memset(global, 0, sizeof(global_data_t));
1287  global->shm = shm;
1288  odp_atomic_init_u32(&global->exit_threads, 0);
1289  global->crypto_capa = crypto_capa;
1290 
1291  /* Configure scheduler */
1292  odp_schedule_config(NULL);
1293 
1294  /* Must init our databases before parsing args */
1295  ipsec_init_pre();
1296  init_fwd_db();
1297  init_stream_db();
1298 
1299  /* Parse and store the application arguments */
1300  parse_args(argc, argv, &global->appl);
1301 
1302  /* Print both system and application information */
1303  print_info(NO_PATH(argv[0]), &global->appl);
1304 
1305  num_workers = MAX_WORKERS;
1306  if (global->appl.cpu_count && global->appl.cpu_count < MAX_WORKERS)
1307  num_workers = global->appl.cpu_count;
1308 
1309  /* Get default worker cpumask */
1310  num_workers = odp_cpumask_default_worker(&cpumask, num_workers);
1311  (void)odp_cpumask_to_str(&cpumask, cpumaskstr, sizeof(cpumaskstr));
1312 
1313  printf("num worker threads: %i\n", num_workers);
1314  printf("first CPU: %i\n", odp_cpumask_first(&cpumask));
1315  printf("cpu mask: %s\n", cpumaskstr);
1316 
1317  /* Create a barrier to synchronize thread startup */
1318  odp_barrier_init(&global->sync_barrier, num_workers);
1319 
1320  /* Create packet buffer pool */
1321  odp_pool_param_init(&params);
1322  params.pkt.seg_len = SHM_PKT_POOL_BUF_SIZE;
1323  params.pkt.len = SHM_PKT_POOL_BUF_SIZE;
1324  params.pkt.num = SHM_PKT_POOL_BUF_COUNT;
1325  params.type = ODP_POOL_PACKET;
1326 
1327  global->pkt_pool = odp_pool_create("packet_pool", &params);
1328 
1329  if (ODP_POOL_INVALID == global->pkt_pool) {
1330  ODPH_ERR("Error: packet pool create failed.\n");
1331  exit(EXIT_FAILURE);
1332  }
1333 
1334  /* Create context buffer pool */
1335  params.buf.size = SHM_CTX_POOL_BUF_SIZE;
1336  params.buf.align = 0;
1337  params.buf.num = SHM_CTX_POOL_BUF_COUNT;
1338  params.type = ODP_POOL_BUFFER;
1339 
1340  global->ctx_pool = odp_pool_create("ctx_pool", &params);
1341 
1342  if (ODP_POOL_INVALID == global->ctx_pool) {
1343  ODPH_ERR("Error: context pool create failed.\n");
1344  exit(EXIT_FAILURE);
1345  }
1346 
1347  /* Populate our IPsec cache */
1348  printf("Using %s mode for crypto API\n\n",
1349  (CRYPTO_API_SYNC == global->appl.mode) ? "SYNC" : "ASYNC");
1350  ipsec_init_post(global->appl.mode);
1351 
1352  /* Initialize interfaces (which resolves FWD DB entries */
1353  for (i = 0; i < global->appl.if_count; i++)
1354  initialize_intf(global->appl.if_names[i]);
1355 
1356  /* If we have test streams build them before starting workers */
1357  resolve_stream_db();
1358  stream_count = create_stream_db_inputs();
1359  if (stream_count < 0) {
1360  ODPH_ERR("Error: creating input packets failed\n");
1361  exit(EXIT_FAILURE);
1362  }
1363 
1364  /*
1365  * Create and init worker threads
1366  */
1367  odph_thread_common_param_init(&thr_common);
1368  thr_common.instance = instance;
1369  thr_common.cpumask = &cpumask;
1370  thr_common.share_param = 1;
1371 
1372  odph_thread_param_init(&thr_param);
1373  thr_param.start = pktio_thread;
1374  thr_param.arg = NULL;
1375  thr_param.thr_type = ODP_THREAD_WORKER;
1376 
1377  memset(thread_tbl, 0, sizeof(thread_tbl));
1378  odph_thread_create(thread_tbl, &thr_common, &thr_param, num_workers);
1379 
1380  /* If there are streams attempt to verify them. Otherwise, run until
1381  * SIGINT is received. */
1382  if (stream_count) {
1383  odp_bool_t done;
1384 
1385  do {
1386  done = verify_stream_db_outputs();
1387  usleep(100000);
1388  } while (!done);
1389  printf("All received\n");
1390  odp_atomic_store_u32(&global->exit_threads, 1);
1391  }
1392  odph_thread_join(thread_tbl, num_workers);
1393 
1394  /* Stop and close used pktio devices */
1395  for (i = 0; i < global->appl.if_count; i++) {
1396  odp_pktio_t pktio = odp_pktio_lookup(global->appl.if_names[i]);
1397 
1398  if (pktio == ODP_PKTIO_INVALID)
1399  continue;
1400 
1401  if (odp_pktio_stop(pktio) || odp_pktio_close(pktio)) {
1402  ODPH_ERR("Error: failed to close pktio %s\n",
1403  global->appl.if_names[i]);
1404  exit(EXIT_FAILURE);
1405  }
1406  }
1407 
1408  free(global->appl.if_names);
1409  free(global->appl.if_str);
1410 
1411  if (destroy_ipsec_cache())
1412  ODPH_ERR("Error: crypto session destroy failed\n");
1413 
1414  if (odp_queue_destroy(global->completionq))
1415  ODPH_ERR("Error: queue destroy failed\n");
1416  if (odp_queue_destroy(global->seqnumq))
1417  ODPH_ERR("Error: queue destroy failed\n");
1418 
1419  if (odp_pool_destroy(global->pkt_pool))
1420  ODPH_ERR("Error: pool destroy failed\n");
1421  if (odp_pool_destroy(global->ctx_pool))
1422  ODPH_ERR("Error: pool destroy failed\n");
1423  if (odp_pool_destroy(global->out_pool))
1424  ODPH_ERR("Error: pool destroy failed\n");
1425 
1426  shm = odp_shm_lookup("shm_ipsec_cache");
1427  if (odp_shm_free(shm) != 0)
1428  ODPH_ERR("Error: shm free shm_ipsec_cache failed\n");
1429  shm = odp_shm_lookup("shm_fwd_db");
1430  if (odp_shm_free(shm) != 0)
1431  ODPH_ERR("Error: shm free shm_fwd_db failed\n");
1432  shm = odp_shm_lookup("shm_sa_db");
1433  if (odp_shm_free(shm) != 0)
1434  ODPH_ERR("Error: shm free shm_sa_db failed\n");
1435  shm = odp_shm_lookup("shm_tun_db");
1436  if (odp_shm_free(shm) != 0)
1437  ODPH_ERR("Error: shm free shm_tun_db failed\n");
1438  shm = odp_shm_lookup("shm_sp_db");
1439  if (odp_shm_free(shm) != 0)
1440  ODPH_ERR("Error: shm free shm_sp_db failed\n");
1441 
1442  deinit_stream_db();
1443 
1444  if (odp_shm_free(global->shm)) {
1445  ODPH_ERR("Error: shm free global data failed\n");
1446  exit(EXIT_FAILURE);
1447  }
1448 
1449  if (odp_term_local()) {
1450  ODPH_ERR("Error: term local failed\n");
1451  exit(EXIT_FAILURE);
1452  }
1453 
1454  if (odp_term_global(instance)) {
1455  ODPH_ERR("Error: term global failed\n");
1456  exit(EXIT_FAILURE);
1457  }
1458 
1459  printf("Exit\n\n");
1460 
1461  return 0;
1462 }
1463 
1471 static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
1472 {
1473  int opt;
1474  char *token;
1475  size_t len;
1476  int rc = 0;
1477  int i;
1478 
1479  static const struct option longopts[] = {
1480  {"count", required_argument, NULL, 'c'},
1481  {"interface", required_argument, NULL, 'i'}, /* return 'i' */
1482  {"mode", required_argument, NULL, 'm'}, /* return 'm' */
1483  {"route", required_argument, NULL, 'r'}, /* return 'r' */
1484  {"policy", required_argument, NULL, 'p'}, /* return 'p' */
1485  {"ah", required_argument, NULL, 'a'}, /* return 'a' */
1486  {"esp", required_argument, NULL, 'e'}, /* return 'e' */
1487  {"tunnel", required_argument, NULL, 't'}, /* return 't' */
1488  {"stream", required_argument, NULL, 's'}, /* return 's' */
1489  {"help", no_argument, NULL, 'h'}, /* return 'h' */
1490  {NULL, 0, NULL, 0}
1491  };
1492 
1493  static const char *shortopts = "+c:i:m:r:p:a:e:t:s:h";
1494 
1495  printf("\nParsing command line options\n");
1496 
1497  appl_args->cpu_count = 1; /* use one worker by default */
1498  appl_args->mode = 0; /* turn off async crypto API by default */
1499 
1500  while (!rc) {
1501  opt = getopt_long(argc, argv, shortopts, longopts, NULL);
1502 
1503  if (-1 == opt)
1504  break; /* No more options */
1505 
1506  switch (opt) {
1507  case 'c':
1508  appl_args->cpu_count = atoi(optarg);
1509  break;
1510  /* parse packet-io interface names */
1511  case 'i':
1512  len = strlen(optarg);
1513  if (0 == len) {
1514  usage(argv[0]);
1515  exit(EXIT_FAILURE);
1516  }
1517  len += 1; /* add room for '\0' */
1518 
1519  appl_args->if_str = malloc(len);
1520  if (appl_args->if_str == NULL) {
1521  usage(argv[0]);
1522  exit(EXIT_FAILURE);
1523  }
1524 
1525  /* count the number of tokens separated by ',' */
1526  strcpy(appl_args->if_str, optarg);
1527  for (token = strtok(appl_args->if_str, ","), i = 0;
1528  token != NULL;
1529  token = strtok(NULL, ","), i++)
1530  ;
1531 
1532  appl_args->if_count = i;
1533 
1534  if (0 == appl_args->if_count) {
1535  usage(argv[0]);
1536  exit(EXIT_FAILURE);
1537  }
1538 
1539  /* allocate storage for the if names */
1540  appl_args->if_names =
1541  calloc(appl_args->if_count, sizeof(char *));
1542 
1543  /* store the if names (reset names string) */
1544  strcpy(appl_args->if_str, optarg);
1545  for (token = strtok(appl_args->if_str, ","), i = 0;
1546  token != NULL; token = strtok(NULL, ","), i++) {
1547  appl_args->if_names[i] = token;
1548  }
1549  break;
1550 
1551  case 'm':
1552  appl_args->mode = atoi(optarg);
1553  break;
1554 
1555  case 'r':
1556  rc = create_fwd_db_entry(optarg, appl_args->if_names,
1557  appl_args->if_count);
1558  break;
1559 
1560  case 'p':
1561  rc = create_sp_db_entry(optarg, TRUE);
1562  break;
1563 
1564  case 'a':
1565  rc = create_sa_db_entry(optarg, FALSE);
1566  break;
1567 
1568  case 'e':
1569  rc = create_sa_db_entry(optarg, TRUE);
1570  break;
1571 
1572  case 't':
1573  rc = create_tun_db_entry(optarg);
1574  break;
1575 
1576  case 's':
1577  rc = create_stream_db_entry(optarg);
1578  break;
1579 
1580  case 'h':
1581  usage(argv[0]);
1582  exit(EXIT_SUCCESS);
1583  break;
1584 
1585  default:
1586  break;
1587  }
1588  }
1589 
1590  if (rc) {
1591  printf("ERROR: failed parsing -%c option\n", opt);
1592  usage(argv[0]);
1593  exit(EXIT_FAILURE);
1594  }
1595 
1596  if (0 == appl_args->if_count) {
1597  usage(argv[0]);
1598  exit(EXIT_FAILURE);
1599  }
1600 
1601  optind = 1; /* reset 'extern optind' from the getopt lib */
1602 }
1603 
1607 static void print_info(char *progname, appl_args_t *appl_args)
1608 {
1609  int i;
1610 
1612 
1613  printf("Running ODP appl: \"%s\"\n"
1614  "-----------------\n"
1615  "IF-count: %i\n"
1616  "Using IFs: ",
1617  progname, appl_args->if_count);
1618  for (i = 0; i < appl_args->if_count; ++i)
1619  printf(" %s", appl_args->if_names[i]);
1620 
1621  printf("\n");
1622 
1623  dump_fwd_db();
1624  dump_sp_db();
1625  dump_sa_db();
1626  dump_tun_db();
1627  printf("\n\n");
1628  fflush(NULL);
1629 }
1630 
1634 static void usage(char *progname)
1635 {
1636  printf("\n"
1637  "Usage: %s OPTIONS\n"
1638  " E.g. %s -i eth1,eth2,eth3 -m 0\n"
1639  "\n"
1640  "OpenDataPlane example application.\n"
1641  "\n"
1642  "Mandatory OPTIONS:\n"
1643  " -i, --interface Eth interfaces (comma-separated, no spaces)\n"
1644  " -m, --mode 0: SYNC\n"
1645  " 1: ASYNC\n"
1646  " Default: 0: SYNC api mode\n"
1647  "\n"
1648  "Routing / IPSec OPTIONS:\n"
1649  " -r, --route SubNet,Intf,NextHopMAC\n"
1650  " -p, --policy SrcSubNet,DstSubNet,(in|out),(ah|esp|both)\n"
1651  " -e, --esp SrcIP,DstIP,(3des|null),SPI,Key192\n"
1652  " -a, --ah SrcIP,DstIP,(sha256|sha1|md5|null),SPI,Key(256|160|128)\n"
1653  "\n"
1654  " Where: NextHopMAC is raw hex/colon notation, i.e. 03:BA;44:9A:CE:02\n"
1655  " IP is decimal/dot notation, i.e. 192.168.1.1\n"
1656  " SubNet is decimal/dot/slash notation, i.e 192.168.0.0/16\n"
1657  " SPI is raw hex, 32 bits\n"
1658  " KeyXXX is raw hex, XXX bits long\n"
1659  "\n"
1660  " Examples:\n"
1661  " -r 192.168.222.0/24,p8p1,08:00:27:F5:8B:DB\n"
1662  " -p 192.168.111.0/24,192.168.222.0/24,out,esp\n"
1663  " -e 192.168.111.2,192.168.222.2,3des,201,656c8523255ccc23a66c1917aa0cf30991fce83532a4b224\n"
1664  " -a 192.168.111.2,192.168.222.2,md5,201,a731649644c5dee92cbd9c2e7e188ee6\n"
1665  "\n"
1666  "Optional OPTIONS\n"
1667  " -c, --count <number> CPU count, 0=all available, default=1\n"
1668  " -s, --stream SrcIP,DstIP,InIntf,OutIntf,Count,Length\n"
1669  " -h, --help Display help and exit.\n"
1670  " environment variables: ODP_IPSEC_USE_POLL_QUEUES\n"
1671  " to enable use of poll queues instead of scheduled (default)\n"
1672  " ODP_IPSEC_STREAM_VERIFY_MDEQ\n"
1673  " to enable use of multiple dequeue for queue draining during\n"
1674  " stream verification instead of single dequeue (default)\n"
1675  "\n", NO_PATH(progname), NO_PATH(progname)
1676  );
1677 }
1678 
1679 static odp_bool_t cipher_supported(odp_cipher_alg_t alg, const sa_db_entry_t *sa, int *sa_flags)
1680 {
1681  const odp_crypto_cipher_algos_t *algos = &global->crypto_capa.ciphers;
1682  odp_bool_t alg_ok = true;
1683  int num;
1684 
1685  switch (alg) {
1686  case ODP_CIPHER_ALG_NULL:
1687  if (!algos->bit.null)
1688  alg_ok = false;
1689  break;
1691  if (!algos->bit.trides_cbc)
1692  alg_ok = false;
1693  break;
1694  default:
1695  alg_ok = false;
1696  break;
1697  }
1698  if (!alg_ok) {
1699  printf("ERROR: cipher algorithm not supported\n");
1700  return false;
1701  }
1702 
1703  num = odp_crypto_cipher_capability(alg, NULL, 0);
1704  if (num < 0) {
1705  printf("ERROR: odp_crypto_cipher_capability() failed\n");
1706  return false;
1707  }
1708  odp_crypto_cipher_capability_t cipher_capa[num];
1709 
1710  (void)odp_crypto_cipher_capability(alg, cipher_capa, num);
1711  for (int n = 0; n < num; n++) {
1712  odp_crypto_cipher_capability_t *capa = &cipher_capa[n];
1713 
1714  if (capa->key_len == sa->key.length &&
1715  capa->iv_len == sa->iv_len) {
1716  if (capa->bit_mode)
1717  *sa_flags |= BIT_MODE_CIPHER;
1718  return true;
1719  }
1720  }
1721  printf("ERROR: cipher key length or IV length not supported\n");
1722  return false;
1723 }
1724 
1725 static odp_bool_t auth_supported(odp_auth_alg_t alg, const sa_db_entry_t *sa, int *sa_flags)
1726 {
1727  const odp_crypto_auth_algos_t *algos = &global->crypto_capa.auths;
1728  odp_bool_t alg_ok = true;
1729  int num;
1730 
1731  switch (alg) {
1732  case ODP_AUTH_ALG_NULL:
1733  if (!algos->bit.null)
1734  alg_ok = false;
1735  break;
1736  case ODP_AUTH_ALG_MD5_HMAC:
1737  if (!algos->bit.md5_hmac)
1738  alg_ok = false;
1739  break;
1741  if (!algos->bit.sha1_hmac)
1742  alg_ok = false;
1743  break;
1745  if (!algos->bit.sha256_hmac)
1746  alg_ok = false;
1747  break;
1748  default:
1749  alg_ok = false;
1750  break;
1751  }
1752  if (!alg_ok) {
1753  printf("ERROR: auth algorithm not supported\n");
1754  return false;
1755  }
1756 
1757  num = odp_crypto_auth_capability(alg, NULL, 0);
1758  if (num < 0) {
1759  printf("ERROR: odp_crypto_auth_capability() failed\n");
1760  return false;
1761  }
1762  odp_crypto_auth_capability_t auth_capa[num];
1763 
1764  (void)odp_crypto_auth_capability(alg, auth_capa, num);
1765  for (int n = 0; n < num; n++) {
1766  odp_crypto_auth_capability_t *capa = &auth_capa[n];
1767 
1768  if (capa->digest_len == sa->icv_len &&
1769  capa->key_len == sa->key.length &&
1770  capa->iv_len == 0) {
1771  if (capa->bit_mode)
1772  *sa_flags |= BIT_MODE_AUTH;
1773  return true;
1774  }
1775  }
1776  printf("ERROR: auth ICV length or key length not supported\n");
1777  return false;
1778 }
1779 
1780 odp_bool_t sa_config_supported(const sa_db_entry_t *sa, int *sa_flags);
1781 
1782 odp_bool_t sa_config_supported(const sa_db_entry_t *sa, int *sa_flags)
1783 {
1784  return sa->alg.cipher ? cipher_supported(sa->alg.u.cipher, sa, sa_flags)
1785  : auth_supported(sa->alg.u.auth, sa, sa_flags);
1786 }
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
uint16_t odp_be_to_cpu_16(odp_u16be_t be16)
Convert 16bit big endian to cpu native uint16_t.
odp_u32be_t odp_cpu_to_be_32(uint32_t cpu32)
Convert cpu native uint32_t to 32bit big endian.
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_...
int odp_crypto_cipher_capability(odp_cipher_alg_t cipher, odp_crypto_cipher_capability_t capa[], int num)
Query supported cipher algorithm capabilities.
odp_cipher_alg_t
Crypto API cipher algorithm.
int odp_crypto_capability(odp_crypto_capability_t *capa)
Query crypto capabilities.
int odp_crypto_result(odp_crypto_packet_result_t *result, odp_packet_t packet)
Get crypto operation results from a crypto processed packet.
int odp_crypto_op(const odp_packet_t pkt_in[], odp_packet_t pkt_out[], const odp_crypto_packet_op_param_t param[], int num_pkt)
Crypto packet operation.
odp_auth_alg_t
Crypto API authentication algorithm.
int odp_crypto_op_enq(const odp_packet_t pkt_in[], const odp_packet_t pkt_out[], const odp_crypto_packet_op_param_t param[], int num_pkt)
Crypto packet operation.
int odp_crypto_auth_capability(odp_auth_alg_t auth, odp_crypto_auth_capability_t capa[], int num)
Query supported authentication algorithm capabilities.
@ ODP_CIPHER_ALG_3DES_CBC
Triple DES with cipher block chaining.
@ ODP_CIPHER_ALG_NULL
No cipher algorithm specified.
@ ODP_AUTH_ALG_NULL
No authentication algorithm specified.
@ ODP_AUTH_ALG_MD5_HMAC
HMAC-MD5.
@ ODP_AUTH_ALG_SHA1_HMAC
HMAC-SHA-1.
@ ODP_AUTH_ALG_SHA256_HMAC
HMAC-SHA-256.
_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_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.
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_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_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.
int odp_packet_has_ipv4(odp_packet_t pkt)
Check for IPv4.
void * odp_packet_data(odp_packet_t pkt)
Packet data pointer.
int odp_packet_has_eth(odp_packet_t pkt)
Check for Ethernet header.
void * odp_packet_push_tail(odp_packet_t pkt, uint32_t len)
Push out packet tail.
int odp_packet_has_error(odp_packet_t pkt)
Check for all parse errors in packet.
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.
void * odp_packet_l2_ptr(odp_packet_t pkt, uint32_t *len)
Layer 2 start pointer.
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.
void * odp_packet_pull_tail(odp_packet_t pkt, uint32_t len)
Pull in packet tail.
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.
int odp_queue_enq(odp_queue_t queue, odp_event_t ev)
Enqueue an event to a queue.
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.
int32_t odp_random_data(uint8_t *buf, uint32_t len, odp_random_kind_t kind)
Generate random byte data.
@ ODP_RANDOM_CRYPTO
Cryptographic quality random.
#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.
Authentication algorithm capabilities.
odp_bool_t bit_mode
Auth algorithm supports bit mode.
uint32_t digest_len
Digest length in bytes.
uint32_t key_len
Key length in bytes.
uint32_t iv_len
IV length in bytes.
odp_bool_t queue_type_sched
Scheduled crypto completion queue support.
odp_bool_t queue_type_plain
Plain crypto completion queue support.
Cipher algorithm capabilities.
odp_bool_t bit_mode
Cipher supports bit mode.
uint32_t key_len
Key length in bytes.
uint32_t iv_len
IV length in bytes.
Crypto packet API per packet operation parameters.
uint32_t hash_result_offset
Offset from start of packet for hash result.
const uint8_t * cipher_iv_ptr
IV pointer for cipher.
odp_packet_data_range_t cipher_range
Data range to be ciphered.
odp_crypto_session_t session
Session handle from creation.
odp_packet_data_range_t auth_range
Data range to be authenticated.
Global initialization parameters.
odp_mem_model_t mem_model
Application memory model.
uint32_t offset
Offset from beginning of packet.
uint32_t length
Length of data to operate on.
Packet input queue parameters.
odp_queue_param_t queue_param
Queue parameters.
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.
Authentication algorithms in a bit field structure.
uint32_t null
ODP_AUTH_ALG_NULL.
uint32_t sha1_hmac
ODP_AUTH_ALG_SHA1_HMAC.
uint32_t md5_hmac
ODP_AUTH_ALG_MD5_HMAC.
struct odp_crypto_auth_algos_t::@28 bit
Authentication algorithms.
uint32_t sha256_hmac
ODP_AUTH_ALG_SHA256_HMAC.
Cipher algorithms in a bit field structure.
uint32_t trides_cbc
ODP_CIPHER_ALG_3DES_CBC.
struct odp_crypto_cipher_algos_t::@27 bit
Cipher algorithms.
uint32_t null
ODP_CIPHER_ALG_NULL.