[dpdk-dev] [PATCH v3 11/13] examples/ipsec-secgw: add driver mode worker

Lukasz Bartosik lbartosik at marvell.com
Tue Feb 4 14:58:39 CET 2020


Add driver inbound and outbound worker thread for ipsec-secgw. In driver
mode application does as little as possible. It simply forwards packets
back to port from which traffic was received instructing HW to apply
inline security processing using first outbound SA configured for
a given port. If a port does not have SA configured outbound traffic
on that port will be silently dropped. The aim of this mode is to
measure HW capabilities. Driver mode is selected with single-sa option.
The single-sa option accepts SA index however in event mode the SA
index is ignored.

Example command to run ipsec-secgw in driver mode:
ipsec-secgw -w 0002:02:00.0,ipsec_in_max_spi=128
-w 0002:03:00.0,ipsec_in_max_spi=128 -w 0002:0e:00.0 -w 0002:10:00.1
--log-level=8 -c 0x1 -- -P -p 0x3 -u 0x1 --config "(1,0,0),(0,0,0)"
-f aes-gcm.cfg --transfer-mode event --event-schedule-type parallel
--single-sa 0

Signed-off-by: Anoob Joseph <anoobj at marvell.com>
Signed-off-by: Ankur Dwivedi <adwivedi at marvell.com>
Signed-off-by: Lukasz Bartosik <lbartosik at marvell.com>
---
 examples/ipsec-secgw/Makefile       |   1 +
 examples/ipsec-secgw/ipsec-secgw.c  |  32 +++--
 examples/ipsec-secgw/ipsec-secgw.h  |  21 ++++
 examples/ipsec-secgw/ipsec.h        |  11 ++
 examples/ipsec-secgw/ipsec_worker.c | 243 ++++++++++++++++++++++++++++++++++++
 examples/ipsec-secgw/meson.build    |   2 +-
 6 files changed, 292 insertions(+), 18 deletions(-)
 create mode 100644 examples/ipsec-secgw/ipsec-secgw.h
 create mode 100644 examples/ipsec-secgw/ipsec_worker.c

diff --git a/examples/ipsec-secgw/Makefile b/examples/ipsec-secgw/Makefile
index 09e3c5a..f6fd94c 100644
--- a/examples/ipsec-secgw/Makefile
+++ b/examples/ipsec-secgw/Makefile
@@ -15,6 +15,7 @@ SRCS-y += sa.c
 SRCS-y += rt.c
 SRCS-y += ipsec_process.c
 SRCS-y += ipsec-secgw.c
+SRCS-y += ipsec_worker.c
 SRCS-y += event_helper.c
 
 CFLAGS += -gdwarf-2
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index 7d7092d..acd7135 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -70,8 +70,6 @@ volatile bool force_quit;
 
 #define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
 
-#define NB_SOCKETS 4
-
 /* Configure how many packets ahead to prefetch, when reading packets */
 #define PREFETCH_OFFSET	3
 
@@ -79,8 +77,6 @@ volatile bool force_quit;
 
 #define MAX_LCORE_PARAMS 1024
 
-#define UNPROTECTED_PORT(port) (unprotected_port_mask & (1 << portid))
-
 /*
  * Configurable number of RX/TX ring descriptors
  */
@@ -187,15 +183,15 @@ static const struct option lgopts[] = {
 	{NULL, 0, 0, 0}
 };
 
+uint32_t unprotected_port_mask;
+uint32_t single_sa_idx;
 /* mask of enabled ports */
 static uint32_t enabled_port_mask;
 static uint64_t enabled_cryptodev_mask = UINT64_MAX;
-static uint32_t unprotected_port_mask;
 static int32_t promiscuous_on = 1;
 static int32_t numa_on = 1; /**< NUMA is enabled by default. */
 static uint32_t nb_lcores;
 static uint32_t single_sa;
-static uint32_t single_sa_idx;
 
 /*
  * RX/TX HW offload capabilities to enable/use on ethernet ports.
@@ -278,7 +274,7 @@ static struct rte_eth_conf port_conf = {
 	},
 };
 
-static struct socket_ctx socket_ctx[NB_SOCKETS];
+struct socket_ctx socket_ctx[NB_SOCKETS];
 
 /*
  * Determine is multi-segment support required:
@@ -997,12 +993,12 @@ process_pkts(struct lcore_conf *qconf, struct rte_mbuf **pkts,
 	prepare_traffic(pkts, &traffic, nb_pkts);
 
 	if (unlikely(single_sa)) {
-		if (UNPROTECTED_PORT(portid))
+		if (is_unprotected_port(portid))
 			process_pkts_inbound_nosp(&qconf->inbound, &traffic);
 		else
 			process_pkts_outbound_nosp(&qconf->outbound, &traffic);
 	} else {
-		if (UNPROTECTED_PORT(portid))
+		if (is_unprotected_port(portid))
 			process_pkts_inbound(&qconf->inbound, &traffic);
 		else
 			process_pkts_outbound(&qconf->outbound, &traffic);
@@ -1113,8 +1109,8 @@ drain_outbound_crypto_queues(const struct lcore_conf *qconf,
 }
 
 /* main processing loop */
