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