fix spelling in comments and strings
[dpdk.git] / examples / ipsec-secgw / ipsec-secgw.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2016 Intel Corporation
3  */
4
5 #include <stdbool.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <stdint.h>
9 #include <inttypes.h>
10 #include <sys/types.h>
11 #include <netinet/in.h>
12 #include <netinet/ip.h>
13 #include <netinet/ip6.h>
14 #include <string.h>
15 #include <sys/queue.h>
16 #include <stdarg.h>
17 #include <errno.h>
18 #include <signal.h>
19 #include <getopt.h>
20
21 #include <rte_common.h>
22 #include <rte_bitmap.h>
23 #include <rte_byteorder.h>
24 #include <rte_log.h>
25 #include <rte_eal.h>
26 #include <rte_launch.h>
27 #include <rte_cycles.h>
28 #include <rte_prefetch.h>
29 #include <rte_lcore.h>
30 #include <rte_per_lcore.h>
31 #include <rte_branch_prediction.h>
32 #include <rte_interrupts.h>
33 #include <rte_random.h>
34 #include <rte_debug.h>
35 #include <rte_ether.h>
36 #include <rte_ethdev.h>
37 #include <rte_mempool.h>
38 #include <rte_mbuf.h>
39 #include <rte_acl.h>
40 #include <rte_lpm.h>
41 #include <rte_lpm6.h>
42 #include <rte_hash.h>
43 #include <rte_jhash.h>
44 #include <rte_cryptodev.h>
45 #include <rte_security.h>
46 #include <rte_eventdev.h>
47 #include <rte_ip.h>
48 #include <rte_ip_frag.h>
49 #include <rte_alarm.h>
50 #include <rte_telemetry.h>
51
52 #include "event_helper.h"
53 #include "flow.h"
54 #include "ipsec.h"
55 #include "ipsec_worker.h"
56 #include "parser.h"
57 #include "sad.h"
58
59 volatile bool force_quit;
60
61 #define MAX_JUMBO_PKT_LEN  9600
62
63 #define MEMPOOL_CACHE_SIZE 256
64
65 #define CDEV_QUEUE_DESC 2048
66 #define CDEV_MAP_ENTRIES 16384
67 #define CDEV_MP_CACHE_SZ 64
68 #define CDEV_MP_CACHE_MULTIPLIER 1.5 /* from rte_mempool.c */
69 #define MAX_QUEUE_PAIRS 1
70
71 #define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
72
73 /* Configure how many packets ahead to prefetch, when reading packets */
74 #define PREFETCH_OFFSET 3
75
76 #define MAX_RX_QUEUE_PER_LCORE 16
77
78 #define MAX_LCORE_PARAMS 1024
79
80 /*
81  * Configurable number of RX/TX ring descriptors
82  */
83 #define IPSEC_SECGW_RX_DESC_DEFAULT 1024
84 #define IPSEC_SECGW_TX_DESC_DEFAULT 1024
85 static uint16_t nb_rxd = IPSEC_SECGW_RX_DESC_DEFAULT;
86 static uint16_t nb_txd = IPSEC_SECGW_TX_DESC_DEFAULT;
87
88 #define ETHADDR_TO_UINT64(addr) __BYTES_TO_UINT64( \
89                 (addr)->addr_bytes[0], (addr)->addr_bytes[1], \
90                 (addr)->addr_bytes[2], (addr)->addr_bytes[3], \
91                 (addr)->addr_bytes[4], (addr)->addr_bytes[5], \
92                 0, 0)
93
94 #define FRAG_TBL_BUCKET_ENTRIES 4
95 #define MAX_FRAG_TTL_NS         (10LL * NS_PER_S)
96
97 #define MTU_TO_FRAMELEN(x)      ((x) + RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN)
98
99 struct ethaddr_info ethaddr_tbl[RTE_MAX_ETHPORTS] = {
100         { 0, ETHADDR(0x00, 0x16, 0x3e, 0x7e, 0x94, 0x9a) },
101         { 0, ETHADDR(0x00, 0x16, 0x3e, 0x22, 0xa1, 0xd9) },
102         { 0, ETHADDR(0x00, 0x16, 0x3e, 0x08, 0x69, 0x26) },
103         { 0, ETHADDR(0x00, 0x16, 0x3e, 0x49, 0x9e, 0xdd) }
104 };
105
106 struct flow_info flow_info_tbl[RTE_MAX_ETHPORTS];
107
108 #define CMD_LINE_OPT_CONFIG             "config"
109 #define CMD_LINE_OPT_SINGLE_SA          "single-sa"
110 #define CMD_LINE_OPT_CRYPTODEV_MASK     "cryptodev_mask"
111 #define CMD_LINE_OPT_TRANSFER_MODE      "transfer-mode"
112 #define CMD_LINE_OPT_SCHEDULE_TYPE      "event-schedule-type"
113 #define CMD_LINE_OPT_RX_OFFLOAD         "rxoffload"
114 #define CMD_LINE_OPT_TX_OFFLOAD         "txoffload"
115 #define CMD_LINE_OPT_REASSEMBLE         "reassemble"
116 #define CMD_LINE_OPT_MTU                "mtu"
117 #define CMD_LINE_OPT_FRAG_TTL           "frag-ttl"
118 #define CMD_LINE_OPT_EVENT_VECTOR       "event-vector"
119 #define CMD_LINE_OPT_VECTOR_SIZE        "vector-size"
120 #define CMD_LINE_OPT_VECTOR_TIMEOUT     "vector-tmo"
121
122 #define CMD_LINE_ARG_EVENT      "event"
123 #define CMD_LINE_ARG_POLL       "poll"
124 #define CMD_LINE_ARG_ORDERED    "ordered"
125 #define CMD_LINE_ARG_ATOMIC     "atomic"
126 #define CMD_LINE_ARG_PARALLEL   "parallel"
127
128 enum {
129         /* long options mapped to a short option */
130
131         /* first long only option value must be >= 256, so that we won't
132          * conflict with short options
133          */
134         CMD_LINE_OPT_MIN_NUM = 256,
135         CMD_LINE_OPT_CONFIG_NUM,
136         CMD_LINE_OPT_SINGLE_SA_NUM,
137         CMD_LINE_OPT_CRYPTODEV_MASK_NUM,
138         CMD_LINE_OPT_TRANSFER_MODE_NUM,
139         CMD_LINE_OPT_SCHEDULE_TYPE_NUM,
140         CMD_LINE_OPT_RX_OFFLOAD_NUM,
141         CMD_LINE_OPT_TX_OFFLOAD_NUM,
142         CMD_LINE_OPT_REASSEMBLE_NUM,
143         CMD_LINE_OPT_MTU_NUM,
144         CMD_LINE_OPT_FRAG_TTL_NUM,
145         CMD_LINE_OPT_EVENT_VECTOR_NUM,
146         CMD_LINE_OPT_VECTOR_SIZE_NUM,
147         CMD_LINE_OPT_VECTOR_TIMEOUT_NUM,
148 };
149
150 static const struct option lgopts[] = {
151         {CMD_LINE_OPT_CONFIG, 1, 0, CMD_LINE_OPT_CONFIG_NUM},
152         {CMD_LINE_OPT_SINGLE_SA, 1, 0, CMD_LINE_OPT_SINGLE_SA_NUM},
153         {CMD_LINE_OPT_CRYPTODEV_MASK, 1, 0, CMD_LINE_OPT_CRYPTODEV_MASK_NUM},
154         {CMD_LINE_OPT_TRANSFER_MODE, 1, 0, CMD_LINE_OPT_TRANSFER_MODE_NUM},
155         {CMD_LINE_OPT_SCHEDULE_TYPE, 1, 0, CMD_LINE_OPT_SCHEDULE_TYPE_NUM},
156         {CMD_LINE_OPT_RX_OFFLOAD, 1, 0, CMD_LINE_OPT_RX_OFFLOAD_NUM},
157         {CMD_LINE_OPT_TX_OFFLOAD, 1, 0, CMD_LINE_OPT_TX_OFFLOAD_NUM},
158         {CMD_LINE_OPT_REASSEMBLE, 1, 0, CMD_LINE_OPT_REASSEMBLE_NUM},
159         {CMD_LINE_OPT_MTU, 1, 0, CMD_LINE_OPT_MTU_NUM},
160         {CMD_LINE_OPT_FRAG_TTL, 1, 0, CMD_LINE_OPT_FRAG_TTL_NUM},
161         {CMD_LINE_OPT_EVENT_VECTOR, 0, 0, CMD_LINE_OPT_EVENT_VECTOR_NUM},
162         {CMD_LINE_OPT_VECTOR_SIZE, 1, 0, CMD_LINE_OPT_VECTOR_SIZE_NUM},
163         {CMD_LINE_OPT_VECTOR_TIMEOUT, 1, 0, CMD_LINE_OPT_VECTOR_TIMEOUT_NUM},
164         {NULL, 0, 0, 0}
165 };
166
167 uint32_t unprotected_port_mask;
168 uint32_t single_sa_idx;
169 /* mask of enabled ports */
170 static uint32_t enabled_port_mask;
171 static uint64_t enabled_cryptodev_mask = UINT64_MAX;
172 static int32_t promiscuous_on = 1;
173 static int32_t numa_on = 1; /**< NUMA is enabled by default. */
174 static uint32_t nb_lcores;
175 static uint32_t single_sa;
176 uint32_t nb_bufs_in_pool;
177
178 /*
179  * RX/TX HW offload capabilities to enable/use on ethernet ports.
180  * By default all capabilities are enabled.
181  */
182 static uint64_t dev_rx_offload = UINT64_MAX;
183 static uint64_t dev_tx_offload = UINT64_MAX;
184
185 /*
186  * global values that determine multi-seg policy
187  */
188 static uint32_t frag_tbl_sz;
189 static uint32_t frame_buf_size = RTE_MBUF_DEFAULT_BUF_SIZE;
190 static uint32_t mtu_size = RTE_ETHER_MTU;
191 static uint64_t frag_ttl_ns = MAX_FRAG_TTL_NS;
192 static uint32_t stats_interval;
193
194 /* application wide librte_ipsec/SA parameters */
195 struct app_sa_prm app_sa_prm = {
196                         .enable = 0,
197                         .cache_sz = SA_CACHE_SZ,
198                         .udp_encap = 0
199                 };
200 static const char *cfgfile;
201
202 struct lcore_rx_queue {
203         uint16_t port_id;
204         uint8_t queue_id;
205 } __rte_cache_aligned;
206
207 struct lcore_params {
208         uint16_t port_id;
209         uint8_t queue_id;
210         uint8_t lcore_id;
211 } __rte_cache_aligned;
212
213 static struct lcore_params lcore_params_array[MAX_LCORE_PARAMS];
214
215 static struct lcore_params *lcore_params;
216 static uint16_t nb_lcore_params;
217
218 static struct rte_hash *cdev_map_in;
219 static struct rte_hash *cdev_map_out;
220
221 struct buffer {
222         uint16_t len;
223         struct rte_mbuf *m_table[MAX_PKT_BURST] __rte_aligned(sizeof(void *));
224 };
225
226 struct lcore_conf {
227         uint16_t nb_rx_queue;
228         struct lcore_rx_queue rx_queue_list[MAX_RX_QUEUE_PER_LCORE];
229         uint16_t tx_queue_id[RTE_MAX_ETHPORTS];
230         struct buffer tx_mbufs[RTE_MAX_ETHPORTS];
231         struct ipsec_ctx inbound;
232         struct ipsec_ctx outbound;
233         struct rt_ctx *rt4_ctx;
234         struct rt_ctx *rt6_ctx;
235         struct {
236                 struct rte_ip_frag_tbl *tbl;
237                 struct rte_mempool *pool_dir;
238                 struct rte_mempool *pool_indir;
239                 struct rte_ip_frag_death_row dr;
240         } frag;
241 } __rte_cache_aligned;
242
243 static struct lcore_conf lcore_conf[RTE_MAX_LCORE];
244
245 static struct rte_eth_conf port_conf = {
246         .rxmode = {
247                 .mq_mode        = RTE_ETH_MQ_RX_RSS,
248                 .split_hdr_size = 0,
249                 .offloads = RTE_ETH_RX_OFFLOAD_CHECKSUM,
250         },
251         .rx_adv_conf = {
252                 .rss_conf = {
253                         .rss_key = NULL,
254                         .rss_hf = RTE_ETH_RSS_IP | RTE_ETH_RSS_UDP |
255                                 RTE_ETH_RSS_TCP | RTE_ETH_RSS_SCTP,
256                 },
257         },
258         .txmode = {
259                 .mq_mode = RTE_ETH_MQ_TX_NONE,
260         },
261 };
262
263 struct socket_ctx socket_ctx[NB_SOCKETS];
264
265 /*
266  * Determine is multi-segment support required:
267  *  - either frame buffer size is smaller then mtu
268  *  - or reassemble support is requested
269  */
270 static int
271 multi_seg_required(void)
272 {
273         return (MTU_TO_FRAMELEN(mtu_size) + RTE_PKTMBUF_HEADROOM >
274                 frame_buf_size || frag_tbl_sz != 0);
275 }
276
277 static inline void
278 adjust_ipv4_pktlen(struct rte_mbuf *m, const struct rte_ipv4_hdr *iph,
279         uint32_t l2_len)
280 {
281         uint32_t plen, trim;
282
283         plen = rte_be_to_cpu_16(iph->total_length) + l2_len;
284         if (plen < m->pkt_len) {
285                 trim = m->pkt_len - plen;
286                 rte_pktmbuf_trim(m, trim);
287         }
288 }
289
290 static inline void
291 adjust_ipv6_pktlen(struct rte_mbuf *m, const struct rte_ipv6_hdr *iph,
292         uint32_t l2_len)
293 {
294         uint32_t plen, trim;
295
296         plen = rte_be_to_cpu_16(iph->payload_len) + sizeof(*iph) + l2_len;
297         if (plen < m->pkt_len) {
298                 trim = m->pkt_len - plen;
299                 rte_pktmbuf_trim(m, trim);
300         }
301 }
302
303
304 struct ipsec_core_statistics core_statistics[RTE_MAX_LCORE];
305
306 /* Print out statistics on packet distribution */
307 static void
308 print_stats_cb(__rte_unused void *param)
309 {
310         uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
311         float burst_percent, rx_per_call, tx_per_call;
312         unsigned int coreid;
313
314         total_packets_dropped = 0;
315         total_packets_tx = 0;
316         total_packets_rx = 0;
317
318         const char clr[] = { 27, '[', '2', 'J', '\0' };
319         const char topLeft[] = { 27, '[', '1', ';', '1', 'H', '\0' };
320
321         /* Clear screen and move to top left */
322         printf("%s%s", clr, topLeft);
323
324         printf("\nCore statistics ====================================");
325
326         for (coreid = 0; coreid < RTE_MAX_LCORE; coreid++) {
327                 /* skip disabled cores */
328                 if (rte_lcore_is_enabled(coreid) == 0)
329                         continue;
330                 burst_percent = (float)(core_statistics[coreid].burst_rx * 100)/
331                                         core_statistics[coreid].rx;
332                 rx_per_call =  (float)(core_statistics[coreid].rx)/
333                                        core_statistics[coreid].rx_call;
334                 tx_per_call =  (float)(core_statistics[coreid].tx)/
335                                        core_statistics[coreid].tx_call;
336                 printf("\nStatistics for core %u ------------------------------"
337                            "\nPackets received: %20"PRIu64
338                            "\nPackets sent: %24"PRIu64
339                            "\nPackets dropped: %21"PRIu64
340                            "\nBurst percent: %23.2f"
341                            "\nPackets per Rx call: %17.2f"
342                            "\nPackets per Tx call: %17.2f",
343                            coreid,
344                            core_statistics[coreid].rx,
345                            core_statistics[coreid].tx,
346                            core_statistics[coreid].dropped,
347                            burst_percent,
348                            rx_per_call,
349                            tx_per_call);
350
351                 total_packets_dropped += core_statistics[coreid].dropped;
352                 total_packets_tx += core_statistics[coreid].tx;
353                 total_packets_rx += core_statistics[coreid].rx;
354         }
355         printf("\nAggregate statistics ==============================="
356                    "\nTotal packets received: %14"PRIu64
357                    "\nTotal packets sent: %18"PRIu64
358                    "\nTotal packets dropped: %15"PRIu64,
359                    total_packets_rx,
360                    total_packets_tx,
361                    total_packets_dropped);
362         printf("\n====================================================\n");
363
364         rte_eal_alarm_set(stats_interval * US_PER_S, print_stats_cb, NULL);
365 }
366
367 static inline void
368 prepare_one_packet(struct rte_mbuf *pkt, struct ipsec_traffic *t)
369 {
370         const struct rte_ether_hdr *eth;
371         const struct rte_ipv4_hdr *iph4;
372         const struct rte_ipv6_hdr *iph6;
373         const struct rte_udp_hdr *udp;
374         uint16_t ip4_hdr_len;
375         uint16_t nat_port;
376
377         eth = rte_pktmbuf_mtod(pkt, const struct rte_ether_hdr *);
378         if (eth->ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) {
379
380                 iph4 = (const struct rte_ipv4_hdr *)rte_pktmbuf_adj(pkt,
381                         RTE_ETHER_HDR_LEN);
382                 adjust_ipv4_pktlen(pkt, iph4, 0);
383
384                 switch (iph4->next_proto_id) {
385                 case IPPROTO_ESP:
386                         t->ipsec.pkts[(t->ipsec.num)++] = pkt;
387                         break;
388                 case IPPROTO_UDP:
389                         if (app_sa_prm.udp_encap == 1) {
390                                 ip4_hdr_len = ((iph4->version_ihl &
391                                         RTE_IPV4_HDR_IHL_MASK) *
392                                         RTE_IPV4_IHL_MULTIPLIER);
393                                 udp = rte_pktmbuf_mtod_offset(pkt,
394                                         struct rte_udp_hdr *, ip4_hdr_len);
395                                 nat_port = rte_cpu_to_be_16(IPSEC_NAT_T_PORT);
396                                 if (udp->src_port == nat_port ||
397                                         udp->dst_port == nat_port){
398                                         t->ipsec.pkts[(t->ipsec.num)++] = pkt;
399                                         pkt->packet_type |=
400                                                 MBUF_PTYPE_TUNNEL_ESP_IN_UDP;
401                                         break;
402                                 }
403                         }
404                 /* Fall through */
405                 default:
406                         t->ip4.data[t->ip4.num] = &iph4->next_proto_id;
407                         t->ip4.pkts[(t->ip4.num)++] = pkt;
408                 }
409                 pkt->l2_len = 0;
410                 pkt->l3_len = sizeof(*iph4);
411                 pkt->packet_type |= RTE_PTYPE_L3_IPV4;
412                 if  (pkt->packet_type & RTE_PTYPE_L4_TCP)
413                         pkt->l4_len = sizeof(struct rte_tcp_hdr);
414                 else if (pkt->packet_type & RTE_PTYPE_L4_UDP)
415                         pkt->l4_len = sizeof(struct rte_udp_hdr);
416         } else if (eth->ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6)) {
417                 int next_proto;
418                 size_t l3len, ext_len;
419                 uint8_t *p;
420
421                 /* get protocol type */
422                 iph6 = (const struct rte_ipv6_hdr *)rte_pktmbuf_adj(pkt,
423                         RTE_ETHER_HDR_LEN);
424                 adjust_ipv6_pktlen(pkt, iph6, 0);
425
426                 next_proto = iph6->proto;
427
428                 /* determine l3 header size up to ESP extension */
429                 l3len = sizeof(struct ip6_hdr);
430                 p = rte_pktmbuf_mtod(pkt, uint8_t *);
431                 while (next_proto != IPPROTO_ESP && l3len < pkt->data_len &&
432                         (next_proto = rte_ipv6_get_next_ext(p + l3len,
433                                                 next_proto, &ext_len)) >= 0)
434                         l3len += ext_len;
435
436                 /* drop packet when IPv6 header exceeds first segment length */
437                 if (unlikely(l3len > pkt->data_len)) {
438                         free_pkts(&pkt, 1);
439                         return;
440                 }
441
442                 switch (next_proto) {
443                 case IPPROTO_ESP:
444                         t->ipsec.pkts[(t->ipsec.num)++] = pkt;
445                         break;
446                 case IPPROTO_UDP:
447                         if (app_sa_prm.udp_encap == 1) {
448                                 udp = rte_pktmbuf_mtod_offset(pkt,
449                                         struct rte_udp_hdr *, l3len);
450                                 nat_port = rte_cpu_to_be_16(IPSEC_NAT_T_PORT);
451                                 if (udp->src_port == nat_port ||
452                                         udp->dst_port == nat_port){
453                                         t->ipsec.pkts[(t->ipsec.num)++] = pkt;
454                                         pkt->packet_type |=
455                                                 MBUF_PTYPE_TUNNEL_ESP_IN_UDP;
456                                         break;
457                                 }
458                         }
459                 /* Fall through */
460                 default:
461                         t->ip6.data[t->ip6.num] = &iph6->proto;
462                         t->ip6.pkts[(t->ip6.num)++] = pkt;
463                 }
464                 pkt->l2_len = 0;
465                 pkt->l3_len = l3len;
466                 pkt->packet_type |= RTE_PTYPE_L3_IPV6;
467         } else {
468                 /* Unknown/Unsupported type, drop the packet */
469                 RTE_LOG(ERR, IPSEC, "Unsupported packet type 0x%x\n",
470                         rte_be_to_cpu_16(eth->ether_type));
471                 free_pkts(&pkt, 1);
472                 return;
473         }
474
475         /* Check if the packet has been processed inline. For inline protocol
476          * processed packets, the metadata in the mbuf can be used to identify
477          * the security processing done on the packet. The metadata will be
478          * used to retrieve the application registered userdata associated
479          * with the security session.
480          */
481
482         if (pkt->ol_flags & RTE_MBUF_F_RX_SEC_OFFLOAD &&
483                         rte_security_dynfield_is_registered()) {
484                 struct ipsec_sa *sa;
485                 struct ipsec_mbuf_metadata *priv;
486                 struct rte_security_ctx *ctx = (struct rte_security_ctx *)
487                                                 rte_eth_dev_get_sec_ctx(
488                                                 pkt->port);
489
490                 /* Retrieve the userdata registered. Here, the userdata
491                  * registered is the SA pointer.
492                  */
493                 sa = (struct ipsec_sa *)rte_security_get_userdata(ctx,
494                                 *rte_security_dynfield(pkt));
495                 if (sa == NULL) {
496                         /* userdata could not be retrieved */
497                         return;
498                 }
499
500                 /* Save SA as priv member in mbuf. This will be used in the
501                  * IPsec selector(SP-SA) check.
502                  */
503
504                 priv = get_priv(pkt);
505                 priv->sa = sa;
506         }
507 }
508
509 static inline void
510 prepare_traffic(struct rte_mbuf **pkts, struct ipsec_traffic *t,
511                 uint16_t nb_pkts)
512 {
513         int32_t i;
514
515         t->ipsec.num = 0;
516         t->ip4.num = 0;
517         t->ip6.num = 0;
518
519         for (i = 0; i < (nb_pkts - PREFETCH_OFFSET); i++) {
520                 rte_prefetch0(rte_pktmbuf_mtod(pkts[i + PREFETCH_OFFSET],
521                                         void *));
522                 prepare_one_packet(pkts[i], t);
523         }
524         /* Process left packets */
525         for (; i < nb_pkts; i++)
526                 prepare_one_packet(pkts[i], t);
527 }
528
529 static inline void
530 prepare_tx_pkt(struct rte_mbuf *pkt, uint16_t port,
531                 const struct lcore_conf *qconf)
532 {
533         struct ip *ip;
534         struct rte_ether_hdr *ethhdr;
535
536         ip = rte_pktmbuf_mtod(pkt, struct ip *);
537
538         ethhdr = (struct rte_ether_hdr *)
539                 rte_pktmbuf_prepend(pkt, RTE_ETHER_HDR_LEN);
540
541         if (ip->ip_v == IPVERSION) {
542                 pkt->ol_flags |= qconf->outbound.ipv4_offloads;
543                 pkt->l3_len = sizeof(struct ip);
544                 pkt->l2_len = RTE_ETHER_HDR_LEN;
545
546                 ip->ip_sum = 0;
547
548                 /* calculate IPv4 cksum in SW */
549                 if ((pkt->ol_flags & RTE_MBUF_F_TX_IP_CKSUM) == 0)
550                         ip->ip_sum = rte_ipv4_cksum((struct rte_ipv4_hdr *)ip);
551
552                 ethhdr->ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
553         } else {
554                 pkt->ol_flags |= qconf->outbound.ipv6_offloads;
555                 pkt->l3_len = sizeof(struct ip6_hdr);
556                 pkt->l2_len = RTE_ETHER_HDR_LEN;
557
558                 ethhdr->ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
559         }
560
561         memcpy(&ethhdr->src_addr, &ethaddr_tbl[port].src,
562                         sizeof(struct rte_ether_addr));
563         memcpy(&ethhdr->dst_addr, &ethaddr_tbl[port].dst,
564                         sizeof(struct rte_ether_addr));
565 }
566
567 static inline void
568 prepare_tx_burst(struct rte_mbuf *pkts[], uint16_t nb_pkts, uint16_t port,
569                 const struct lcore_conf *qconf)
570 {
571         int32_t i;
572         const int32_t prefetch_offset = 2;
573
574         for (i = 0; i < (nb_pkts - prefetch_offset); i++) {
575                 rte_mbuf_prefetch_part2(pkts[i + prefetch_offset]);
576                 prepare_tx_pkt(pkts[i], port, qconf);
577         }
578         /* Process left packets */
579         for (; i < nb_pkts; i++)
580                 prepare_tx_pkt(pkts[i], port, qconf);
581 }
582
583 /* Send burst of packets on an output interface */
584 static inline int32_t
585 send_burst(struct lcore_conf *qconf, uint16_t n, uint16_t port)
586 {
587         struct rte_mbuf **m_table;
588         int32_t ret;
589         uint16_t queueid;
590
591         queueid = qconf->tx_queue_id[port];
592         m_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table;
593
594         prepare_tx_burst(m_table, n, port, qconf);
595
596         ret = rte_eth_tx_burst(port, queueid, m_table, n);
597
598         core_stats_update_tx(ret);
599
600         if (unlikely(ret < n)) {
601                 do {
602                         free_pkts(&m_table[ret], 1);
603                 } while (++ret < n);
604         }
605
606         return 0;
607 }
608
609 /*
610  * Helper function to fragment and queue for TX one packet.
611  */
612 static inline uint32_t
613 send_fragment_packet(struct lcore_conf *qconf, struct rte_mbuf *m,
614         uint16_t port, uint8_t proto)
615 {
616         struct buffer *tbl;
617         uint32_t len, n;
618         int32_t rc;
619
620         tbl =  qconf->tx_mbufs + port;
621         len = tbl->len;
622
623         /* free space for new fragments */
624         if (len + RTE_LIBRTE_IP_FRAG_MAX_FRAG >=  RTE_DIM(tbl->m_table)) {
625                 send_burst(qconf, len, port);
626                 len = 0;
627         }
628
629         n = RTE_DIM(tbl->m_table) - len;
630
631         if (proto == IPPROTO_IP)
632                 rc = rte_ipv4_fragment_packet(m, tbl->m_table + len,
633                         n, mtu_size, qconf->frag.pool_dir,
634                         qconf->frag.pool_indir);
635         else
636                 rc = rte_ipv6_fragment_packet(m, tbl->m_table + len,
637                         n, mtu_size, qconf->frag.pool_dir,
638                         qconf->frag.pool_indir);
639
640         if (rc >= 0)
641                 len += rc;
642         else
643                 RTE_LOG(ERR, IPSEC,
644                         "%s: failed to fragment packet with size %u, "
645                         "error code: %d\n",
646                         __func__, m->pkt_len, rte_errno);
647
648         free_pkts(&m, 1);
649         return len;
650 }
651
652 /* Enqueue a single packet, and send burst if queue is filled */
653 static inline int32_t
654 send_single_packet(struct rte_mbuf *m, uint16_t port, uint8_t proto)
655 {
656         uint32_t lcore_id;
657         uint16_t len;
658         struct lcore_conf *qconf;
659
660         lcore_id = rte_lcore_id();
661
662         qconf = &lcore_conf[lcore_id];
663         len = qconf->tx_mbufs[port].len;
664
665         if (m->pkt_len <= mtu_size) {
666                 qconf->tx_mbufs[port].m_table[len] = m;
667                 len++;
668
669         /* need to fragment the packet */
670         } else if (frag_tbl_sz > 0)
671                 len = send_fragment_packet(qconf, m, port, proto);
672         else
673                 free_pkts(&m, 1);
674
675         /* enough pkts to be sent */
676         if (unlikely(len == MAX_PKT_BURST)) {
677                 send_burst(qconf, MAX_PKT_BURST, port);
678                 len = 0;
679         }
680
681         qconf->tx_mbufs[port].len = len;
682         return 0;
683 }
684
685 static inline void
686 inbound_sp_sa(struct sp_ctx *sp, struct sa_ctx *sa, struct traffic_type *ip,
687                 uint16_t lim, struct ipsec_spd_stats *stats)
688 {
689         struct rte_mbuf *m;
690         uint32_t i, j, res, sa_idx;
691
692         if (ip->num == 0 || sp == NULL)
693                 return;
694
695         rte_acl_classify((struct rte_acl_ctx *)sp, ip->data, ip->res,
696                         ip->num, DEFAULT_MAX_CATEGORIES);
697
698         j = 0;
699         for (i = 0; i < ip->num; i++) {
700                 m = ip->pkts[i];
701                 res = ip->res[i];
702                 if (res == BYPASS) {
703                         ip->pkts[j++] = m;
704                         stats->bypass++;
705                         continue;
706                 }
707                 if (res == DISCARD) {
708                         free_pkts(&m, 1);
709                         stats->discard++;
710                         continue;
711                 }
712
713                 /* Only check SPI match for processed IPSec packets */
714                 if (i < lim && ((m->ol_flags & RTE_MBUF_F_RX_SEC_OFFLOAD) == 0)) {
715                         stats->discard++;
716                         free_pkts(&m, 1);
717                         continue;
718                 }
719
720                 sa_idx = res - 1;
721                 if (!inbound_sa_check(sa, m, sa_idx)) {
722                         stats->discard++;
723                         free_pkts(&m, 1);
724                         continue;
725                 }
726                 ip->pkts[j++] = m;
727                 stats->protect++;
728         }
729         ip->num = j;
730 }
731
732 static void
733 split46_traffic(struct ipsec_traffic *trf, struct rte_mbuf *mb[], uint32_t num)
734 {
735         uint32_t i, n4, n6;
736         struct ip *ip;
737         struct rte_mbuf *m;
738
739         n4 = trf->ip4.num;
740         n6 = trf->ip6.num;
741
742         for (i = 0; i < num; i++) {
743
744                 m = mb[i];
745                 ip = rte_pktmbuf_mtod(m, struct ip *);
746
747                 if (ip->ip_v == IPVERSION) {
748                         trf->ip4.pkts[n4] = m;
749                         trf->ip4.data[n4] = rte_pktmbuf_mtod_offset(m,
750                                         uint8_t *, offsetof(struct ip, ip_p));
751                         n4++;
752                 } else if (ip->ip_v == IP6_VERSION) {
753                         trf->ip6.pkts[n6] = m;
754                         trf->ip6.data[n6] = rte_pktmbuf_mtod_offset(m,
755                                         uint8_t *,
756                                         offsetof(struct ip6_hdr, ip6_nxt));
757                         n6++;
758                 } else
759                         free_pkts(&m, 1);
760         }
761
762         trf->ip4.num = n4;
763         trf->ip6.num = n6;
764 }
765
766
767 static inline void
768 process_pkts_inbound(struct ipsec_ctx *ipsec_ctx,
769                 struct ipsec_traffic *traffic)
770 {
771         unsigned int lcoreid = rte_lcore_id();
772         uint16_t nb_pkts_in, n_ip4, n_ip6;
773
774         n_ip4 = traffic->ip4.num;
775         n_ip6 = traffic->ip6.num;
776
777         if (app_sa_prm.enable == 0) {
778                 nb_pkts_in = ipsec_inbound(ipsec_ctx, traffic->ipsec.pkts,
779                                 traffic->ipsec.num, MAX_PKT_BURST);
780                 split46_traffic(traffic, traffic->ipsec.pkts, nb_pkts_in);
781         } else {
782                 inbound_sa_lookup(ipsec_ctx->sa_ctx, traffic->ipsec.pkts,
783                         traffic->ipsec.saptr, traffic->ipsec.num);
784                 ipsec_process(ipsec_ctx, traffic);
785         }
786
787         inbound_sp_sa(ipsec_ctx->sp4_ctx,
788                 ipsec_ctx->sa_ctx, &traffic->ip4, n_ip4,
789                 &core_statistics[lcoreid].inbound.spd4);
790
791         inbound_sp_sa(ipsec_ctx->sp6_ctx,
792                 ipsec_ctx->sa_ctx, &traffic->ip6, n_ip6,
793                 &core_statistics[lcoreid].inbound.spd6);
794 }
795
796 static inline void
797 outbound_spd_lookup(struct sp_ctx *sp,
798                 struct traffic_type *ip,
799                 struct traffic_type *ipsec,
800                 struct ipsec_spd_stats *stats)
801 {
802         struct rte_mbuf *m;
803         uint32_t i, j, sa_idx;
804
805         if (ip->num == 0 || sp == NULL)
806                 return;
807
808         rte_acl_classify((struct rte_acl_ctx *)sp, ip->data, ip->res,
809                         ip->num, DEFAULT_MAX_CATEGORIES);
810
811         for (i = 0, j = 0; i < ip->num; i++) {
812                 m = ip->pkts[i];
813                 sa_idx = ip->res[i] - 1;
814
815                 if (unlikely(ip->res[i] == DISCARD)) {
816                         free_pkts(&m, 1);
817
818                         stats->discard++;
819                 } else if (unlikely(ip->res[i] == BYPASS)) {
820                         ip->pkts[j++] = m;
821
822                         stats->bypass++;
823                 } else {
824                         ipsec->res[ipsec->num] = sa_idx;
825                         ipsec->pkts[ipsec->num++] = m;
826
827                         stats->protect++;
828                 }
829         }
830         ip->num = j;
831 }
832
833 static inline void
834 process_pkts_outbound(struct ipsec_ctx *ipsec_ctx,
835                 struct ipsec_traffic *traffic)
836 {
837         struct rte_mbuf *m;
838         uint16_t idx, nb_pkts_out, i;
839         unsigned int lcoreid = rte_lcore_id();
840
841         /* Drop any IPsec traffic from protected ports */
842         free_pkts(traffic->ipsec.pkts, traffic->ipsec.num);
843
844         traffic->ipsec.num = 0;
845
846         outbound_spd_lookup(ipsec_ctx->sp4_ctx,
847                 &traffic->ip4, &traffic->ipsec,
848                 &core_statistics[lcoreid].outbound.spd4);
849
850         outbound_spd_lookup(ipsec_ctx->sp6_ctx,
851                 &traffic->ip6, &traffic->ipsec,
852                 &core_statistics[lcoreid].outbound.spd6);
853
854         if (app_sa_prm.enable == 0) {
855
856                 nb_pkts_out = ipsec_outbound(ipsec_ctx, traffic->ipsec.pkts,
857                                 traffic->ipsec.res, traffic->ipsec.num,
858                                 MAX_PKT_BURST);
859
860                 for (i = 0; i < nb_pkts_out; i++) {
861                         m = traffic->ipsec.pkts[i];
862                         struct ip *ip = rte_pktmbuf_mtod(m, struct ip *);
863                         if (ip->ip_v == IPVERSION) {
864                                 idx = traffic->ip4.num++;
865                                 traffic->ip4.pkts[idx] = m;
866                         } else {
867                                 idx = traffic->ip6.num++;
868                                 traffic->ip6.pkts[idx] = m;
869                         }
870                 }
871         } else {
872                 outbound_sa_lookup(ipsec_ctx->sa_ctx, traffic->ipsec.res,
873                         traffic->ipsec.saptr, traffic->ipsec.num);
874                 ipsec_process(ipsec_ctx, traffic);
875         }
876 }
877
878 static inline void
879 process_pkts_inbound_nosp(struct ipsec_ctx *ipsec_ctx,
880                 struct ipsec_traffic *traffic)
881 {
882         struct rte_mbuf *m;
883         uint32_t nb_pkts_in, i, idx;
884
885         if (app_sa_prm.enable == 0) {
886
887                 nb_pkts_in = ipsec_inbound(ipsec_ctx, traffic->ipsec.pkts,
888                                 traffic->ipsec.num, MAX_PKT_BURST);
889
890                 for (i = 0; i < nb_pkts_in; i++) {
891                         m = traffic->ipsec.pkts[i];
892                         struct ip *ip = rte_pktmbuf_mtod(m, struct ip *);
893                         if (ip->ip_v == IPVERSION) {
894                                 idx = traffic->ip4.num++;
895                                 traffic->ip4.pkts[idx] = m;
896                         } else {
897                                 idx = traffic->ip6.num++;
898                                 traffic->ip6.pkts[idx] = m;
899                         }
900                 }
901         } else {
902                 inbound_sa_lookup(ipsec_ctx->sa_ctx, traffic->ipsec.pkts,
903                         traffic->ipsec.saptr, traffic->ipsec.num);
904                 ipsec_process(ipsec_ctx, traffic);
905         }
906 }
907
908 static inline void
909 process_pkts_outbound_nosp(struct ipsec_ctx *ipsec_ctx,
910                 struct ipsec_traffic *traffic)
911 {
912         struct rte_mbuf *m;
913         uint32_t nb_pkts_out, i, n;
914         struct ip *ip;
915
916         /* Drop any IPsec traffic from protected ports */
917         free_pkts(traffic->ipsec.pkts, traffic->ipsec.num);
918
919         n = 0;
920
921         for (i = 0; i < traffic->ip4.num; i++) {
922                 traffic->ipsec.pkts[n] = traffic->ip4.pkts[i];
923                 traffic->ipsec.res[n++] = single_sa_idx;
924         }
925
926         for (i = 0; i < traffic->ip6.num; i++) {
927                 traffic->ipsec.pkts[n] = traffic->ip6.pkts[i];
928                 traffic->ipsec.res[n++] = single_sa_idx;
929         }
930
931         traffic->ip4.num = 0;
932         traffic->ip6.num = 0;
933         traffic->ipsec.num = n;
934
935         if (app_sa_prm.enable == 0) {
936
937                 nb_pkts_out = ipsec_outbound(ipsec_ctx, traffic->ipsec.pkts,
938                                 traffic->ipsec.res, traffic->ipsec.num,
939                                 MAX_PKT_BURST);
940
941                 /* They all sue the same SA (ip4 or ip6 tunnel) */
942                 m = traffic->ipsec.pkts[0];
943                 ip = rte_pktmbuf_mtod(m, struct ip *);
944                 if (ip->ip_v == IPVERSION) {
945                         traffic->ip4.num = nb_pkts_out;
946                         for (i = 0; i < nb_pkts_out; i++)
947                                 traffic->ip4.pkts[i] = traffic->ipsec.pkts[i];
948                 } else {
949                         traffic->ip6.num = nb_pkts_out;
950                         for (i = 0; i < nb_pkts_out; i++)
951                                 traffic->ip6.pkts[i] = traffic->ipsec.pkts[i];
952                 }
953         } else {
954                 outbound_sa_lookup(ipsec_ctx->sa_ctx, traffic->ipsec.res,
955                         traffic->ipsec.saptr, traffic->ipsec.num);
956                 ipsec_process(ipsec_ctx, traffic);
957         }
958 }
959
960 static inline int32_t
961 get_hop_for_offload_pkt(struct rte_mbuf *pkt, int is_ipv6)
962 {
963         struct ipsec_mbuf_metadata *priv;
964         struct ipsec_sa *sa;
965
966         priv = get_priv(pkt);
967
968         sa = priv->sa;
969         if (unlikely(sa == NULL)) {
970                 RTE_LOG(ERR, IPSEC, "SA not saved in private data\n");
971                 goto fail;
972         }
973
974         if (is_ipv6)
975                 return sa->portid;
976
977         /* else */
978         return (sa->portid | RTE_LPM_LOOKUP_SUCCESS);
979
980 fail:
981         if (is_ipv6)
982                 return -1;
983
984         /* else */
985         return 0;
986 }
987
988 static inline void
989 route4_pkts(struct rt_ctx *rt_ctx, struct rte_mbuf *pkts[], uint8_t nb_pkts)
990 {
991         uint32_t hop[MAX_PKT_BURST * 2];
992         uint32_t dst_ip[MAX_PKT_BURST * 2];
993         int32_t pkt_hop = 0;
994         uint16_t i, offset;
995         uint16_t lpm_pkts = 0;
996         unsigned int lcoreid = rte_lcore_id();
997
998         if (nb_pkts == 0)
999                 return;
1000
1001         /* Need to do an LPM lookup for non-inline packets. Inline packets will
1002          * have port ID in the SA
1003          */
1004
1005         for (i = 0; i < nb_pkts; i++) {
1006                 if (!(pkts[i]->ol_flags & RTE_MBUF_F_TX_SEC_OFFLOAD)) {
1007                         /* Security offload not enabled. So an LPM lookup is
1008                          * required to get the hop
1009                          */
1010                         offset = offsetof(struct ip, ip_dst);
1011                         dst_ip[lpm_pkts] = *rte_pktmbuf_mtod_offset(pkts[i],
1012                                         uint32_t *, offset);
1013                         dst_ip[lpm_pkts] = rte_be_to_cpu_32(dst_ip[lpm_pkts]);
1014                         lpm_pkts++;
1015                 }
1016         }
1017
1018         rte_lpm_lookup_bulk((struct rte_lpm *)rt_ctx, dst_ip, hop, lpm_pkts);
1019
1020         lpm_pkts = 0;
1021
1022         for (i = 0; i < nb_pkts; i++) {
1023                 if (pkts[i]->ol_flags & RTE_MBUF_F_TX_SEC_OFFLOAD) {
1024                         /* Read hop from the SA */
1025                         pkt_hop = get_hop_for_offload_pkt(pkts[i], 0);
1026                 } else {
1027                         /* Need to use hop returned by lookup */
1028                         pkt_hop = hop[lpm_pkts++];
1029                 }
1030
1031                 if ((pkt_hop & RTE_LPM_LOOKUP_SUCCESS) == 0) {
1032                         core_statistics[lcoreid].lpm4.miss++;
1033                         free_pkts(&pkts[i], 1);
1034                         continue;
1035                 }
1036                 send_single_packet(pkts[i], pkt_hop & 0xff, IPPROTO_IP);
1037         }
1038 }
1039
1040 static inline void
1041 route6_pkts(struct rt_ctx *rt_ctx, struct rte_mbuf *pkts[], uint8_t nb_pkts)
1042 {
1043         int32_t hop[MAX_PKT_BURST * 2];
1044         uint8_t dst_ip[MAX_PKT_BURST * 2][16];
1045         uint8_t *ip6_dst;
1046         int32_t pkt_hop = 0;
1047         uint16_t i, offset;
1048         uint16_t lpm_pkts = 0;
1049         unsigned int lcoreid = rte_lcore_id();
1050
1051         if (nb_pkts == 0)
1052                 return;
1053
1054         /* Need to do an LPM lookup for non-inline packets. Inline packets will
1055          * have port ID in the SA
1056          */
1057
1058         for (i = 0; i < nb_pkts; i++) {
1059                 if (!(pkts[i]->ol_flags & RTE_MBUF_F_TX_SEC_OFFLOAD)) {
1060                         /* Security offload not enabled. So an LPM lookup is
1061                          * required to get the hop
1062                          */
1063                         offset = offsetof(struct ip6_hdr, ip6_dst);
1064                         ip6_dst = rte_pktmbuf_mtod_offset(pkts[i], uint8_t *,
1065                                         offset);
1066                         memcpy(&dst_ip[lpm_pkts][0], ip6_dst, 16);
1067                         lpm_pkts++;
1068                 }
1069         }
1070
1071         rte_lpm6_lookup_bulk_func((struct rte_lpm6 *)rt_ctx, dst_ip, hop,
1072                         lpm_pkts);
1073
1074         lpm_pkts = 0;
1075
1076         for (i = 0; i < nb_pkts; i++) {
1077                 if (pkts[i]->ol_flags & RTE_MBUF_F_TX_SEC_OFFLOAD) {
1078                         /* Read hop from the SA */
1079                         pkt_hop = get_hop_for_offload_pkt(pkts[i], 1);
1080                 } else {
1081                         /* Need to use hop returned by lookup */
1082                         pkt_hop = hop[lpm_pkts++];
1083                 }
1084
1085                 if (pkt_hop == -1) {
1086                         core_statistics[lcoreid].lpm6.miss++;
1087                         free_pkts(&pkts[i], 1);
1088                         continue;
1089                 }
1090                 send_single_packet(pkts[i], pkt_hop & 0xff, IPPROTO_IPV6);
1091         }
1092 }
1093
1094 static inline void
1095 process_pkts(struct lcore_conf *qconf, struct rte_mbuf **pkts,
1096                 uint8_t nb_pkts, uint16_t portid)
1097 {
1098         struct ipsec_traffic traffic;
1099
1100         prepare_traffic(pkts, &traffic, nb_pkts);
1101
1102         if (unlikely(single_sa)) {
1103                 if (is_unprotected_port(portid))
1104                         process_pkts_inbound_nosp(&qconf->inbound, &traffic);
1105                 else
1106                         process_pkts_outbound_nosp(&qconf->outbound, &traffic);
1107         } else {
1108                 if (is_unprotected_port(portid))
1109                         process_pkts_inbound(&qconf->inbound, &traffic);
1110                 else
1111                         process_pkts_outbound(&qconf->outbound, &traffic);
1112         }
1113
1114         route4_pkts(qconf->rt4_ctx, traffic.ip4.pkts, traffic.ip4.num);
1115         route6_pkts(qconf->rt6_ctx, traffic.ip6.pkts, traffic.ip6.num);
1116 }
1117
1118 static inline void
1119 drain_tx_buffers(struct lcore_conf *qconf)
1120 {
1121         struct buffer *buf;
1122         uint32_t portid;
1123
1124         for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
1125                 buf = &qconf->tx_mbufs[portid];
1126                 if (buf->len == 0)
1127                         continue;
1128                 send_burst(qconf, buf->len, portid);
1129                 buf->len = 0;
1130         }
1131 }
1132
1133 static inline void
1134 drain_crypto_buffers(struct lcore_conf *qconf)
1135 {
1136         uint32_t i;
1137         struct ipsec_ctx *ctx;
1138
1139         /* drain inbound buffers*/
1140         ctx = &qconf->inbound;
1141         for (i = 0; i != ctx->nb_qps; i++) {
1142                 if (ctx->tbl[i].len != 0)
1143                         enqueue_cop_burst(ctx->tbl  + i);
1144         }
1145
1146         /* drain outbound buffers*/
1147         ctx = &qconf->outbound;
1148         for (i = 0; i != ctx->nb_qps; i++) {
1149                 if (ctx->tbl[i].len != 0)
1150                         enqueue_cop_burst(ctx->tbl  + i);
1151         }
1152 }
1153
1154 static void
1155 drain_inbound_crypto_queues(const struct lcore_conf *qconf,
1156                 struct ipsec_ctx *ctx)
1157 {
1158         uint32_t n;
1159         struct ipsec_traffic trf;
1160         unsigned int lcoreid = rte_lcore_id();
1161
1162         if (app_sa_prm.enable == 0) {
1163
1164                 /* dequeue packets from crypto-queue */
1165                 n = ipsec_inbound_cqp_dequeue(ctx, trf.ipsec.pkts,
1166                         RTE_DIM(trf.ipsec.pkts));
1167
1168                 trf.ip4.num = 0;
1169                 trf.ip6.num = 0;
1170
1171                 /* split traffic by ipv4-ipv6 */
1172                 split46_traffic(&trf, trf.ipsec.pkts, n);
1173         } else
1174                 ipsec_cqp_process(ctx, &trf);
1175
1176         /* process ipv4 packets */
1177         if (trf.ip4.num != 0) {
1178                 inbound_sp_sa(ctx->sp4_ctx, ctx->sa_ctx, &trf.ip4, 0,
1179                         &core_statistics[lcoreid].inbound.spd4);
1180                 route4_pkts(qconf->rt4_ctx, trf.ip4.pkts, trf.ip4.num);
1181         }
1182
1183         /* process ipv6 packets */
1184         if (trf.ip6.num != 0) {
1185                 inbound_sp_sa(ctx->sp6_ctx, ctx->sa_ctx, &trf.ip6, 0,
1186                         &core_statistics[lcoreid].inbound.spd6);
1187                 route6_pkts(qconf->rt6_ctx, trf.ip6.pkts, trf.ip6.num);
1188         }
1189 }
1190
1191 static void
1192 drain_outbound_crypto_queues(const struct lcore_conf *qconf,
1193                 struct ipsec_ctx *ctx)
1194 {
1195         uint32_t n;
1196         struct ipsec_traffic trf;
1197
1198         if (app_sa_prm.enable == 0) {
1199
1200                 /* dequeue packets from crypto-queue */
1201                 n = ipsec_outbound_cqp_dequeue(ctx, trf.ipsec.pkts,
1202                         RTE_DIM(trf.ipsec.pkts));
1203
1204                 trf.ip4.num = 0;
1205                 trf.ip6.num = 0;
1206
1207                 /* split traffic by ipv4-ipv6 */
1208                 split46_traffic(&trf, trf.ipsec.pkts, n);
1209         } else
1210                 ipsec_cqp_process(ctx, &trf);
1211
1212         /* process ipv4 packets */
1213         if (trf.ip4.num != 0)
1214                 route4_pkts(qconf->rt4_ctx, trf.ip4.pkts, trf.ip4.num);
1215
1216         /* process ipv6 packets */
1217         if (trf.ip6.num != 0)
1218                 route6_pkts(qconf->rt6_ctx, trf.ip6.pkts, trf.ip6.num);
1219 }
1220
1221 /* main processing loop */
1222 void
1223 ipsec_poll_mode_worker(void)
1224 {
1225         struct rte_mbuf *pkts[MAX_PKT_BURST];
1226         uint32_t lcore_id;
1227         uint64_t prev_tsc, diff_tsc, cur_tsc;
1228         int32_t i, nb_rx;
1229         uint16_t portid;
1230         uint8_t queueid;
1231         struct lcore_conf *qconf;
1232         int32_t rc, socket_id;
1233         const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1)
1234                         / US_PER_S * BURST_TX_DRAIN_US;
1235         struct lcore_rx_queue *rxql;
1236
1237         prev_tsc = 0;
1238         lcore_id = rte_lcore_id();
1239         qconf = &lcore_conf[lcore_id];
1240         rxql = qconf->rx_queue_list;
1241         socket_id = rte_lcore_to_socket_id(lcore_id);
1242
1243         qconf->rt4_ctx = socket_ctx[socket_id].rt_ip4;
1244         qconf->rt6_ctx = socket_ctx[socket_id].rt_ip6;
1245         qconf->inbound.sp4_ctx = socket_ctx[socket_id].sp_ip4_in;
1246         qconf->inbound.sp6_ctx = socket_ctx[socket_id].sp_ip6_in;
1247         qconf->inbound.sa_ctx = socket_ctx[socket_id].sa_in;
1248         qconf->inbound.cdev_map = cdev_map_in;
1249         qconf->inbound.session_pool = socket_ctx[socket_id].session_pool;
1250         qconf->inbound.session_priv_pool =
1251                         socket_ctx[socket_id].session_priv_pool;
1252         qconf->outbound.sp4_ctx = socket_ctx[socket_id].sp_ip4_out;
1253         qconf->outbound.sp6_ctx = socket_ctx[socket_id].sp_ip6_out;
1254         qconf->outbound.sa_ctx = socket_ctx[socket_id].sa_out;
1255         qconf->outbound.cdev_map = cdev_map_out;
1256         qconf->outbound.session_pool = socket_ctx[socket_id].session_pool;
1257         qconf->outbound.session_priv_pool =
1258                         socket_ctx[socket_id].session_priv_pool;
1259         qconf->frag.pool_dir = socket_ctx[socket_id].mbuf_pool;
1260         qconf->frag.pool_indir = socket_ctx[socket_id].mbuf_pool_indir;
1261
1262         rc = ipsec_sad_lcore_cache_init(app_sa_prm.cache_sz);
1263         if (rc != 0) {
1264                 RTE_LOG(ERR, IPSEC,
1265                         "SAD cache init on lcore %u, failed with code: %d\n",
1266                         lcore_id, rc);
1267                 return;
1268         }
1269
1270         if (qconf->nb_rx_queue == 0) {
1271                 RTE_LOG(DEBUG, IPSEC, "lcore %u has nothing to do\n",
1272                         lcore_id);
1273                 return;
1274         }
1275
1276         RTE_LOG(INFO, IPSEC, "entering main loop on lcore %u\n", lcore_id);
1277
1278         for (i = 0; i < qconf->nb_rx_queue; i++) {
1279                 portid = rxql[i].port_id;
1280                 queueid = rxql[i].queue_id;
1281                 RTE_LOG(INFO, IPSEC,
1282                         " -- lcoreid=%u portid=%u rxqueueid=%hhu\n",
1283                         lcore_id, portid, queueid);
1284         }
1285
1286         while (!force_quit) {
1287                 cur_tsc = rte_rdtsc();
1288
1289                 /* TX queue buffer drain */
1290                 diff_tsc = cur_tsc - prev_tsc;
1291
1292                 if (unlikely(diff_tsc > drain_tsc)) {
1293                         drain_tx_buffers(qconf);
1294                         drain_crypto_buffers(qconf);
1295                         prev_tsc = cur_tsc;
1296                 }
1297
1298                 for (i = 0; i < qconf->nb_rx_queue; ++i) {
1299
1300                         /* Read packets from RX queues */
1301                         portid = rxql[i].port_id;
1302                         queueid = rxql[i].queue_id;
1303                         nb_rx = rte_eth_rx_burst(portid, queueid,
1304                                         pkts, MAX_PKT_BURST);
1305
1306                         if (nb_rx > 0) {
1307                                 core_stats_update_rx(nb_rx);
1308                                 process_pkts(qconf, pkts, nb_rx, portid);
1309                         }
1310
1311                         /* dequeue and process completed crypto-ops */
1312                         if (is_unprotected_port(portid))
1313                                 drain_inbound_crypto_queues(qconf,
1314                                         &qconf->inbound);
1315                         else
1316                                 drain_outbound_crypto_queues(qconf,
1317                                         &qconf->outbound);
1318                 }
1319         }
1320 }
1321
1322 int
1323 check_flow_params(uint16_t fdir_portid, uint8_t fdir_qid)
1324 {
1325         uint16_t i;
1326         uint16_t portid;
1327         uint8_t queueid;
1328
1329         for (i = 0; i < nb_lcore_params; ++i) {
1330                 portid = lcore_params_array[i].port_id;
1331                 if (portid == fdir_portid) {
1332                         queueid = lcore_params_array[i].queue_id;
1333                         if (queueid == fdir_qid)
1334                                 break;
1335                 }
1336
1337                 if (i == nb_lcore_params - 1)
1338                         return -1;
1339         }
1340
1341         return 1;
1342 }
1343
1344 static int32_t
1345 check_poll_mode_params(struct eh_conf *eh_conf)
1346 {
1347         uint8_t lcore;
1348         uint16_t portid;
1349         uint16_t i;
1350         int32_t socket_id;
1351
1352         if (!eh_conf)
1353                 return -EINVAL;
1354
1355         if (eh_conf->mode != EH_PKT_TRANSFER_MODE_POLL)
1356                 return 0;
1357
1358         if (lcore_params == NULL) {
1359                 printf("Error: No port/queue/core mappings\n");
1360                 return -1;
1361         }
1362
1363         for (i = 0; i < nb_lcore_params; ++i) {
1364                 lcore = lcore_params[i].lcore_id;
1365                 if (!rte_lcore_is_enabled(lcore)) {
1366                         printf("error: lcore %hhu is not enabled in "
1367                                 "lcore mask\n", lcore);
1368                         return -1;
1369                 }
1370                 socket_id = rte_lcore_to_socket_id(lcore);
1371                 if (socket_id != 0 && numa_on == 0) {
1372                         printf("warning: lcore %hhu is on socket %d "
1373                                 "with numa off\n",
1374                                 lcore, socket_id);
1375                 }
1376                 portid = lcore_params[i].port_id;
1377                 if ((enabled_port_mask & (1 << portid)) == 0) {
1378                         printf("port %u is not enabled in port mask\n", portid);
1379                         return -1;
1380                 }
1381                 if (!rte_eth_dev_is_valid_port(portid)) {
1382                         printf("port %u is not present on the board\n", portid);
1383                         return -1;
1384                 }
1385         }
1386         return 0;
1387 }
1388
1389 static uint8_t
1390 get_port_nb_rx_queues(const uint16_t port)
1391 {
1392         int32_t queue = -1;
1393         uint16_t i;
1394
1395         for (i = 0; i < nb_lcore_params; ++i) {
1396                 if (lcore_params[i].port_id == port &&
1397                                 lcore_params[i].queue_id > queue)
1398                         queue = lcore_params[i].queue_id;
1399         }
1400         return (uint8_t)(++queue);
1401 }
1402
1403 static int32_t
1404 init_lcore_rx_queues(void)
1405 {
1406         uint16_t i, nb_rx_queue;
1407         uint8_t lcore;
1408
1409         for (i = 0; i < nb_lcore_params; ++i) {
1410                 lcore = lcore_params[i].lcore_id;
1411                 nb_rx_queue = lcore_conf[lcore].nb_rx_queue;
1412                 if (nb_rx_queue >= MAX_RX_QUEUE_PER_LCORE) {
1413                         printf("error: too many queues (%u) for lcore: %u\n",
1414                                         nb_rx_queue + 1, lcore);
1415                         return -1;
1416                 }
1417                 lcore_conf[lcore].rx_queue_list[nb_rx_queue].port_id =
1418                         lcore_params[i].port_id;
1419                 lcore_conf[lcore].rx_queue_list[nb_rx_queue].queue_id =
1420                         lcore_params[i].queue_id;
1421                 lcore_conf[lcore].nb_rx_queue++;
1422         }
1423         return 0;
1424 }
1425
1426 /* display usage */
1427 static void
1428 print_usage(const char *prgname)
1429 {
1430         fprintf(stderr, "%s [EAL options] --"
1431                 " -p PORTMASK"
1432                 " [-P]"
1433                 " [-u PORTMASK]"
1434                 " [-j FRAMESIZE]"
1435                 " [-l]"
1436                 " [-w REPLAY_WINDOW_SIZE]"
1437                 " [-e]"
1438                 " [-a]"
1439                 " [-c]"
1440                 " [-t STATS_INTERVAL]"
1441                 " [-s NUMBER_OF_MBUFS_IN_PKT_POOL]"
1442                 " -f CONFIG_FILE"
1443                 " --config (port,queue,lcore)[,(port,queue,lcore)]"
1444                 " [--single-sa SAIDX]"
1445                 " [--cryptodev_mask MASK]"
1446                 " [--transfer-mode MODE]"
1447                 " [--event-schedule-type TYPE]"
1448                 " [--" CMD_LINE_OPT_RX_OFFLOAD " RX_OFFLOAD_MASK]"
1449                 " [--" CMD_LINE_OPT_TX_OFFLOAD " TX_OFFLOAD_MASK]"
1450                 " [--" CMD_LINE_OPT_REASSEMBLE " REASSEMBLE_TABLE_SIZE]"
1451                 " [--" CMD_LINE_OPT_MTU " MTU]"
1452                 " [--event-vector]"
1453                 " [--vector-size SIZE]"
1454                 " [--vector-tmo TIMEOUT in ns]"
1455                 "\n\n"
1456                 "  -p PORTMASK: Hexadecimal bitmask of ports to configure\n"
1457                 "  -P : Enable promiscuous mode\n"
1458                 "  -u PORTMASK: Hexadecimal bitmask of unprotected ports\n"
1459                 "  -j FRAMESIZE: Data buffer size, minimum (and default)\n"
1460                 "     value: RTE_MBUF_DEFAULT_BUF_SIZE\n"
1461                 "  -l enables code-path that uses librte_ipsec\n"
1462                 "  -w REPLAY_WINDOW_SIZE specifies IPsec SQN replay window\n"
1463                 "     size for each SA\n"
1464                 "  -e enables ESN\n"
1465                 "  -a enables SA SQN atomic behaviour\n"
1466                 "  -c specifies inbound SAD cache size,\n"
1467                 "     zero value disables the cache (default value: 128)\n"
1468                 "  -t specifies statistics screen update interval,\n"
1469                 "     zero disables statistics screen (default value: 0)\n"
1470                 "  -s number of mbufs in packet pool, if not specified number\n"
1471                 "     of mbufs will be calculated based on number of cores,\n"
1472                 "     ports and crypto queues\n"
1473                 "  -f CONFIG_FILE: Configuration file\n"
1474                 "  --config (port,queue,lcore): Rx queue configuration. In poll\n"
1475                 "                               mode determines which queues from\n"
1476                 "                               which ports are mapped to which cores.\n"
1477                 "                               In event mode this option is not used\n"
1478                 "                               as packets are dynamically scheduled\n"
1479                 "                               to cores by HW.\n"
1480                 "  --single-sa SAIDX: In poll mode use single SA index for\n"
1481                 "                     outbound traffic, bypassing the SP\n"
1482                 "                     In event mode selects driver submode,\n"
1483                 "                     SA index value is ignored\n"
1484                 "  --cryptodev_mask MASK: Hexadecimal bitmask of the crypto\n"
1485                 "                         devices to configure\n"
1486                 "  --transfer-mode MODE\n"
1487                 "               \"poll\"  : Packet transfer via polling (default)\n"
1488                 "               \"event\" : Packet transfer via event device\n"
1489                 "  --event-schedule-type TYPE queue schedule type, used only when\n"
1490                 "                             transfer mode is set to event\n"
1491                 "               \"ordered\"  : Ordered (default)\n"
1492                 "               \"atomic\"   : Atomic\n"
1493                 "               \"parallel\" : Parallel\n"
1494                 "  --" CMD_LINE_OPT_RX_OFFLOAD
1495                 ": bitmask of the RX HW offload capabilities to enable/use\n"
1496                 "                         (RTE_ETH_RX_OFFLOAD_*)\n"
1497                 "  --" CMD_LINE_OPT_TX_OFFLOAD
1498                 ": bitmask of the TX HW offload capabilities to enable/use\n"
1499                 "                         (RTE_ETH_TX_OFFLOAD_*)\n"
1500                 "  --" CMD_LINE_OPT_REASSEMBLE " NUM"
1501                 ": max number of entries in reassemble(fragment) table\n"
1502                 "    (zero (default value) disables reassembly)\n"
1503                 "  --" CMD_LINE_OPT_MTU " MTU"
1504                 ": MTU value on all ports (default value: 1500)\n"
1505                 "    outgoing packets with bigger size will be fragmented\n"
1506                 "    incoming packets with bigger size will be discarded\n"
1507                 "  --" CMD_LINE_OPT_FRAG_TTL " FRAG_TTL_NS"
1508                 ": fragments lifetime in nanoseconds, default\n"
1509                 "    and maximum value is 10.000.000.000 ns (10 s)\n"
1510                 "  --event-vector enables event vectorization\n"
1511                 "  --vector-size Max vector size (default value: 16)\n"
1512                 "  --vector-tmo Max vector timeout in nanoseconds"
1513                 "    (default value: 102400)\n"
1514                 "\n",
1515                 prgname);
1516 }
1517
1518 static int
1519 parse_mask(const char *str, uint64_t *val)
1520 {
1521         char *end;
1522         unsigned long t;
1523
1524         errno = 0;
1525         t = strtoul(str, &end, 0);
1526         if (errno != 0 || end[0] != 0)
1527                 return -EINVAL;
1528
1529         *val = t;
1530         return 0;
1531 }
1532
1533 static int32_t
1534 parse_portmask(const char *portmask)
1535 {
1536         char *end = NULL;
1537         unsigned long pm;
1538
1539         errno = 0;
1540
1541         /* parse hexadecimal string */
1542         pm = strtoul(portmask, &end, 16);
1543         if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
1544                 return -1;
1545
1546         if ((pm == 0) && errno)
1547                 return -1;
1548
1549         return pm;
1550 }
1551
1552 static int64_t
1553 parse_decimal(const char *str)
1554 {
1555         char *end = NULL;
1556         uint64_t num;
1557
1558         num = strtoull(str, &end, 10);
1559         if ((str[0] == '\0') || (end == NULL) || (*end != '\0')
1560                 || num > INT64_MAX)
1561                 return -1;
1562
1563         return num;
1564 }
1565
1566 static int32_t
1567 parse_config(const char *q_arg)
1568 {
1569         char s[256];
1570         const char *p, *p0 = q_arg;
1571         char *end;
1572         enum fieldnames {
1573                 FLD_PORT = 0,
1574                 FLD_QUEUE,
1575                 FLD_LCORE,
1576                 _NUM_FLD
1577         };
1578         unsigned long int_fld[_NUM_FLD];
1579         char *str_fld[_NUM_FLD];
1580         int32_t i;
1581         uint32_t size;
1582
1583         nb_lcore_params = 0;
1584
1585         while ((p = strchr(p0, '(')) != NULL) {
1586                 ++p;
1587                 p0 = strchr(p, ')');
1588                 if (p0 == NULL)
1589                         return -1;
1590
1591                 size = p0 - p;
1592                 if (size >= sizeof(s))
1593                         return -1;
1594
1595                 snprintf(s, sizeof(s), "%.*s", size, p);
1596                 if (rte_strsplit(s, sizeof(s), str_fld, _NUM_FLD, ',') !=
1597                                 _NUM_FLD)
1598                         return -1;
1599                 for (i = 0; i < _NUM_FLD; i++) {
1600                         errno = 0;
1601                         int_fld[i] = strtoul(str_fld[i], &end, 0);
1602                         if (errno != 0 || end == str_fld[i] || int_fld[i] > 255)
1603                                 return -1;
1604                 }
1605                 if (nb_lcore_params >= MAX_LCORE_PARAMS) {
1606                         printf("exceeded max number of lcore params: %hu\n",
1607                                 nb_lcore_params);
1608                         return -1;
1609                 }
1610                 lcore_params_array[nb_lcore_params].port_id =
1611                         (uint8_t)int_fld[FLD_PORT];
1612                 lcore_params_array[nb_lcore_params].queue_id =
1613                         (uint8_t)int_fld[FLD_QUEUE];
1614                 lcore_params_array[nb_lcore_params].lcore_id =
1615                         (uint8_t)int_fld[FLD_LCORE];
1616                 ++nb_lcore_params;
1617         }
1618         lcore_params = lcore_params_array;
1619         return 0;
1620 }
1621
1622 static void
1623 print_app_sa_prm(const struct app_sa_prm *prm)
1624 {
1625         printf("librte_ipsec usage: %s\n",
1626                 (prm->enable == 0) ? "disabled" : "enabled");
1627
1628         printf("replay window size: %u\n", prm->window_size);
1629         printf("ESN: %s\n", (prm->enable_esn == 0) ? "disabled" : "enabled");
1630         printf("SA flags: %#" PRIx64 "\n", prm->flags);
1631         printf("Frag TTL: %" PRIu64 " ns\n", frag_ttl_ns);
1632 }
1633
1634 static int
1635 parse_transfer_mode(struct eh_conf *conf, const char *optarg)
1636 {
1637         if (!strcmp(CMD_LINE_ARG_POLL, optarg))
1638                 conf->mode = EH_PKT_TRANSFER_MODE_POLL;
1639         else if (!strcmp(CMD_LINE_ARG_EVENT, optarg))
1640                 conf->mode = EH_PKT_TRANSFER_MODE_EVENT;
1641         else {
1642                 printf("Unsupported packet transfer mode\n");
1643                 return -EINVAL;
1644         }
1645
1646         return 0;
1647 }
1648
1649 static int
1650 parse_schedule_type(struct eh_conf *conf, const char *optarg)
1651 {
1652         struct eventmode_conf *em_conf = NULL;
1653
1654         /* Get eventmode conf */
1655         em_conf = conf->mode_params;
1656
1657         if (!strcmp(CMD_LINE_ARG_ORDERED, optarg))
1658                 em_conf->ext_params.sched_type = RTE_SCHED_TYPE_ORDERED;
1659         else if (!strcmp(CMD_LINE_ARG_ATOMIC, optarg))
1660                 em_conf->ext_params.sched_type = RTE_SCHED_TYPE_ATOMIC;
1661         else if (!strcmp(CMD_LINE_ARG_PARALLEL, optarg))
1662                 em_conf->ext_params.sched_type = RTE_SCHED_TYPE_PARALLEL;
1663         else {
1664                 printf("Unsupported queue schedule type\n");
1665                 return -EINVAL;
1666         }
1667
1668         return 0;
1669 }
1670
1671 static int32_t
1672 parse_args(int32_t argc, char **argv, struct eh_conf *eh_conf)
1673 {
1674         int opt;
1675         int64_t ret;
1676         char **argvopt;
1677         int32_t option_index;
1678         char *prgname = argv[0];
1679         int32_t f_present = 0;
1680         struct eventmode_conf *em_conf = NULL;
1681
1682         argvopt = argv;
1683
1684         while ((opt = getopt_long(argc, argvopt, "aelp:Pu:f:j:w:c:t:s:",
1685                                 lgopts, &option_index)) != EOF) {
1686
1687                 switch (opt) {
1688                 case 'p':
1689                         enabled_port_mask = parse_portmask(optarg);
1690                         if (enabled_port_mask == 0) {
1691                                 printf("invalid portmask\n");
1692                                 print_usage(prgname);
1693                                 return -1;
1694                         }
1695                         break;
1696                 case 'P':
1697                         printf("Promiscuous mode selected\n");
1698                         promiscuous_on = 1;
1699                         break;
1700                 case 'u':
1701                         unprotected_port_mask = parse_portmask(optarg);
1702                         if (unprotected_port_mask == 0) {
1703                                 printf("invalid unprotected portmask\n");
1704                                 print_usage(prgname);
1705                                 return -1;
1706                         }
1707                         break;
1708                 case 'f':
1709                         if (f_present == 1) {
1710                                 printf("\"-f\" option present more than "
1711                                         "once!\n");
1712                                 print_usage(prgname);
1713                                 return -1;
1714                         }
1715                         cfgfile = optarg;
1716                         f_present = 1;
1717                         break;
1718
1719                 case 's':
1720                         ret = parse_decimal(optarg);
1721                         if (ret < 0) {
1722                                 printf("Invalid number of buffers in a pool: "
1723                                         "%s\n", optarg);
1724                                 print_usage(prgname);
1725                                 return -1;
1726                         }
1727
1728                         nb_bufs_in_pool = ret;
1729                         break;
1730
1731                 case 'j':
1732                         ret = parse_decimal(optarg);
1733                         if (ret < RTE_MBUF_DEFAULT_BUF_SIZE ||
1734                                         ret > UINT16_MAX) {
1735                                 printf("Invalid frame buffer size value: %s\n",
1736                                         optarg);
1737                                 print_usage(prgname);
1738                                 return -1;
1739                         }
1740                         frame_buf_size = ret;
1741                         printf("Custom frame buffer size %u\n", frame_buf_size);
1742                         break;
1743                 case 'l':
1744                         app_sa_prm.enable = 1;
1745                         break;
1746                 case 'w':
1747                         app_sa_prm.window_size = parse_decimal(optarg);
1748                         break;
1749                 case 'e':
1750                         app_sa_prm.enable_esn = 1;
1751                         break;
1752                 case 'a':
1753                         app_sa_prm.enable = 1;
1754                         app_sa_prm.flags |= RTE_IPSEC_SAFLAG_SQN_ATOM;
1755                         break;
1756                 case 'c':
1757                         ret = parse_decimal(optarg);
1758                         if (ret < 0) {
1759                                 printf("Invalid SA cache size: %s\n", optarg);
1760                                 print_usage(prgname);
1761                                 return -1;
1762                         }
1763                         app_sa_prm.cache_sz = ret;
1764                         break;
1765                 case 't':
1766                         ret = parse_decimal(optarg);
1767                         if (ret < 0) {
1768                                 printf("Invalid interval value: %s\n", optarg);
1769                                 print_usage(prgname);
1770                                 return -1;
1771                         }
1772                         stats_interval = ret;
1773                         break;
1774                 case CMD_LINE_OPT_CONFIG_NUM:
1775                         ret = parse_config(optarg);
1776                         if (ret) {
1777                                 printf("Invalid config\n");
1778                                 print_usage(prgname);
1779                                 return -1;
1780                         }
1781                         break;
1782                 case CMD_LINE_OPT_SINGLE_SA_NUM:
1783                         ret = parse_decimal(optarg);
1784                         if (ret == -1 || ret > UINT32_MAX) {
1785                                 printf("Invalid argument[sa_idx]\n");
1786                                 print_usage(prgname);
1787                                 return -1;
1788                         }
1789
1790                         /* else */
1791                         single_sa = 1;
1792                         single_sa_idx = ret;
1793                         eh_conf->ipsec_mode = EH_IPSEC_MODE_TYPE_DRIVER;
1794                         printf("Configured with single SA index %u\n",
1795                                         single_sa_idx);
1796                         break;
1797                 case CMD_LINE_OPT_CRYPTODEV_MASK_NUM:
1798                         ret = parse_portmask(optarg);
1799                         if (ret == -1) {
1800                                 printf("Invalid argument[portmask]\n");
1801                                 print_usage(prgname);
1802                                 return -1;
1803                         }
1804
1805                         /* else */
1806                         enabled_cryptodev_mask = ret;
1807                         break;
1808
1809                 case CMD_LINE_OPT_TRANSFER_MODE_NUM:
1810                         ret = parse_transfer_mode(eh_conf, optarg);
1811                         if (ret < 0) {
1812                                 printf("Invalid packet transfer mode\n");
1813                                 print_usage(prgname);
1814                                 return -1;
1815                         }
1816                         break;
1817
1818                 case CMD_LINE_OPT_SCHEDULE_TYPE_NUM:
1819                         ret = parse_schedule_type(eh_conf, optarg);
1820                         if (ret < 0) {
1821                                 printf("Invalid queue schedule type\n");
1822                                 print_usage(prgname);
1823                                 return -1;
1824                         }
1825                         break;
1826
1827                 case CMD_LINE_OPT_RX_OFFLOAD_NUM:
1828                         ret = parse_mask(optarg, &dev_rx_offload);
1829                         if (ret != 0) {
1830                                 printf("Invalid argument for \'%s\': %s\n",
1831                                         CMD_LINE_OPT_RX_OFFLOAD, optarg);
1832                                 print_usage(prgname);
1833                                 return -1;
1834                         }
1835                         break;
1836                 case CMD_LINE_OPT_TX_OFFLOAD_NUM:
1837                         ret = parse_mask(optarg, &dev_tx_offload);
1838                         if (ret != 0) {
1839                                 printf("Invalid argument for \'%s\': %s\n",
1840                                         CMD_LINE_OPT_TX_OFFLOAD, optarg);
1841                                 print_usage(prgname);
1842                                 return -1;
1843                         }
1844                         break;
1845                 case CMD_LINE_OPT_REASSEMBLE_NUM:
1846                         ret = parse_decimal(optarg);
1847                         if (ret < 0 || ret > UINT32_MAX) {
1848                                 printf("Invalid argument for \'%s\': %s\n",
1849                                         CMD_LINE_OPT_REASSEMBLE, optarg);
1850                                 print_usage(prgname);
1851                                 return -1;
1852                         }
1853                         frag_tbl_sz = ret;
1854                         break;
1855                 case CMD_LINE_OPT_MTU_NUM:
1856                         ret = parse_decimal(optarg);
1857                         if (ret < 0 || ret > RTE_IPV4_MAX_PKT_LEN) {
1858                                 printf("Invalid argument for \'%s\': %s\n",
1859                                         CMD_LINE_OPT_MTU, optarg);
1860                                 print_usage(prgname);
1861                                 return -1;
1862                         }
1863                         mtu_size = ret;
1864                         break;
1865                 case CMD_LINE_OPT_FRAG_TTL_NUM:
1866                         ret = parse_decimal(optarg);
1867                         if (ret < 0 || ret > MAX_FRAG_TTL_NS) {
1868                                 printf("Invalid argument for \'%s\': %s\n",
1869                                         CMD_LINE_OPT_MTU, optarg);
1870                                 print_usage(prgname);
1871                                 return -1;
1872                         }
1873                         frag_ttl_ns = ret;
1874                         break;
1875                 case CMD_LINE_OPT_EVENT_VECTOR_NUM:
1876                         em_conf = eh_conf->mode_params;
1877                         em_conf->ext_params.event_vector = 1;
1878                         break;
1879                 case CMD_LINE_OPT_VECTOR_SIZE_NUM:
1880                         ret = parse_decimal(optarg);
1881
1882                         if (ret > MAX_PKT_BURST) {
1883                                 printf("Invalid argument for \'%s\': %s\n",
1884                                         CMD_LINE_OPT_VECTOR_SIZE, optarg);
1885                                 print_usage(prgname);
1886                                 return -1;
1887                         }
1888                         em_conf = eh_conf->mode_params;
1889                         em_conf->ext_params.vector_size = ret;
1890                         break;
1891                 case CMD_LINE_OPT_VECTOR_TIMEOUT_NUM:
1892                         ret = parse_decimal(optarg);
1893
1894                         em_conf = eh_conf->mode_params;
1895                         em_conf->vector_tmo_ns = ret;
1896                         break;
1897                 default:
1898                         print_usage(prgname);
1899                         return -1;
1900                 }
1901         }
1902
1903         if (f_present == 0) {
1904                 printf("Mandatory option \"-f\" not present\n");
1905                 return -1;
1906         }
1907
1908         /* check do we need to enable multi-seg support */
1909         if (multi_seg_required()) {
1910                 /* legacy mode doesn't support multi-seg */
1911                 app_sa_prm.enable = 1;
1912                 printf("frame buf size: %u, mtu: %u, "
1913                         "number of reassemble entries: %u\n"
1914                         "multi-segment support is required\n",
1915                         frame_buf_size, mtu_size, frag_tbl_sz);
1916         }
1917
1918         print_app_sa_prm(&app_sa_prm);
1919
1920         if (optind >= 0)
1921                 argv[optind-1] = prgname;
1922
1923         ret = optind-1;
1924         optind = 1; /* reset getopt lib */
1925         return ret;
1926 }
1927
1928 static void
1929 print_ethaddr(const char *name, const struct rte_ether_addr *eth_addr)
1930 {
1931         char buf[RTE_ETHER_ADDR_FMT_SIZE];
1932         rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, eth_addr);
1933         printf("%s%s", name, buf);
1934 }
1935
1936 /*
1937  * Update destination ethaddr for the port.
1938  */
1939 int
1940 add_dst_ethaddr(uint16_t port, const struct rte_ether_addr *addr)
1941 {
1942         if (port >= RTE_DIM(ethaddr_tbl))
1943                 return -EINVAL;
1944
1945         ethaddr_tbl[port].dst = ETHADDR_TO_UINT64(addr);
1946         return 0;
1947 }
1948
1949 /* Check the link status of all ports in up to 9s, and print them finally */
1950 static void
1951 check_all_ports_link_status(uint32_t port_mask)
1952 {
1953 #define CHECK_INTERVAL 100 /* 100ms */
1954 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
1955         uint16_t portid;
1956         uint8_t count, all_ports_up, print_flag = 0;
1957         struct rte_eth_link link;
1958         int ret;
1959         char link_status_text[RTE_ETH_LINK_MAX_STR_LEN];
1960
1961         printf("\nChecking link status");
1962         fflush(stdout);
1963         for (count = 0; count <= MAX_CHECK_TIME; count++) {
1964                 all_ports_up = 1;
1965                 RTE_ETH_FOREACH_DEV(portid) {
1966                         if ((port_mask & (1 << portid)) == 0)
1967                                 continue;
1968                         memset(&link, 0, sizeof(link));
1969                         ret = rte_eth_link_get_nowait(portid, &link);
1970                         if (ret < 0) {
1971                                 all_ports_up = 0;
1972                                 if (print_flag == 1)
1973                                         printf("Port %u link get failed: %s\n",
1974                                                 portid, rte_strerror(-ret));
1975                                 continue;
1976                         }
1977                         /* print link status if flag set */
1978                         if (print_flag == 1) {
1979                                 rte_eth_link_to_str(link_status_text,
1980                                         sizeof(link_status_text), &link);
1981                                 printf("Port %d %s\n", portid,
1982                                        link_status_text);
1983                                 continue;
1984                         }
1985                         /* clear all_ports_up flag if any link down */
1986                         if (link.link_status == RTE_ETH_LINK_DOWN) {
1987                                 all_ports_up = 0;
1988                                 break;
1989                         }
1990                 }
1991                 /* after finally printing all link status, get out */
1992                 if (print_flag == 1)
1993                         break;
1994
1995                 if (all_ports_up == 0) {
1996                         printf(".");
1997                         fflush(stdout);
1998                         rte_delay_ms(CHECK_INTERVAL);
1999                 }
2000
2001                 /* set the print_flag if all ports up or timeout */
2002                 if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
2003                         print_flag = 1;
2004                         printf("done\n");
2005                 }
2006         }
2007 }
2008
2009 static int32_t
2010 add_mapping(struct rte_hash *map, const char *str, uint16_t cdev_id,
2011                 uint16_t qp, struct lcore_params *params,
2012                 struct ipsec_ctx *ipsec_ctx,
2013                 const struct rte_cryptodev_capabilities *cipher,
2014                 const struct rte_cryptodev_capabilities *auth,
2015                 const struct rte_cryptodev_capabilities *aead)
2016 {
2017         int32_t ret = 0;
2018         unsigned long i;
2019         struct cdev_key key = { 0 };
2020
2021         key.lcore_id = params->lcore_id;
2022         if (cipher)
2023                 key.cipher_algo = cipher->sym.cipher.algo;
2024         if (auth)
2025                 key.auth_algo = auth->sym.auth.algo;
2026         if (aead)
2027                 key.aead_algo = aead->sym.aead.algo;
2028
2029         ret = rte_hash_lookup(map, &key);
2030         if (ret != -ENOENT)
2031                 return 0;
2032
2033         for (i = 0; i < ipsec_ctx->nb_qps; i++)
2034                 if (ipsec_ctx->tbl[i].id == cdev_id)
2035                         break;
2036
2037         if (i == ipsec_ctx->nb_qps) {
2038                 if (ipsec_ctx->nb_qps == MAX_QP_PER_LCORE) {
2039                         printf("Maximum number of crypto devices assigned to "
2040                                 "a core, increase MAX_QP_PER_LCORE value\n");
2041                         return 0;
2042                 }
2043                 ipsec_ctx->tbl[i].id = cdev_id;
2044                 ipsec_ctx->tbl[i].qp = qp;
2045                 ipsec_ctx->nb_qps++;
2046                 printf("%s cdev mapping: lcore %u using cdev %u qp %u "
2047                                 "(cdev_id_qp %lu)\n", str, key.lcore_id,
2048                                 cdev_id, qp, i);
2049         }
2050
2051         ret = rte_hash_add_key_data(map, &key, (void *)i);
2052         if (ret < 0) {
2053                 printf("Failed to insert cdev mapping for (lcore %u, "
2054                                 "cdev %u, qp %u), errno %d\n",
2055                                 key.lcore_id, ipsec_ctx->tbl[i].id,
2056                                 ipsec_ctx->tbl[i].qp, ret);
2057                 return 0;
2058         }
2059
2060         return 1;
2061 }
2062
2063 static int32_t
2064 add_cdev_mapping(struct rte_cryptodev_info *dev_info, uint16_t cdev_id,
2065                 uint16_t qp, struct lcore_params *params)
2066 {
2067         int32_t ret = 0;
2068         const struct rte_cryptodev_capabilities *i, *j;
2069         struct rte_hash *map;
2070         struct lcore_conf *qconf;
2071         struct ipsec_ctx *ipsec_ctx;
2072         const char *str;
2073
2074         qconf = &lcore_conf[params->lcore_id];
2075
2076         if ((unprotected_port_mask & (1 << params->port_id)) == 0) {
2077                 map = cdev_map_out;
2078                 ipsec_ctx = &qconf->outbound;
2079                 str = "Outbound";
2080         } else {
2081                 map = cdev_map_in;
2082                 ipsec_ctx = &qconf->inbound;
2083                 str = "Inbound";
2084         }
2085
2086         /* Required cryptodevs with operation chaining */
2087         if (!(dev_info->feature_flags &
2088                                 RTE_CRYPTODEV_FF_SYM_OPERATION_CHAINING))
2089                 return ret;
2090
2091         for (i = dev_info->capabilities;
2092                         i->op != RTE_CRYPTO_OP_TYPE_UNDEFINED; i++) {
2093                 if (i->op != RTE_CRYPTO_OP_TYPE_SYMMETRIC)
2094                         continue;
2095
2096                 if (i->sym.xform_type == RTE_CRYPTO_SYM_XFORM_AEAD) {
2097                         ret |= add_mapping(map, str, cdev_id, qp, params,
2098                                         ipsec_ctx, NULL, NULL, i);
2099                         continue;
2100                 }
2101
2102                 if (i->sym.xform_type != RTE_CRYPTO_SYM_XFORM_CIPHER)
2103                         continue;
2104
2105                 for (j = dev_info->capabilities;
2106                                 j->op != RTE_CRYPTO_OP_TYPE_UNDEFINED; j++) {
2107                         if (j->op != RTE_CRYPTO_OP_TYPE_SYMMETRIC)
2108                                 continue;
2109
2110                         if (j->sym.xform_type != RTE_CRYPTO_SYM_XFORM_AUTH)
2111                                 continue;
2112
2113                         ret |= add_mapping(map, str, cdev_id, qp, params,
2114                                                 ipsec_ctx, i, j, NULL);
2115                 }
2116         }
2117
2118         return ret;
2119 }
2120
2121 /* Check if the device is enabled by cryptodev_mask */
2122 static int
2123 check_cryptodev_mask(uint8_t cdev_id)
2124 {
2125         if (enabled_cryptodev_mask & (1 << cdev_id))
2126                 return 0;
2127
2128         return -1;
2129 }
2130
2131 static uint16_t
2132 cryptodevs_init(uint16_t req_queue_num)
2133 {
2134         struct rte_cryptodev_config dev_conf;
2135         struct rte_cryptodev_qp_conf qp_conf;
2136         uint16_t idx, max_nb_qps, qp, total_nb_qps, i;
2137         int16_t cdev_id;
2138         struct rte_hash_parameters params = { 0 };
2139
2140         const uint64_t mseg_flag = multi_seg_required() ?
2141                                 RTE_CRYPTODEV_FF_IN_PLACE_SGL : 0;
2142
2143         params.entries = CDEV_MAP_ENTRIES;
2144         params.key_len = sizeof(struct cdev_key);
2145         params.hash_func = rte_jhash;
2146         params.hash_func_init_val = 0;
2147         params.socket_id = rte_socket_id();
2148
2149         params.name = "cdev_map_in";
2150         cdev_map_in = rte_hash_create(&params);
2151         if (cdev_map_in == NULL)
2152                 rte_panic("Failed to create cdev_map hash table, errno = %d\n",
2153                                 rte_errno);
2154
2155         params.name = "cdev_map_out";
2156         cdev_map_out = rte_hash_create(&params);
2157         if (cdev_map_out == NULL)
2158                 rte_panic("Failed to create cdev_map hash table, errno = %d\n",
2159                                 rte_errno);
2160
2161         printf("lcore/cryptodev/qp mappings:\n");
2162
2163         idx = 0;
2164         total_nb_qps = 0;
2165         for (cdev_id = 0; cdev_id < rte_cryptodev_count(); cdev_id++) {
2166                 struct rte_cryptodev_info cdev_info;
2167
2168                 if (check_cryptodev_mask((uint8_t)cdev_id))
2169                         continue;
2170
2171                 rte_cryptodev_info_get(cdev_id, &cdev_info);
2172
2173                 if ((mseg_flag & cdev_info.feature_flags) != mseg_flag)
2174                         rte_exit(EXIT_FAILURE,
2175                                 "Device %hd does not support \'%s\' feature\n",
2176                                 cdev_id,
2177                                 rte_cryptodev_get_feature_name(mseg_flag));
2178
2179                 if (nb_lcore_params > cdev_info.max_nb_queue_pairs)
2180                         max_nb_qps = cdev_info.max_nb_queue_pairs;
2181                 else
2182                         max_nb_qps = nb_lcore_params;
2183
2184                 qp = 0;
2185                 i = 0;
2186                 while (qp < max_nb_qps && i < nb_lcore_params) {
2187                         if (add_cdev_mapping(&cdev_info, cdev_id, qp,
2188                                                 &lcore_params[idx]))
2189                                 qp++;
2190                         idx++;
2191                         idx = idx % nb_lcore_params;
2192                         i++;
2193                 }
2194
2195                 qp = RTE_MIN(max_nb_qps, RTE_MAX(req_queue_num, qp));
2196                 if (qp == 0)
2197                         continue;
2198
2199                 total_nb_qps += qp;
2200                 dev_conf.socket_id = rte_cryptodev_socket_id(cdev_id);
2201                 dev_conf.nb_queue_pairs = qp;
2202                 dev_conf.ff_disable = RTE_CRYPTODEV_FF_ASYMMETRIC_CRYPTO;
2203
2204                 uint32_t dev_max_sess = cdev_info.sym.max_nb_sessions;
2205                 if (dev_max_sess != 0 &&
2206                                 dev_max_sess < get_nb_crypto_sessions())
2207                         rte_exit(EXIT_FAILURE,
2208                                 "Device does not support at least %u "
2209                                 "sessions", get_nb_crypto_sessions());
2210
2211                 if (rte_cryptodev_configure(cdev_id, &dev_conf))
2212                         rte_panic("Failed to initialize cryptodev %u\n",
2213                                         cdev_id);
2214
2215                 qp_conf.nb_descriptors = CDEV_QUEUE_DESC;
2216                 qp_conf.mp_session =
2217                         socket_ctx[dev_conf.socket_id].session_pool;
2218                 qp_conf.mp_session_private =
2219                         socket_ctx[dev_conf.socket_id].session_priv_pool;
2220                 for (qp = 0; qp < dev_conf.nb_queue_pairs; qp++)
2221                         if (rte_cryptodev_queue_pair_setup(cdev_id, qp,
2222                                         &qp_conf, dev_conf.socket_id))
2223                                 rte_panic("Failed to setup queue %u for "
2224                                                 "cdev_id %u\n", 0, cdev_id);
2225
2226                 if (rte_cryptodev_start(cdev_id))
2227                         rte_panic("Failed to start cryptodev %u\n",
2228                                         cdev_id);
2229         }
2230
2231         printf("\n");
2232
2233         return total_nb_qps;
2234 }
2235
2236 static void
2237 port_init(uint16_t portid, uint64_t req_rx_offloads, uint64_t req_tx_offloads)
2238 {
2239         struct rte_eth_dev_info dev_info;
2240         struct rte_eth_txconf *txconf;
2241         uint16_t nb_tx_queue, nb_rx_queue;
2242         uint16_t tx_queueid, rx_queueid, queue, lcore_id;
2243         int32_t ret, socket_id;
2244         struct lcore_conf *qconf;
2245         struct rte_ether_addr ethaddr;
2246         struct rte_eth_conf local_port_conf = port_conf;
2247
2248         ret = rte_eth_dev_info_get(portid, &dev_info);
2249         if (ret != 0)
2250                 rte_exit(EXIT_FAILURE,
2251                         "Error during getting device (port %u) info: %s\n",
2252                         portid, strerror(-ret));
2253
2254         /* limit allowed HW offloads, as user requested */
2255         dev_info.rx_offload_capa &= dev_rx_offload;
2256         dev_info.tx_offload_capa &= dev_tx_offload;
2257
2258         printf("Configuring device port %u:\n", portid);
2259
2260         ret = rte_eth_macaddr_get(portid, &ethaddr);
2261         if (ret != 0)
2262                 rte_exit(EXIT_FAILURE,
2263                         "Error getting MAC address (port %u): %s\n",
2264                         portid, rte_strerror(-ret));
2265
2266         ethaddr_tbl[portid].src = ETHADDR_TO_UINT64(&ethaddr);
2267         print_ethaddr("Address: ", &ethaddr);
2268         printf("\n");
2269
2270         nb_rx_queue = get_port_nb_rx_queues(portid);
2271         nb_tx_queue = nb_lcores;
2272
2273         if (nb_rx_queue > dev_info.max_rx_queues)
2274                 rte_exit(EXIT_FAILURE, "Error: queue %u not available "
2275                                 "(max rx queue is %u)\n",
2276                                 nb_rx_queue, dev_info.max_rx_queues);
2277
2278         if (nb_tx_queue > dev_info.max_tx_queues)
2279                 rte_exit(EXIT_FAILURE, "Error: queue %u not available "
2280                                 "(max tx queue is %u)\n",
2281                                 nb_tx_queue, dev_info.max_tx_queues);
2282
2283         printf("Creating queues: nb_rx_queue=%d nb_tx_queue=%u...\n",
2284                         nb_rx_queue, nb_tx_queue);
2285
2286         local_port_conf.rxmode.mtu = mtu_size;
2287
2288         if (multi_seg_required()) {
2289                 local_port_conf.rxmode.offloads |= RTE_ETH_RX_OFFLOAD_SCATTER;
2290                 local_port_conf.txmode.offloads |= RTE_ETH_TX_OFFLOAD_MULTI_SEGS;
2291         }
2292
2293         local_port_conf.rxmode.offloads |= req_rx_offloads;
2294         local_port_conf.txmode.offloads |= req_tx_offloads;
2295
2296         /* Check that all required capabilities are supported */
2297         if ((local_port_conf.rxmode.offloads & dev_info.rx_offload_capa) !=
2298                         local_port_conf.rxmode.offloads)
2299                 rte_exit(EXIT_FAILURE,
2300                         "Error: port %u required RX offloads: 0x%" PRIx64
2301                         ", available RX offloads: 0x%" PRIx64 "\n",
2302                         portid, local_port_conf.rxmode.offloads,
2303                         dev_info.rx_offload_capa);
2304
2305         if ((local_port_conf.txmode.offloads & dev_info.tx_offload_capa) !=
2306                         local_port_conf.txmode.offloads)
2307                 rte_exit(EXIT_FAILURE,
2308                         "Error: port %u required TX offloads: 0x%" PRIx64
2309                         ", available TX offloads: 0x%" PRIx64 "\n",
2310                         portid, local_port_conf.txmode.offloads,
2311                         dev_info.tx_offload_capa);
2312
2313         if (dev_info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE)
2314                 local_port_conf.txmode.offloads |=
2315                         RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE;
2316
2317         if (dev_info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_IPV4_CKSUM)
2318                 local_port_conf.txmode.offloads |= RTE_ETH_TX_OFFLOAD_IPV4_CKSUM;
2319
2320         printf("port %u configuring rx_offloads=0x%" PRIx64
2321                 ", tx_offloads=0x%" PRIx64 "\n",
2322                 portid, local_port_conf.rxmode.offloads,
2323                 local_port_conf.txmode.offloads);
2324
2325         local_port_conf.rx_adv_conf.rss_conf.rss_hf &=
2326                 dev_info.flow_type_rss_offloads;
2327         if (local_port_conf.rx_adv_conf.rss_conf.rss_hf !=
2328                         port_conf.rx_adv_conf.rss_conf.rss_hf) {
2329                 printf("Port %u modified RSS hash function based on hardware support,"
2330                         "requested:%#"PRIx64" configured:%#"PRIx64"\n",
2331                         portid,
2332                         port_conf.rx_adv_conf.rss_conf.rss_hf,
2333                         local_port_conf.rx_adv_conf.rss_conf.rss_hf);
2334         }
2335
2336         ret = rte_eth_dev_configure(portid, nb_rx_queue, nb_tx_queue,
2337                         &local_port_conf);
2338         if (ret < 0)
2339                 rte_exit(EXIT_FAILURE, "Cannot configure device: "
2340                                 "err=%d, port=%d\n", ret, portid);
2341
2342         ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd, &nb_txd);
2343         if (ret < 0)
2344                 rte_exit(EXIT_FAILURE, "Cannot adjust number of descriptors: "
2345                                 "err=%d, port=%d\n", ret, portid);
2346
2347         /* init one TX queue per lcore */
2348         tx_queueid = 0;
2349         for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
2350                 if (rte_lcore_is_enabled(lcore_id) == 0)
2351                         continue;
2352
2353                 if (numa_on)
2354                         socket_id = (uint8_t)rte_lcore_to_socket_id(lcore_id);
2355                 else
2356                         socket_id = 0;
2357
2358                 /* init TX queue */
2359                 printf("Setup txq=%u,%d,%d\n", lcore_id, tx_queueid, socket_id);
2360
2361                 txconf = &dev_info.default_txconf;
2362                 txconf->offloads = local_port_conf.txmode.offloads;
2363
2364                 ret = rte_eth_tx_queue_setup(portid, tx_queueid, nb_txd,
2365                                 socket_id, txconf);
2366                 if (ret < 0)
2367                         rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup: "
2368                                         "err=%d, port=%d\n", ret, portid);
2369
2370                 qconf = &lcore_conf[lcore_id];
2371                 qconf->tx_queue_id[portid] = tx_queueid;
2372
2373                 /* Pre-populate pkt offloads based on capabilities */
2374                 qconf->outbound.ipv4_offloads = RTE_MBUF_F_TX_IPV4;
2375                 qconf->outbound.ipv6_offloads = RTE_MBUF_F_TX_IPV6;
2376                 if (local_port_conf.txmode.offloads & RTE_ETH_TX_OFFLOAD_IPV4_CKSUM)
2377                         qconf->outbound.ipv4_offloads |= RTE_MBUF_F_TX_IP_CKSUM;
2378
2379                 tx_queueid++;
2380
2381                 /* init RX queues */
2382                 for (queue = 0; queue < qconf->nb_rx_queue; ++queue) {
2383                         struct rte_eth_rxconf rxq_conf;
2384
2385                         if (portid != qconf->rx_queue_list[queue].port_id)
2386                                 continue;
2387
2388                         rx_queueid = qconf->rx_queue_list[queue].queue_id;
2389
2390                         printf("Setup rxq=%d,%d,%d\n", portid, rx_queueid,
2391                                         socket_id);
2392
2393                         rxq_conf = dev_info.default_rxconf;
2394                         rxq_conf.offloads = local_port_conf.rxmode.offloads;
2395                         ret = rte_eth_rx_queue_setup(portid, rx_queueid,
2396                                         nb_rxd, socket_id, &rxq_conf,
2397                                         socket_ctx[socket_id].mbuf_pool);
2398                         if (ret < 0)
2399                                 rte_exit(EXIT_FAILURE,
2400                                         "rte_eth_rx_queue_setup: err=%d, "
2401                                         "port=%d\n", ret, portid);
2402                 }
2403         }
2404         printf("\n");
2405 }
2406
2407 static size_t
2408 max_session_size(void)
2409 {
2410         size_t max_sz, sz;
2411         void *sec_ctx;
2412         int16_t cdev_id, port_id, n;
2413
2414         max_sz = 0;
2415         n =  rte_cryptodev_count();
2416         for (cdev_id = 0; cdev_id != n; cdev_id++) {
2417                 sz = rte_cryptodev_sym_get_private_session_size(cdev_id);
2418                 if (sz > max_sz)
2419                         max_sz = sz;
2420                 /*
2421                  * If crypto device is security capable, need to check the
2422                  * size of security session as well.
2423                  */
2424
2425                 /* Get security context of the crypto device */
2426                 sec_ctx = rte_cryptodev_get_sec_ctx(cdev_id);
2427                 if (sec_ctx == NULL)
2428                         continue;
2429
2430                 /* Get size of security session */
2431                 sz = rte_security_session_get_size(sec_ctx);
2432                 if (sz > max_sz)
2433                         max_sz = sz;
2434         }
2435
2436         RTE_ETH_FOREACH_DEV(port_id) {
2437                 if ((enabled_port_mask & (1 << port_id)) == 0)
2438                         continue;
2439
2440                 sec_ctx = rte_eth_dev_get_sec_ctx(port_id);
2441                 if (sec_ctx == NULL)
2442                         continue;
2443
2444                 sz = rte_security_session_get_size(sec_ctx);
2445                 if (sz > max_sz)
2446                         max_sz = sz;
2447         }
2448
2449         return max_sz;
2450 }
2451
2452 static void
2453 session_pool_init(struct socket_ctx *ctx, int32_t socket_id, size_t sess_sz)
2454 {
2455         char mp_name[RTE_MEMPOOL_NAMESIZE];
2456         struct rte_mempool *sess_mp;
2457         uint32_t nb_sess;
2458
2459         snprintf(mp_name, RTE_MEMPOOL_NAMESIZE,
2460                         "sess_mp_%u", socket_id);
2461         nb_sess = (get_nb_crypto_sessions() + CDEV_MP_CACHE_SZ *
2462                 rte_lcore_count());
2463         nb_sess = RTE_MAX(nb_sess, CDEV_MP_CACHE_SZ *
2464                         CDEV_MP_CACHE_MULTIPLIER);
2465         sess_mp = rte_cryptodev_sym_session_pool_create(
2466                         mp_name, nb_sess, sess_sz, CDEV_MP_CACHE_SZ, 0,
2467                         socket_id);
2468         ctx->session_pool = sess_mp;
2469
2470         if (ctx->session_pool == NULL)
2471                 rte_exit(EXIT_FAILURE,
2472                         "Cannot init session pool on socket %d\n", socket_id);
2473         else
2474                 printf("Allocated session pool on socket %d\n", socket_id);
2475 }
2476
2477 static void
2478 session_priv_pool_init(struct socket_ctx *ctx, int32_t socket_id,
2479         size_t sess_sz)
2480 {
2481         char mp_name[RTE_MEMPOOL_NAMESIZE];
2482         struct rte_mempool *sess_mp;
2483         uint32_t nb_sess;
2484
2485         snprintf(mp_name, RTE_MEMPOOL_NAMESIZE,
2486                         "sess_mp_priv_%u", socket_id);
2487         nb_sess = (get_nb_crypto_sessions() + CDEV_MP_CACHE_SZ *
2488                 rte_lcore_count());
2489         nb_sess = RTE_MAX(nb_sess, CDEV_MP_CACHE_SZ *
2490                         CDEV_MP_CACHE_MULTIPLIER);
2491         sess_mp = rte_mempool_create(mp_name,
2492                         nb_sess,
2493                         sess_sz,
2494                         CDEV_MP_CACHE_SZ,
2495                         0, NULL, NULL, NULL,
2496                         NULL, socket_id,
2497                         0);
2498         ctx->session_priv_pool = sess_mp;
2499
2500         if (ctx->session_priv_pool == NULL)
2501                 rte_exit(EXIT_FAILURE,
2502                         "Cannot init session priv pool on socket %d\n",
2503                         socket_id);
2504         else
2505                 printf("Allocated session priv pool on socket %d\n",
2506                         socket_id);
2507 }
2508
2509 static void
2510 pool_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t nb_mbuf)
2511 {
2512         char s[64];
2513         int32_t ms;
2514
2515         snprintf(s, sizeof(s), "mbuf_pool_%d", socket_id);
2516         ctx->mbuf_pool = rte_pktmbuf_pool_create(s, nb_mbuf,
2517                         MEMPOOL_CACHE_SIZE, ipsec_metadata_size(),
2518                         frame_buf_size, socket_id);
2519
2520         /*
2521          * if multi-segment support is enabled, then create a pool
2522          * for indirect mbufs.
2523          */
2524         ms = multi_seg_required();
2525         if (ms != 0) {
2526                 snprintf(s, sizeof(s), "mbuf_pool_indir_%d", socket_id);
2527                 ctx->mbuf_pool_indir = rte_pktmbuf_pool_create(s, nb_mbuf,
2528                         MEMPOOL_CACHE_SIZE, 0, 0, socket_id);
2529         }
2530
2531         if (ctx->mbuf_pool == NULL || (ms != 0 && ctx->mbuf_pool_indir == NULL))
2532                 rte_exit(EXIT_FAILURE, "Cannot init mbuf pool on socket %d\n",
2533                                 socket_id);
2534         else
2535                 printf("Allocated mbuf pool on socket %d\n", socket_id);
2536 }
2537
2538 static inline int
2539 inline_ipsec_event_esn_overflow(struct rte_security_ctx *ctx, uint64_t md)
2540 {
2541         struct ipsec_sa *sa;
2542
2543         /* For inline protocol processing, the metadata in the event will
2544          * uniquely identify the security session which raised the event.
2545          * Application would then need the userdata it had registered with the
2546          * security session to process the event.
2547          */
2548
2549         sa = (struct ipsec_sa *)rte_security_get_userdata(ctx, md);
2550
2551         if (sa == NULL) {
2552                 /* userdata could not be retrieved */
2553                 return -1;
2554         }
2555
2556         /* Sequence number over flow. SA need to be re-established */
2557         RTE_SET_USED(sa);
2558         return 0;
2559 }
2560
2561 static int
2562 inline_ipsec_event_callback(uint16_t port_id, enum rte_eth_event_type type,
2563                  void *param, void *ret_param)
2564 {
2565         uint64_t md;
2566         struct rte_eth_event_ipsec_desc *event_desc = NULL;
2567         struct rte_security_ctx *ctx = (struct rte_security_ctx *)
2568                                         rte_eth_dev_get_sec_ctx(port_id);
2569
2570         RTE_SET_USED(param);
2571
2572         if (type != RTE_ETH_EVENT_IPSEC)
2573                 return -1;
2574
2575         event_desc = ret_param;
2576         if (event_desc == NULL) {
2577                 printf("Event descriptor not set\n");
2578                 return -1;
2579         }
2580
2581         md = event_desc->metadata;
2582
2583         if (event_desc->subtype == RTE_ETH_EVENT_IPSEC_ESN_OVERFLOW)
2584                 return inline_ipsec_event_esn_overflow(ctx, md);
2585         else if (event_desc->subtype >= RTE_ETH_EVENT_IPSEC_MAX) {
2586                 printf("Invalid IPsec event reported\n");
2587                 return -1;
2588         }
2589
2590         return -1;
2591 }
2592
2593 static int
2594 ethdev_reset_event_callback(uint16_t port_id,
2595                 enum rte_eth_event_type type,
2596                  void *param __rte_unused, void *ret_param __rte_unused)
2597 {
2598         printf("Reset Event on port id %d type %d\n", port_id, type);
2599         printf("Force quit application");
2600         force_quit = true;
2601         return 0;
2602 }
2603
2604 static uint16_t
2605 rx_callback(__rte_unused uint16_t port, __rte_unused uint16_t queue,
2606         struct rte_mbuf *pkt[], uint16_t nb_pkts,
2607         __rte_unused uint16_t max_pkts, void *user_param)
2608 {
2609         uint64_t tm;
2610         uint32_t i, k;
2611         struct lcore_conf *lc;
2612         struct rte_mbuf *mb;
2613         struct rte_ether_hdr *eth;
2614
2615         lc = user_param;
2616         k = 0;
2617         tm = 0;
2618
2619         for (i = 0; i != nb_pkts; i++) {
2620
2621                 mb = pkt[i];
2622                 eth = rte_pktmbuf_mtod(mb, struct rte_ether_hdr *);
2623                 if (eth->ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) {
2624
2625                         struct rte_ipv4_hdr *iph;
2626
2627                         iph = (struct rte_ipv4_hdr *)(eth + 1);
2628                         if (rte_ipv4_frag_pkt_is_fragmented(iph)) {
2629
2630                                 mb->l2_len = sizeof(*eth);
2631                                 mb->l3_len = sizeof(*iph);
2632                                 tm = (tm != 0) ? tm : rte_rdtsc();
2633                                 mb = rte_ipv4_frag_reassemble_packet(
2634                                         lc->frag.tbl, &lc->frag.dr,
2635                                         mb, tm, iph);
2636
2637                                 if (mb != NULL) {
2638                                         /* fix ip cksum after reassemble. */
2639                                         iph = rte_pktmbuf_mtod_offset(mb,
2640                                                 struct rte_ipv4_hdr *,
2641                                                 mb->l2_len);
2642                                         iph->hdr_checksum = 0;
2643                                         iph->hdr_checksum = rte_ipv4_cksum(iph);
2644                                 }
2645                         }
2646                 } else if (eth->ether_type ==
2647                                 rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6)) {
2648
2649                         struct rte_ipv6_hdr *iph;
2650                         struct rte_ipv6_fragment_ext *fh;
2651
2652                         iph = (struct rte_ipv6_hdr *)(eth + 1);
2653                         fh = rte_ipv6_frag_get_ipv6_fragment_header(iph);
2654                         if (fh != NULL) {
2655                                 mb->l2_len = sizeof(*eth);
2656                                 mb->l3_len = (uintptr_t)fh - (uintptr_t)iph +
2657                                         sizeof(*fh);
2658                                 tm = (tm != 0) ? tm : rte_rdtsc();
2659                                 mb = rte_ipv6_frag_reassemble_packet(
2660                                         lc->frag.tbl, &lc->frag.dr,
2661                                         mb, tm, iph, fh);
2662                                 if (mb != NULL)
2663                                         /* fix l3_len after reassemble. */
2664                                         mb->l3_len = mb->l3_len - sizeof(*fh);
2665                         }
2666                 }
2667
2668                 pkt[k] = mb;
2669                 k += (mb != NULL);
2670         }
2671
2672         /* some fragments were encountered, drain death row */
2673         if (tm != 0)
2674                 rte_ip_frag_free_death_row(&lc->frag.dr, 0);
2675
2676         return k;
2677 }
2678
2679
2680 static int
2681 reassemble_lcore_init(struct lcore_conf *lc, uint32_t cid)
2682 {
2683         int32_t sid;
2684         uint32_t i;
2685         uint64_t frag_cycles;
2686         const struct lcore_rx_queue *rxq;
2687         const struct rte_eth_rxtx_callback *cb;
2688
2689         /* create fragment table */
2690         sid = rte_lcore_to_socket_id(cid);
2691         frag_cycles = (rte_get_tsc_hz() + NS_PER_S - 1) /
2692                 NS_PER_S * frag_ttl_ns;
2693
2694         lc->frag.tbl = rte_ip_frag_table_create(frag_tbl_sz,
2695                 FRAG_TBL_BUCKET_ENTRIES, frag_tbl_sz, frag_cycles, sid);
2696         if (lc->frag.tbl == NULL) {
2697                 printf("%s(%u): failed to create fragment table of size: %u, "
2698                         "error code: %d\n",
2699                         __func__, cid, frag_tbl_sz, rte_errno);
2700                 return -ENOMEM;
2701         }
2702
2703         /* setup reassemble RX callbacks for all queues */
2704         for (i = 0; i != lc->nb_rx_queue; i++) {
2705
2706                 rxq = lc->rx_queue_list + i;
2707                 cb = rte_eth_add_rx_callback(rxq->port_id, rxq->queue_id,
2708                         rx_callback, lc);
2709                 if (cb == NULL) {
2710                         printf("%s(%u): failed to install RX callback for "
2711                                 "portid=%u, queueid=%u, error code: %d\n",
2712                                 __func__, cid,
2713                                 rxq->port_id, rxq->queue_id, rte_errno);
2714                         return -ENOMEM;
2715                 }
2716         }
2717
2718         return 0;
2719 }
2720
2721 static int
2722 reassemble_init(void)
2723 {
2724         int32_t rc;
2725         uint32_t i, lc;
2726
2727         rc = 0;
2728         for (i = 0; i != nb_lcore_params; i++) {
2729                 lc = lcore_params[i].lcore_id;
2730                 rc = reassemble_lcore_init(lcore_conf + lc, lc);
2731                 if (rc != 0)
2732                         break;
2733         }
2734
2735         return rc;
2736 }
2737
2738 static void
2739 create_default_ipsec_flow(uint16_t port_id, uint64_t rx_offloads)
2740 {
2741         struct rte_flow_action action[2];
2742         struct rte_flow_item pattern[2];
2743         struct rte_flow_attr attr = {0};
2744         struct rte_flow_error err;
2745         struct rte_flow *flow;
2746         int ret;
2747
2748         if (!(rx_offloads & RTE_ETH_RX_OFFLOAD_SECURITY))
2749                 return;
2750
2751         /* Add the default rte_flow to enable SECURITY for all ESP packets */
2752
2753         pattern[0].type = RTE_FLOW_ITEM_TYPE_ESP;
2754         pattern[0].spec = NULL;
2755         pattern[0].mask = NULL;
2756         pattern[0].last = NULL;
2757         pattern[1].type = RTE_FLOW_ITEM_TYPE_END;
2758
2759         action[0].type = RTE_FLOW_ACTION_TYPE_SECURITY;
2760         action[0].conf = NULL;
2761         action[1].type = RTE_FLOW_ACTION_TYPE_END;
2762         action[1].conf = NULL;
2763
2764         attr.ingress = 1;
2765
2766         ret = rte_flow_validate(port_id, &attr, pattern, action, &err);
2767         if (ret)
2768                 return;
2769
2770         flow = rte_flow_create(port_id, &attr, pattern, action, &err);
2771         if (flow == NULL)
2772                 return;
2773
2774         flow_info_tbl[port_id].rx_def_flow = flow;
2775         RTE_LOG(INFO, IPSEC,
2776                 "Created default flow enabling SECURITY for all ESP traffic on port %d\n",
2777                 port_id);
2778 }
2779
2780 static void
2781 signal_handler(int signum)
2782 {
2783         if (signum == SIGINT || signum == SIGTERM) {
2784                 printf("\n\nSignal %d received, preparing to exit...\n",
2785                                 signum);
2786                 force_quit = true;
2787         }
2788 }
2789
2790 static void
2791 ev_mode_sess_verify(struct ipsec_sa *sa, int nb_sa)
2792 {
2793         struct rte_ipsec_session *ips;
2794         int32_t i;
2795
2796         if (!sa || !nb_sa)
2797                 return;
2798
2799         for (i = 0; i < nb_sa; i++) {
2800                 ips = ipsec_get_primary_session(&sa[i]);
2801                 if (ips->type != RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL)
2802                         rte_exit(EXIT_FAILURE, "Event mode supports only "
2803                                  "inline protocol sessions\n");
2804         }
2805
2806 }
2807
2808 static int32_t
2809 check_event_mode_params(struct eh_conf *eh_conf)
2810 {
2811         struct eventmode_conf *em_conf = NULL;
2812         struct lcore_params *params;
2813         uint16_t portid;
2814
2815         if (!eh_conf || !eh_conf->mode_params)
2816                 return -EINVAL;
2817
2818         /* Get eventmode conf */
2819         em_conf = eh_conf->mode_params;
2820
2821         if (eh_conf->mode == EH_PKT_TRANSFER_MODE_POLL &&
2822             em_conf->ext_params.sched_type != SCHED_TYPE_NOT_SET) {
2823                 printf("error: option --event-schedule-type applies only to "
2824                        "event mode\n");
2825                 return -EINVAL;
2826         }
2827
2828         if (eh_conf->mode != EH_PKT_TRANSFER_MODE_EVENT)
2829                 return 0;
2830
2831         /* Set schedule type to ORDERED if it wasn't explicitly set by user */
2832         if (em_conf->ext_params.sched_type == SCHED_TYPE_NOT_SET)
2833                 em_conf->ext_params.sched_type = RTE_SCHED_TYPE_ORDERED;
2834
2835         /*
2836          * Event mode currently supports only inline protocol sessions.
2837          * If there are other types of sessions configured then exit with
2838          * error.
2839          */
2840         ev_mode_sess_verify(sa_in, nb_sa_in);
2841         ev_mode_sess_verify(sa_out, nb_sa_out);
2842
2843
2844         /* Option --config does not apply to event mode */
2845         if (nb_lcore_params > 0) {
2846                 printf("error: option --config applies only to poll mode\n");
2847                 return -EINVAL;
2848         }
2849
2850         /*
2851          * In order to use the same port_init routine for both poll and event
2852          * modes initialize lcore_params with one queue for each eth port
2853          */
2854         lcore_params = lcore_params_array;
2855         RTE_ETH_FOREACH_DEV(portid) {
2856                 if ((enabled_port_mask & (1 << portid)) == 0)
2857                         continue;
2858
2859                 params = &lcore_params[nb_lcore_params++];
2860                 params->port_id = portid;
2861                 params->queue_id = 0;
2862                 params->lcore_id = rte_get_next_lcore(0, 0, 1);
2863         }
2864
2865         return 0;
2866 }
2867
2868 static void
2869 inline_sessions_free(struct sa_ctx *sa_ctx)
2870 {
2871         struct rte_ipsec_session *ips;
2872         struct ipsec_sa *sa;
2873         int32_t ret;
2874         uint32_t i;
2875
2876         if (!sa_ctx)
2877                 return;
2878
2879         for (i = 0; i < sa_ctx->nb_sa; i++) {
2880
2881                 sa = &sa_ctx->sa[i];
2882                 if (!sa->spi)
2883                         continue;
2884
2885                 ips = ipsec_get_primary_session(sa);
2886                 if (ips->type != RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL &&
2887                     ips->type != RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO)
2888                         continue;
2889
2890                 if (!rte_eth_dev_is_valid_port(sa->portid))
2891                         continue;
2892
2893                 ret = rte_security_session_destroy(
2894                                 rte_eth_dev_get_sec_ctx(sa->portid),
2895                                 ips->security.ses);
2896                 if (ret)
2897                         RTE_LOG(ERR, IPSEC, "Failed to destroy security "
2898                                             "session type %d, spi %d\n",
2899                                             ips->type, sa->spi);
2900         }
2901 }
2902
2903 static uint32_t
2904 calculate_nb_mbufs(uint16_t nb_ports, uint16_t nb_crypto_qp, uint32_t nb_rxq,
2905                 uint32_t nb_txq)
2906 {
2907         return RTE_MAX((nb_rxq * nb_rxd +
2908                         nb_ports * nb_lcores * MAX_PKT_BURST +
2909                         nb_ports * nb_txq * nb_txd +
2910                         nb_lcores * MEMPOOL_CACHE_SIZE +
2911                         nb_crypto_qp * CDEV_QUEUE_DESC +
2912                         nb_lcores * frag_tbl_sz *
2913                         FRAG_TBL_BUCKET_ENTRIES),
2914                        8192U);
2915 }
2916
2917
2918 static int
2919 handle_telemetry_cmd_ipsec_secgw_stats(const char *cmd __rte_unused,
2920                 const char *params, struct rte_tel_data *data)
2921 {
2922         uint64_t total_pkts_dropped = 0, total_pkts_tx = 0, total_pkts_rx = 0;
2923         unsigned int coreid;
2924
2925         rte_tel_data_start_dict(data);
2926
2927         if (params) {
2928                 coreid = (uint32_t)atoi(params);
2929                 if (rte_lcore_is_enabled(coreid) == 0)
2930                         return -EINVAL;
2931
2932                 total_pkts_dropped = core_statistics[coreid].dropped;
2933                 total_pkts_tx = core_statistics[coreid].tx;
2934                 total_pkts_rx = core_statistics[coreid].rx;
2935
2936         } else {
2937                 for (coreid = 0; coreid < RTE_MAX_LCORE; coreid++) {
2938
2939                         /* skip disabled cores */
2940                         if (rte_lcore_is_enabled(coreid) == 0)
2941                                 continue;
2942
2943                         total_pkts_dropped += core_statistics[coreid].dropped;
2944                         total_pkts_tx += core_statistics[coreid].tx;
2945                         total_pkts_rx += core_statistics[coreid].rx;
2946                 }
2947         }
2948
2949         /* add telemetry key/values pairs */
2950         rte_tel_data_add_dict_u64(data, "packets received",
2951                                 total_pkts_rx);
2952
2953         rte_tel_data_add_dict_u64(data, "packets transmitted",
2954                                 total_pkts_tx);
2955
2956         rte_tel_data_add_dict_u64(data, "packets dropped",
2957                                 total_pkts_dropped);
2958
2959
2960         return 0;
2961 }
2962
2963 static void
2964 update_lcore_statistics(struct ipsec_core_statistics *total, uint32_t coreid)
2965 {
2966         struct ipsec_core_statistics *lcore_stats;
2967
2968         /* skip disabled cores */
2969         if (rte_lcore_is_enabled(coreid) == 0)
2970                 return;
2971
2972         lcore_stats = &core_statistics[coreid];
2973
2974         total->rx = lcore_stats->rx;
2975         total->dropped = lcore_stats->dropped;
2976         total->tx = lcore_stats->tx;
2977
2978         /* outbound stats */
2979         total->outbound.spd6.protect += lcore_stats->outbound.spd6.protect;
2980         total->outbound.spd6.bypass += lcore_stats->outbound.spd6.bypass;
2981         total->outbound.spd6.discard += lcore_stats->outbound.spd6.discard;
2982
2983         total->outbound.spd4.protect += lcore_stats->outbound.spd4.protect;
2984         total->outbound.spd4.bypass += lcore_stats->outbound.spd4.bypass;
2985         total->outbound.spd4.discard += lcore_stats->outbound.spd4.discard;
2986
2987         total->outbound.sad.miss += lcore_stats->outbound.sad.miss;
2988
2989         /* inbound stats */
2990         total->inbound.spd6.protect += lcore_stats->inbound.spd6.protect;
2991         total->inbound.spd6.bypass += lcore_stats->inbound.spd6.bypass;
2992         total->inbound.spd6.discard += lcore_stats->inbound.spd6.discard;
2993
2994         total->inbound.spd4.protect += lcore_stats->inbound.spd4.protect;
2995         total->inbound.spd4.bypass += lcore_stats->inbound.spd4.bypass;
2996         total->inbound.spd4.discard += lcore_stats->inbound.spd4.discard;
2997
2998         total->inbound.sad.miss += lcore_stats->inbound.sad.miss;
2999
3000
3001         /* routing stats */
3002         total->lpm4.miss += lcore_stats->lpm4.miss;
3003         total->lpm6.miss += lcore_stats->lpm6.miss;
3004 }
3005
3006 static void
3007 update_statistics(struct ipsec_core_statistics *total, uint32_t coreid)
3008 {
3009         memset(total, 0, sizeof(*total));
3010
3011         if (coreid != UINT32_MAX) {
3012                 update_lcore_statistics(total, coreid);
3013         } else {
3014                 for (coreid = 0; coreid < RTE_MAX_LCORE; coreid++)
3015                         update_lcore_statistics(total, coreid);
3016         }
3017 }
3018
3019 static int
3020 handle_telemetry_cmd_ipsec_secgw_stats_outbound(const char *cmd __rte_unused,
3021                 const char *params, struct rte_tel_data *data)
3022 {
3023         struct ipsec_core_statistics total_stats;
3024
3025         struct rte_tel_data *spd4_data = rte_tel_data_alloc();
3026         struct rte_tel_data *spd6_data = rte_tel_data_alloc();
3027         struct rte_tel_data *sad_data = rte_tel_data_alloc();
3028         unsigned int coreid = UINT32_MAX;
3029         int rc = 0;
3030
3031         /* verify allocated telemetry data structures */
3032         if (!spd4_data || !spd6_data || !sad_data) {
3033                 rc = -ENOMEM;
3034                 goto exit;
3035         }
3036
3037         /* initialize telemetry data structs as dicts */
3038         rte_tel_data_start_dict(data);
3039
3040         rte_tel_data_start_dict(spd4_data);
3041         rte_tel_data_start_dict(spd6_data);
3042         rte_tel_data_start_dict(sad_data);
3043
3044         if (params) {
3045                 coreid = (uint32_t)atoi(params);
3046                 if (rte_lcore_is_enabled(coreid) == 0) {
3047                         rc = -EINVAL;
3048                         goto exit;
3049                 }
3050         }
3051
3052         update_statistics(&total_stats, coreid);
3053
3054         /* add spd 4 telemetry key/values pairs */
3055
3056         rte_tel_data_add_dict_u64(spd4_data, "protect",
3057                 total_stats.outbound.spd4.protect);
3058         rte_tel_data_add_dict_u64(spd4_data, "bypass",
3059                 total_stats.outbound.spd4.bypass);
3060         rte_tel_data_add_dict_u64(spd4_data, "discard",
3061                 total_stats.outbound.spd4.discard);
3062
3063         rte_tel_data_add_dict_container(data, "spd4", spd4_data, 0);
3064
3065         /* add spd 6 telemetry key/values pairs */
3066
3067         rte_tel_data_add_dict_u64(spd6_data, "protect",
3068                 total_stats.outbound.spd6.protect);
3069         rte_tel_data_add_dict_u64(spd6_data, "bypass",
3070                 total_stats.outbound.spd6.bypass);
3071         rte_tel_data_add_dict_u64(spd6_data, "discard",
3072                 total_stats.outbound.spd6.discard);
3073
3074         rte_tel_data_add_dict_container(data, "spd6", spd6_data, 0);
3075
3076         /* add sad telemetry key/values pairs */
3077
3078         rte_tel_data_add_dict_u64(sad_data, "miss",
3079                 total_stats.outbound.sad.miss);
3080
3081         rte_tel_data_add_dict_container(data, "sad", sad_data, 0);
3082
3083 exit:
3084         if (rc) {
3085                 rte_tel_data_free(spd4_data);
3086                 rte_tel_data_free(spd6_data);
3087                 rte_tel_data_free(sad_data);
3088         }
3089         return rc;
3090 }
3091
3092 static int
3093 handle_telemetry_cmd_ipsec_secgw_stats_inbound(const char *cmd __rte_unused,
3094                 const char *params, struct rte_tel_data *data)
3095 {
3096         struct ipsec_core_statistics total_stats;
3097
3098         struct rte_tel_data *spd4_data = rte_tel_data_alloc();
3099         struct rte_tel_data *spd6_data = rte_tel_data_alloc();
3100         struct rte_tel_data *sad_data = rte_tel_data_alloc();
3101         unsigned int coreid = UINT32_MAX;
3102         int rc = 0;
3103
3104         /* verify allocated telemetry data structures */
3105         if (!spd4_data || !spd6_data || !sad_data) {
3106                 rc = -ENOMEM;
3107                 goto exit;
3108         }
3109
3110         /* initialize telemetry data structs as dicts */
3111         rte_tel_data_start_dict(data);
3112         rte_tel_data_start_dict(spd4_data);
3113         rte_tel_data_start_dict(spd6_data);
3114         rte_tel_data_start_dict(sad_data);
3115
3116         /* add children dicts to parent dict */
3117
3118         if (params) {
3119                 coreid = (uint32_t)atoi(params);
3120                 if (rte_lcore_is_enabled(coreid) == 0) {
3121                         rc = -EINVAL;
3122                         goto exit;
3123                 }
3124         }
3125
3126         update_statistics(&total_stats, coreid);
3127
3128         /* add sad telemetry key/values pairs */
3129
3130         rte_tel_data_add_dict_u64(sad_data, "miss",
3131                 total_stats.inbound.sad.miss);
3132
3133         rte_tel_data_add_dict_container(data, "sad", sad_data, 0);
3134
3135         /* add spd 4 telemetry key/values pairs */
3136
3137         rte_tel_data_add_dict_u64(spd4_data, "protect",
3138                 total_stats.inbound.spd4.protect);
3139         rte_tel_data_add_dict_u64(spd4_data, "bypass",
3140                 total_stats.inbound.spd4.bypass);
3141         rte_tel_data_add_dict_u64(spd4_data, "discard",
3142                 total_stats.inbound.spd4.discard);
3143
3144         rte_tel_data_add_dict_container(data, "spd4", spd4_data, 0);
3145
3146         /* add spd 6 telemetry key/values pairs */
3147
3148         rte_tel_data_add_dict_u64(spd6_data, "protect",
3149                 total_stats.inbound.spd6.protect);
3150         rte_tel_data_add_dict_u64(spd6_data, "bypass",
3151                 total_stats.inbound.spd6.bypass);
3152         rte_tel_data_add_dict_u64(spd6_data, "discard",
3153                 total_stats.inbound.spd6.discard);
3154
3155         rte_tel_data_add_dict_container(data, "spd6", spd6_data, 0);
3156
3157 exit:
3158         if (rc) {
3159                 rte_tel_data_free(spd4_data);
3160                 rte_tel_data_free(spd6_data);
3161                 rte_tel_data_free(sad_data);
3162         }
3163         return rc;
3164 }
3165
3166 static int
3167 handle_telemetry_cmd_ipsec_secgw_stats_routing(const char *cmd __rte_unused,
3168                 const char *params, struct rte_tel_data *data)
3169 {
3170         struct ipsec_core_statistics total_stats;
3171
3172         struct rte_tel_data *lpm4_data = rte_tel_data_alloc();
3173         struct rte_tel_data *lpm6_data = rte_tel_data_alloc();
3174         unsigned int coreid = UINT32_MAX;
3175         int rc = 0;
3176
3177         /* verify allocated telemetry data structures */
3178         if (!lpm4_data || !lpm6_data) {
3179                 rc = -ENOMEM;
3180                 goto exit;
3181         }
3182
3183         /* initialize telemetry data structs as dicts */
3184         rte_tel_data_start_dict(data);
3185         rte_tel_data_start_dict(lpm4_data);
3186         rte_tel_data_start_dict(lpm6_data);
3187
3188
3189         if (params) {
3190                 coreid = (uint32_t)atoi(params);
3191                 if (rte_lcore_is_enabled(coreid) == 0) {
3192                         rc = -EINVAL;
3193                         goto exit;
3194                 }
3195         }
3196
3197         update_statistics(&total_stats, coreid);
3198
3199         /* add lpm 4 telemetry key/values pairs */
3200         rte_tel_data_add_dict_u64(lpm4_data, "miss",
3201                 total_stats.lpm4.miss);
3202
3203         rte_tel_data_add_dict_container(data, "IPv4 LPM", lpm4_data, 0);
3204
3205         /* add lpm 6 telemetry key/values pairs */
3206         rte_tel_data_add_dict_u64(lpm6_data, "miss",
3207                 total_stats.lpm6.miss);
3208
3209         rte_tel_data_add_dict_container(data, "IPv6 LPM", lpm6_data, 0);
3210
3211 exit:
3212         if (rc) {
3213                 rte_tel_data_free(lpm4_data);
3214                 rte_tel_data_free(lpm6_data);
3215         }
3216         return rc;
3217 }
3218
3219 static void
3220 ipsec_secgw_telemetry_init(void)
3221 {
3222         rte_telemetry_register_cmd("/examples/ipsec-secgw/stats",
3223                 handle_telemetry_cmd_ipsec_secgw_stats,
3224                 "Returns global stats. "
3225                 "Optional Parameters: int <logical core id>");
3226
3227         rte_telemetry_register_cmd("/examples/ipsec-secgw/stats/outbound",
3228                 handle_telemetry_cmd_ipsec_secgw_stats_outbound,
3229                 "Returns outbound global stats. "
3230                 "Optional Parameters: int <logical core id>");
3231
3232         rte_telemetry_register_cmd("/examples/ipsec-secgw/stats/inbound",
3233                 handle_telemetry_cmd_ipsec_secgw_stats_inbound,
3234                 "Returns inbound global stats. "
3235                 "Optional Parameters: int <logical core id>");
3236
3237         rte_telemetry_register_cmd("/examples/ipsec-secgw/stats/routing",
3238                 handle_telemetry_cmd_ipsec_secgw_stats_routing,
3239                 "Returns routing stats. "
3240                 "Optional Parameters: int <logical core id>");
3241 }
3242
3243
3244 int32_t
3245 main(int32_t argc, char **argv)
3246 {
3247         int32_t ret;
3248         uint32_t lcore_id, nb_txq, nb_rxq = 0;
3249         uint32_t cdev_id;
3250         uint32_t i;
3251         uint8_t socket_id;
3252         uint16_t portid, nb_crypto_qp, nb_ports = 0;
3253         uint64_t req_rx_offloads[RTE_MAX_ETHPORTS];
3254         uint64_t req_tx_offloads[RTE_MAX_ETHPORTS];
3255         struct eh_conf *eh_conf = NULL;
3256         size_t sess_sz;
3257
3258         nb_bufs_in_pool = 0;
3259
3260         /* init EAL */
3261         ret = rte_eal_init(argc, argv);
3262         if (ret < 0)
3263                 rte_exit(EXIT_FAILURE, "Invalid EAL parameters\n");
3264         argc -= ret;
3265         argv += ret;
3266
3267         force_quit = false;
3268         signal(SIGINT, signal_handler);
3269         signal(SIGTERM, signal_handler);
3270
3271         /* initialize event helper configuration */
3272         eh_conf = eh_conf_init();
3273         if (eh_conf == NULL)
3274                 rte_exit(EXIT_FAILURE, "Failed to init event helper config");
3275
3276         /* parse application arguments (after the EAL ones) */
3277         ret = parse_args(argc, argv, eh_conf);
3278         if (ret < 0)
3279                 rte_exit(EXIT_FAILURE, "Invalid parameters\n");
3280
3281         ipsec_secgw_telemetry_init();
3282
3283         /* parse configuration file */
3284         if (parse_cfg_file(cfgfile) < 0) {
3285                 printf("parsing file \"%s\" failed\n",
3286                         optarg);
3287                 print_usage(argv[0]);
3288                 return -1;
3289         }
3290
3291         if ((unprotected_port_mask & enabled_port_mask) !=
3292                         unprotected_port_mask)
3293                 rte_exit(EXIT_FAILURE, "Invalid unprotected portmask 0x%x\n",
3294                                 unprotected_port_mask);
3295
3296         if (check_poll_mode_params(eh_conf) < 0)
3297                 rte_exit(EXIT_FAILURE, "check_poll_mode_params failed\n");
3298
3299         if (check_event_mode_params(eh_conf) < 0)
3300                 rte_exit(EXIT_FAILURE, "check_event_mode_params failed\n");
3301
3302         ret = init_lcore_rx_queues();
3303         if (ret < 0)
3304                 rte_exit(EXIT_FAILURE, "init_lcore_rx_queues failed\n");
3305
3306         nb_lcores = rte_lcore_count();
3307
3308         sess_sz = max_session_size();
3309
3310         /*
3311          * In event mode request minimum number of crypto queues
3312          * to be reserved equal to number of ports.
3313          */
3314         if (eh_conf->mode == EH_PKT_TRANSFER_MODE_EVENT)
3315                 nb_crypto_qp = rte_eth_dev_count_avail();
3316         else
3317                 nb_crypto_qp = 0;
3318
3319         nb_crypto_qp = cryptodevs_init(nb_crypto_qp);
3320
3321         if (nb_bufs_in_pool == 0) {
3322                 RTE_ETH_FOREACH_DEV(portid) {
3323                         if ((enabled_port_mask & (1 << portid)) == 0)
3324                                 continue;
3325                         nb_ports++;
3326                         nb_rxq += get_port_nb_rx_queues(portid);
3327                 }
3328
3329                 nb_txq = nb_lcores;
3330
3331                 nb_bufs_in_pool = calculate_nb_mbufs(nb_ports, nb_crypto_qp,
3332                                                 nb_rxq, nb_txq);
3333         }
3334
3335         for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
3336                 if (rte_lcore_is_enabled(lcore_id) == 0)
3337                         continue;
3338
3339                 if (numa_on)
3340                         socket_id = (uint8_t)rte_lcore_to_socket_id(lcore_id);
3341                 else
3342                         socket_id = 0;
3343
3344                 /* mbuf_pool is initialised by the pool_init() function*/
3345                 if (socket_ctx[socket_id].mbuf_pool)
3346                         continue;
3347
3348                 pool_init(&socket_ctx[socket_id], socket_id, nb_bufs_in_pool);
3349                 session_pool_init(&socket_ctx[socket_id], socket_id, sess_sz);
3350                 session_priv_pool_init(&socket_ctx[socket_id], socket_id,
3351                         sess_sz);
3352         }
3353         printf("Number of mbufs in packet pool %d\n", nb_bufs_in_pool);
3354
3355         RTE_ETH_FOREACH_DEV(portid) {
3356                 if ((enabled_port_mask & (1 << portid)) == 0)
3357                         continue;
3358
3359                 sa_check_offloads(portid, &req_rx_offloads[portid],
3360                                 &req_tx_offloads[portid]);
3361                 port_init(portid, req_rx_offloads[portid],
3362                                 req_tx_offloads[portid]);
3363         }
3364
3365         /*
3366          * Set the enabled port mask in helper config for use by helper
3367          * sub-system. This will be used while initializing devices using
3368          * helper sub-system.
3369          */
3370         eh_conf->eth_portmask = enabled_port_mask;
3371
3372         /* Initialize eventmode components */
3373         ret = eh_devs_init(eh_conf);
3374         if (ret < 0)
3375                 rte_exit(EXIT_FAILURE, "eh_devs_init failed, err=%d\n", ret);
3376
3377         /* start ports */
3378         RTE_ETH_FOREACH_DEV(portid) {
3379                 if ((enabled_port_mask & (1 << portid)) == 0)
3380                         continue;
3381
3382                 /* Create flow before starting the device */
3383                 create_default_ipsec_flow(portid, req_rx_offloads[portid]);
3384
3385                 ret = rte_eth_dev_start(portid);
3386                 if (ret < 0)
3387                         rte_exit(EXIT_FAILURE, "rte_eth_dev_start: "
3388                                         "err=%d, port=%d\n", ret, portid);
3389                 /*
3390                  * If enabled, put device in promiscuous mode.
3391                  * This allows IO forwarding mode to forward packets
3392                  * to itself through 2 cross-connected  ports of the
3393                  * target machine.
3394                  */
3395                 if (promiscuous_on) {
3396                         ret = rte_eth_promiscuous_enable(portid);
3397                         if (ret != 0)
3398                                 rte_exit(EXIT_FAILURE,
3399                                         "rte_eth_promiscuous_enable: err=%s, port=%d\n",
3400                                         rte_strerror(-ret), portid);
3401                 }
3402
3403                 rte_eth_dev_callback_register(portid, RTE_ETH_EVENT_INTR_RESET,
3404                         ethdev_reset_event_callback, NULL);
3405
3406                 rte_eth_dev_callback_register(portid,
3407                         RTE_ETH_EVENT_IPSEC, inline_ipsec_event_callback, NULL);
3408         }
3409
3410         /* fragment reassemble is enabled */
3411         if (frag_tbl_sz != 0) {
3412                 ret = reassemble_init();
3413                 if (ret != 0)
3414                         rte_exit(EXIT_FAILURE, "failed at reassemble init");
3415         }
3416
3417         /* Replicate each context per socket */
3418         for (i = 0; i < NB_SOCKETS && i < rte_socket_count(); i++) {
3419                 socket_id = rte_socket_id_by_idx(i);
3420                 if ((socket_ctx[socket_id].mbuf_pool != NULL) &&
3421                         (socket_ctx[socket_id].sa_in == NULL) &&
3422                         (socket_ctx[socket_id].sa_out == NULL)) {
3423                         sa_init(&socket_ctx[socket_id], socket_id);
3424                         sp4_init(&socket_ctx[socket_id], socket_id);
3425                         sp6_init(&socket_ctx[socket_id], socket_id);
3426                         rt_init(&socket_ctx[socket_id], socket_id);
3427                 }
3428         }
3429
3430         flow_init();
3431
3432         check_all_ports_link_status(enabled_port_mask);
3433
3434         if (stats_interval > 0)
3435                 rte_eal_alarm_set(stats_interval * US_PER_S,
3436                                 print_stats_cb, NULL);
3437         else
3438                 RTE_LOG(INFO, IPSEC, "Stats display disabled\n");
3439
3440         /* launch per-lcore init on every lcore */
3441         rte_eal_mp_remote_launch(ipsec_launch_one_lcore, eh_conf, CALL_MAIN);
3442         RTE_LCORE_FOREACH_WORKER(lcore_id) {
3443                 if (rte_eal_wait_lcore(lcore_id) < 0)
3444                         return -1;
3445         }
3446
3447         /* Uninitialize eventmode components */
3448         ret = eh_devs_uninit(eh_conf);
3449         if (ret < 0)
3450                 rte_exit(EXIT_FAILURE, "eh_devs_uninit failed, err=%d\n", ret);
3451
3452         /* Free eventmode configuration memory */
3453         eh_conf_uninit(eh_conf);
3454
3455         /* Destroy inline inbound and outbound sessions */
3456         for (i = 0; i < NB_SOCKETS && i < rte_socket_count(); i++) {
3457                 socket_id = rte_socket_id_by_idx(i);
3458                 inline_sessions_free(socket_ctx[socket_id].sa_in);
3459                 inline_sessions_free(socket_ctx[socket_id].sa_out);
3460         }
3461
3462         for (cdev_id = 0; cdev_id < rte_cryptodev_count(); cdev_id++) {
3463                 printf("Closing cryptodev %d...", cdev_id);
3464                 rte_cryptodev_stop(cdev_id);
3465                 rte_cryptodev_close(cdev_id);
3466                 printf(" Done\n");
3467         }
3468
3469         RTE_ETH_FOREACH_DEV(portid) {
3470                 if ((enabled_port_mask & (1 << portid)) == 0)
3471                         continue;
3472
3473                 printf("Closing port %d...", portid);
3474                 if (flow_info_tbl[portid].rx_def_flow) {
3475                         struct rte_flow_error err;
3476
3477                         ret = rte_flow_destroy(portid,
3478                                 flow_info_tbl[portid].rx_def_flow, &err);
3479                         if (ret)
3480                                 RTE_LOG(ERR, IPSEC, "Failed to destroy flow "
3481                                         " for port %u, err msg: %s\n", portid,
3482                                         err.message);
3483                 }
3484                 ret = rte_eth_dev_stop(portid);
3485                 if (ret != 0)
3486                         RTE_LOG(ERR, IPSEC,
3487                                 "rte_eth_dev_stop: err=%s, port=%u\n",
3488                                 rte_strerror(-ret), portid);
3489
3490                 rte_eth_dev_close(portid);
3491                 printf(" Done\n");
3492         }
3493
3494         /* clean up the EAL */
3495         rte_eal_cleanup();
3496         printf("Bye...\n");
3497
3498         return 0;
3499 }