-static int32_t
-main_loop(__attribute__((unused)) void *dummy)
+void
+ipsec_poll_mode_worker(void)
 {
 	struct rte_mbuf *pkts[MAX_PKT_BURST];
 	uint32_t lcore_id;
@@ -1156,7 +1152,7 @@ main_loop(__attribute__((unused)) void *dummy)
 	if (qconf->nb_rx_queue == 0) {
 		RTE_LOG(DEBUG, IPSEC, "lcore %u has nothing to do\n",
 			lcore_id);
-		return 0;
+		return;
 	}
 
 	RTE_LOG(INFO, IPSEC, "entering main loop on lcore %u\n", lcore_id);
@@ -1169,7 +1165,7 @@ main_loop(__attribute__((unused)) void *dummy)
 			lcore_id, portid, queueid);
 	}
 
-	while (1) {
+	while (!force_quit) {
 		cur_tsc = rte_rdtsc();
 
 		/* TX queue buffer drain */
@@ -1193,7 +1189,7 @@ main_loop(__attribute__((unused)) void *dummy)
 				process_pkts(qconf, pkts, nb_rx, portid);
 
 			/* dequeue and process completed crypto-ops */
-			if (UNPROTECTED_PORT(portid))
+			if (is_unprotected_port(portid))
 				drain_inbound_crypto_queues(qconf,
 					&qconf->inbound);
 			else
@@ -1315,8 +1311,10 @@ print_usage(const char *prgname)
 		"  -a enables SA SQN atomic behaviour\n"
 		"  -f CONFIG_FILE: Configuration file\n"
 		"  --config (port,queue,lcore): Rx queue configuration\n"
-		"  --single-sa SAIDX: Use single SA index for outbound traffic,\n"
-		"                     bypassing the SP\n"
+		"  --single-sa SAIDX: In poll mode use single SA index for\n"
+		"                     outbound traffic, bypassing the SP\n"
+		"                     In event mode selects driver mode,\n"
+		"                     SA index value is ignored\n"
 		"  --cryptodev_mask MASK: Hexadecimal bitmask of the crypto\n"
 		"                         devices to configure\n"
 		"  --transfer-mode MODE\n"
@@ -2792,7 +2790,7 @@ main(int32_t argc, char **argv)
 	check_all_ports_link_status(enabled_port_mask);
 
 	/* launch per-lcore init on every lcore */
-	rte_eal_mp_remote_launch(main_loop, NULL, CALL_MASTER);
+	rte_eal_mp_remote_launch(ipsec_launch_one_lcore, eh_conf, CALL_MASTER);
 
 	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
 		if (rte_eal_wait_lcore(lcore_id) < 0)
diff --git a/examples/ipsec-secgw/ipsec-secgw.h b/examples/ipsec-secgw/ipsec-secgw.h
new file mode 100644
index 0000000..06995cf
--- /dev/null
+++ b/examples/ipsec-secgw/ipsec-secgw.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C) 2020 Marvell International Ltd.
+ */
+#ifndef _IPSEC_SECGW_H_
+#define _IPSEC_SECGW_H_
+
+#define NB_SOCKETS 4
+
+/* Port mask to identify the unprotected ports */
+extern uint32_t unprotected_port_mask;
+
+/* Index of SA in single mode */
+extern uint32_t single_sa_idx;
+
+static inline uint8_t
+is_unprotected_port(uint16_t port_id)
+{
+	return unprotected_port_mask & (1 << port_id);
+}
+
+#endif /* _IPSEC_SECGW_H_ */
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index 383a379..15360fb 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -13,6 +13,8 @@
 #include <rte_flow.h>
 #include <rte_ipsec.h>
 
+#include "ipsec-secgw.h"
+
 #define RTE_LOGTYPE_IPSEC       RTE_LOGTYPE_USER1
 #define RTE_LOGTYPE_IPSEC_ESP   RTE_LOGTYPE_USER2
 #define RTE_LOGTYPE_IPSEC_IPIP  RTE_LOGTYPE_USER3
@@ -258,6 +260,15 @@ struct ipsec_traffic {
 	struct traffic_type ip6;
 };
 
+/* Socket ctx */
+extern struct socket_ctx socket_ctx[NB_SOCKETS];
+
+void
+ipsec_poll_mode_worker(void);
+
+int
+ipsec_launch_one_lcore(void *args);
+
 extern struct ipsec_sa sa_out[IPSEC_SA_MAX_ENTRIES];
 extern uint32_t nb_sa_out;
 
diff --git a/examples/ipsec-secgw/ipsec_worker.c b/examples/ipsec-secgw/ipsec_worker.c
new file mode 100644
index 0000000..3f63ab0
--- /dev/null
+++ b/examples/ipsec-secgw/ipsec_worker.c
@@ -0,0 +1,243 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2016 Intel Corporation
+ * Copyright (C) 2020 Marvell International Ltd.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <stdbool.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_memcpy.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_event_eth_tx_adapter.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_eventdev.h>
+#include <rte_malloc.h>
+#include <rte_mbuf.h>
+
+#include "event_helper.h"
+#include "ipsec.h"
+#include "ipsec-secgw.h"
+
+extern volatile bool force_quit;
+
+static inline void
+ipsec_event_pre_forward(struct rte_mbuf *m, unsigned int port_id)
+{
+	/* Save the destination port in the mbuf */
+	m->port = port_id;
+
+	/* Save eth queue for Tx */
+	rte_event_eth_tx_adapter_txq_set(m, 0);
+}
+
+static inline void
+prepare_out_sessions_tbl(struct sa_ctx *sa_out,
+		struct rte_security_session **sess_tbl, uint16_t size)
+{
+	struct rte_ipsec_session *pri_sess;
+	struct ipsec_sa *sa;
+	int i;
+
+	if (!sa_out)
+		return;
+
+	for (i = 0; i < IPSEC_SA_MAX_ENTRIES; i++) {
+
+		sa = &sa_out->sa[i];
+		if (!sa->spi)
+			continue;
+
+		pri_sess = ipsec_get_primary_session(sa);
+		if (pri_sess->type !=
+			RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) {
+
+			RTE_LOG(ERR, IPSEC, "Invalid session type %d\n",
+				pri_sess->type);
+			continue;
+		}
+
+		if (sa->portid >= size) {
+			RTE_LOG(ERR, IPSEC,
+				"Port id >= than table size %d, %d\n",
+				sa->portid, size);
+			continue;
+		}
+
+		/* Use only first inline session found for a given port */
+		if (sess_tbl[sa->portid])
+			continue;
+		sess_tbl[sa->portid] = pri_sess->security.ses;
+	}
+}
+
+/*
+ * Event mode exposes various operating modes depending on the
+ * capabilities of the event device and the operating mode
+ * selected.
+ */
+
+/* Workers registered */
+#define IPSEC_EVENTMODE_WORKERS		1
+
+/*
+ * Event mode worker
+ * Operating parameters : non-burst - Tx internal port - driver mode
+ */
+static void
+ipsec_wrkr_non_burst_int_port_drv_mode(struct eh_event_link_info *links,
+		uint8_t nb_links)
+{
+	struct rte_security_session *sess_tbl[RTE_MAX_ETHPORTS] = { NULL };
+	unsigned int nb_rx = 0;
+	struct rte_mbuf *pkt;
+	struct rte_event ev;
+	uint32_t lcore_id;
+	int32_t socket_id;
+	int16_t port_id;
+
+	/* Check if we have links registered for this lcore */
+	if (nb_links == 0) {
+		/* No links registered - exit */
+		return;
+	}
+
+	/* Get core ID */
+	lcore_id = rte_lcore_id();
+
+	/* Get socket ID */
+	socket_id = rte_lcore_to_socket_id(lcore_id);
+
+	/*
+	 * Prepare security sessions table. In outbound driver mode
+	 * we always use first session configured for a given port
+	 */
+	prepare_out_sessions_tbl(socket_ctx[socket_id].sa_out, sess_tbl,
+			RTE_MAX_ETHPORTS);
+
+	RTE_LOG(INFO, IPSEC,
+		"Launching event mode worker (non-burst - Tx internal port - "
+		"driver mode) on lcore %d\n", lcore_id);
+
+	/* We have valid links */
+
+	/* Check if it's single link */
+	if (nb_links != 1) {
+		RTE_LOG(INFO, IPSEC,
+			"Multiple links not supported. Using first link\n");
+	}
+
+	RTE_LOG(INFO, IPSEC, " -- lcoreid=%u event_port_id=%u\n", lcore_id,
+			links[0].event_port_id);
+	while (!force_quit) {
+		/* Read packet from event queues */
+		nb_rx = rte_event_dequeue_burst(links[0].eventdev_id,
+				links[0].event_port_id,
+				&ev,	/* events */
+				1,	/* nb_events */
+				0	/* timeout_ticks */);
+
+		if (nb_rx == 0)
+			continue;
+
+		pkt = ev.mbuf;
+		port_id = pkt->port;
+
+		rte_prefetch0(rte_pktmbuf_mtod(pkt, void *));
+
+		/* Process packet */
+		ipsec_event_pre_forward(pkt, port_id);
+
+		if (!is_unprotected_port(port_id)) {
+
+			if (unlikely(!sess_tbl[port_id])) {
+				rte_pktmbuf_free(pkt);
+				continue;
+			}
+
+			/* Save security session */
+			pkt->udata64 = (uint64_t) sess_tbl[port_id];
+
+			/* Mark the packet for Tx security offload */
+			pkt->ol_flags |= PKT_TX_SEC_OFFLOAD;
+		}
+
+		/*
+		 * Since tx internal port is available, events can be
+		 * directly enqueued to the adapter and it would be
+		 * internally submitted to the eth device.
+		 */
+		rte_event_eth_tx_adapter_enqueue(links[0].eventdev_id,
+				links[0].event_port_id,
+				&ev,	/* events */
+				1,	/* nb_events */
+				0	/* flags */);
+	}
+}
+
+static uint8_t
+ipsec_eventmode_populate_wrkr_params(struct eh_app_worker_params *wrkrs)
+{
+	struct eh_app_worker_params *wrkr;
+	uint8_t nb_wrkr_param = 0;
+
+	/* Save workers */
+	wrkr = wrkrs;
+
+	/* Non-burst - Tx internal port - driver mode */
+	wrkr->cap.burst = EH_RX_TYPE_NON_BURST;
+	wrkr->cap.tx_internal_port = EH_TX_TYPE_INTERNAL_PORT;
+	wrkr->cap.ipsec_mode = EH_IPSEC_MODE_TYPE_DRIVER;
+	wrkr->worker_thread = ipsec_wrkr_non_burst_int_port_drv_mode;
+	wrkr++;
+
+	return nb_wrkr_param;
+}
+
+static void
+ipsec_eventmode_worker(struct eh_conf *conf)
+{
+	struct eh_app_worker_params ipsec_wrkr[IPSEC_EVENTMODE_WORKERS] = {
+					{{{0} }, NULL } };
+	uint8_t nb_wrkr_param;
+
+	/* Populate l2fwd_wrkr params */
+	nb_wrkr_param = ipsec_eventmode_populate_wrkr_params(ipsec_wrkr);
+
+	/*
+	 * Launch correct worker after checking
+	 * the event device's capabilities.
+	 */
+	eh_launch_worker(conf, ipsec_wrkr, nb_wrkr_param);
+}
+
+int ipsec_launch_one_lcore(void *args)
+{
+	struct eh_conf *conf;
+
+	conf = (struct eh_conf *)args;
+
+	if (conf->mode == EH_PKT_TRANSFER_MODE_POLL) {
+		/* Run in poll mode */
+		ipsec_poll_mode_worker();
+	} else if (conf->mode == EH_PKT_TRANSFER_MODE_EVENT) {
+		/* Run in event mode */
+		ipsec_eventmode_worker(conf);
+	}
+	return 0;
+}
diff --git a/examples/ipsec-secgw/meson.build b/examples/ipsec-secgw/meson.build
index 20f4064..ab40ca5 100644
--- a/examples/ipsec-secgw/meson.build
+++ b/examples/ipsec-secgw/meson.build
@@ -10,5 +10,5 @@ deps += ['security', 'lpm', 'acl', 'hash', 'ip_frag', 'ipsec', 'eventdev']
 allow_experimental_apis = true
 sources = files(
 	'esp.c', 'ipsec.c', 'ipsec_process.c', 'ipsec-secgw.c',
-	'parser.c', 'rt.c', 'sa.c', 'sp4.c', 'sp6.c', 'event_helper.c'
+	'parser.c', 'rt.c', 'sa.c', 'sp4.c', 'sp6.c', 'event_helper.c', 'ipsec_worker.c'
 )
-- 
2.7.4



More information about the dev mailing list