xref: /dpdk/examples/l2fwd-macsec/main.c (revision e0d947a1e6c2f80aa039a4f7082a8aa16797d8b9)
1322ebca6SAkhil Goyal /* SPDX-License-Identifier: BSD-3-Clause
2322ebca6SAkhil Goyal  * Copyright(C) 2023 Marvell.
3322ebca6SAkhil Goyal  */
4322ebca6SAkhil Goyal 
5322ebca6SAkhil Goyal #include <stdio.h>
6322ebca6SAkhil Goyal #include <stdlib.h>
7322ebca6SAkhil Goyal #include <string.h>
8322ebca6SAkhil Goyal #include <stdint.h>
9322ebca6SAkhil Goyal #include <inttypes.h>
10322ebca6SAkhil Goyal #include <sys/types.h>
11322ebca6SAkhil Goyal #include <sys/queue.h>
12322ebca6SAkhil Goyal #include <setjmp.h>
13322ebca6SAkhil Goyal #include <stdarg.h>
14322ebca6SAkhil Goyal #include <ctype.h>
15322ebca6SAkhil Goyal #include <errno.h>
16322ebca6SAkhil Goyal #include <getopt.h>
17322ebca6SAkhil Goyal #include <signal.h>
18322ebca6SAkhil Goyal #include <stdbool.h>
19322ebca6SAkhil Goyal 
20322ebca6SAkhil Goyal #include <rte_common.h>
21322ebca6SAkhil Goyal #include <rte_log.h>
22322ebca6SAkhil Goyal #include <rte_malloc.h>
23322ebca6SAkhil Goyal #include <rte_memory.h>
24322ebca6SAkhil Goyal #include <rte_memcpy.h>
25322ebca6SAkhil Goyal #include <rte_eal.h>
26322ebca6SAkhil Goyal #include <rte_launch.h>
27322ebca6SAkhil Goyal #include <rte_cycles.h>
28322ebca6SAkhil Goyal #include <rte_prefetch.h>
29322ebca6SAkhil Goyal #include <rte_lcore.h>
30322ebca6SAkhil Goyal #include <rte_per_lcore.h>
31322ebca6SAkhil Goyal #include <rte_branch_prediction.h>
32322ebca6SAkhil Goyal #include <rte_interrupts.h>
33322ebca6SAkhil Goyal #include <rte_random.h>
34322ebca6SAkhil Goyal #include <rte_debug.h>
35322ebca6SAkhil Goyal #include <rte_ether.h>
36322ebca6SAkhil Goyal #include <rte_ethdev.h>
37322ebca6SAkhil Goyal #include <rte_mempool.h>
38322ebca6SAkhil Goyal #include <rte_mbuf.h>
39322ebca6SAkhil Goyal #include <rte_security.h>
40322ebca6SAkhil Goyal #include <rte_string_fns.h>
41322ebca6SAkhil Goyal 
42322ebca6SAkhil Goyal static volatile bool force_quit;
43322ebca6SAkhil Goyal 
44322ebca6SAkhil Goyal /* MAC updating enabled by default */
45322ebca6SAkhil Goyal static int mac_updating;
46322ebca6SAkhil Goyal 
47322ebca6SAkhil Goyal /* Ports set in promiscuous mode on by default. */
48322ebca6SAkhil Goyal static int promiscuous_on = 1;
49322ebca6SAkhil Goyal 
50322ebca6SAkhil Goyal #define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
51322ebca6SAkhil Goyal 
52322ebca6SAkhil Goyal #define MAX_PKT_BURST 32
53322ebca6SAkhil Goyal #define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
54322ebca6SAkhil Goyal #define MEMPOOL_CACHE_SIZE 256
55322ebca6SAkhil Goyal #define SESSION_POOL_CACHE_SIZE 0
56322ebca6SAkhil Goyal 
57322ebca6SAkhil Goyal /* Configurable number of RX/TX ring descriptors */
58322ebca6SAkhil Goyal #define RX_DESC_DEFAULT 1024
59322ebca6SAkhil Goyal #define TX_DESC_DEFAULT 1024
60322ebca6SAkhil Goyal static uint16_t nb_rxd = RX_DESC_DEFAULT;
61322ebca6SAkhil Goyal static uint16_t nb_txd = TX_DESC_DEFAULT;
62322ebca6SAkhil Goyal 
63322ebca6SAkhil Goyal /* ethernet addresses of ports */
64322ebca6SAkhil Goyal static struct rte_ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
65322ebca6SAkhil Goyal 
66322ebca6SAkhil Goyal /* Ethernet header configuration for MACsec flow on each port. */
67322ebca6SAkhil Goyal static struct rte_ether_hdr port_ether_hdr_config[RTE_MAX_ETHPORTS];
68322ebca6SAkhil Goyal 
69322ebca6SAkhil Goyal /* mask of enabled ports */
70322ebca6SAkhil Goyal static uint32_t l2fwd_enabled_port_mask;
71322ebca6SAkhil Goyal 
72322ebca6SAkhil Goyal /* list of enabled ports */
73322ebca6SAkhil Goyal static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
74322ebca6SAkhil Goyal 
757e06c0deSTyler Retzlaff struct __rte_cache_aligned port_pair_params {
76322ebca6SAkhil Goyal #define NUM_PORTS	2
77322ebca6SAkhil Goyal 	uint16_t port[NUM_PORTS];
787e06c0deSTyler Retzlaff };
79322ebca6SAkhil Goyal 
80322ebca6SAkhil Goyal static struct port_pair_params port_pair_params_array[RTE_MAX_ETHPORTS / 2];
81322ebca6SAkhil Goyal static struct port_pair_params *port_pair_params;
82322ebca6SAkhil Goyal static uint16_t nb_port_pair_params;
83322ebca6SAkhil Goyal 
84322ebca6SAkhil Goyal static unsigned int l2fwd_rx_queue_per_lcore = 1;
85322ebca6SAkhil Goyal 
86322ebca6SAkhil Goyal #define MAX_RX_QUEUE_PER_LCORE 16
87322ebca6SAkhil Goyal #define MAX_TX_QUEUE_PER_PORT 16
88322ebca6SAkhil Goyal /* List of queues to be polled for a given lcore. 8< */
897e06c0deSTyler Retzlaff struct __rte_cache_aligned lcore_queue_conf {
90322ebca6SAkhil Goyal 	unsigned int n_rx_port;
91322ebca6SAkhil Goyal 	unsigned int rx_port_list[MAX_RX_QUEUE_PER_LCORE];
927e06c0deSTyler Retzlaff };
93322ebca6SAkhil Goyal struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
94322ebca6SAkhil Goyal /* >8 End of list of queues to be polled for a given lcore. */
95322ebca6SAkhil Goyal 
96322ebca6SAkhil Goyal static struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];
97322ebca6SAkhil Goyal 
98322ebca6SAkhil Goyal static struct rte_eth_conf port_conf = {
99322ebca6SAkhil Goyal 	.txmode = {
100322ebca6SAkhil Goyal 		.mq_mode = RTE_ETH_MQ_TX_NONE,
101322ebca6SAkhil Goyal 	},
102322ebca6SAkhil Goyal };
103322ebca6SAkhil Goyal 
104322ebca6SAkhil Goyal /* Mempools for mbuf and security session */
105322ebca6SAkhil Goyal struct rte_mempool *l2fwd_pktmbuf_pool;
106322ebca6SAkhil Goyal 
107322ebca6SAkhil Goyal /* Per-port statistics struct */
1087e06c0deSTyler Retzlaff struct __rte_cache_aligned l2fwd_port_statistics {
109322ebca6SAkhil Goyal 	uint64_t tx;
110322ebca6SAkhil Goyal 	uint64_t rx;
111322ebca6SAkhil Goyal 	uint64_t dropped;
1127e06c0deSTyler Retzlaff };
113322ebca6SAkhil Goyal struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
114322ebca6SAkhil Goyal 
115322ebca6SAkhil Goyal #define MAX_TIMER_PERIOD 86400 /* 1 day max */
116322ebca6SAkhil Goyal /* A tsc-based timer responsible for triggering statistics printout */
117322ebca6SAkhil Goyal static uint64_t timer_period = 10; /* default period is 10 seconds */
118322ebca6SAkhil Goyal 
119322ebca6SAkhil Goyal #define MCS_MAX_KEY_LEN		32
120322ebca6SAkhil Goyal #define MCS_SALT_LEN		12
121322ebca6SAkhil Goyal 
122322ebca6SAkhil Goyal struct l2fwd_key {
123322ebca6SAkhil Goyal 	uint8_t data[MCS_MAX_KEY_LEN];
124322ebca6SAkhil Goyal 	uint32_t len;
125322ebca6SAkhil Goyal 	rte_iova_t phys_addr;
126322ebca6SAkhil Goyal };
127322ebca6SAkhil Goyal 
128322ebca6SAkhil Goyal /** l2fwd macsec application command line options */
129322ebca6SAkhil Goyal struct l2fwd_macsec_options {
130322ebca6SAkhil Goyal 	unsigned int portmask;
131322ebca6SAkhil Goyal 	unsigned int tx_portmask;
132322ebca6SAkhil Goyal 	unsigned int rx_portmask;
133322ebca6SAkhil Goyal 	unsigned int nb_ports_per_lcore;
134322ebca6SAkhil Goyal 	unsigned int refresh_period;
135322ebca6SAkhil Goyal 	unsigned int single_lcore:1;
136322ebca6SAkhil Goyal };
137322ebca6SAkhil Goyal 
138322ebca6SAkhil Goyal /** l2fwd macsec lcore params */
139322ebca6SAkhil Goyal struct l2fwd_macsec_port_params {
140322ebca6SAkhil Goyal 	uint8_t dev_id;
141322ebca6SAkhil Goyal 	uint8_t qp_id;
142322ebca6SAkhil Goyal 	void *sec_ctx;
143322ebca6SAkhil Goyal 	struct rte_mempool *sess_pool;
144322ebca6SAkhil Goyal 
145322ebca6SAkhil Goyal 	void *sess;
146322ebca6SAkhil Goyal 	uint16_t sa_id[4];
147322ebca6SAkhil Goyal 	uint16_t sc_id;
148322ebca6SAkhil Goyal 	struct rte_flow *tx_flow;
149322ebca6SAkhil Goyal 	struct rte_flow *rx_flow;
150322ebca6SAkhil Goyal 
151322ebca6SAkhil Goyal 	enum rte_security_macsec_direction dir;
152322ebca6SAkhil Goyal 	enum rte_security_macsec_alg alg;
153322ebca6SAkhil Goyal 	struct l2fwd_key sa_key;
154322ebca6SAkhil Goyal 	uint8_t salt[MCS_SALT_LEN];
155322ebca6SAkhil Goyal 
156322ebca6SAkhil Goyal 	uint8_t eth_hdr[RTE_ETHER_HDR_LEN];
157322ebca6SAkhil Goyal 	uint32_t ssci;
158322ebca6SAkhil Goyal 	uint64_t sci;
159322ebca6SAkhil Goyal 	uint64_t pn_threshold;
160322ebca6SAkhil Goyal 	uint32_t xpn;
161322ebca6SAkhil Goyal 	uint32_t next_pn;
162322ebca6SAkhil Goyal 	uint32_t mtu;
163322ebca6SAkhil Goyal 	uint8_t sectag_insert_mode;
164322ebca6SAkhil Goyal 	bool encrypt;
165322ebca6SAkhil Goyal 	bool protect_frames;
166322ebca6SAkhil Goyal 	bool replay_protect;
167322ebca6SAkhil Goyal 	int val_frames;
168322ebca6SAkhil Goyal 	uint32_t replay_win_sz;
169322ebca6SAkhil Goyal 	bool send_sci;
170322ebca6SAkhil Goyal 	bool end_station;
171322ebca6SAkhil Goyal 	bool scb;
172322ebca6SAkhil Goyal 	uint8_t an;
173322ebca6SAkhil Goyal };
174322ebca6SAkhil Goyal struct l2fwd_macsec_port_params mcs_port_params[RTE_MAX_ETHPORTS];
175322ebca6SAkhil Goyal 
176322ebca6SAkhil Goyal static void
177322ebca6SAkhil Goyal mcs_stats_dump(uint16_t portid)
178322ebca6SAkhil Goyal {
179322ebca6SAkhil Goyal 	struct rte_security_stats sess_stats = {0};
180322ebca6SAkhil Goyal 	struct rte_security_macsec_secy_stats *secy_stat;
181322ebca6SAkhil Goyal 	struct rte_security_macsec_sc_stats sc_stat = {0};
182322ebca6SAkhil Goyal 
183322ebca6SAkhil Goyal 	if (mcs_port_params[portid].dir == RTE_SECURITY_MACSEC_DIR_RX) {
184322ebca6SAkhil Goyal 		printf("\n********* RX SECY STATS ************\n");
185322ebca6SAkhil Goyal 		rte_security_session_stats_get(mcs_port_params[portid].sec_ctx,
186322ebca6SAkhil Goyal 				mcs_port_params[portid].sess, &sess_stats);
187322ebca6SAkhil Goyal 		secy_stat = &sess_stats.macsec;
188322ebca6SAkhil Goyal 
189322ebca6SAkhil Goyal 		if (secy_stat->ctl_pkt_bcast_cnt)
190322ebca6SAkhil Goyal 			printf("RX: ctl_pkt_bcast_cnt: 0x%" PRIx64 "\n",
191322ebca6SAkhil Goyal 					secy_stat->ctl_pkt_bcast_cnt);
192322ebca6SAkhil Goyal 		if (secy_stat->ctl_pkt_mcast_cnt)
193322ebca6SAkhil Goyal 			printf("RX: ctl_pkt_mcast_cnt: 0x%" PRIx64 "\n",
194322ebca6SAkhil Goyal 					secy_stat->ctl_pkt_mcast_cnt);
195322ebca6SAkhil Goyal 		if (secy_stat->ctl_pkt_ucast_cnt)
196322ebca6SAkhil Goyal 			printf("RX: ctl_pkt_ucast_cnt: 0x%" PRIx64 "\n",
197322ebca6SAkhil Goyal 					secy_stat->ctl_pkt_ucast_cnt);
198322ebca6SAkhil Goyal 		if (secy_stat->ctl_octet_cnt)
199322ebca6SAkhil Goyal 			printf("RX: ctl_octet_cnt: 0x%" PRIx64 "\n", secy_stat->ctl_octet_cnt);
200322ebca6SAkhil Goyal 		if (secy_stat->unctl_pkt_bcast_cnt)
201322ebca6SAkhil Goyal 			printf("RX: unctl_pkt_bcast_cnt: 0x%" PRIx64 "\n",
202322ebca6SAkhil Goyal 					secy_stat->unctl_pkt_bcast_cnt);
203322ebca6SAkhil Goyal 		if (secy_stat->unctl_pkt_mcast_cnt)
204322ebca6SAkhil Goyal 			printf("RX: unctl_pkt_mcast_cnt: 0x%" PRIx64 "\n",
205322ebca6SAkhil Goyal 					secy_stat->unctl_pkt_mcast_cnt);
206322ebca6SAkhil Goyal 		if (secy_stat->unctl_pkt_ucast_cnt)
207322ebca6SAkhil Goyal 			printf("RX: unctl_pkt_ucast_cnt: 0x%" PRIx64 "\n",
208322ebca6SAkhil Goyal 					secy_stat->unctl_pkt_ucast_cnt);
209322ebca6SAkhil Goyal 		if (secy_stat->unctl_octet_cnt)
210322ebca6SAkhil Goyal 			printf("RX: unctl_octet_cnt: 0x%" PRIx64 "\n", secy_stat->unctl_octet_cnt);
211322ebca6SAkhil Goyal 		/* Valid only for RX */
212322ebca6SAkhil Goyal 		if (secy_stat->octet_decrypted_cnt)
213322ebca6SAkhil Goyal 			printf("RX: octet_decrypted_cnt: 0x%" PRIx64 "\n",
214322ebca6SAkhil Goyal 					secy_stat->octet_decrypted_cnt);
215322ebca6SAkhil Goyal 		if (secy_stat->octet_validated_cnt)
216322ebca6SAkhil Goyal 			printf("RX: octet_validated_cnt: 0x%" PRIx64 "\n",
217322ebca6SAkhil Goyal 					secy_stat->octet_validated_cnt);
218322ebca6SAkhil Goyal 		if (secy_stat->pkt_port_disabled_cnt)
219322ebca6SAkhil Goyal 			printf("RX: pkt_port_disabled_cnt: 0x%" PRIx64 "\n",
220322ebca6SAkhil Goyal 					secy_stat->pkt_port_disabled_cnt);
221322ebca6SAkhil Goyal 		if (secy_stat->pkt_badtag_cnt)
222322ebca6SAkhil Goyal 			printf("RX: pkt_badtag_cnt: 0x%" PRIx64 "\n", secy_stat->pkt_badtag_cnt);
223322ebca6SAkhil Goyal 		if (secy_stat->pkt_nosa_cnt)
224322ebca6SAkhil Goyal 			printf("RX: pkt_nosa_cnt: 0x%" PRIx64 "\n", secy_stat->pkt_nosa_cnt);
225322ebca6SAkhil Goyal 		if (secy_stat->pkt_nosaerror_cnt)
226322ebca6SAkhil Goyal 			printf("RX: pkt_nosaerror_cnt: 0x%" PRIx64 "\n",
227322ebca6SAkhil Goyal 					secy_stat->pkt_nosaerror_cnt);
228322ebca6SAkhil Goyal 		if (secy_stat->pkt_tagged_ctl_cnt)
229322ebca6SAkhil Goyal 			printf("RX: pkt_tagged_ctl_cnt: 0x%" PRIx64 "\n",
230322ebca6SAkhil Goyal 					secy_stat->pkt_tagged_ctl_cnt);
231322ebca6SAkhil Goyal 		if (secy_stat->pkt_untaged_cnt)
232322ebca6SAkhil Goyal 			printf("RX: pkt_untaged_cnt: 0x%" PRIx64 "\n", secy_stat->pkt_untaged_cnt);
233322ebca6SAkhil Goyal 		if (secy_stat->pkt_ctl_cnt)
234322ebca6SAkhil Goyal 			printf("RX: pkt_ctl_cnt: 0x%" PRIx64 "\n", secy_stat->pkt_ctl_cnt);
235322ebca6SAkhil Goyal 		if (secy_stat->pkt_notag_cnt)
236322ebca6SAkhil Goyal 			printf("RX: pkt_notag_cnt: 0x%" PRIx64 "\n", secy_stat->pkt_notag_cnt);
237322ebca6SAkhil Goyal 		printf("\n");
238322ebca6SAkhil Goyal 		printf("\n********** RX SC[%u] STATS **************\n",
239322ebca6SAkhil Goyal 				mcs_port_params[portid].sc_id);
240322ebca6SAkhil Goyal 
241322ebca6SAkhil Goyal 		rte_security_macsec_sc_stats_get(mcs_port_params[portid].sec_ctx,
242322ebca6SAkhil Goyal 				mcs_port_params[portid].sc_id, RTE_SECURITY_MACSEC_DIR_RX,
243322ebca6SAkhil Goyal 						 &sc_stat);
244322ebca6SAkhil Goyal 		/* RX */
245322ebca6SAkhil Goyal 		if (sc_stat.hit_cnt)
246322ebca6SAkhil Goyal 			printf("RX hit_cnt: 0x%" PRIx64 "\n", sc_stat.hit_cnt);
247322ebca6SAkhil Goyal 		if (sc_stat.pkt_invalid_cnt)
248322ebca6SAkhil Goyal 			printf("RX pkt_invalid_cnt: 0x%" PRIx64 "\n", sc_stat.pkt_invalid_cnt);
249322ebca6SAkhil Goyal 		if (sc_stat.pkt_late_cnt)
250322ebca6SAkhil Goyal 			printf("RX pkt_late_cnt: 0x%" PRIx64 "\n", sc_stat.pkt_late_cnt);
251322ebca6SAkhil Goyal 		if (sc_stat.pkt_notvalid_cnt)
252322ebca6SAkhil Goyal 			printf("RX pkt_notvalid_cnt: 0x%" PRIx64 "\n", sc_stat.pkt_notvalid_cnt);
253322ebca6SAkhil Goyal 		if (sc_stat.pkt_unchecked_cnt)
254322ebca6SAkhil Goyal 			printf("RX pkt_unchecked_cnt: 0x%" PRIx64 "\n", sc_stat.pkt_unchecked_cnt);
255322ebca6SAkhil Goyal 		if (sc_stat.pkt_delay_cnt)
256322ebca6SAkhil Goyal 			printf("RX pkt_delay_cnt: 0x%" PRIx64 "\n", sc_stat.pkt_delay_cnt);
257322ebca6SAkhil Goyal 		if (sc_stat.pkt_ok_cnt)
258322ebca6SAkhil Goyal 			printf("RX pkt_ok_cnt: 0x%" PRIx64 "\n", sc_stat.pkt_ok_cnt);
259322ebca6SAkhil Goyal 		if (sc_stat.octet_decrypt_cnt)
260322ebca6SAkhil Goyal 			printf("RX octet_decrypt_cnt: 0x%" PRIx64 "\n", sc_stat.octet_decrypt_cnt);
261322ebca6SAkhil Goyal 		if (sc_stat.octet_validate_cnt)
262322ebca6SAkhil Goyal 			printf("RX octet_validate_cnt: 0x%" PRIx64 "\n",
263322ebca6SAkhil Goyal 					sc_stat.octet_validate_cnt);
264322ebca6SAkhil Goyal 	}
265322ebca6SAkhil Goyal 
266322ebca6SAkhil Goyal 	if (mcs_port_params[portid].dir == RTE_SECURITY_MACSEC_DIR_TX) {
267322ebca6SAkhil Goyal 		memset(&sess_stats, 0, sizeof(struct rte_security_stats));
268322ebca6SAkhil Goyal 		rte_security_session_stats_get(mcs_port_params[portid].sec_ctx,
269322ebca6SAkhil Goyal 				mcs_port_params[portid].sess, &sess_stats);
270322ebca6SAkhil Goyal 		secy_stat = &sess_stats.macsec;
271322ebca6SAkhil Goyal 
272322ebca6SAkhil Goyal 		printf("\n********* TX SECY STATS ************\n");
273322ebca6SAkhil Goyal 		if (secy_stat->ctl_pkt_bcast_cnt)
274322ebca6SAkhil Goyal 			printf("TX: ctl_pkt_bcast_cnt: 0x%" PRIx64 "\n",
275322ebca6SAkhil Goyal 					secy_stat->ctl_pkt_bcast_cnt);
276322ebca6SAkhil Goyal 		if (secy_stat->ctl_pkt_mcast_cnt)
277322ebca6SAkhil Goyal 			printf("TX: ctl_pkt_mcast_cnt: 0x%" PRIx64 "\n",
278322ebca6SAkhil Goyal 					secy_stat->ctl_pkt_mcast_cnt);
279322ebca6SAkhil Goyal 		if (secy_stat->ctl_pkt_ucast_cnt)
280322ebca6SAkhil Goyal 			printf("TX: ctl_pkt_ucast_cnt: 0x%" PRIx64 "\n",
281322ebca6SAkhil Goyal 					secy_stat->ctl_pkt_ucast_cnt);
282322ebca6SAkhil Goyal 		if (secy_stat->ctl_octet_cnt)
283322ebca6SAkhil Goyal 			printf("TX: ctl_octet_cnt: 0x%" PRIx64 "\n", secy_stat->ctl_octet_cnt);
284322ebca6SAkhil Goyal 		if (secy_stat->unctl_pkt_bcast_cnt)
285322ebca6SAkhil Goyal 			printf("TX: unctl_pkt_bcast_cnt: 0x%" PRIx64 "\n",
286322ebca6SAkhil Goyal 					secy_stat->unctl_pkt_bcast_cnt);
287322ebca6SAkhil Goyal 		if (secy_stat->unctl_pkt_mcast_cnt)
288322ebca6SAkhil Goyal 			printf("TX: unctl_pkt_mcast_cnt: 0x%" PRIx64 "\n",
289322ebca6SAkhil Goyal 					secy_stat->unctl_pkt_mcast_cnt);
290322ebca6SAkhil Goyal 		if (secy_stat->unctl_pkt_ucast_cnt)
291322ebca6SAkhil Goyal 			printf("TX: unctl_pkt_ucast_cnt: 0x%" PRIx64 "\n",
292322ebca6SAkhil Goyal 					secy_stat->unctl_pkt_ucast_cnt);
293322ebca6SAkhil Goyal 		if (secy_stat->unctl_octet_cnt)
294322ebca6SAkhil Goyal 			printf("TX: unctl_octet_cnt: 0x%" PRIx64 "\n",
295322ebca6SAkhil Goyal 					secy_stat->unctl_octet_cnt);
296322ebca6SAkhil Goyal 		/* Valid only for TX */
297322ebca6SAkhil Goyal 		if (secy_stat->octet_encrypted_cnt)
298322ebca6SAkhil Goyal 			printf("TX: octet_encrypted_cnt: 0x%" PRIx64 "\n",
299322ebca6SAkhil Goyal 					secy_stat->octet_encrypted_cnt);
300322ebca6SAkhil Goyal 		if (secy_stat->octet_protected_cnt)
301322ebca6SAkhil Goyal 			printf("TX: octet_protected_cnt: 0x%" PRIx64 "\n",
302322ebca6SAkhil Goyal 					secy_stat->octet_protected_cnt);
303322ebca6SAkhil Goyal 		if (secy_stat->pkt_noactivesa_cnt)
304322ebca6SAkhil Goyal 			printf("TX: pkt_noactivesa_cnt: 0x%" PRIx64 "\n",
305322ebca6SAkhil Goyal 					secy_stat->pkt_noactivesa_cnt);
306322ebca6SAkhil Goyal 		if (secy_stat->pkt_toolong_cnt)
307322ebca6SAkhil Goyal 			printf("TX: pkt_toolong_cnt: 0x%" PRIx64 "\n", secy_stat->pkt_toolong_cnt);
308322ebca6SAkhil Goyal 		if (secy_stat->pkt_untagged_cnt)
309322ebca6SAkhil Goyal 			printf("TX: pkt_untagged_cnt: 0x%" PRIx64 "\n",
310322ebca6SAkhil Goyal 					secy_stat->pkt_untagged_cnt);
311322ebca6SAkhil Goyal 
312322ebca6SAkhil Goyal 
313322ebca6SAkhil Goyal 		memset(&sc_stat, 0, sizeof(struct rte_security_macsec_sc_stats));
314322ebca6SAkhil Goyal 		rte_security_macsec_sc_stats_get(mcs_port_params[portid].sec_ctx,
315322ebca6SAkhil Goyal 				mcs_port_params[portid].sc_id, RTE_SECURITY_MACSEC_DIR_TX,
316322ebca6SAkhil Goyal 				&sc_stat);
317322ebca6SAkhil Goyal 		printf("\n********** TX SC[%u] STATS **************\n",
318322ebca6SAkhil Goyal 				mcs_port_params[portid].sc_id);
319322ebca6SAkhil Goyal 		if (sc_stat.pkt_encrypt_cnt)
320322ebca6SAkhil Goyal 			printf("TX pkt_encrypt_cnt: 0x%" PRIx64 "\n", sc_stat.pkt_encrypt_cnt);
321322ebca6SAkhil Goyal 		if (sc_stat.pkt_protected_cnt)
322322ebca6SAkhil Goyal 			printf("TX pkt_protected_cnt: 0x%" PRIx64 "\n", sc_stat.pkt_protected_cnt);
323322ebca6SAkhil Goyal 		if (sc_stat.octet_encrypt_cnt)
324322ebca6SAkhil Goyal 			printf("TX octet_encrypt_cnt: 0x%" PRIx64 "\n", sc_stat.octet_encrypt_cnt);
325322ebca6SAkhil Goyal 	}
326322ebca6SAkhil Goyal }
327322ebca6SAkhil Goyal 
328322ebca6SAkhil Goyal /* Print out statistics on packets dropped */
329322ebca6SAkhil Goyal static void
330322ebca6SAkhil Goyal print_stats(void)
331322ebca6SAkhil Goyal {
332322ebca6SAkhil Goyal 	uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
333322ebca6SAkhil Goyal 	unsigned int portid;
334322ebca6SAkhil Goyal 
335322ebca6SAkhil Goyal 	total_packets_dropped = 0;
336322ebca6SAkhil Goyal 	total_packets_tx = 0;
337322ebca6SAkhil Goyal 	total_packets_rx = 0;
338322ebca6SAkhil Goyal 
339322ebca6SAkhil Goyal 	const char clr[] = { 27, '[', '2', 'J', '\0' };
340322ebca6SAkhil Goyal 	const char topLeft[] = { 27, '[', '1', ';', '1', 'H', '\0' };
341322ebca6SAkhil Goyal 
342322ebca6SAkhil Goyal 		/* Clear screen and move to top left */
343322ebca6SAkhil Goyal 	printf("%s%s", clr, topLeft);
344322ebca6SAkhil Goyal 
345322ebca6SAkhil Goyal 	printf("\nPort statistics ====================================");
346322ebca6SAkhil Goyal 
347322ebca6SAkhil Goyal 	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
348322ebca6SAkhil Goyal 		/* skip disabled ports */
349322ebca6SAkhil Goyal 		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
350322ebca6SAkhil Goyal 			continue;
351322ebca6SAkhil Goyal 		printf("\nStatistics for port %u ------------------------------"
352322ebca6SAkhil Goyal 			   "\nPackets sent: %24"PRIu64
353322ebca6SAkhil Goyal 			   "\nPackets received: %20"PRIu64
354322ebca6SAkhil Goyal 			   "\nPackets dropped: %21"PRIu64,
355322ebca6SAkhil Goyal 			   portid,
356322ebca6SAkhil Goyal 			   port_statistics[portid].tx,
357322ebca6SAkhil Goyal 			   port_statistics[portid].rx,
358322ebca6SAkhil Goyal 			   port_statistics[portid].dropped);
359322ebca6SAkhil Goyal 
360322ebca6SAkhil Goyal 		total_packets_dropped += port_statistics[portid].dropped;
361322ebca6SAkhil Goyal 		total_packets_tx += port_statistics[portid].tx;
362322ebca6SAkhil Goyal 		total_packets_rx += port_statistics[portid].rx;
363322ebca6SAkhil Goyal 
364322ebca6SAkhil Goyal 		mcs_stats_dump(portid);
365322ebca6SAkhil Goyal 	}
366322ebca6SAkhil Goyal 	printf("\nAggregate statistics ==============================="
367322ebca6SAkhil Goyal 		   "\nTotal packets sent: %18"PRIu64
368322ebca6SAkhil Goyal 		   "\nTotal packets received: %14"PRIu64
369322ebca6SAkhil Goyal 		   "\nTotal packets dropped: %15"PRIu64,
370322ebca6SAkhil Goyal 		   total_packets_tx,
371322ebca6SAkhil Goyal 		   total_packets_rx,
372322ebca6SAkhil Goyal 		   total_packets_dropped);
373322ebca6SAkhil Goyal 	printf("\n====================================================\n");
374322ebca6SAkhil Goyal 
375322ebca6SAkhil Goyal 	fflush(stdout);
376322ebca6SAkhil Goyal }
377322ebca6SAkhil Goyal 
378322ebca6SAkhil Goyal static void
379322ebca6SAkhil Goyal l2fwd_mac_updating(struct rte_mbuf *m, unsigned int dest_portid)
380322ebca6SAkhil Goyal {
381322ebca6SAkhil Goyal 	struct rte_ether_hdr *eth;
382322ebca6SAkhil Goyal 	void *tmp;
383322ebca6SAkhil Goyal 
384322ebca6SAkhil Goyal 	eth = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
385322ebca6SAkhil Goyal 
386322ebca6SAkhil Goyal 	/* 02:00:00:00:00:xx */
387322ebca6SAkhil Goyal 	tmp = &eth->dst_addr.addr_bytes[0];
388322ebca6SAkhil Goyal 	*((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dest_portid << 40);
389322ebca6SAkhil Goyal 
390322ebca6SAkhil Goyal 	/* src addr */
391322ebca6SAkhil Goyal 	rte_ether_addr_copy(&l2fwd_ports_eth_addr[dest_portid], &eth->src_addr);
392322ebca6SAkhil Goyal }
393322ebca6SAkhil Goyal 
394322ebca6SAkhil Goyal static void
395322ebca6SAkhil Goyal l2fwd_simple_forward(struct rte_mbuf *m, unsigned int portid)
396322ebca6SAkhil Goyal {
397322ebca6SAkhil Goyal 	unsigned int dst_port;
398322ebca6SAkhil Goyal 	int sent;
399322ebca6SAkhil Goyal 	struct rte_eth_dev_tx_buffer *buffer;
400322ebca6SAkhil Goyal 
401322ebca6SAkhil Goyal 	dst_port = l2fwd_dst_ports[portid];
402322ebca6SAkhil Goyal 
403322ebca6SAkhil Goyal 	if (mac_updating)
404322ebca6SAkhil Goyal 		l2fwd_mac_updating(m, dst_port);
405322ebca6SAkhil Goyal 
406322ebca6SAkhil Goyal 	buffer = tx_buffer[dst_port];
407322ebca6SAkhil Goyal 	sent = rte_eth_tx_buffer(dst_port, 0, buffer, m);
408322ebca6SAkhil Goyal 	if (sent)
409322ebca6SAkhil Goyal 		port_statistics[dst_port].tx += sent;
410322ebca6SAkhil Goyal }
411322ebca6SAkhil Goyal 
412322ebca6SAkhil Goyal static void
413322ebca6SAkhil Goyal fill_macsec_sa_conf(uint16_t portid, struct rte_security_macsec_sa *sa)
414322ebca6SAkhil Goyal {
415322ebca6SAkhil Goyal 	sa->dir = mcs_port_params[portid].dir;
416322ebca6SAkhil Goyal 
417322ebca6SAkhil Goyal 	sa->key.data = mcs_port_params[portid].sa_key.data;
418322ebca6SAkhil Goyal 	sa->key.length = mcs_port_params[portid].sa_key.len;
419322ebca6SAkhil Goyal 
420322ebca6SAkhil Goyal 	memcpy((uint8_t *)sa->salt, (const uint8_t *)mcs_port_params[portid].salt,
421322ebca6SAkhil Goyal 		RTE_SECURITY_MACSEC_SALT_LEN);
422322ebca6SAkhil Goyal 
423322ebca6SAkhil Goyal 	/* AN is set as per the value in secure packet in test vector */
424322ebca6SAkhil Goyal 	sa->an = mcs_port_params[portid].an & RTE_MACSEC_AN_MASK;
425322ebca6SAkhil Goyal 
426322ebca6SAkhil Goyal 	sa->ssci = mcs_port_params[portid].ssci;
427322ebca6SAkhil Goyal 	sa->xpn = mcs_port_params[portid].xpn;
428322ebca6SAkhil Goyal 	/* Starting packet number which is expected to come next.
429322ebca6SAkhil Goyal 	 * It is take from the test vector so that we can match the out packet.
430322ebca6SAkhil Goyal 	 */
431322ebca6SAkhil Goyal 	sa->next_pn = mcs_port_params[portid].next_pn;
432322ebca6SAkhil Goyal }
433322ebca6SAkhil Goyal 
434322ebca6SAkhil Goyal static void
435322ebca6SAkhil Goyal fill_macsec_sc_conf(uint16_t portid, struct rte_security_macsec_sc *sc_conf)
436322ebca6SAkhil Goyal {
437322ebca6SAkhil Goyal 	uint8_t i;
438322ebca6SAkhil Goyal 
439322ebca6SAkhil Goyal 	sc_conf->dir = mcs_port_params[portid].dir;
440322ebca6SAkhil Goyal 	sc_conf->pn_threshold = mcs_port_params[portid].pn_threshold;
441322ebca6SAkhil Goyal 	if (sc_conf->dir == RTE_SECURITY_MACSEC_DIR_TX) {
442322ebca6SAkhil Goyal 		sc_conf->sc_tx.sa_id = mcs_port_params[portid].sa_id[0];
443322ebca6SAkhil Goyal 		if (mcs_port_params[portid].sa_id[1] != 0xFFFF) {
444322ebca6SAkhil Goyal 			sc_conf->sc_tx.sa_id_rekey = mcs_port_params[portid].sa_id[1];
445322ebca6SAkhil Goyal 			sc_conf->sc_tx.re_key_en = 1;
446322ebca6SAkhil Goyal 		}
447322ebca6SAkhil Goyal 		sc_conf->sc_tx.active = 1;
448322ebca6SAkhil Goyal 		sc_conf->sc_tx.sci = mcs_port_params[portid].sci;
4490d187ba8SAkhil Goyal 		if (mcs_port_params[portid].alg == RTE_SECURITY_MACSEC_ALG_GCM_XPN_128 ||
4500d187ba8SAkhil Goyal 			       mcs_port_params[portid].alg == RTE_SECURITY_MACSEC_ALG_GCM_XPN_256)
451322ebca6SAkhil Goyal 			sc_conf->sc_tx.is_xpn = 1;
452322ebca6SAkhil Goyal 	} else {
453322ebca6SAkhil Goyal 		for (i = 0; i < RTE_SECURITY_MACSEC_NUM_AN; i++) {
454322ebca6SAkhil Goyal 			if (mcs_port_params[portid].sa_id[i] != 0xFFFF) {
455322ebca6SAkhil Goyal 				sc_conf->sc_rx.sa_id[i] = mcs_port_params[portid].sa_id[i];
456322ebca6SAkhil Goyal 				sc_conf->sc_rx.sa_in_use[i] = 1;
457322ebca6SAkhil Goyal 			}
458322ebca6SAkhil Goyal 		}
459322ebca6SAkhil Goyal 		sc_conf->sc_rx.active = 1;
4600d187ba8SAkhil Goyal 		if (mcs_port_params[portid].alg == RTE_SECURITY_MACSEC_ALG_GCM_XPN_128 ||
4610d187ba8SAkhil Goyal 			       mcs_port_params[portid].alg == RTE_SECURITY_MACSEC_ALG_GCM_XPN_256)
462322ebca6SAkhil Goyal 			sc_conf->sc_rx.is_xpn = 1;
463322ebca6SAkhil Goyal 	}
464322ebca6SAkhil Goyal }
465322ebca6SAkhil Goyal 
466322ebca6SAkhil Goyal /* Create Inline MACsec session */
467322ebca6SAkhil Goyal static int
468322ebca6SAkhil Goyal fill_session_conf(uint16_t portid, struct rte_security_session_conf *sess_conf)
469322ebca6SAkhil Goyal {
470322ebca6SAkhil Goyal 	sess_conf->action_type = RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL;
471322ebca6SAkhil Goyal 	sess_conf->protocol = RTE_SECURITY_PROTOCOL_MACSEC;
472322ebca6SAkhil Goyal 	sess_conf->macsec.dir = mcs_port_params[portid].dir;
473322ebca6SAkhil Goyal 	sess_conf->macsec.alg = mcs_port_params[portid].alg;
474322ebca6SAkhil Goyal 	sess_conf->macsec.cipher_off = 0;
475322ebca6SAkhil Goyal 	sess_conf->macsec.sci = mcs_port_params[portid].sci;
476322ebca6SAkhil Goyal 	sess_conf->macsec.sc_id = mcs_port_params[portid].sc_id;
477322ebca6SAkhil Goyal 	if (mcs_port_params[portid].dir == RTE_SECURITY_MACSEC_DIR_TX) {
478322ebca6SAkhil Goyal 		sess_conf->macsec.tx_secy.mtu = mcs_port_params[portid].mtu;
479322ebca6SAkhil Goyal 		sess_conf->macsec.tx_secy.sectag_off =
480322ebca6SAkhil Goyal 			(mcs_port_params[portid].sectag_insert_mode == 1) ?
481322ebca6SAkhil Goyal 					2 * RTE_ETHER_ADDR_LEN : RTE_VLAN_HLEN;
482322ebca6SAkhil Goyal 		sess_conf->macsec.tx_secy.sectag_insert_mode =
483322ebca6SAkhil Goyal 			mcs_port_params[portid].sectag_insert_mode;
484322ebca6SAkhil Goyal 		sess_conf->macsec.tx_secy.ctrl_port_enable = 1;
485322ebca6SAkhil Goyal 		sess_conf->macsec.tx_secy.sectag_version = 0;
486322ebca6SAkhil Goyal 		sess_conf->macsec.tx_secy.end_station = mcs_port_params[portid].end_station;
487322ebca6SAkhil Goyal 		sess_conf->macsec.tx_secy.send_sci = mcs_port_params[portid].send_sci;
488322ebca6SAkhil Goyal 		sess_conf->macsec.tx_secy.scb = mcs_port_params[portid].scb;
489322ebca6SAkhil Goyal 		sess_conf->macsec.tx_secy.encrypt = mcs_port_params[portid].encrypt;
490322ebca6SAkhil Goyal 		sess_conf->macsec.tx_secy.protect_frames = mcs_port_params[portid].protect_frames;
491322ebca6SAkhil Goyal 		sess_conf->macsec.tx_secy.icv_include_da_sa = 1;
492322ebca6SAkhil Goyal 	} else {
493322ebca6SAkhil Goyal 		sess_conf->macsec.rx_secy.replay_win_sz = mcs_port_params[portid].replay_win_sz;
494322ebca6SAkhil Goyal 		sess_conf->macsec.rx_secy.replay_protect = mcs_port_params[portid].replay_protect;
495322ebca6SAkhil Goyal 		sess_conf->macsec.rx_secy.icv_include_da_sa = 1;
496322ebca6SAkhil Goyal 		sess_conf->macsec.rx_secy.ctrl_port_enable = 1;
497322ebca6SAkhil Goyal 		sess_conf->macsec.rx_secy.preserve_sectag = 0;
498322ebca6SAkhil Goyal 		sess_conf->macsec.rx_secy.preserve_icv = 0;
499322ebca6SAkhil Goyal 		sess_conf->macsec.rx_secy.validate_frames = mcs_port_params[portid].val_frames;
500322ebca6SAkhil Goyal 	}
501322ebca6SAkhil Goyal 
502322ebca6SAkhil Goyal 	return 0;
503322ebca6SAkhil Goyal }
504322ebca6SAkhil Goyal 
505322ebca6SAkhil Goyal static int
506322ebca6SAkhil Goyal create_default_flow(uint16_t portid)
507322ebca6SAkhil Goyal {
508322ebca6SAkhil Goyal 	struct rte_flow_action action[2];
509322ebca6SAkhil Goyal 	struct rte_flow_item pattern[2];
510322ebca6SAkhil Goyal 	struct rte_flow_attr attr = {0};
511322ebca6SAkhil Goyal 	struct rte_flow_error err;
512322ebca6SAkhil Goyal 	struct rte_flow *flow;
513322ebca6SAkhil Goyal 	struct rte_flow_item_eth eth;
514322ebca6SAkhil Goyal 	static const struct rte_flow_item_eth eth_mask = {
515*e0d947a1SFerruh Yigit 		.hdr.dst_addr.addr_bytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
516*e0d947a1SFerruh Yigit 		.hdr.src_addr.addr_bytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
517322ebca6SAkhil Goyal 		.hdr.ether_type = RTE_BE16(0xFFFF),
518322ebca6SAkhil Goyal 	};
519322ebca6SAkhil Goyal 	int ret;
520322ebca6SAkhil Goyal 
521322ebca6SAkhil Goyal 	eth.has_vlan = 0;
522322ebca6SAkhil Goyal 	memcpy(&eth.hdr, mcs_port_params[portid].eth_hdr, RTE_ETHER_HDR_LEN);
523322ebca6SAkhil Goyal 
524322ebca6SAkhil Goyal 	printf("Creating flow on port %u with DST MAC address: " RTE_ETHER_ADDR_PRT_FMT
525322ebca6SAkhil Goyal 			", SRC MAC address: "RTE_ETHER_ADDR_PRT_FMT"\n\n",
526322ebca6SAkhil Goyal 			portid,
527322ebca6SAkhil Goyal 			RTE_ETHER_ADDR_BYTES(&eth.hdr.dst_addr),
528322ebca6SAkhil Goyal 			RTE_ETHER_ADDR_BYTES(&eth.hdr.src_addr));
529322ebca6SAkhil Goyal 
530322ebca6SAkhil Goyal 	pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
531322ebca6SAkhil Goyal 	pattern[0].spec = &eth;
532322ebca6SAkhil Goyal 	pattern[0].mask = &eth_mask;
533322ebca6SAkhil Goyal 	pattern[0].last = NULL;
534322ebca6SAkhil Goyal 	pattern[1].type = RTE_FLOW_ITEM_TYPE_END;
535322ebca6SAkhil Goyal 
536322ebca6SAkhil Goyal 	action[0].type = RTE_FLOW_ACTION_TYPE_SECURITY;
537322ebca6SAkhil Goyal 	action[0].conf = mcs_port_params[portid].sess;
538322ebca6SAkhil Goyal 	action[1].type = RTE_FLOW_ACTION_TYPE_END;
539322ebca6SAkhil Goyal 	action[1].conf = NULL;
540322ebca6SAkhil Goyal 
541322ebca6SAkhil Goyal 	attr.ingress = (mcs_port_params[portid].dir == RTE_SECURITY_MACSEC_DIR_RX) ? 1 : 0;
542322ebca6SAkhil Goyal 	attr.egress = (mcs_port_params[portid].dir == RTE_SECURITY_MACSEC_DIR_TX) ? 1 : 0;
543322ebca6SAkhil Goyal 
544322ebca6SAkhil Goyal 	ret = rte_flow_validate(portid, &attr, pattern, action, &err);
545322ebca6SAkhil Goyal 	if (ret) {
546322ebca6SAkhil Goyal 		printf("\nValidate flow failed, ret = %d\n", ret);
547322ebca6SAkhil Goyal 		return -1;
548322ebca6SAkhil Goyal 	}
549322ebca6SAkhil Goyal 	flow = rte_flow_create(portid, &attr, pattern, action, &err);
550322ebca6SAkhil Goyal 	if (flow == NULL) {
551322ebca6SAkhil Goyal 		printf("\nDefault flow rule create failed\n");
552322ebca6SAkhil Goyal 		return -1;
553322ebca6SAkhil Goyal 	}
554322ebca6SAkhil Goyal 
555322ebca6SAkhil Goyal 	if (mcs_port_params[portid].dir == RTE_SECURITY_MACSEC_DIR_TX)
556322ebca6SAkhil Goyal 		mcs_port_params[portid].tx_flow = flow;
557322ebca6SAkhil Goyal 	else
558322ebca6SAkhil Goyal 		mcs_port_params[portid].rx_flow = flow;
559322ebca6SAkhil Goyal 
560322ebca6SAkhil Goyal 	return 0;
561322ebca6SAkhil Goyal }
562322ebca6SAkhil Goyal 
563322ebca6SAkhil Goyal static void
564322ebca6SAkhil Goyal destroy_default_flow(uint16_t portid)
565322ebca6SAkhil Goyal {
566322ebca6SAkhil Goyal 	struct rte_flow_error err;
567322ebca6SAkhil Goyal 	int ret;
568322ebca6SAkhil Goyal 
569322ebca6SAkhil Goyal 	if (mcs_port_params[portid].tx_flow) {
570322ebca6SAkhil Goyal 		ret = rte_flow_destroy(portid, mcs_port_params[portid].tx_flow, &err);
571322ebca6SAkhil Goyal 		if (ret) {
572322ebca6SAkhil Goyal 			printf("\nDefault Tx flow rule destroy failed\n");
573322ebca6SAkhil Goyal 			return;
574322ebca6SAkhil Goyal 		}
575322ebca6SAkhil Goyal 		mcs_port_params[portid].tx_flow = NULL;
576322ebca6SAkhil Goyal 	}
577322ebca6SAkhil Goyal 	if (mcs_port_params[portid].rx_flow) {
578322ebca6SAkhil Goyal 		ret = rte_flow_destroy(portid, mcs_port_params[portid].rx_flow, &err);
579322ebca6SAkhil Goyal 		if (ret) {
580322ebca6SAkhil Goyal 			printf("\nDefault Rx flow rule destroy failed\n");
581322ebca6SAkhil Goyal 			return;
582322ebca6SAkhil Goyal 		}
583322ebca6SAkhil Goyal 		mcs_port_params[portid].rx_flow = NULL;
584322ebca6SAkhil Goyal 	}
585322ebca6SAkhil Goyal }
586322ebca6SAkhil Goyal 
587322ebca6SAkhil Goyal static void
588322ebca6SAkhil Goyal clean_macsec_resources(uint16_t portid)
589322ebca6SAkhil Goyal {
590322ebca6SAkhil Goyal 	uint8_t an;
591322ebca6SAkhil Goyal 
592322ebca6SAkhil Goyal 	destroy_default_flow(portid);
593322ebca6SAkhil Goyal 	rte_security_session_destroy(mcs_port_params[portid].sec_ctx,
594322ebca6SAkhil Goyal 				mcs_port_params[portid].sess);
595322ebca6SAkhil Goyal 	rte_security_macsec_sc_destroy(mcs_port_params[portid].sec_ctx,
596322ebca6SAkhil Goyal 				mcs_port_params[portid].sc_id,
597322ebca6SAkhil Goyal 				mcs_port_params[portid].dir);
598322ebca6SAkhil Goyal 	for (an = 0; an < RTE_SECURITY_MACSEC_NUM_AN; an++) {
599322ebca6SAkhil Goyal 		if (mcs_port_params[portid].sa_id[an] != 0xFFFF)
600322ebca6SAkhil Goyal 			rte_security_macsec_sa_destroy(mcs_port_params[portid].sec_ctx,
601322ebca6SAkhil Goyal 				mcs_port_params[portid].sa_id[an],
602322ebca6SAkhil Goyal 				mcs_port_params[portid].dir);
603322ebca6SAkhil Goyal 	}
604322ebca6SAkhil Goyal }
605322ebca6SAkhil Goyal 
606322ebca6SAkhil Goyal static int
607322ebca6SAkhil Goyal initialize_macsec_session(uint8_t portid)
608322ebca6SAkhil Goyal {
609322ebca6SAkhil Goyal 	struct rte_security_session_conf sess_conf = {0};
610322ebca6SAkhil Goyal 	struct rte_security_macsec_sa sa_conf = {0};
611322ebca6SAkhil Goyal 	struct rte_security_macsec_sc sc_conf = {0};
612322ebca6SAkhil Goyal 	int id, ret;
613322ebca6SAkhil Goyal 
614322ebca6SAkhil Goyal 	/* Create MACsec SA. */
615322ebca6SAkhil Goyal 	fill_macsec_sa_conf(portid, &sa_conf);
616322ebca6SAkhil Goyal 	id = rte_security_macsec_sa_create(mcs_port_params[portid].sec_ctx, &sa_conf);
617322ebca6SAkhil Goyal 	if (id < 0) {
618322ebca6SAkhil Goyal 		printf("MACsec SA create failed : %d.\n", id);
619322ebca6SAkhil Goyal 		return -1;
620322ebca6SAkhil Goyal 	}
621322ebca6SAkhil Goyal 	mcs_port_params[portid].sa_id[0] = (uint16_t)id;
622322ebca6SAkhil Goyal 	mcs_port_params[portid].sa_id[1] = 0xFFFF;
623322ebca6SAkhil Goyal 	mcs_port_params[portid].sa_id[2] = 0xFFFF;
624322ebca6SAkhil Goyal 	mcs_port_params[portid].sa_id[3] = 0xFFFF;
625322ebca6SAkhil Goyal 
626322ebca6SAkhil Goyal 	printf("\nsa_id %d created.\n", mcs_port_params[portid].sa_id[0]);
627322ebca6SAkhil Goyal 
628322ebca6SAkhil Goyal 	/* Create MACsec SC. */
629322ebca6SAkhil Goyal 	fill_macsec_sc_conf(portid, &sc_conf);
630322ebca6SAkhil Goyal 	id = rte_security_macsec_sc_create(mcs_port_params[portid].sec_ctx, &sc_conf);
631322ebca6SAkhil Goyal 	if (id < 0) {
632322ebca6SAkhil Goyal 		printf("MACsec SC create failed : %d.\n", id);
633322ebca6SAkhil Goyal 		goto out;
634322ebca6SAkhil Goyal 	}
635322ebca6SAkhil Goyal 	mcs_port_params[portid].sc_id = (uint16_t)id;
636322ebca6SAkhil Goyal 	printf("\nsc_id %d created.\n", mcs_port_params[portid].sc_id);
637322ebca6SAkhil Goyal 
638322ebca6SAkhil Goyal 	/* Create Inline MACsec session. */
639322ebca6SAkhil Goyal 	ret = fill_session_conf(portid, &sess_conf);
640322ebca6SAkhil Goyal 	if (ret) {
641322ebca6SAkhil Goyal 		printf("MACsec Session conf failed.\n");
642322ebca6SAkhil Goyal 		goto out;
643322ebca6SAkhil Goyal 	}
644322ebca6SAkhil Goyal 	mcs_port_params[portid].sess =
645322ebca6SAkhil Goyal 		rte_security_session_create(mcs_port_params[portid].sec_ctx,
646322ebca6SAkhil Goyal 				&sess_conf, mcs_port_params[portid].sess_pool);
647322ebca6SAkhil Goyal 	if (mcs_port_params[portid].sess == NULL) {
648322ebca6SAkhil Goyal 		printf("MACSEC Session init failed errno: %d.\n", rte_errno);
649322ebca6SAkhil Goyal 		goto out;
650322ebca6SAkhil Goyal 	}
651322ebca6SAkhil Goyal 
652322ebca6SAkhil Goyal 	/* Create MACsec flow. */
653322ebca6SAkhil Goyal 	ret = create_default_flow(portid);
654322ebca6SAkhil Goyal 	if (ret)
655322ebca6SAkhil Goyal 		goto out;
656322ebca6SAkhil Goyal 
657322ebca6SAkhil Goyal 	return 0;
658322ebca6SAkhil Goyal out:
659322ebca6SAkhil Goyal 	clean_macsec_resources(portid);
660322ebca6SAkhil Goyal 	return -1;
661322ebca6SAkhil Goyal }
662322ebca6SAkhil Goyal 
663322ebca6SAkhil Goyal /* main processing loop */
664322ebca6SAkhil Goyal static void
665322ebca6SAkhil Goyal l2fwd_main_loop(void)
666322ebca6SAkhil Goyal {
667322ebca6SAkhil Goyal 	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
668322ebca6SAkhil Goyal 	struct rte_mbuf *m;
669322ebca6SAkhil Goyal 	int sent;
670322ebca6SAkhil Goyal 	unsigned int lcore_id;
671322ebca6SAkhil Goyal 	uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
672322ebca6SAkhil Goyal 	unsigned int i, j, portid, nb_rx;
673322ebca6SAkhil Goyal 	struct lcore_queue_conf *qconf;
674322ebca6SAkhil Goyal 	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S *
675322ebca6SAkhil Goyal 			BURST_TX_DRAIN_US;
676322ebca6SAkhil Goyal 	struct rte_eth_dev_tx_buffer *buffer;
677322ebca6SAkhil Goyal 
678322ebca6SAkhil Goyal 	prev_tsc = 0;
679322ebca6SAkhil Goyal 	timer_tsc = 0;
680322ebca6SAkhil Goyal 
681322ebca6SAkhil Goyal 	lcore_id = rte_lcore_id();
682322ebca6SAkhil Goyal 	qconf = &lcore_queue_conf[lcore_id];
683322ebca6SAkhil Goyal 
684322ebca6SAkhil Goyal 	if (qconf->n_rx_port == 0) {
685322ebca6SAkhil Goyal 		RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
686322ebca6SAkhil Goyal 		return;
687322ebca6SAkhil Goyal 	}
688322ebca6SAkhil Goyal 
689322ebca6SAkhil Goyal 	RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
690322ebca6SAkhil Goyal 
691322ebca6SAkhil Goyal 	for (i = 0; i < qconf->n_rx_port; i++) {
692322ebca6SAkhil Goyal 
693322ebca6SAkhil Goyal 		portid = qconf->rx_port_list[i];
694322ebca6SAkhil Goyal 
695322ebca6SAkhil Goyal 		RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
696322ebca6SAkhil Goyal 			portid);
697322ebca6SAkhil Goyal 	}
698322ebca6SAkhil Goyal 
699322ebca6SAkhil Goyal 	while (!force_quit) {
700322ebca6SAkhil Goyal 
701322ebca6SAkhil Goyal 		/* Drains TX queue in its main loop. 8< */
702322ebca6SAkhil Goyal 		cur_tsc = rte_rdtsc();
703322ebca6SAkhil Goyal 
704322ebca6SAkhil Goyal 		/*
705322ebca6SAkhil Goyal 		 * TX burst queue drain
706322ebca6SAkhil Goyal 		 */
707322ebca6SAkhil Goyal 		diff_tsc = cur_tsc - prev_tsc;
708322ebca6SAkhil Goyal 		if (unlikely(diff_tsc > drain_tsc)) {
709322ebca6SAkhil Goyal 
710322ebca6SAkhil Goyal 			for (i = 0; i < qconf->n_rx_port; i++) {
711322ebca6SAkhil Goyal 
712322ebca6SAkhil Goyal 				portid = l2fwd_dst_ports[qconf->rx_port_list[i]];
713322ebca6SAkhil Goyal 				buffer = tx_buffer[portid];
714322ebca6SAkhil Goyal 
715322ebca6SAkhil Goyal 				sent = rte_eth_tx_buffer_flush(portid, 0, buffer);
716322ebca6SAkhil Goyal 				if (sent)
717322ebca6SAkhil Goyal 					port_statistics[portid].tx += sent;
718322ebca6SAkhil Goyal 
719322ebca6SAkhil Goyal 			}
720322ebca6SAkhil Goyal 
721322ebca6SAkhil Goyal 			/* if timer is enabled */
722322ebca6SAkhil Goyal 			if (timer_period > 0) {
723322ebca6SAkhil Goyal 
724322ebca6SAkhil Goyal 				/* advance the timer */
725322ebca6SAkhil Goyal 				timer_tsc += diff_tsc;
726322ebca6SAkhil Goyal 
727322ebca6SAkhil Goyal 				/* if timer has reached its timeout */
728322ebca6SAkhil Goyal 				if (unlikely(timer_tsc >= timer_period)) {
729322ebca6SAkhil Goyal 
730322ebca6SAkhil Goyal 					/* do this only on main core */
731322ebca6SAkhil Goyal 					if (lcore_id == rte_get_main_lcore()) {
732322ebca6SAkhil Goyal 						print_stats();
733322ebca6SAkhil Goyal 						/* reset the timer */
734322ebca6SAkhil Goyal 						timer_tsc = 0;
735322ebca6SAkhil Goyal 					}
736322ebca6SAkhil Goyal 				}
737322ebca6SAkhil Goyal 			}
738322ebca6SAkhil Goyal 
739322ebca6SAkhil Goyal 			prev_tsc = cur_tsc;
740322ebca6SAkhil Goyal 		}
741322ebca6SAkhil Goyal 		/* >8 End of draining TX queue. */
742322ebca6SAkhil Goyal 
743322ebca6SAkhil Goyal 		/* Read packet from RX queues. 8< */
744322ebca6SAkhil Goyal 		for (i = 0; i < qconf->n_rx_port; i++) {
745322ebca6SAkhil Goyal 
746322ebca6SAkhil Goyal 			portid = qconf->rx_port_list[i];
747322ebca6SAkhil Goyal 			nb_rx = rte_eth_rx_burst(portid, 0,
748322ebca6SAkhil Goyal 						 pkts_burst, MAX_PKT_BURST);
749322ebca6SAkhil Goyal 
750322ebca6SAkhil Goyal 			if (unlikely(nb_rx == 0))
751322ebca6SAkhil Goyal 				continue;
752322ebca6SAkhil Goyal 
753322ebca6SAkhil Goyal 			port_statistics[portid].rx += nb_rx;
754322ebca6SAkhil Goyal 
755322ebca6SAkhil Goyal 			for (j = 0; j < nb_rx; j++) {
756322ebca6SAkhil Goyal 				m = pkts_burst[j];
757322ebca6SAkhil Goyal 				rte_prefetch0(rte_pktmbuf_mtod(m, void *));
758322ebca6SAkhil Goyal 				l2fwd_simple_forward(m, portid);
759322ebca6SAkhil Goyal 			}
760322ebca6SAkhil Goyal 		}
761322ebca6SAkhil Goyal 		/* >8 End of read packet from RX queues. */
762322ebca6SAkhil Goyal 	}
763322ebca6SAkhil Goyal 	if (force_quit) {
764322ebca6SAkhil Goyal 		for (i = 0; i < qconf->n_rx_port; i++) {
765322ebca6SAkhil Goyal 			portid = qconf->rx_port_list[i];
766322ebca6SAkhil Goyal 			clean_macsec_resources(portid);
767322ebca6SAkhil Goyal 		}
768322ebca6SAkhil Goyal 	}
769322ebca6SAkhil Goyal }
770322ebca6SAkhil Goyal static int
771322ebca6SAkhil Goyal l2fwd_launch_one_lcore(__rte_unused void *arg)
772322ebca6SAkhil Goyal {
773322ebca6SAkhil Goyal 	l2fwd_main_loop();
774322ebca6SAkhil Goyal 	return 0;
775322ebca6SAkhil Goyal }
776322ebca6SAkhil Goyal 
777322ebca6SAkhil Goyal /* display usage */
778322ebca6SAkhil Goyal static void
779322ebca6SAkhil Goyal l2fwd_usage(const char *prgname)
780322ebca6SAkhil Goyal {
781322ebca6SAkhil Goyal 	printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
782322ebca6SAkhil Goyal 	       "  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
783322ebca6SAkhil Goyal 	       "  -q NQ: number of queue (=ports) per lcore (default is 1)\n"
784322ebca6SAkhil Goyal 	       "  -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n"
785322ebca6SAkhil Goyal 	       "  --mcs-tx-portmask: Hexadecimal bitmask for MACsec Tx(Encap) ports\n"
786322ebca6SAkhil Goyal 	       "  --mcs-rx-portmask: Hexadecimal bitmask for MACsec Rx(Decap) ports\n"
787322ebca6SAkhil Goyal 	       "  --mcs-port-config '(<port>,<src-mac>,<dst-mac>)'\n"
788322ebca6SAkhil Goyal 	       "  --portmap: Configure forwarding port pair mapping\n"
789322ebca6SAkhil Goyal 	       "	      Default: alternate port pairs\n\n",
790322ebca6SAkhil Goyal 	       prgname);
791322ebca6SAkhil Goyal }
792322ebca6SAkhil Goyal 
793322ebca6SAkhil Goyal static int
794322ebca6SAkhil Goyal l2fwd_parse_portmask(const char *portmask)
795322ebca6SAkhil Goyal {
796322ebca6SAkhil Goyal 	char *end = NULL;
797322ebca6SAkhil Goyal 	unsigned long pm;
798322ebca6SAkhil Goyal 
799322ebca6SAkhil Goyal 	/* parse hexadecimal string */
800322ebca6SAkhil Goyal 	pm = strtoul(portmask, &end, 16);
801322ebca6SAkhil Goyal 	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
802322ebca6SAkhil Goyal 		return 0;
803322ebca6SAkhil Goyal 
804322ebca6SAkhil Goyal 	return pm;
805322ebca6SAkhil Goyal }
806322ebca6SAkhil Goyal 
807322ebca6SAkhil Goyal static int
808322ebca6SAkhil Goyal l2fwd_parse_port_pair_config(const char *q_arg)
809322ebca6SAkhil Goyal {
810322ebca6SAkhil Goyal 	enum fieldnames {
811322ebca6SAkhil Goyal 		FLD_PORT1 = 0,
812322ebca6SAkhil Goyal 		FLD_PORT2,
813322ebca6SAkhil Goyal 		_NUM_FLD
814322ebca6SAkhil Goyal 	};
815322ebca6SAkhil Goyal 	unsigned long int_fld[_NUM_FLD];
816322ebca6SAkhil Goyal 	const char *p, *p0 = q_arg;
817322ebca6SAkhil Goyal 	char *str_fld[_NUM_FLD];
818322ebca6SAkhil Goyal 	unsigned int size;
819322ebca6SAkhil Goyal 	char s[256];
820322ebca6SAkhil Goyal 	char *end;
821322ebca6SAkhil Goyal 	int i;
822322ebca6SAkhil Goyal 
823322ebca6SAkhil Goyal 	nb_port_pair_params = 0;
824322ebca6SAkhil Goyal 
825322ebca6SAkhil Goyal 	while ((p = strchr(p0, '(')) != NULL) {
826322ebca6SAkhil Goyal 		++p;
827322ebca6SAkhil Goyal 		p0 = strchr(p, ')');
828322ebca6SAkhil Goyal 		if (p0 == NULL)
829322ebca6SAkhil Goyal 			return -1;
830322ebca6SAkhil Goyal 
831322ebca6SAkhil Goyal 		size = p0 - p;
832322ebca6SAkhil Goyal 		if (size >= sizeof(s))
833322ebca6SAkhil Goyal 			return -1;
834322ebca6SAkhil Goyal 
835322ebca6SAkhil Goyal 		memcpy(s, p, size);
836322ebca6SAkhil Goyal 		s[size] = '\0';
837322ebca6SAkhil Goyal 		if (rte_strsplit(s, sizeof(s), str_fld,
838322ebca6SAkhil Goyal 				 _NUM_FLD, ',') != _NUM_FLD)
839322ebca6SAkhil Goyal 			return -1;
840322ebca6SAkhil Goyal 		for (i = 0; i < _NUM_FLD; i++) {
841322ebca6SAkhil Goyal 			errno = 0;
842322ebca6SAkhil Goyal 			int_fld[i] = strtoul(str_fld[i], &end, 0);
843322ebca6SAkhil Goyal 			if (errno != 0 || end == str_fld[i] ||
844322ebca6SAkhil Goyal 			    int_fld[i] >= RTE_MAX_ETHPORTS)
845322ebca6SAkhil Goyal 				return -1;
846322ebca6SAkhil Goyal 		}
847322ebca6SAkhil Goyal 		if (nb_port_pair_params >= RTE_MAX_ETHPORTS/2) {
848322ebca6SAkhil Goyal 			printf("exceeded max number of port pair params: %hu\n",
849322ebca6SAkhil Goyal 				nb_port_pair_params);
850322ebca6SAkhil Goyal 			return -1;
851322ebca6SAkhil Goyal 		}
852322ebca6SAkhil Goyal 		port_pair_params_array[nb_port_pair_params].port[0] =
853322ebca6SAkhil Goyal 				(uint16_t)int_fld[FLD_PORT1];
854322ebca6SAkhil Goyal 		port_pair_params_array[nb_port_pair_params].port[1] =
855322ebca6SAkhil Goyal 				(uint16_t)int_fld[FLD_PORT2];
856322ebca6SAkhil Goyal 		++nb_port_pair_params;
857322ebca6SAkhil Goyal 	}
858322ebca6SAkhil Goyal 	port_pair_params = port_pair_params_array;
859322ebca6SAkhil Goyal 	return 0;
860322ebca6SAkhil Goyal }
861322ebca6SAkhil Goyal 
862322ebca6SAkhil Goyal static int
863322ebca6SAkhil Goyal l2fwd_parse_macsec_port_config(const char *q_arg)
864322ebca6SAkhil Goyal {
865322ebca6SAkhil Goyal 	enum fieldnames {
866322ebca6SAkhil Goyal 		FLD_PORT = 0,
867322ebca6SAkhil Goyal 		FLD_SRC,
868322ebca6SAkhil Goyal 		FLD_DST,
869322ebca6SAkhil Goyal 		_NUM_FLD
870322ebca6SAkhil Goyal 	};
871322ebca6SAkhil Goyal 	unsigned int portid;
872322ebca6SAkhil Goyal 	struct rte_ether_addr src, dst;
873322ebca6SAkhil Goyal 	const char *p, *p0 = q_arg;
874322ebca6SAkhil Goyal 	char *str_fld[_NUM_FLD];
875322ebca6SAkhil Goyal 	unsigned int size;
876322ebca6SAkhil Goyal 	char s[256];
877322ebca6SAkhil Goyal 	char *end;
878322ebca6SAkhil Goyal 
879322ebca6SAkhil Goyal 	nb_port_pair_params = 0;
880322ebca6SAkhil Goyal 
881322ebca6SAkhil Goyal 	while ((p = strchr(p0, '(')) != NULL) {
882322ebca6SAkhil Goyal 		++p;
883322ebca6SAkhil Goyal 		p0 = strchr(p, ')');
884322ebca6SAkhil Goyal 		if (p0 == NULL)
885322ebca6SAkhil Goyal 			return -1;
886322ebca6SAkhil Goyal 
887322ebca6SAkhil Goyal 		size = p0 - p;
888322ebca6SAkhil Goyal 		if (size >= sizeof(s))
889322ebca6SAkhil Goyal 			return -1;
890322ebca6SAkhil Goyal 
891322ebca6SAkhil Goyal 		memcpy(s, p, size);
892322ebca6SAkhil Goyal 		s[size] = '\0';
893322ebca6SAkhil Goyal 		if (rte_strsplit(s, sizeof(s), str_fld,
894322ebca6SAkhil Goyal 				 _NUM_FLD, ',') != _NUM_FLD)
895322ebca6SAkhil Goyal 			return -1;
896322ebca6SAkhil Goyal 		errno = 0;
897322ebca6SAkhil Goyal 		portid = strtoul(str_fld[FLD_PORT], &end, 0);
898322ebca6SAkhil Goyal 		if (errno != 0 || end == str_fld[FLD_PORT] || portid >= RTE_MAX_ETHPORTS)
899322ebca6SAkhil Goyal 			return -1;
900322ebca6SAkhil Goyal 		if (port_ether_hdr_config[portid].ether_type == 0x0800) {
901322ebca6SAkhil Goyal 			printf("MACsec src-dst MAC addr already parsed for port: %d\n",
902322ebca6SAkhil Goyal 					portid);
903322ebca6SAkhil Goyal 			return -1;
904322ebca6SAkhil Goyal 		}
905322ebca6SAkhil Goyal 		if (rte_ether_unformat_addr(str_fld[FLD_SRC], &src) ||
906322ebca6SAkhil Goyal 				rte_ether_unformat_addr(str_fld[FLD_DST], &dst))
907322ebca6SAkhil Goyal 			return -1;
908322ebca6SAkhil Goyal 
909322ebca6SAkhil Goyal 		memcpy(&port_ether_hdr_config[portid].src_addr, &src, sizeof(src));
910322ebca6SAkhil Goyal 		memcpy(&port_ether_hdr_config[portid].dst_addr, &dst, sizeof(dst));
911322ebca6SAkhil Goyal 		port_ether_hdr_config[portid].ether_type = 0x0800;
912322ebca6SAkhil Goyal 	}
913322ebca6SAkhil Goyal 
914322ebca6SAkhil Goyal 	return 0;
915322ebca6SAkhil Goyal }
916322ebca6SAkhil Goyal 
917322ebca6SAkhil Goyal 
918322ebca6SAkhil Goyal static unsigned int
919322ebca6SAkhil Goyal l2fwd_parse_nqueue(const char *q_arg)
920322ebca6SAkhil Goyal {
921322ebca6SAkhil Goyal 	char *end = NULL;
922322ebca6SAkhil Goyal 	unsigned long n;
923322ebca6SAkhil Goyal 
924322ebca6SAkhil Goyal 	/* parse hexadecimal string */
925322ebca6SAkhil Goyal 	n = strtoul(q_arg, &end, 10);
926322ebca6SAkhil Goyal 	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
927322ebca6SAkhil Goyal 		return 0;
928322ebca6SAkhil Goyal 	if (n == 0)
929322ebca6SAkhil Goyal 		return 0;
930322ebca6SAkhil Goyal 	if (n >= MAX_RX_QUEUE_PER_LCORE)
931322ebca6SAkhil Goyal 		return 0;
932322ebca6SAkhil Goyal 
933322ebca6SAkhil Goyal 	return n;
934322ebca6SAkhil Goyal }
935322ebca6SAkhil Goyal 
936322ebca6SAkhil Goyal static int
937322ebca6SAkhil Goyal l2fwd_parse_timer_period(const char *q_arg)
938322ebca6SAkhil Goyal {
939322ebca6SAkhil Goyal 	char *end = NULL;
940322ebca6SAkhil Goyal 	int n;
941322ebca6SAkhil Goyal 
942322ebca6SAkhil Goyal 	/* parse number string */
943322ebca6SAkhil Goyal 	n = strtol(q_arg, &end, 10);
944322ebca6SAkhil Goyal 	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
945322ebca6SAkhil Goyal 		return -1;
946322ebca6SAkhil Goyal 	if (n >= MAX_TIMER_PERIOD)
947322ebca6SAkhil Goyal 		return -1;
948322ebca6SAkhil Goyal 
949322ebca6SAkhil Goyal 	return n;
950322ebca6SAkhil Goyal }
951322ebca6SAkhil Goyal 
952322ebca6SAkhil Goyal static const char short_options[] =
953322ebca6SAkhil Goyal 	"p:"  /* portmask */
954322ebca6SAkhil Goyal 	"P"   /* promiscuous */
955322ebca6SAkhil Goyal 	"q:"  /* number of queues */
956322ebca6SAkhil Goyal 	"T:"  /* timer period */
957322ebca6SAkhil Goyal 	;
958322ebca6SAkhil Goyal 
959322ebca6SAkhil Goyal #define CMD_LINE_OPT_NO_MAC_UPDATING	"no-mac-updating"
960322ebca6SAkhil Goyal #define CMD_LINE_OPT_PORTMAP_CONFIG	"portmap"
961322ebca6SAkhil Goyal #define CMD_LINE_OPT_MACSEC_TX_PORTMASK	"mcs-tx-portmask"
962322ebca6SAkhil Goyal #define CMD_LINE_OPT_MACSEC_RX_PORTMASK	"mcs-rx-portmask"
963322ebca6SAkhil Goyal #define CMD_LINE_OPT_MACSEC_PORT_CONFIG	"mcs-port-config"
964322ebca6SAkhil Goyal 
965322ebca6SAkhil Goyal enum {
966322ebca6SAkhil Goyal 	/* Long options mapped to a short option.
967322ebca6SAkhil Goyal 	 * First long only option value must be >= 256,
968322ebca6SAkhil Goyal 	 * so that we won't conflict with short options.
969322ebca6SAkhil Goyal 	 */
970322ebca6SAkhil Goyal 	CMD_LINE_OPT_NO_MAC_UPDATING_NUM = 256,
971322ebca6SAkhil Goyal 	CMD_LINE_OPT_PORTMAP_NUM,
972322ebca6SAkhil Goyal 	CMD_LINE_OPT_MACSEC_TX_PORTMASK_NUM,
973322ebca6SAkhil Goyal 	CMD_LINE_OPT_MACSEC_RX_PORTMASK_NUM,
974322ebca6SAkhil Goyal 	CMD_LINE_OPT_MACSEC_PORT_CFG_NUM,
975322ebca6SAkhil Goyal };
976322ebca6SAkhil Goyal 
977322ebca6SAkhil Goyal static const struct option lgopts[] = {
978322ebca6SAkhil Goyal 	{ CMD_LINE_OPT_NO_MAC_UPDATING, no_argument, 0,
979322ebca6SAkhil Goyal 		CMD_LINE_OPT_NO_MAC_UPDATING_NUM},
980322ebca6SAkhil Goyal 	{ CMD_LINE_OPT_PORTMAP_CONFIG, 1, 0, CMD_LINE_OPT_PORTMAP_NUM},
981322ebca6SAkhil Goyal 	{ CMD_LINE_OPT_MACSEC_TX_PORTMASK, required_argument, 0,
982322ebca6SAkhil Goyal 		CMD_LINE_OPT_MACSEC_TX_PORTMASK_NUM},
983322ebca6SAkhil Goyal 	{ CMD_LINE_OPT_MACSEC_RX_PORTMASK, required_argument, 0,
984322ebca6SAkhil Goyal 		CMD_LINE_OPT_MACSEC_RX_PORTMASK_NUM},
985322ebca6SAkhil Goyal 	{ CMD_LINE_OPT_MACSEC_PORT_CONFIG, 1, 0, CMD_LINE_OPT_MACSEC_PORT_CFG_NUM},
986322ebca6SAkhil Goyal 	{NULL, 0, 0, 0}
987322ebca6SAkhil Goyal };
988322ebca6SAkhil Goyal 
989322ebca6SAkhil Goyal /** Generate default options for application. */
990322ebca6SAkhil Goyal static void
991322ebca6SAkhil Goyal l2fwd_macsec_default_options(struct l2fwd_macsec_options *options)
992322ebca6SAkhil Goyal {
993322ebca6SAkhil Goyal 	uint16_t portid;
994322ebca6SAkhil Goyal 	uint8_t salt[MCS_SALT_LEN] = {0};
995322ebca6SAkhil Goyal 	uint8_t key[16] = {
996322ebca6SAkhil Goyal 			0x07, 0x1B, 0x11, 0x3B, 0x0C, 0xA7, 0x43, 0xFE,
997322ebca6SAkhil Goyal 			0xCC, 0xCF, 0x3D, 0x05, 0x1F, 0x73, 0x73, 0x82
998322ebca6SAkhil Goyal 		};
999322ebca6SAkhil Goyal 
1000322ebca6SAkhil Goyal 	options->portmask = 0xffffffff;
1001322ebca6SAkhil Goyal 	options->nb_ports_per_lcore = 1;
1002322ebca6SAkhil Goyal 	options->single_lcore = 0;
1003322ebca6SAkhil Goyal 
1004322ebca6SAkhil Goyal 	RTE_ETH_FOREACH_DEV(portid) {
1005322ebca6SAkhil Goyal 		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
1006322ebca6SAkhil Goyal 			continue;
1007322ebca6SAkhil Goyal 		if ((options->tx_portmask & (1 << portid)) != 0)
1008322ebca6SAkhil Goyal 			mcs_port_params[portid].dir = RTE_SECURITY_MACSEC_DIR_TX;
1009322ebca6SAkhil Goyal 
1010322ebca6SAkhil Goyal 		if ((options->rx_portmask & (1 << portid)) != 0)
1011322ebca6SAkhil Goyal 			mcs_port_params[portid].dir = RTE_SECURITY_MACSEC_DIR_RX;
1012322ebca6SAkhil Goyal 
10130d187ba8SAkhil Goyal 		mcs_port_params[portid].alg = RTE_SECURITY_MACSEC_ALG_GCM_XPN_128;
1014322ebca6SAkhil Goyal 		memcpy(mcs_port_params[portid].sa_key.data, key, 16);
1015322ebca6SAkhil Goyal 		mcs_port_params[portid].sa_key.len = 16;
1016322ebca6SAkhil Goyal 		memcpy(mcs_port_params[portid].salt, salt, MCS_SALT_LEN);
1017322ebca6SAkhil Goyal 
1018322ebca6SAkhil Goyal 		memcpy(mcs_port_params[portid].eth_hdr, &port_ether_hdr_config[portid],
1019322ebca6SAkhil Goyal 				RTE_ETHER_HDR_LEN);
1020322ebca6SAkhil Goyal 
1021322ebca6SAkhil Goyal 		mcs_port_params[portid].ssci = 0;
1022322ebca6SAkhil Goyal 		mcs_port_params[portid].pn_threshold = 0xffffffffffffffff;
1023322ebca6SAkhil Goyal 		mcs_port_params[portid].xpn = 0;
1024322ebca6SAkhil Goyal 		mcs_port_params[portid].next_pn = 1;
1025322ebca6SAkhil Goyal 		mcs_port_params[portid].mtu = 1500;
1026322ebca6SAkhil Goyal 		mcs_port_params[portid].sectag_insert_mode = 1;
1027322ebca6SAkhil Goyal 		mcs_port_params[portid].encrypt = true;
1028322ebca6SAkhil Goyal 		mcs_port_params[portid].protect_frames = true;
1029322ebca6SAkhil Goyal 		mcs_port_params[portid].replay_protect = false;
1030322ebca6SAkhil Goyal 		mcs_port_params[portid].val_frames = RTE_SECURITY_MACSEC_VALIDATE_STRICT;
1031322ebca6SAkhil Goyal 		mcs_port_params[portid].send_sci = true;
1032322ebca6SAkhil Goyal 		mcs_port_params[portid].end_station = false;
1033322ebca6SAkhil Goyal 		mcs_port_params[portid].scb = false;
1034322ebca6SAkhil Goyal 	}
1035322ebca6SAkhil Goyal }
1036322ebca6SAkhil Goyal 
1037322ebca6SAkhil Goyal /* Parse the argument given in the command line of the application */
1038322ebca6SAkhil Goyal static int
1039322ebca6SAkhil Goyal l2fwd_parse_args(struct l2fwd_macsec_options *options,
1040322ebca6SAkhil Goyal 		int argc, char **argv)
1041322ebca6SAkhil Goyal {
1042322ebca6SAkhil Goyal 	int opt, ret, timer_secs;
1043322ebca6SAkhil Goyal 	char **argvopt;
1044322ebca6SAkhil Goyal 	int option_index;
1045322ebca6SAkhil Goyal 	char *prgname = argv[0];
1046322ebca6SAkhil Goyal 
1047322ebca6SAkhil Goyal 	argvopt = argv;
1048322ebca6SAkhil Goyal 	port_pair_params = NULL;
1049322ebca6SAkhil Goyal 
1050322ebca6SAkhil Goyal 	while ((opt = getopt_long(argc, argvopt, short_options,
1051322ebca6SAkhil Goyal 				  lgopts, &option_index)) != EOF) {
1052322ebca6SAkhil Goyal 
1053322ebca6SAkhil Goyal 		switch (opt) {
1054322ebca6SAkhil Goyal 		/* portmask */
1055322ebca6SAkhil Goyal 		case 'p':
1056322ebca6SAkhil Goyal 			l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
1057322ebca6SAkhil Goyal 			if (l2fwd_enabled_port_mask == 0) {
1058322ebca6SAkhil Goyal 				printf("invalid portmask\n");
1059322ebca6SAkhil Goyal 				l2fwd_usage(prgname);
1060322ebca6SAkhil Goyal 				return -1;
1061322ebca6SAkhil Goyal 			}
1062322ebca6SAkhil Goyal 			break;
1063322ebca6SAkhil Goyal 		case 'P':
1064322ebca6SAkhil Goyal 			promiscuous_on = 1;
1065322ebca6SAkhil Goyal 			break;
1066322ebca6SAkhil Goyal 
1067322ebca6SAkhil Goyal 		/* nqueue */
1068322ebca6SAkhil Goyal 		case 'q':
1069322ebca6SAkhil Goyal 			l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
1070322ebca6SAkhil Goyal 			if (l2fwd_rx_queue_per_lcore == 0) {
1071322ebca6SAkhil Goyal 				printf("invalid queue number\n");
1072322ebca6SAkhil Goyal 				l2fwd_usage(prgname);
1073322ebca6SAkhil Goyal 				return -1;
1074322ebca6SAkhil Goyal 			}
1075322ebca6SAkhil Goyal 			break;
1076322ebca6SAkhil Goyal 
1077322ebca6SAkhil Goyal 		/* timer period */
1078322ebca6SAkhil Goyal 		case 'T':
1079322ebca6SAkhil Goyal 			timer_secs = l2fwd_parse_timer_period(optarg);
1080322ebca6SAkhil Goyal 			if (timer_secs < 0) {
1081322ebca6SAkhil Goyal 				printf("invalid timer period\n");
1082322ebca6SAkhil Goyal 				l2fwd_usage(prgname);
1083322ebca6SAkhil Goyal 				return -1;
1084322ebca6SAkhil Goyal 			}
1085322ebca6SAkhil Goyal 			timer_period = timer_secs;
1086322ebca6SAkhil Goyal 			break;
1087322ebca6SAkhil Goyal 
1088322ebca6SAkhil Goyal 		/* long options */
1089322ebca6SAkhil Goyal 		case CMD_LINE_OPT_PORTMAP_NUM:
1090322ebca6SAkhil Goyal 			ret = l2fwd_parse_port_pair_config(optarg);
1091322ebca6SAkhil Goyal 			if (ret) {
1092322ebca6SAkhil Goyal 				fprintf(stderr, "Invalid config\n");
1093322ebca6SAkhil Goyal 				l2fwd_usage(prgname);
1094322ebca6SAkhil Goyal 				return -1;
1095322ebca6SAkhil Goyal 			}
1096322ebca6SAkhil Goyal 			break;
1097322ebca6SAkhil Goyal 
1098322ebca6SAkhil Goyal 		case CMD_LINE_OPT_NO_MAC_UPDATING_NUM:
1099322ebca6SAkhil Goyal 			mac_updating = 0;
1100322ebca6SAkhil Goyal 			break;
1101322ebca6SAkhil Goyal 
1102322ebca6SAkhil Goyal 		case CMD_LINE_OPT_MACSEC_TX_PORTMASK_NUM:
1103322ebca6SAkhil Goyal 			options->tx_portmask = l2fwd_parse_portmask(optarg);
1104322ebca6SAkhil Goyal 			if (options->tx_portmask == 0) {
1105322ebca6SAkhil Goyal 				l2fwd_usage(prgname);
1106322ebca6SAkhil Goyal 				return -1;
1107322ebca6SAkhil Goyal 			}
1108322ebca6SAkhil Goyal 			break;
1109322ebca6SAkhil Goyal 
1110322ebca6SAkhil Goyal 		case CMD_LINE_OPT_MACSEC_RX_PORTMASK_NUM:
1111322ebca6SAkhil Goyal 			options->rx_portmask = l2fwd_parse_portmask(optarg);
1112322ebca6SAkhil Goyal 			if (options->rx_portmask == 0) {
1113322ebca6SAkhil Goyal 				l2fwd_usage(prgname);
1114322ebca6SAkhil Goyal 				return -1;
1115322ebca6SAkhil Goyal 			}
1116322ebca6SAkhil Goyal 			break;
1117322ebca6SAkhil Goyal 
1118322ebca6SAkhil Goyal 		case CMD_LINE_OPT_MACSEC_PORT_CFG_NUM:
1119322ebca6SAkhil Goyal 			ret = l2fwd_parse_macsec_port_config(optarg);
1120322ebca6SAkhil Goyal 			if (ret) {
1121322ebca6SAkhil Goyal 				fprintf(stderr, "Invalid MACsec port config\n");
1122322ebca6SAkhil Goyal 				l2fwd_usage(prgname);
1123322ebca6SAkhil Goyal 				return -1;
1124322ebca6SAkhil Goyal 			}
1125322ebca6SAkhil Goyal 			break;
1126322ebca6SAkhil Goyal 
1127322ebca6SAkhil Goyal 		default:
1128322ebca6SAkhil Goyal 			l2fwd_usage(prgname);
1129322ebca6SAkhil Goyal 			return -1;
1130322ebca6SAkhil Goyal 		}
1131322ebca6SAkhil Goyal 	}
1132322ebca6SAkhil Goyal 	l2fwd_macsec_default_options(options);
1133322ebca6SAkhil Goyal 
1134322ebca6SAkhil Goyal 	if (optind >= 0)
1135322ebca6SAkhil Goyal 		argv[optind-1] = prgname;
1136322ebca6SAkhil Goyal 
1137322ebca6SAkhil Goyal 	ret = optind-1;
1138322ebca6SAkhil Goyal 	optind = 1; /* reset getopt lib */
1139322ebca6SAkhil Goyal 	return ret;
1140322ebca6SAkhil Goyal }
1141322ebca6SAkhil Goyal 
1142322ebca6SAkhil Goyal /*
1143322ebca6SAkhil Goyal  * Check port pair config with enabled port mask,
1144322ebca6SAkhil Goyal  * and for valid port pair combinations.
1145322ebca6SAkhil Goyal  */
1146322ebca6SAkhil Goyal static int
1147322ebca6SAkhil Goyal check_port_pair_config(void)
1148322ebca6SAkhil Goyal {
1149322ebca6SAkhil Goyal 	uint32_t port_pair_config_mask = 0;
1150322ebca6SAkhil Goyal 	uint32_t port_pair_mask = 0;
1151322ebca6SAkhil Goyal 	uint16_t index, i, portid;
1152322ebca6SAkhil Goyal 
1153322ebca6SAkhil Goyal 	for (index = 0; index < nb_port_pair_params; index++) {
1154322ebca6SAkhil Goyal 		port_pair_mask = 0;
1155322ebca6SAkhil Goyal 
1156322ebca6SAkhil Goyal 		for (i = 0; i < NUM_PORTS; i++)  {
1157322ebca6SAkhil Goyal 			portid = port_pair_params[index].port[i];
1158322ebca6SAkhil Goyal 			if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
1159322ebca6SAkhil Goyal 				printf("port %u is not enabled in port mask\n",
1160322ebca6SAkhil Goyal 				       portid);
1161322ebca6SAkhil Goyal 				return -1;
1162322ebca6SAkhil Goyal 			}
1163322ebca6SAkhil Goyal 			if (!rte_eth_dev_is_valid_port(portid)) {
1164322ebca6SAkhil Goyal 				printf("port %u is not present on the board\n",
1165322ebca6SAkhil Goyal 				       portid);
1166322ebca6SAkhil Goyal 				return -1;
1167322ebca6SAkhil Goyal 			}
1168322ebca6SAkhil Goyal 
1169322ebca6SAkhil Goyal 			port_pair_mask |= 1 << portid;
1170322ebca6SAkhil Goyal 		}
1171322ebca6SAkhil Goyal 
1172322ebca6SAkhil Goyal 		if (port_pair_config_mask & port_pair_mask) {
1173322ebca6SAkhil Goyal 			printf("port %u is used in other port pairs\n", portid);
1174322ebca6SAkhil Goyal 			return -1;
1175322ebca6SAkhil Goyal 		}
1176322ebca6SAkhil Goyal 		port_pair_config_mask |= port_pair_mask;
1177322ebca6SAkhil Goyal 	}
1178322ebca6SAkhil Goyal 
1179322ebca6SAkhil Goyal 	l2fwd_enabled_port_mask &= port_pair_config_mask;
1180322ebca6SAkhil Goyal 
1181322ebca6SAkhil Goyal 	return 0;
1182322ebca6SAkhil Goyal }
1183322ebca6SAkhil Goyal 
1184322ebca6SAkhil Goyal /* Check the link status of all ports in up to 9s, and print them finally */
1185322ebca6SAkhil Goyal static void
1186322ebca6SAkhil Goyal check_all_ports_link_status(uint32_t port_mask)
1187322ebca6SAkhil Goyal {
1188322ebca6SAkhil Goyal #define CHECK_INTERVAL 100 /* 100ms */
1189322ebca6SAkhil Goyal #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
1190322ebca6SAkhil Goyal 	uint16_t portid;
1191322ebca6SAkhil Goyal 	uint8_t count, all_ports_up, print_flag = 0;
1192322ebca6SAkhil Goyal 	struct rte_eth_link link;
1193322ebca6SAkhil Goyal 	int ret;
1194322ebca6SAkhil Goyal 	char link_status_text[RTE_ETH_LINK_MAX_STR_LEN];
1195322ebca6SAkhil Goyal 
1196322ebca6SAkhil Goyal 	printf("\nChecking link status");
1197322ebca6SAkhil Goyal 	fflush(stdout);
1198322ebca6SAkhil Goyal 	for (count = 0; count <= MAX_CHECK_TIME; count++) {
1199322ebca6SAkhil Goyal 		if (force_quit)
1200322ebca6SAkhil Goyal 			return;
1201322ebca6SAkhil Goyal 		all_ports_up = 1;
1202322ebca6SAkhil Goyal 		RTE_ETH_FOREACH_DEV(portid) {
1203322ebca6SAkhil Goyal 			if (force_quit)
1204322ebca6SAkhil Goyal 				return;
1205322ebca6SAkhil Goyal 			if ((port_mask & (1 << portid)) == 0)
1206322ebca6SAkhil Goyal 				continue;
1207322ebca6SAkhil Goyal 			memset(&link, 0, sizeof(link));
1208322ebca6SAkhil Goyal 			ret = rte_eth_link_get_nowait(portid, &link);
1209322ebca6SAkhil Goyal 			if (ret < 0) {
1210322ebca6SAkhil Goyal 				all_ports_up = 0;
1211322ebca6SAkhil Goyal 				if (print_flag == 1)
1212322ebca6SAkhil Goyal 					printf("Port %u link get failed: %s\n",
1213322ebca6SAkhil Goyal 						portid, rte_strerror(-ret));
1214322ebca6SAkhil Goyal 				continue;
1215322ebca6SAkhil Goyal 			}
1216322ebca6SAkhil Goyal 			/* print link status if flag set */
1217322ebca6SAkhil Goyal 			if (print_flag == 1) {
1218322ebca6SAkhil Goyal 				rte_eth_link_to_str(link_status_text,
1219322ebca6SAkhil Goyal 					sizeof(link_status_text), &link);
1220322ebca6SAkhil Goyal 				printf("Port %d %s\n", portid,
1221322ebca6SAkhil Goyal 				       link_status_text);
1222322ebca6SAkhil Goyal 				continue;
1223322ebca6SAkhil Goyal 			}
1224322ebca6SAkhil Goyal 			/* clear all_ports_up flag if any link down */
1225322ebca6SAkhil Goyal 			if (link.link_status == RTE_ETH_LINK_DOWN) {
1226322ebca6SAkhil Goyal 				all_ports_up = 0;
1227322ebca6SAkhil Goyal 				break;
1228322ebca6SAkhil Goyal 			}
1229322ebca6SAkhil Goyal 		}
1230322ebca6SAkhil Goyal 		/* after finally printing all link status, get out */
1231322ebca6SAkhil Goyal 		if (print_flag == 1)
1232322ebca6SAkhil Goyal 			break;
1233322ebca6SAkhil Goyal 
1234322ebca6SAkhil Goyal 		if (all_ports_up == 0) {
1235322ebca6SAkhil Goyal 			printf(".");
1236322ebca6SAkhil Goyal 			fflush(stdout);
1237322ebca6SAkhil Goyal 			rte_delay_ms(CHECK_INTERVAL);
1238322ebca6SAkhil Goyal 		}
1239322ebca6SAkhil Goyal 
1240322ebca6SAkhil Goyal 		/* set the print_flag if all ports up or timeout */
1241322ebca6SAkhil Goyal 		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
1242322ebca6SAkhil Goyal 			print_flag = 1;
1243322ebca6SAkhil Goyal 			printf("done\n");
1244322ebca6SAkhil Goyal 		}
1245322ebca6SAkhil Goyal 	}
1246322ebca6SAkhil Goyal }
1247322ebca6SAkhil Goyal 
1248322ebca6SAkhil Goyal static void
1249322ebca6SAkhil Goyal signal_handler(int signum)
1250322ebca6SAkhil Goyal {
1251322ebca6SAkhil Goyal 	if (signum == SIGINT || signum == SIGTERM) {
1252322ebca6SAkhil Goyal 		printf("\n\nSignal %d received, preparing to exit...\n",
1253322ebca6SAkhil Goyal 				signum);
1254322ebca6SAkhil Goyal 		force_quit = true;
1255322ebca6SAkhil Goyal 	}
1256322ebca6SAkhil Goyal }
1257322ebca6SAkhil Goyal 
1258322ebca6SAkhil Goyal int
1259322ebca6SAkhil Goyal main(int argc, char **argv)
1260322ebca6SAkhil Goyal {
1261322ebca6SAkhil Goyal 	struct l2fwd_macsec_options options = {0};
1262322ebca6SAkhil Goyal 	struct lcore_queue_conf *qconf;
1263322ebca6SAkhil Goyal 	int ret;
1264322ebca6SAkhil Goyal 	uint16_t nb_ports;
1265322ebca6SAkhil Goyal 	uint16_t nb_ports_available = 0;
1266322ebca6SAkhil Goyal 	uint16_t portid, last_port;
1267322ebca6SAkhil Goyal 	unsigned int lcore_id, rx_lcore_id;
1268322ebca6SAkhil Goyal 	unsigned int nb_ports_in_mask = 0;
1269322ebca6SAkhil Goyal 	unsigned int nb_lcores = 0;
1270322ebca6SAkhil Goyal 	unsigned int nb_mbufs;
1271322ebca6SAkhil Goyal 	uint16_t nb_sess = 512;
1272322ebca6SAkhil Goyal 	uint32_t sess_sz;
1273322ebca6SAkhil Goyal 	char s[64];
1274322ebca6SAkhil Goyal 
1275322ebca6SAkhil Goyal 	/* Init EAL. 8< */
1276322ebca6SAkhil Goyal 	ret = rte_eal_init(argc, argv);
1277322ebca6SAkhil Goyal 	if (ret < 0)
1278322ebca6SAkhil Goyal 		rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
1279322ebca6SAkhil Goyal 	argc -= ret;
1280322ebca6SAkhil Goyal 	argv += ret;
1281322ebca6SAkhil Goyal 
1282322ebca6SAkhil Goyal 	force_quit = false;
1283322ebca6SAkhil Goyal 	signal(SIGINT, signal_handler);
1284322ebca6SAkhil Goyal 	signal(SIGTERM, signal_handler);
1285322ebca6SAkhil Goyal 
1286322ebca6SAkhil Goyal 	/* parse application arguments (after the EAL ones) */
1287322ebca6SAkhil Goyal 	ret = l2fwd_parse_args(&options, argc, argv);
1288322ebca6SAkhil Goyal 	if (ret < 0)
1289322ebca6SAkhil Goyal 		rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
1290322ebca6SAkhil Goyal 	/* >8 End of init EAL. */
1291322ebca6SAkhil Goyal 
1292322ebca6SAkhil Goyal 	printf("MAC updating %s\n", mac_updating ? "enabled" : "disabled");
1293322ebca6SAkhil Goyal 
1294322ebca6SAkhil Goyal 	/* convert to number of cycles */
1295322ebca6SAkhil Goyal 	timer_period *= rte_get_timer_hz();
1296322ebca6SAkhil Goyal 
1297322ebca6SAkhil Goyal 	nb_ports = rte_eth_dev_count_avail();
1298322ebca6SAkhil Goyal 	if (nb_ports == 0)
1299322ebca6SAkhil Goyal 		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
1300322ebca6SAkhil Goyal 
1301322ebca6SAkhil Goyal 	if (port_pair_params != NULL) {
1302322ebca6SAkhil Goyal 		if (check_port_pair_config() < 0)
1303322ebca6SAkhil Goyal 			rte_exit(EXIT_FAILURE, "Invalid port pair config\n");
1304322ebca6SAkhil Goyal 	}
1305322ebca6SAkhil Goyal 
1306322ebca6SAkhil Goyal 	/* check port mask to possible port mask */
1307322ebca6SAkhil Goyal 	if (l2fwd_enabled_port_mask & ~((1 << nb_ports) - 1))
1308322ebca6SAkhil Goyal 		rte_exit(EXIT_FAILURE, "Invalid portmask; possible (0x%x)\n",
1309322ebca6SAkhil Goyal 			(1 << nb_ports) - 1);
1310322ebca6SAkhil Goyal 
1311322ebca6SAkhil Goyal 	/* Initialization of the driver. 8< */
1312322ebca6SAkhil Goyal 
1313322ebca6SAkhil Goyal 	/* reset l2fwd_dst_ports */
1314322ebca6SAkhil Goyal 	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
1315322ebca6SAkhil Goyal 		l2fwd_dst_ports[portid] = 0;
1316322ebca6SAkhil Goyal 	last_port = 0;
1317322ebca6SAkhil Goyal 
1318322ebca6SAkhil Goyal 	/* populate destination port details */
1319322ebca6SAkhil Goyal 	if (port_pair_params != NULL) {
1320322ebca6SAkhil Goyal 		uint16_t idx, p;
1321322ebca6SAkhil Goyal 
1322322ebca6SAkhil Goyal 		for (idx = 0; idx < (nb_port_pair_params << 1); idx++) {
1323322ebca6SAkhil Goyal 			p = idx & 1;
1324322ebca6SAkhil Goyal 			portid = port_pair_params[idx >> 1].port[p];
1325322ebca6SAkhil Goyal 			l2fwd_dst_ports[portid] =
1326322ebca6SAkhil Goyal 				port_pair_params[idx >> 1].port[p ^ 1];
1327322ebca6SAkhil Goyal 		}
1328322ebca6SAkhil Goyal 	} else {
1329322ebca6SAkhil Goyal 		RTE_ETH_FOREACH_DEV(portid) {
1330322ebca6SAkhil Goyal 			/* skip ports that are not enabled */
1331322ebca6SAkhil Goyal 			if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
1332322ebca6SAkhil Goyal 				continue;
1333322ebca6SAkhil Goyal 
1334322ebca6SAkhil Goyal 			if (nb_ports_in_mask % 2) {
1335322ebca6SAkhil Goyal 				l2fwd_dst_ports[portid] = last_port;
1336322ebca6SAkhil Goyal 				l2fwd_dst_ports[last_port] = portid;
1337322ebca6SAkhil Goyal 			} else {
1338322ebca6SAkhil Goyal 				last_port = portid;
1339322ebca6SAkhil Goyal 			}
1340322ebca6SAkhil Goyal 
1341322ebca6SAkhil Goyal 			nb_ports_in_mask++;
1342322ebca6SAkhil Goyal 		}
1343322ebca6SAkhil Goyal 		if (nb_ports_in_mask % 2) {
1344322ebca6SAkhil Goyal 			printf("Notice: odd number of ports in portmask.\n");
1345322ebca6SAkhil Goyal 			l2fwd_dst_ports[last_port] = last_port;
1346322ebca6SAkhil Goyal 		}
1347322ebca6SAkhil Goyal 	}
1348322ebca6SAkhil Goyal 	/* >8 End of initialization of the driver. */
1349322ebca6SAkhil Goyal 
1350322ebca6SAkhil Goyal 	rx_lcore_id = 0;
1351322ebca6SAkhil Goyal 	qconf = NULL;
1352322ebca6SAkhil Goyal 
1353322ebca6SAkhil Goyal 	/* Initialize the port/queue configuration of each logical core */
1354322ebca6SAkhil Goyal 	RTE_ETH_FOREACH_DEV(portid) {
1355322ebca6SAkhil Goyal 		/* skip ports that are not enabled */
1356322ebca6SAkhil Goyal 		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
1357322ebca6SAkhil Goyal 			continue;
1358322ebca6SAkhil Goyal 
1359322ebca6SAkhil Goyal 		/* get the lcore_id for this port */
1360322ebca6SAkhil Goyal 		while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
1361322ebca6SAkhil Goyal 		       lcore_queue_conf[rx_lcore_id].n_rx_port ==
1362322ebca6SAkhil Goyal 		       l2fwd_rx_queue_per_lcore) {
1363322ebca6SAkhil Goyal 			rx_lcore_id++;
1364322ebca6SAkhil Goyal 			if (rx_lcore_id >= RTE_MAX_LCORE)
1365322ebca6SAkhil Goyal 				rte_exit(EXIT_FAILURE, "Not enough cores\n");
1366322ebca6SAkhil Goyal 		}
1367322ebca6SAkhil Goyal 
1368322ebca6SAkhil Goyal 		if (qconf != &lcore_queue_conf[rx_lcore_id]) {
1369322ebca6SAkhil Goyal 			/* Assigned a new logical core in the loop above. */
1370322ebca6SAkhil Goyal 			qconf = &lcore_queue_conf[rx_lcore_id];
1371322ebca6SAkhil Goyal 			nb_lcores++;
1372322ebca6SAkhil Goyal 		}
1373322ebca6SAkhil Goyal 
1374322ebca6SAkhil Goyal 		qconf->rx_port_list[qconf->n_rx_port] = portid;
1375322ebca6SAkhil Goyal 		qconf->n_rx_port++;
1376322ebca6SAkhil Goyal 		printf("Lcore %u: RX port %u TX port %u\n", rx_lcore_id,
1377322ebca6SAkhil Goyal 		       portid, l2fwd_dst_ports[portid]);
1378322ebca6SAkhil Goyal 	}
1379322ebca6SAkhil Goyal 
1380322ebca6SAkhil Goyal 	nb_mbufs = RTE_MAX(nb_ports * (nb_rxd + nb_txd + MAX_PKT_BURST +
1381322ebca6SAkhil Goyal 		nb_lcores * MEMPOOL_CACHE_SIZE), 8192U);
1382322ebca6SAkhil Goyal 
1383322ebca6SAkhil Goyal 	/* Create the mbuf pool. 8< */
1384322ebca6SAkhil Goyal 	l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", nb_mbufs,
1385322ebca6SAkhil Goyal 		MEMPOOL_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE,
1386322ebca6SAkhil Goyal 		rte_socket_id());
1387322ebca6SAkhil Goyal 	if (l2fwd_pktmbuf_pool == NULL)
1388322ebca6SAkhil Goyal 		rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
1389322ebca6SAkhil Goyal 	/* >8 End of create the mbuf pool. */
1390322ebca6SAkhil Goyal 
1391322ebca6SAkhil Goyal 	/* Initialise each port */
1392322ebca6SAkhil Goyal 	RTE_ETH_FOREACH_DEV(portid) {
1393322ebca6SAkhil Goyal 		struct rte_eth_rxconf rxq_conf;
1394322ebca6SAkhil Goyal 		struct rte_eth_txconf txq_conf;
1395322ebca6SAkhil Goyal 		struct rte_eth_conf local_port_conf = port_conf;
1396322ebca6SAkhil Goyal 		struct rte_eth_dev_info dev_info;
1397322ebca6SAkhil Goyal 
1398322ebca6SAkhil Goyal 		/* skip ports that are not enabled */
1399322ebca6SAkhil Goyal 		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
1400322ebca6SAkhil Goyal 			printf("Skipping disabled port %u\n", portid);
1401322ebca6SAkhil Goyal 			continue;
1402322ebca6SAkhil Goyal 		}
1403322ebca6SAkhil Goyal 		nb_ports_available++;
1404322ebca6SAkhil Goyal 
1405322ebca6SAkhil Goyal 		/* init port */
1406322ebca6SAkhil Goyal 		printf("Initializing port %u... ", portid);
1407322ebca6SAkhil Goyal 		fflush(stdout);
1408322ebca6SAkhil Goyal 
1409322ebca6SAkhil Goyal 		ret = rte_eth_dev_info_get(portid, &dev_info);
1410322ebca6SAkhil Goyal 		if (ret != 0)
1411322ebca6SAkhil Goyal 			rte_exit(EXIT_FAILURE,
1412322ebca6SAkhil Goyal 				"Error during getting device (port %u) info: %s\n",
1413322ebca6SAkhil Goyal 				portid, strerror(-ret));
1414322ebca6SAkhil Goyal 
1415322ebca6SAkhil Goyal 		if (dev_info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE)
1416322ebca6SAkhil Goyal 			local_port_conf.txmode.offloads |=
1417322ebca6SAkhil Goyal 				RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE;
1418322ebca6SAkhil Goyal 		/* Configure the number of queues for a port. */
1419322ebca6SAkhil Goyal 		ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf);
1420322ebca6SAkhil Goyal 		if (ret < 0)
1421322ebca6SAkhil Goyal 			rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n",
1422322ebca6SAkhil Goyal 				  ret, portid);
1423322ebca6SAkhil Goyal 		/* >8 End of configuration of the number of queues for a port. */
1424322ebca6SAkhil Goyal 
1425322ebca6SAkhil Goyal 		ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd,
1426322ebca6SAkhil Goyal 						       &nb_txd);
1427322ebca6SAkhil Goyal 		if (ret < 0)
1428322ebca6SAkhil Goyal 			rte_exit(EXIT_FAILURE,
1429322ebca6SAkhil Goyal 				 "Cannot adjust number of descriptors: err=%d, port=%u\n",
1430322ebca6SAkhil Goyal 				 ret, portid);
1431322ebca6SAkhil Goyal 
1432322ebca6SAkhil Goyal 		ret = rte_eth_macaddr_get(portid,
1433322ebca6SAkhil Goyal 					  &l2fwd_ports_eth_addr[portid]);
1434322ebca6SAkhil Goyal 		if (ret < 0)
1435322ebca6SAkhil Goyal 			rte_exit(EXIT_FAILURE,
1436322ebca6SAkhil Goyal 				 "Cannot get MAC address: err=%d, port=%u\n",
1437322ebca6SAkhil Goyal 				 ret, portid);
1438322ebca6SAkhil Goyal 
1439322ebca6SAkhil Goyal 		/* init one RX queue */
1440322ebca6SAkhil Goyal 		fflush(stdout);
1441322ebca6SAkhil Goyal 		rxq_conf = dev_info.default_rxconf;
1442322ebca6SAkhil Goyal 		rxq_conf.offloads = local_port_conf.rxmode.offloads;
1443322ebca6SAkhil Goyal 		/* RX queue setup. 8< */
1444322ebca6SAkhil Goyal 		ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
1445322ebca6SAkhil Goyal 					     rte_eth_dev_socket_id(portid),
1446322ebca6SAkhil Goyal 					     &rxq_conf,
1447322ebca6SAkhil Goyal 					     l2fwd_pktmbuf_pool);
1448322ebca6SAkhil Goyal 		if (ret < 0)
1449322ebca6SAkhil Goyal 			rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n",
1450322ebca6SAkhil Goyal 				  ret, portid);
1451322ebca6SAkhil Goyal 		/* >8 End of RX queue setup. */
1452322ebca6SAkhil Goyal 
1453322ebca6SAkhil Goyal 		/* Init one TX queue on each port. 8< */
1454322ebca6SAkhil Goyal 		fflush(stdout);
1455322ebca6SAkhil Goyal 		txq_conf = dev_info.default_txconf;
1456322ebca6SAkhil Goyal 		txq_conf.offloads = local_port_conf.txmode.offloads;
1457322ebca6SAkhil Goyal 		ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
1458322ebca6SAkhil Goyal 				rte_eth_dev_socket_id(portid),
1459322ebca6SAkhil Goyal 				&txq_conf);
1460322ebca6SAkhil Goyal 		if (ret < 0)
1461322ebca6SAkhil Goyal 			rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n",
1462322ebca6SAkhil Goyal 				ret, portid);
1463322ebca6SAkhil Goyal 		/* >8 End of init one TX queue on each port. */
1464322ebca6SAkhil Goyal 
1465322ebca6SAkhil Goyal 		/* Initialize TX buffers */
1466322ebca6SAkhil Goyal 		tx_buffer[portid] = rte_zmalloc_socket("tx_buffer",
1467322ebca6SAkhil Goyal 				RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,
1468322ebca6SAkhil Goyal 				rte_eth_dev_socket_id(portid));
1469322ebca6SAkhil Goyal 		if (tx_buffer[portid] == NULL)
1470322ebca6SAkhil Goyal 			rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n",
1471322ebca6SAkhil Goyal 					portid);
1472322ebca6SAkhil Goyal 
1473322ebca6SAkhil Goyal 		rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST);
1474322ebca6SAkhil Goyal 
1475322ebca6SAkhil Goyal 		ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid],
1476322ebca6SAkhil Goyal 				rte_eth_tx_buffer_count_callback,
1477322ebca6SAkhil Goyal 				&port_statistics[portid].dropped);
1478322ebca6SAkhil Goyal 		if (ret < 0)
1479322ebca6SAkhil Goyal 			rte_exit(EXIT_FAILURE,
1480322ebca6SAkhil Goyal 			"Cannot set error callback for tx buffer on port %u\n",
1481322ebca6SAkhil Goyal 				 portid);
1482322ebca6SAkhil Goyal 
1483322ebca6SAkhil Goyal 		ret = rte_eth_dev_set_ptypes(portid, RTE_PTYPE_UNKNOWN, NULL,
1484322ebca6SAkhil Goyal 					     0);
1485322ebca6SAkhil Goyal 		if (ret < 0)
1486322ebca6SAkhil Goyal 			printf("Port %u, Failed to disable Ptype parsing\n",
1487322ebca6SAkhil Goyal 					portid);
1488322ebca6SAkhil Goyal 		/* Start device */
1489322ebca6SAkhil Goyal 		ret = rte_eth_dev_start(portid);
1490322ebca6SAkhil Goyal 		if (ret < 0)
1491322ebca6SAkhil Goyal 			rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n",
1492322ebca6SAkhil Goyal 				  ret, portid);
1493322ebca6SAkhil Goyal 
1494322ebca6SAkhil Goyal 		printf("done:\n");
1495322ebca6SAkhil Goyal 		if (promiscuous_on) {
1496322ebca6SAkhil Goyal 			ret = rte_eth_promiscuous_enable(portid);
1497322ebca6SAkhil Goyal 			if (ret != 0)
1498322ebca6SAkhil Goyal 				rte_exit(EXIT_FAILURE,
1499322ebca6SAkhil Goyal 					"rte_eth_promiscuous_enable:err=%s, port=%u\n",
1500322ebca6SAkhil Goyal 					rte_strerror(-ret), portid);
1501322ebca6SAkhil Goyal 		}
1502322ebca6SAkhil Goyal 
1503322ebca6SAkhil Goyal 		printf("Port %u, MAC address: " RTE_ETHER_ADDR_PRT_FMT "\n\n",
1504322ebca6SAkhil Goyal 			portid,
1505322ebca6SAkhil Goyal 			RTE_ETHER_ADDR_BYTES(&l2fwd_ports_eth_addr[portid]));
1506322ebca6SAkhil Goyal 
1507322ebca6SAkhil Goyal 		/* initialize port stats */
1508322ebca6SAkhil Goyal 		memset(&port_statistics, 0, sizeof(port_statistics));
1509322ebca6SAkhil Goyal 
1510322ebca6SAkhil Goyal 		mcs_port_params[portid].sec_ctx = rte_eth_dev_get_sec_ctx(portid);
1511322ebca6SAkhil Goyal 		if (mcs_port_params[portid].sec_ctx == NULL)
1512322ebca6SAkhil Goyal 			rte_exit(EXIT_FAILURE, "Device does not support Security ctx\n");
1513322ebca6SAkhil Goyal 
1514322ebca6SAkhil Goyal 		sess_sz = rte_security_session_get_size(mcs_port_params[portid].sec_ctx);
1515322ebca6SAkhil Goyal 		if (mcs_port_params[portid].sess_pool == NULL) {
1516322ebca6SAkhil Goyal 			snprintf(s, sizeof(s), "sess_pool_p%d", portid);
1517322ebca6SAkhil Goyal 			mcs_port_params[portid].sess_pool = rte_mempool_create(s,
1518322ebca6SAkhil Goyal 							nb_sess, sess_sz,
1519322ebca6SAkhil Goyal 							SESSION_POOL_CACHE_SIZE, 0,
1520322ebca6SAkhil Goyal 							NULL, NULL, NULL, NULL,
1521322ebca6SAkhil Goyal 							SOCKET_ID_ANY, 0);
1522322ebca6SAkhil Goyal 			if (mcs_port_params[portid].sess_pool == NULL)
1523322ebca6SAkhil Goyal 				rte_exit(EXIT_FAILURE, "Cannot init sess pool\n");
1524322ebca6SAkhil Goyal 
1525322ebca6SAkhil Goyal 			printf("Allocated sess pool\n");
1526322ebca6SAkhil Goyal 		}
1527322ebca6SAkhil Goyal 
1528322ebca6SAkhil Goyal 		if (((options.tx_portmask & (1 << portid)) != 0) ||
1529322ebca6SAkhil Goyal 				((options.rx_portmask & (1 << portid)) != 0)) {
1530322ebca6SAkhil Goyal 			ret = initialize_macsec_session(portid);
1531322ebca6SAkhil Goyal 			if (ret < 0)
1532322ebca6SAkhil Goyal 				rte_exit(EXIT_FAILURE,
1533322ebca6SAkhil Goyal 					"Failed to initialize MACsec session for port: %d\n",
1534322ebca6SAkhil Goyal 					portid);
1535322ebca6SAkhil Goyal 		}
1536322ebca6SAkhil Goyal 	}
1537322ebca6SAkhil Goyal 
1538322ebca6SAkhil Goyal 	if (!nb_ports_available) {
1539322ebca6SAkhil Goyal 		rte_exit(EXIT_FAILURE,
1540322ebca6SAkhil Goyal 			"All available ports are disabled. Please set portmask.\n");
1541322ebca6SAkhil Goyal 	}
1542322ebca6SAkhil Goyal 
1543322ebca6SAkhil Goyal 	check_all_ports_link_status(l2fwd_enabled_port_mask);
1544322ebca6SAkhil Goyal 
1545322ebca6SAkhil Goyal 	ret = 0;
1546322ebca6SAkhil Goyal 	/* launch per-lcore init on every lcore */
1547322ebca6SAkhil Goyal 	rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MAIN);
1548322ebca6SAkhil Goyal 	RTE_LCORE_FOREACH_WORKER(lcore_id) {
1549322ebca6SAkhil Goyal 		if (rte_eal_wait_lcore(lcore_id) < 0) {
1550322ebca6SAkhil Goyal 			ret = -1;
1551322ebca6SAkhil Goyal 			break;
1552322ebca6SAkhil Goyal 		}
1553322ebca6SAkhil Goyal 	}
1554322ebca6SAkhil Goyal 
1555322ebca6SAkhil Goyal 	RTE_ETH_FOREACH_DEV(portid) {
1556322ebca6SAkhil Goyal 		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
1557322ebca6SAkhil Goyal 			continue;
1558322ebca6SAkhil Goyal 		printf("Closing port %d...", portid);
1559322ebca6SAkhil Goyal 		ret = rte_eth_dev_stop(portid);
1560322ebca6SAkhil Goyal 		if (ret != 0)
1561322ebca6SAkhil Goyal 			printf("rte_eth_dev_stop: err=%d, port=%d\n",
1562322ebca6SAkhil Goyal 			       ret, portid);
1563322ebca6SAkhil Goyal 		rte_eth_dev_close(portid);
1564322ebca6SAkhil Goyal 		printf(" Done\n");
1565322ebca6SAkhil Goyal 	}
1566322ebca6SAkhil Goyal 
1567322ebca6SAkhil Goyal 	/* clean up the EAL */
1568322ebca6SAkhil Goyal 	rte_eal_cleanup();
1569322ebca6SAkhil Goyal 	printf("Bye...\n");
1570322ebca6SAkhil Goyal 
1571322ebca6SAkhil Goyal 	return ret;
1572322ebca6SAkhil Goyal }
1573