xref: /dpdk/examples/l2fwd-macsec/main.c (revision e0d947a1e6c2f80aa039a4f7082a8aa16797d8b9)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2023 Marvell.
3  */
4 
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <stdint.h>
9 #include <inttypes.h>
10 #include <sys/types.h>
11 #include <sys/queue.h>
12 #include <setjmp.h>
13 #include <stdarg.h>
14 #include <ctype.h>
15 #include <errno.h>
16 #include <getopt.h>
17 #include <signal.h>
18 #include <stdbool.h>
19 
20 #include <rte_common.h>
21 #include <rte_log.h>
22 #include <rte_malloc.h>
23 #include <rte_memory.h>
24 #include <rte_memcpy.h>
25 #include <rte_eal.h>
26 #include <rte_launch.h>
27 #include <rte_cycles.h>
28 #include <rte_prefetch.h>
29 #include <rte_lcore.h>
30 #include <rte_per_lcore.h>
31 #include <rte_branch_prediction.h>
32 #include <rte_interrupts.h>
33 #include <rte_random.h>
34 #include <rte_debug.h>
35 #include <rte_ether.h>
36 #include <rte_ethdev.h>
37 #include <rte_mempool.h>
38 #include <rte_mbuf.h>
39 #include <rte_security.h>
40 #include <rte_string_fns.h>
41 
42 static volatile bool force_quit;
43 
44 /* MAC updating enabled by default */
45 static int mac_updating;
46 
47 /* Ports set in promiscuous mode on by default. */
48 static int promiscuous_on = 1;
49 
50 #define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
51 
52 #define MAX_PKT_BURST 32
53 #define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
54 #define MEMPOOL_CACHE_SIZE 256
55 #define SESSION_POOL_CACHE_SIZE 0
56 
57 /* Configurable number of RX/TX ring descriptors */
58 #define RX_DESC_DEFAULT 1024
59 #define TX_DESC_DEFAULT 1024
60 static uint16_t nb_rxd = RX_DESC_DEFAULT;
61 static uint16_t nb_txd = TX_DESC_DEFAULT;
62 
63 /* ethernet addresses of ports */
64 static struct rte_ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
65 
66 /* Ethernet header configuration for MACsec flow on each port. */
67 static struct rte_ether_hdr port_ether_hdr_config[RTE_MAX_ETHPORTS];
68 
69 /* mask of enabled ports */
70 static uint32_t l2fwd_enabled_port_mask;
71 
72 /* list of enabled ports */
73 static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
74 
75 struct __rte_cache_aligned port_pair_params {
76 #define NUM_PORTS	2
77 	uint16_t port[NUM_PORTS];
78 };
79 
80 static struct port_pair_params port_pair_params_array[RTE_MAX_ETHPORTS / 2];
81 static struct port_pair_params *port_pair_params;
82 static uint16_t nb_port_pair_params;
83 
84 static unsigned int l2fwd_rx_queue_per_lcore = 1;
85 
86 #define MAX_RX_QUEUE_PER_LCORE 16
87 #define MAX_TX_QUEUE_PER_PORT 16
88 /* List of queues to be polled for a given lcore. 8< */
89 struct __rte_cache_aligned lcore_queue_conf {
90 	unsigned int n_rx_port;
91 	unsigned int rx_port_list[MAX_RX_QUEUE_PER_LCORE];
92 };
93 struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
94 /* >8 End of list of queues to be polled for a given lcore. */
95 
96 static struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];
97 
98 static struct rte_eth_conf port_conf = {
99 	.txmode = {
100 		.mq_mode = RTE_ETH_MQ_TX_NONE,
101 	},
102 };
103 
104 /* Mempools for mbuf and security session */
105 struct rte_mempool *l2fwd_pktmbuf_pool;
106 
107 /* Per-port statistics struct */
108 struct __rte_cache_aligned l2fwd_port_statistics {
109 	uint64_t tx;
110 	uint64_t rx;
111 	uint64_t dropped;
112 };
113 struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
114 
115 #define MAX_TIMER_PERIOD 86400 /* 1 day max */
116 /* A tsc-based timer responsible for triggering statistics printout */
117 static uint64_t timer_period = 10; /* default period is 10 seconds */
118 
119 #define MCS_MAX_KEY_LEN		32
120 #define MCS_SALT_LEN		12
121 
122 struct l2fwd_key {
123 	uint8_t data[MCS_MAX_KEY_LEN];
124 	uint32_t len;
125 	rte_iova_t phys_addr;
126 };
127 
128 /** l2fwd macsec application command line options */
129 struct l2fwd_macsec_options {
130 	unsigned int portmask;
131 	unsigned int tx_portmask;
132 	unsigned int rx_portmask;
133 	unsigned int nb_ports_per_lcore;
134 	unsigned int refresh_period;
135 	unsigned int single_lcore:1;
136 };
137 
138 /** l2fwd macsec lcore params */
139 struct l2fwd_macsec_port_params {
140 	uint8_t dev_id;
141 	uint8_t qp_id;
142 	void *sec_ctx;
143 	struct rte_mempool *sess_pool;
144 
145 	void *sess;
146 	uint16_t sa_id[4];
147 	uint16_t sc_id;
148 	struct rte_flow *tx_flow;
149 	struct rte_flow *rx_flow;
150 
151 	enum rte_security_macsec_direction dir;
152 	enum rte_security_macsec_alg alg;
153 	struct l2fwd_key sa_key;
154 	uint8_t salt[MCS_SALT_LEN];
155 
156 	uint8_t eth_hdr[RTE_ETHER_HDR_LEN];
157 	uint32_t ssci;
158 	uint64_t sci;
159 	uint64_t pn_threshold;
160 	uint32_t xpn;
161 	uint32_t next_pn;
162 	uint32_t mtu;
163 	uint8_t sectag_insert_mode;
164 	bool encrypt;
165 	bool protect_frames;
166 	bool replay_protect;
167 	int val_frames;
168 	uint32_t replay_win_sz;
169 	bool send_sci;
170 	bool end_station;
171 	bool scb;
172 	uint8_t an;
173 };
174 struct l2fwd_macsec_port_params mcs_port_params[RTE_MAX_ETHPORTS];
175 
176 static void
177 mcs_stats_dump(uint16_t portid)
178 {
179 	struct rte_security_stats sess_stats = {0};
180 	struct rte_security_macsec_secy_stats *secy_stat;
181 	struct rte_security_macsec_sc_stats sc_stat = {0};
182 
183 	if (mcs_port_params[portid].dir == RTE_SECURITY_MACSEC_DIR_RX) {
184 		printf("\n********* RX SECY STATS ************\n");
185 		rte_security_session_stats_get(mcs_port_params[portid].sec_ctx,
186 				mcs_port_params[portid].sess, &sess_stats);
187 		secy_stat = &sess_stats.macsec;
188 
189 		if (secy_stat->ctl_pkt_bcast_cnt)
190 			printf("RX: ctl_pkt_bcast_cnt: 0x%" PRIx64 "\n",
191 					secy_stat->ctl_pkt_bcast_cnt);
192 		if (secy_stat->ctl_pkt_mcast_cnt)
193 			printf("RX: ctl_pkt_mcast_cnt: 0x%" PRIx64 "\n",
194 					secy_stat->ctl_pkt_mcast_cnt);
195 		if (secy_stat->ctl_pkt_ucast_cnt)
196 			printf("RX: ctl_pkt_ucast_cnt: 0x%" PRIx64 "\n",
197 					secy_stat->ctl_pkt_ucast_cnt);
198 		if (secy_stat->ctl_octet_cnt)
199 			printf("RX: ctl_octet_cnt: 0x%" PRIx64 "\n", secy_stat->ctl_octet_cnt);
200 		if (secy_stat->unctl_pkt_bcast_cnt)
201 			printf("RX: unctl_pkt_bcast_cnt: 0x%" PRIx64 "\n",
202 					secy_stat->unctl_pkt_bcast_cnt);
203 		if (secy_stat->unctl_pkt_mcast_cnt)
204 			printf("RX: unctl_pkt_mcast_cnt: 0x%" PRIx64 "\n",
205 					secy_stat->unctl_pkt_mcast_cnt);
206 		if (secy_stat->unctl_pkt_ucast_cnt)
207 			printf("RX: unctl_pkt_ucast_cnt: 0x%" PRIx64 "\n",
208 					secy_stat->unctl_pkt_ucast_cnt);
209 		if (secy_stat->unctl_octet_cnt)
210 			printf("RX: unctl_octet_cnt: 0x%" PRIx64 "\n", secy_stat->unctl_octet_cnt);
211 		/* Valid only for RX */
212 		if (secy_stat->octet_decrypted_cnt)
213 			printf("RX: octet_decrypted_cnt: 0x%" PRIx64 "\n",
214 					secy_stat->octet_decrypted_cnt);
215 		if (secy_stat->octet_validated_cnt)
216 			printf("RX: octet_validated_cnt: 0x%" PRIx64 "\n",
217 					secy_stat->octet_validated_cnt);
218 		if (secy_stat->pkt_port_disabled_cnt)
219 			printf("RX: pkt_port_disabled_cnt: 0x%" PRIx64 "\n",
220 					secy_stat->pkt_port_disabled_cnt);
221 		if (secy_stat->pkt_badtag_cnt)
222 			printf("RX: pkt_badtag_cnt: 0x%" PRIx64 "\n", secy_stat->pkt_badtag_cnt);
223 		if (secy_stat->pkt_nosa_cnt)
224 			printf("RX: pkt_nosa_cnt: 0x%" PRIx64 "\n", secy_stat->pkt_nosa_cnt);
225 		if (secy_stat->pkt_nosaerror_cnt)
226 			printf("RX: pkt_nosaerror_cnt: 0x%" PRIx64 "\n",
227 					secy_stat->pkt_nosaerror_cnt);
228 		if (secy_stat->pkt_tagged_ctl_cnt)
229 			printf("RX: pkt_tagged_ctl_cnt: 0x%" PRIx64 "\n",
230 					secy_stat->pkt_tagged_ctl_cnt);
231 		if (secy_stat->pkt_untaged_cnt)
232 			printf("RX: pkt_untaged_cnt: 0x%" PRIx64 "\n", secy_stat->pkt_untaged_cnt);
233 		if (secy_stat->pkt_ctl_cnt)
234 			printf("RX: pkt_ctl_cnt: 0x%" PRIx64 "\n", secy_stat->pkt_ctl_cnt);
235 		if (secy_stat->pkt_notag_cnt)
236 			printf("RX: pkt_notag_cnt: 0x%" PRIx64 "\n", secy_stat->pkt_notag_cnt);
237 		printf("\n");
238 		printf("\n********** RX SC[%u] STATS **************\n",
239 				mcs_port_params[portid].sc_id);
240 
241 		rte_security_macsec_sc_stats_get(mcs_port_params[portid].sec_ctx,
242 				mcs_port_params[portid].sc_id, RTE_SECURITY_MACSEC_DIR_RX,
243 						 &sc_stat);
244 		/* RX */
245 		if (sc_stat.hit_cnt)
246 			printf("RX hit_cnt: 0x%" PRIx64 "\n", sc_stat.hit_cnt);
247 		if (sc_stat.pkt_invalid_cnt)
248 			printf("RX pkt_invalid_cnt: 0x%" PRIx64 "\n", sc_stat.pkt_invalid_cnt);
249 		if (sc_stat.pkt_late_cnt)
250 			printf("RX pkt_late_cnt: 0x%" PRIx64 "\n", sc_stat.pkt_late_cnt);
251 		if (sc_stat.pkt_notvalid_cnt)
252 			printf("RX pkt_notvalid_cnt: 0x%" PRIx64 "\n", sc_stat.pkt_notvalid_cnt);
253 		if (sc_stat.pkt_unchecked_cnt)
254 			printf("RX pkt_unchecked_cnt: 0x%" PRIx64 "\n", sc_stat.pkt_unchecked_cnt);
255 		if (sc_stat.pkt_delay_cnt)
256 			printf("RX pkt_delay_cnt: 0x%" PRIx64 "\n", sc_stat.pkt_delay_cnt);
257 		if (sc_stat.pkt_ok_cnt)
258 			printf("RX pkt_ok_cnt: 0x%" PRIx64 "\n", sc_stat.pkt_ok_cnt);
259 		if (sc_stat.octet_decrypt_cnt)
260 			printf("RX octet_decrypt_cnt: 0x%" PRIx64 "\n", sc_stat.octet_decrypt_cnt);
261 		if (sc_stat.octet_validate_cnt)
262 			printf("RX octet_validate_cnt: 0x%" PRIx64 "\n",
263 					sc_stat.octet_validate_cnt);
264 	}
265 
266 	if (mcs_port_params[portid].dir == RTE_SECURITY_MACSEC_DIR_TX) {
267 		memset(&sess_stats, 0, sizeof(struct rte_security_stats));
268 		rte_security_session_stats_get(mcs_port_params[portid].sec_ctx,
269 				mcs_port_params[portid].sess, &sess_stats);
270 		secy_stat = &sess_stats.macsec;
271 
272 		printf("\n********* TX SECY STATS ************\n");
273 		if (secy_stat->ctl_pkt_bcast_cnt)
274 			printf("TX: ctl_pkt_bcast_cnt: 0x%" PRIx64 "\n",
275 					secy_stat->ctl_pkt_bcast_cnt);
276 		if (secy_stat->ctl_pkt_mcast_cnt)
277 			printf("TX: ctl_pkt_mcast_cnt: 0x%" PRIx64 "\n",
278 					secy_stat->ctl_pkt_mcast_cnt);
279 		if (secy_stat->ctl_pkt_ucast_cnt)
280 			printf("TX: ctl_pkt_ucast_cnt: 0x%" PRIx64 "\n",
281 					secy_stat->ctl_pkt_ucast_cnt);
282 		if (secy_stat->ctl_octet_cnt)
283 			printf("TX: ctl_octet_cnt: 0x%" PRIx64 "\n", secy_stat->ctl_octet_cnt);
284 		if (secy_stat->unctl_pkt_bcast_cnt)
285 			printf("TX: unctl_pkt_bcast_cnt: 0x%" PRIx64 "\n",
286 					secy_stat->unctl_pkt_bcast_cnt);
287 		if (secy_stat->unctl_pkt_mcast_cnt)
288 			printf("TX: unctl_pkt_mcast_cnt: 0x%" PRIx64 "\n",
289 					secy_stat->unctl_pkt_mcast_cnt);
290 		if (secy_stat->unctl_pkt_ucast_cnt)
291 			printf("TX: unctl_pkt_ucast_cnt: 0x%" PRIx64 "\n",
292 					secy_stat->unctl_pkt_ucast_cnt);
293 		if (secy_stat->unctl_octet_cnt)
294 			printf("TX: unctl_octet_cnt: 0x%" PRIx64 "\n",
295 					secy_stat->unctl_octet_cnt);
296 		/* Valid only for TX */
297 		if (secy_stat->octet_encrypted_cnt)
298 			printf("TX: octet_encrypted_cnt: 0x%" PRIx64 "\n",
299 					secy_stat->octet_encrypted_cnt);
300 		if (secy_stat->octet_protected_cnt)
301 			printf("TX: octet_protected_cnt: 0x%" PRIx64 "\n",
302 					secy_stat->octet_protected_cnt);
303 		if (secy_stat->pkt_noactivesa_cnt)
304 			printf("TX: pkt_noactivesa_cnt: 0x%" PRIx64 "\n",
305 					secy_stat->pkt_noactivesa_cnt);
306 		if (secy_stat->pkt_toolong_cnt)
307 			printf("TX: pkt_toolong_cnt: 0x%" PRIx64 "\n", secy_stat->pkt_toolong_cnt);
308 		if (secy_stat->pkt_untagged_cnt)
309 			printf("TX: pkt_untagged_cnt: 0x%" PRIx64 "\n",
310 					secy_stat->pkt_untagged_cnt);
311 
312 
313 		memset(&sc_stat, 0, sizeof(struct rte_security_macsec_sc_stats));
314 		rte_security_macsec_sc_stats_get(mcs_port_params[portid].sec_ctx,
315 				mcs_port_params[portid].sc_id, RTE_SECURITY_MACSEC_DIR_TX,
316 				&sc_stat);
317 		printf("\n********** TX SC[%u] STATS **************\n",
318 				mcs_port_params[portid].sc_id);
319 		if (sc_stat.pkt_encrypt_cnt)
320 			printf("TX pkt_encrypt_cnt: 0x%" PRIx64 "\n", sc_stat.pkt_encrypt_cnt);
321 		if (sc_stat.pkt_protected_cnt)
322 			printf("TX pkt_protected_cnt: 0x%" PRIx64 "\n", sc_stat.pkt_protected_cnt);
323 		if (sc_stat.octet_encrypt_cnt)
324 			printf("TX octet_encrypt_cnt: 0x%" PRIx64 "\n", sc_stat.octet_encrypt_cnt);
325 	}
326 }
327 
328 /* Print out statistics on packets dropped */
329 static void
330 print_stats(void)
331 {
332 	uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
333 	unsigned int portid;
334 
335 	total_packets_dropped = 0;
336 	total_packets_tx = 0;
337 	total_packets_rx = 0;
338 
339 	const char clr[] = { 27, '[', '2', 'J', '\0' };
340 	const char topLeft[] = { 27, '[', '1', ';', '1', 'H', '\0' };
341 
342 		/* Clear screen and move to top left */
343 	printf("%s%s", clr, topLeft);
344 
345 	printf("\nPort statistics ====================================");
346 
347 	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
348 		/* skip disabled ports */
349 		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
350 			continue;
351 		printf("\nStatistics for port %u ------------------------------"
352 			   "\nPackets sent: %24"PRIu64
353 			   "\nPackets received: %20"PRIu64
354 			   "\nPackets dropped: %21"PRIu64,
355 			   portid,
356 			   port_statistics[portid].tx,
357 			   port_statistics[portid].rx,
358 			   port_statistics[portid].dropped);
359 
360 		total_packets_dropped += port_statistics[portid].dropped;
361 		total_packets_tx += port_statistics[portid].tx;
362 		total_packets_rx += port_statistics[portid].rx;
363 
364 		mcs_stats_dump(portid);
365 	}
366 	printf("\nAggregate statistics ==============================="
367 		   "\nTotal packets sent: %18"PRIu64
368 		   "\nTotal packets received: %14"PRIu64
369 		   "\nTotal packets dropped: %15"PRIu64,
370 		   total_packets_tx,
371 		   total_packets_rx,
372 		   total_packets_dropped);
373 	printf("\n====================================================\n");
374 
375 	fflush(stdout);
376 }
377 
378 static void
379 l2fwd_mac_updating(struct rte_mbuf *m, unsigned int dest_portid)
380 {
381 	struct rte_ether_hdr *eth;
382 	void *tmp;
383 
384 	eth = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
385 
386 	/* 02:00:00:00:00:xx */
387 	tmp = &eth->dst_addr.addr_bytes[0];
388 	*((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dest_portid << 40);
389 
390 	/* src addr */
391 	rte_ether_addr_copy(&l2fwd_ports_eth_addr[dest_portid], &eth->src_addr);
392 }
393 
394 static void
395 l2fwd_simple_forward(struct rte_mbuf *m, unsigned int portid)
396 {
397 	unsigned int dst_port;
398 	int sent;
399 	struct rte_eth_dev_tx_buffer *buffer;
400 
401 	dst_port = l2fwd_dst_ports[portid];
402 
403 	if (mac_updating)
404 		l2fwd_mac_updating(m, dst_port);
405 
406 	buffer = tx_buffer[dst_port];
407 	sent = rte_eth_tx_buffer(dst_port, 0, buffer, m);
408 	if (sent)
409 		port_statistics[dst_port].tx += sent;
410 }
411 
412 static void
413 fill_macsec_sa_conf(uint16_t portid, struct rte_security_macsec_sa *sa)
414 {
415 	sa->dir = mcs_port_params[portid].dir;
416 
417 	sa->key.data = mcs_port_params[portid].sa_key.data;
418 	sa->key.length = mcs_port_params[portid].sa_key.len;
419 
420 	memcpy((uint8_t *)sa->salt, (const uint8_t *)mcs_port_params[portid].salt,
421 		RTE_SECURITY_MACSEC_SALT_LEN);
422 
423 	/* AN is set as per the value in secure packet in test vector */
424 	sa->an = mcs_port_params[portid].an & RTE_MACSEC_AN_MASK;
425 
426 	sa->ssci = mcs_port_params[portid].ssci;
427 	sa->xpn = mcs_port_params[portid].xpn;
428 	/* Starting packet number which is expected to come next.
429 	 * It is take from the test vector so that we can match the out packet.
430 	 */
431 	sa->next_pn = mcs_port_params[portid].next_pn;
432 }
433 
434 static void
435 fill_macsec_sc_conf(uint16_t portid, struct rte_security_macsec_sc *sc_conf)
436 {
437 	uint8_t i;
438 
439 	sc_conf->dir = mcs_port_params[portid].dir;
440 	sc_conf->pn_threshold = mcs_port_params[portid].pn_threshold;
441 	if (sc_conf->dir == RTE_SECURITY_MACSEC_DIR_TX) {
442 		sc_conf->sc_tx.sa_id = mcs_port_params[portid].sa_id[0];
443 		if (mcs_port_params[portid].sa_id[1] != 0xFFFF) {
444 			sc_conf->sc_tx.sa_id_rekey = mcs_port_params[portid].sa_id[1];
445 			sc_conf->sc_tx.re_key_en = 1;
446 		}
447 		sc_conf->sc_tx.active = 1;
448 		sc_conf->sc_tx.sci = mcs_port_params[portid].sci;
449 		if (mcs_port_params[portid].alg == RTE_SECURITY_MACSEC_ALG_GCM_XPN_128 ||
450 			       mcs_port_params[portid].alg == RTE_SECURITY_MACSEC_ALG_GCM_XPN_256)
451 			sc_conf->sc_tx.is_xpn = 1;
452 	} else {
453 		for (i = 0; i < RTE_SECURITY_MACSEC_NUM_AN; i++) {
454 			if (mcs_port_params[portid].sa_id[i] != 0xFFFF) {
455 				sc_conf->sc_rx.sa_id[i] = mcs_port_params[portid].sa_id[i];
456 				sc_conf->sc_rx.sa_in_use[i] = 1;
457 			}
458 		}
459 		sc_conf->sc_rx.active = 1;
460 		if (mcs_port_params[portid].alg == RTE_SECURITY_MACSEC_ALG_GCM_XPN_128 ||
461 			       mcs_port_params[portid].alg == RTE_SECURITY_MACSEC_ALG_GCM_XPN_256)
462 			sc_conf->sc_rx.is_xpn = 1;
463 	}
464 }
465 
466 /* Create Inline MACsec session */
467 static int
468 fill_session_conf(uint16_t portid, struct rte_security_session_conf *sess_conf)
469 {
470 	sess_conf->action_type = RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL;
471 	sess_conf->protocol = RTE_SECURITY_PROTOCOL_MACSEC;
472 	sess_conf->macsec.dir = mcs_port_params[portid].dir;
473 	sess_conf->macsec.alg = mcs_port_params[portid].alg;
474 	sess_conf->macsec.cipher_off = 0;
475 	sess_conf->macsec.sci = mcs_port_params[portid].sci;
476 	sess_conf->macsec.sc_id = mcs_port_params[portid].sc_id;
477 	if (mcs_port_params[portid].dir == RTE_SECURITY_MACSEC_DIR_TX) {
478 		sess_conf->macsec.tx_secy.mtu = mcs_port_params[portid].mtu;
479 		sess_conf->macsec.tx_secy.sectag_off =
480 			(mcs_port_params[portid].sectag_insert_mode == 1) ?
481 					2 * RTE_ETHER_ADDR_LEN : RTE_VLAN_HLEN;
482 		sess_conf->macsec.tx_secy.sectag_insert_mode =
483 			mcs_port_params[portid].sectag_insert_mode;
484 		sess_conf->macsec.tx_secy.ctrl_port_enable = 1;
485 		sess_conf->macsec.tx_secy.sectag_version = 0;
486 		sess_conf->macsec.tx_secy.end_station = mcs_port_params[portid].end_station;
487 		sess_conf->macsec.tx_secy.send_sci = mcs_port_params[portid].send_sci;
488 		sess_conf->macsec.tx_secy.scb = mcs_port_params[portid].scb;
489 		sess_conf->macsec.tx_secy.encrypt = mcs_port_params[portid].encrypt;
490 		sess_conf->macsec.tx_secy.protect_frames = mcs_port_params[portid].protect_frames;
491 		sess_conf->macsec.tx_secy.icv_include_da_sa = 1;
492 	} else {
493 		sess_conf->macsec.rx_secy.replay_win_sz = mcs_port_params[portid].replay_win_sz;
494 		sess_conf->macsec.rx_secy.replay_protect = mcs_port_params[portid].replay_protect;
495 		sess_conf->macsec.rx_secy.icv_include_da_sa = 1;
496 		sess_conf->macsec.rx_secy.ctrl_port_enable = 1;
497 		sess_conf->macsec.rx_secy.preserve_sectag = 0;
498 		sess_conf->macsec.rx_secy.preserve_icv = 0;
499 		sess_conf->macsec.rx_secy.validate_frames = mcs_port_params[portid].val_frames;
500 	}
501 
502 	return 0;
503 }
504 
505 static int
506 create_default_flow(uint16_t portid)
507 {
508 	struct rte_flow_action action[2];
509 	struct rte_flow_item pattern[2];
510 	struct rte_flow_attr attr = {0};
511 	struct rte_flow_error err;
512 	struct rte_flow *flow;
513 	struct rte_flow_item_eth eth;
514 	static const struct rte_flow_item_eth eth_mask = {
515 		.hdr.dst_addr.addr_bytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
516 		.hdr.src_addr.addr_bytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
517 		.hdr.ether_type = RTE_BE16(0xFFFF),
518 	};
519 	int ret;
520 
521 	eth.has_vlan = 0;
522 	memcpy(&eth.hdr, mcs_port_params[portid].eth_hdr, RTE_ETHER_HDR_LEN);
523 
524 	printf("Creating flow on port %u with DST MAC address: " RTE_ETHER_ADDR_PRT_FMT
525 			", SRC MAC address: "RTE_ETHER_ADDR_PRT_FMT"\n\n",
526 			portid,
527 			RTE_ETHER_ADDR_BYTES(&eth.hdr.dst_addr),
528 			RTE_ETHER_ADDR_BYTES(&eth.hdr.src_addr));
529 
530 	pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
531 	pattern[0].spec = &eth;
532 	pattern[0].mask = &eth_mask;
533 	pattern[0].last = NULL;
534 	pattern[1].type = RTE_FLOW_ITEM_TYPE_END;
535 
536 	action[0].type = RTE_FLOW_ACTION_TYPE_SECURITY;
537 	action[0].conf = mcs_port_params[portid].sess;
538 	action[1].type = RTE_FLOW_ACTION_TYPE_END;
539 	action[1].conf = NULL;
540 
541 	attr.ingress = (mcs_port_params[portid].dir == RTE_SECURITY_MACSEC_DIR_RX) ? 1 : 0;
542 	attr.egress = (mcs_port_params[portid].dir == RTE_SECURITY_MACSEC_DIR_TX) ? 1 : 0;
543 
544 	ret = rte_flow_validate(portid, &attr, pattern, action, &err);
545 	if (ret) {
546 		printf("\nValidate flow failed, ret = %d\n", ret);
547 		return -1;
548 	}
549 	flow = rte_flow_create(portid, &attr, pattern, action, &err);
550 	if (flow == NULL) {
551 		printf("\nDefault flow rule create failed\n");
552 		return -1;
553 	}
554 
555 	if (mcs_port_params[portid].dir == RTE_SECURITY_MACSEC_DIR_TX)
556 		mcs_port_params[portid].tx_flow = flow;
557 	else
558 		mcs_port_params[portid].rx_flow = flow;
559 
560 	return 0;
561 }
562 
563 static void
564 destroy_default_flow(uint16_t portid)
565 {
566 	struct rte_flow_error err;
567 	int ret;
568 
569 	if (mcs_port_params[portid].tx_flow) {
570 		ret = rte_flow_destroy(portid, mcs_port_params[portid].tx_flow, &err);
571 		if (ret) {
572 			printf("\nDefault Tx flow rule destroy failed\n");
573 			return;
574 		}
575 		mcs_port_params[portid].tx_flow = NULL;
576 	}
577 	if (mcs_port_params[portid].rx_flow) {
578 		ret = rte_flow_destroy(portid, mcs_port_params[portid].rx_flow, &err);
579 		if (ret) {
580 			printf("\nDefault Rx flow rule destroy failed\n");
581 			return;
582 		}
583 		mcs_port_params[portid].rx_flow = NULL;
584 	}
585 }
586 
587 static void
588 clean_macsec_resources(uint16_t portid)
589 {
590 	uint8_t an;
591 
592 	destroy_default_flow(portid);
593 	rte_security_session_destroy(mcs_port_params[portid].sec_ctx,
594 				mcs_port_params[portid].sess);
595 	rte_security_macsec_sc_destroy(mcs_port_params[portid].sec_ctx,
596 				mcs_port_params[portid].sc_id,
597 				mcs_port_params[portid].dir);
598 	for (an = 0; an < RTE_SECURITY_MACSEC_NUM_AN; an++) {
599 		if (mcs_port_params[portid].sa_id[an] != 0xFFFF)
600 			rte_security_macsec_sa_destroy(mcs_port_params[portid].sec_ctx,
601 				mcs_port_params[portid].sa_id[an],
602 				mcs_port_params[portid].dir);
603 	}
604 }
605 
606 static int
607 initialize_macsec_session(uint8_t portid)
608 {
609 	struct rte_security_session_conf sess_conf = {0};
610 	struct rte_security_macsec_sa sa_conf = {0};
611 	struct rte_security_macsec_sc sc_conf = {0};
612 	int id, ret;
613 
614 	/* Create MACsec SA. */
615 	fill_macsec_sa_conf(portid, &sa_conf);
616 	id = rte_security_macsec_sa_create(mcs_port_params[portid].sec_ctx, &sa_conf);
617 	if (id < 0) {
618 		printf("MACsec SA create failed : %d.\n", id);
619 		return -1;
620 	}
621 	mcs_port_params[portid].sa_id[0] = (uint16_t)id;
622 	mcs_port_params[portid].sa_id[1] = 0xFFFF;
623 	mcs_port_params[portid].sa_id[2] = 0xFFFF;
624 	mcs_port_params[portid].sa_id[3] = 0xFFFF;
625 
626 	printf("\nsa_id %d created.\n", mcs_port_params[portid].sa_id[0]);
627 
628 	/* Create MACsec SC. */
629 	fill_macsec_sc_conf(portid, &sc_conf);
630 	id = rte_security_macsec_sc_create(mcs_port_params[portid].sec_ctx, &sc_conf);
631 	if (id < 0) {
632 		printf("MACsec SC create failed : %d.\n", id);
633 		goto out;
634 	}
635 	mcs_port_params[portid].sc_id = (uint16_t)id;
636 	printf("\nsc_id %d created.\n", mcs_port_params[portid].sc_id);
637 
638 	/* Create Inline MACsec session. */
639 	ret = fill_session_conf(portid, &sess_conf);
640 	if (ret) {
641 		printf("MACsec Session conf failed.\n");
642 		goto out;
643 	}
644 	mcs_port_params[portid].sess =
645 		rte_security_session_create(mcs_port_params[portid].sec_ctx,
646 				&sess_conf, mcs_port_params[portid].sess_pool);
647 	if (mcs_port_params[portid].sess == NULL) {
648 		printf("MACSEC Session init failed errno: %d.\n", rte_errno);
649 		goto out;
650 	}
651 
652 	/* Create MACsec flow. */
653 	ret = create_default_flow(portid);
654 	if (ret)
655 		goto out;
656 
657 	return 0;
658 out:
659 	clean_macsec_resources(portid);
660 	return -1;
661 }
662 
663 /* main processing loop */
664 static void
665 l2fwd_main_loop(void)
666 {
667 	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
668 	struct rte_mbuf *m;
669 	int sent;
670 	unsigned int lcore_id;
671 	uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
672 	unsigned int i, j, portid, nb_rx;
673 	struct lcore_queue_conf *qconf;
674 	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S *
675 			BURST_TX_DRAIN_US;
676 	struct rte_eth_dev_tx_buffer *buffer;
677 
678 	prev_tsc = 0;
679 	timer_tsc = 0;
680 
681 	lcore_id = rte_lcore_id();
682 	qconf = &lcore_queue_conf[lcore_id];
683 
684 	if (qconf->n_rx_port == 0) {
685 		RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
686 		return;
687 	}
688 
689 	RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
690 
691 	for (i = 0; i < qconf->n_rx_port; i++) {
692 
693 		portid = qconf->rx_port_list[i];
694 
695 		RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
696 			portid);
697 	}
698 
699 	while (!force_quit) {
700 
701 		/* Drains TX queue in its main loop. 8< */
702 		cur_tsc = rte_rdtsc();
703 
704 		/*
705 		 * TX burst queue drain
706 		 */
707 		diff_tsc = cur_tsc - prev_tsc;
708 		if (unlikely(diff_tsc > drain_tsc)) {
709 
710 			for (i = 0; i < qconf->n_rx_port; i++) {
711 
712 				portid = l2fwd_dst_ports[qconf->rx_port_list[i]];
713 				buffer = tx_buffer[portid];
714 
715 				sent = rte_eth_tx_buffer_flush(portid, 0, buffer);
716 				if (sent)
717 					port_statistics[portid].tx += sent;
718 
719 			}
720 
721 			/* if timer is enabled */
722 			if (timer_period > 0) {
723 
724 				/* advance the timer */
725 				timer_tsc += diff_tsc;
726 
727 				/* if timer has reached its timeout */
728 				if (unlikely(timer_tsc >= timer_period)) {
729 
730 					/* do this only on main core */
731 					if (lcore_id == rte_get_main_lcore()) {
732 						print_stats();
733 						/* reset the timer */
734 						timer_tsc = 0;
735 					}
736 				}
737 			}
738 
739 			prev_tsc = cur_tsc;
740 		}
741 		/* >8 End of draining TX queue. */
742 
743 		/* Read packet from RX queues. 8< */
744 		for (i = 0; i < qconf->n_rx_port; i++) {
745 
746 			portid = qconf->rx_port_list[i];
747 			nb_rx = rte_eth_rx_burst(portid, 0,
748 						 pkts_burst, MAX_PKT_BURST);
749 
750 			if (unlikely(nb_rx == 0))
751 				continue;
752 
753 			port_statistics[portid].rx += nb_rx;
754 
755 			for (j = 0; j < nb_rx; j++) {
756 				m = pkts_burst[j];
757 				rte_prefetch0(rte_pktmbuf_mtod(m, void *));
758 				l2fwd_simple_forward(m, portid);
759 			}
760 		}
761 		/* >8 End of read packet from RX queues. */
762 	}
763 	if (force_quit) {
764 		for (i = 0; i < qconf->n_rx_port; i++) {
765 			portid = qconf->rx_port_list[i];
766 			clean_macsec_resources(portid);
767 		}
768 	}
769 }
770 static int
771 l2fwd_launch_one_lcore(__rte_unused void *arg)
772 {
773 	l2fwd_main_loop();
774 	return 0;
775 }
776 
777 /* display usage */
778 static void
779 l2fwd_usage(const char *prgname)
780 {
781 	printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
782 	       "  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
783 	       "  -q NQ: number of queue (=ports) per lcore (default is 1)\n"
784 	       "  -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n"
785 	       "  --mcs-tx-portmask: Hexadecimal bitmask for MACsec Tx(Encap) ports\n"
786 	       "  --mcs-rx-portmask: Hexadecimal bitmask for MACsec Rx(Decap) ports\n"
787 	       "  --mcs-port-config '(<port>,<src-mac>,<dst-mac>)'\n"
788 	       "  --portmap: Configure forwarding port pair mapping\n"
789 	       "	      Default: alternate port pairs\n\n",
790 	       prgname);
791 }
792 
793 static int
794 l2fwd_parse_portmask(const char *portmask)
795 {
796 	char *end = NULL;
797 	unsigned long pm;
798 
799 	/* parse hexadecimal string */
800 	pm = strtoul(portmask, &end, 16);
801 	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
802 		return 0;
803 
804 	return pm;
805 }
806 
807 static int
808 l2fwd_parse_port_pair_config(const char *q_arg)
809 {
810 	enum fieldnames {
811 		FLD_PORT1 = 0,
812 		FLD_PORT2,
813 		_NUM_FLD
814 	};
815 	unsigned long int_fld[_NUM_FLD];
816 	const char *p, *p0 = q_arg;
817 	char *str_fld[_NUM_FLD];
818 	unsigned int size;
819 	char s[256];
820 	char *end;
821 	int i;
822 
823 	nb_port_pair_params = 0;
824 
825 	while ((p = strchr(p0, '(')) != NULL) {
826 		++p;
827 		p0 = strchr(p, ')');
828 		if (p0 == NULL)
829 			return -1;
830 
831 		size = p0 - p;
832 		if (size >= sizeof(s))
833 			return -1;
834 
835 		memcpy(s, p, size);
836 		s[size] = '\0';
837 		if (rte_strsplit(s, sizeof(s), str_fld,
838 				 _NUM_FLD, ',') != _NUM_FLD)
839 			return -1;
840 		for (i = 0; i < _NUM_FLD; i++) {
841 			errno = 0;
842 			int_fld[i] = strtoul(str_fld[i], &end, 0);
843 			if (errno != 0 || end == str_fld[i] ||
844 			    int_fld[i] >= RTE_MAX_ETHPORTS)
845 				return -1;
846 		}
847 		if (nb_port_pair_params >= RTE_MAX_ETHPORTS/2) {
848 			printf("exceeded max number of port pair params: %hu\n",
849 				nb_port_pair_params);
850 			return -1;
851 		}
852 		port_pair_params_array[nb_port_pair_params].port[0] =
853 				(uint16_t)int_fld[FLD_PORT1];
854 		port_pair_params_array[nb_port_pair_params].port[1] =
855 				(uint16_t)int_fld[FLD_PORT2];
856 		++nb_port_pair_params;
857 	}
858 	port_pair_params = port_pair_params_array;
859 	return 0;
860 }
861 
862 static int
863 l2fwd_parse_macsec_port_config(const char *q_arg)
864 {
865 	enum fieldnames {
866 		FLD_PORT = 0,
867 		FLD_SRC,
868 		FLD_DST,
869 		_NUM_FLD
870 	};
871 	unsigned int portid;
872 	struct rte_ether_addr src, dst;
873 	const char *p, *p0 = q_arg;
874 	char *str_fld[_NUM_FLD];
875 	unsigned int size;
876 	char s[256];
877 	char *end;
878 
879 	nb_port_pair_params = 0;
880 
881 	while ((p = strchr(p0, '(')) != NULL) {
882 		++p;
883 		p0 = strchr(p, ')');
884 		if (p0 == NULL)
885 			return -1;
886 
887 		size = p0 - p;
888 		if (size >= sizeof(s))
889 			return -1;
890 
891 		memcpy(s, p, size);
892 		s[size] = '\0';
893 		if (rte_strsplit(s, sizeof(s), str_fld,
894 				 _NUM_FLD, ',') != _NUM_FLD)
895 			return -1;
896 		errno = 0;
897 		portid = strtoul(str_fld[FLD_PORT], &end, 0);
898 		if (errno != 0 || end == str_fld[FLD_PORT] || portid >= RTE_MAX_ETHPORTS)
899 			return -1;
900 		if (port_ether_hdr_config[portid].ether_type == 0x0800) {
901 			printf("MACsec src-dst MAC addr already parsed for port: %d\n",
902 					portid);
903 			return -1;
904 		}
905 		if (rte_ether_unformat_addr(str_fld[FLD_SRC], &src) ||
906 				rte_ether_unformat_addr(str_fld[FLD_DST], &dst))
907 			return -1;
908 
909 		memcpy(&port_ether_hdr_config[portid].src_addr, &src, sizeof(src));
910 		memcpy(&port_ether_hdr_config[portid].dst_addr, &dst, sizeof(dst));
911 		port_ether_hdr_config[portid].ether_type = 0x0800;
912 	}
913 
914 	return 0;
915 }
916 
917 
918 static unsigned int
919 l2fwd_parse_nqueue(const char *q_arg)
920 {
921 	char *end = NULL;
922 	unsigned long n;
923 
924 	/* parse hexadecimal string */
925 	n = strtoul(q_arg, &end, 10);
926 	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
927 		return 0;
928 	if (n == 0)
929 		return 0;
930 	if (n >= MAX_RX_QUEUE_PER_LCORE)
931 		return 0;
932 
933 	return n;
934 }
935 
936 static int
937 l2fwd_parse_timer_period(const char *q_arg)
938 {
939 	char *end = NULL;
940 	int n;
941 
942 	/* parse number string */
943 	n = strtol(q_arg, &end, 10);
944 	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
945 		return -1;
946 	if (n >= MAX_TIMER_PERIOD)
947 		return -1;
948 
949 	return n;
950 }
951 
952 static const char short_options[] =
953 	"p:"  /* portmask */
954 	"P"   /* promiscuous */
955 	"q:"  /* number of queues */
956 	"T:"  /* timer period */
957 	;
958 
959 #define CMD_LINE_OPT_NO_MAC_UPDATING	"no-mac-updating"
960 #define CMD_LINE_OPT_PORTMAP_CONFIG	"portmap"
961 #define CMD_LINE_OPT_MACSEC_TX_PORTMASK	"mcs-tx-portmask"
962 #define CMD_LINE_OPT_MACSEC_RX_PORTMASK	"mcs-rx-portmask"
963 #define CMD_LINE_OPT_MACSEC_PORT_CONFIG	"mcs-port-config"
964 
965 enum {
966 	/* Long options mapped to a short option.
967 	 * First long only option value must be >= 256,
968 	 * so that we won't conflict with short options.
969 	 */
970 	CMD_LINE_OPT_NO_MAC_UPDATING_NUM = 256,
971 	CMD_LINE_OPT_PORTMAP_NUM,
972 	CMD_LINE_OPT_MACSEC_TX_PORTMASK_NUM,
973 	CMD_LINE_OPT_MACSEC_RX_PORTMASK_NUM,
974 	CMD_LINE_OPT_MACSEC_PORT_CFG_NUM,
975 };
976 
977 static const struct option lgopts[] = {
978 	{ CMD_LINE_OPT_NO_MAC_UPDATING, no_argument, 0,
979 		CMD_LINE_OPT_NO_MAC_UPDATING_NUM},
980 	{ CMD_LINE_OPT_PORTMAP_CONFIG, 1, 0, CMD_LINE_OPT_PORTMAP_NUM},
981 	{ CMD_LINE_OPT_MACSEC_TX_PORTMASK, required_argument, 0,
982 		CMD_LINE_OPT_MACSEC_TX_PORTMASK_NUM},
983 	{ CMD_LINE_OPT_MACSEC_RX_PORTMASK, required_argument, 0,
984 		CMD_LINE_OPT_MACSEC_RX_PORTMASK_NUM},
985 	{ CMD_LINE_OPT_MACSEC_PORT_CONFIG, 1, 0, CMD_LINE_OPT_MACSEC_PORT_CFG_NUM},
986 	{NULL, 0, 0, 0}
987 };
988 
989 /** Generate default options for application. */
990 static void
991 l2fwd_macsec_default_options(struct l2fwd_macsec_options *options)
992 {
993 	uint16_t portid;
994 	uint8_t salt[MCS_SALT_LEN] = {0};
995 	uint8_t key[16] = {
996 			0x07, 0x1B, 0x11, 0x3B, 0x0C, 0xA7, 0x43, 0xFE,
997 			0xCC, 0xCF, 0x3D, 0x05, 0x1F, 0x73, 0x73, 0x82
998 		};
999 
1000 	options->portmask = 0xffffffff;
1001 	options->nb_ports_per_lcore = 1;
1002 	options->single_lcore = 0;
1003 
1004 	RTE_ETH_FOREACH_DEV(portid) {
1005 		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
1006 			continue;
1007 		if ((options->tx_portmask & (1 << portid)) != 0)
1008 			mcs_port_params[portid].dir = RTE_SECURITY_MACSEC_DIR_TX;
1009 
1010 		if ((options->rx_portmask & (1 << portid)) != 0)
1011 			mcs_port_params[portid].dir = RTE_SECURITY_MACSEC_DIR_RX;
1012 
1013 		mcs_port_params[portid].alg = RTE_SECURITY_MACSEC_ALG_GCM_XPN_128;
1014 		memcpy(mcs_port_params[portid].sa_key.data, key, 16);
1015 		mcs_port_params[portid].sa_key.len = 16;
1016 		memcpy(mcs_port_params[portid].salt, salt, MCS_SALT_LEN);
1017 
1018 		memcpy(mcs_port_params[portid].eth_hdr, &port_ether_hdr_config[portid],
1019 				RTE_ETHER_HDR_LEN);
1020 
1021 		mcs_port_params[portid].ssci = 0;
1022 		mcs_port_params[portid].pn_threshold = 0xffffffffffffffff;
1023 		mcs_port_params[portid].xpn = 0;
1024 		mcs_port_params[portid].next_pn = 1;
1025 		mcs_port_params[portid].mtu = 1500;
1026 		mcs_port_params[portid].sectag_insert_mode = 1;
1027 		mcs_port_params[portid].encrypt = true;
1028 		mcs_port_params[portid].protect_frames = true;
1029 		mcs_port_params[portid].replay_protect = false;
1030 		mcs_port_params[portid].val_frames = RTE_SECURITY_MACSEC_VALIDATE_STRICT;
1031 		mcs_port_params[portid].send_sci = true;
1032 		mcs_port_params[portid].end_station = false;
1033 		mcs_port_params[portid].scb = false;
1034 	}
1035 }
1036 
1037 /* Parse the argument given in the command line of the application */
1038 static int
1039 l2fwd_parse_args(struct l2fwd_macsec_options *options,
1040 		int argc, char **argv)
1041 {
1042 	int opt, ret, timer_secs;
1043 	char **argvopt;
1044 	int option_index;
1045 	char *prgname = argv[0];
1046 
1047 	argvopt = argv;
1048 	port_pair_params = NULL;
1049 
1050 	while ((opt = getopt_long(argc, argvopt, short_options,
1051 				  lgopts, &option_index)) != EOF) {
1052 
1053 		switch (opt) {
1054 		/* portmask */
1055 		case 'p':
1056 			l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
1057 			if (l2fwd_enabled_port_mask == 0) {
1058 				printf("invalid portmask\n");
1059 				l2fwd_usage(prgname);
1060 				return -1;
1061 			}
1062 			break;
1063 		case 'P':
1064 			promiscuous_on = 1;
1065 			break;
1066 
1067 		/* nqueue */
1068 		case 'q':
1069 			l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
1070 			if (l2fwd_rx_queue_per_lcore == 0) {
1071 				printf("invalid queue number\n");
1072 				l2fwd_usage(prgname);
1073 				return -1;
1074 			}
1075 			break;
1076 
1077 		/* timer period */
1078 		case 'T':
1079 			timer_secs = l2fwd_parse_timer_period(optarg);
1080 			if (timer_secs < 0) {
1081 				printf("invalid timer period\n");
1082 				l2fwd_usage(prgname);
1083 				return -1;
1084 			}
1085 			timer_period = timer_secs;
1086 			break;
1087 
1088 		/* long options */
1089 		case CMD_LINE_OPT_PORTMAP_NUM:
1090 			ret = l2fwd_parse_port_pair_config(optarg);
1091 			if (ret) {
1092 				fprintf(stderr, "Invalid config\n");
1093 				l2fwd_usage(prgname);
1094 				return -1;
1095 			}
1096 			break;
1097 
1098 		case CMD_LINE_OPT_NO_MAC_UPDATING_NUM:
1099 			mac_updating = 0;
1100 			break;
1101 
1102 		case CMD_LINE_OPT_MACSEC_TX_PORTMASK_NUM:
1103 			options->tx_portmask = l2fwd_parse_portmask(optarg);
1104 			if (options->tx_portmask == 0) {
1105 				l2fwd_usage(prgname);
1106 				return -1;
1107 			}
1108 			break;
1109 
1110 		case CMD_LINE_OPT_MACSEC_RX_PORTMASK_NUM:
1111 			options->rx_portmask = l2fwd_parse_portmask(optarg);
1112 			if (options->rx_portmask == 0) {
1113 				l2fwd_usage(prgname);
1114 				return -1;
1115 			}
1116 			break;
1117 
1118 		case CMD_LINE_OPT_MACSEC_PORT_CFG_NUM:
1119 			ret = l2fwd_parse_macsec_port_config(optarg);
1120 			if (ret) {
1121 				fprintf(stderr, "Invalid MACsec port config\n");
1122 				l2fwd_usage(prgname);
1123 				return -1;
1124 			}
1125 			break;
1126 
1127 		default:
1128 			l2fwd_usage(prgname);
1129 			return -1;
1130 		}
1131 	}
1132 	l2fwd_macsec_default_options(options);
1133 
1134 	if (optind >= 0)
1135 		argv[optind-1] = prgname;
1136 
1137 	ret = optind-1;
1138 	optind = 1; /* reset getopt lib */
1139 	return ret;
1140 }
1141 
1142 /*
1143  * Check port pair config with enabled port mask,
1144  * and for valid port pair combinations.
1145  */
1146 static int
1147 check_port_pair_config(void)
1148 {
1149 	uint32_t port_pair_config_mask = 0;
1150 	uint32_t port_pair_mask = 0;
1151 	uint16_t index, i, portid;
1152 
1153 	for (index = 0; index < nb_port_pair_params; index++) {
1154 		port_pair_mask = 0;
1155 
1156 		for (i = 0; i < NUM_PORTS; i++)  {
1157 			portid = port_pair_params[index].port[i];
1158 			if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
1159 				printf("port %u is not enabled in port mask\n",
1160 				       portid);
1161 				return -1;
1162 			}
1163 			if (!rte_eth_dev_is_valid_port(portid)) {
1164 				printf("port %u is not present on the board\n",
1165 				       portid);
1166 				return -1;
1167 			}
1168 
1169 			port_pair_mask |= 1 << portid;
1170 		}
1171 
1172 		if (port_pair_config_mask & port_pair_mask) {
1173 			printf("port %u is used in other port pairs\n", portid);
1174 			return -1;
1175 		}
1176 		port_pair_config_mask |= port_pair_mask;
1177 	}
1178 
1179 	l2fwd_enabled_port_mask &= port_pair_config_mask;
1180 
1181 	return 0;
1182 }
1183 
1184 /* Check the link status of all ports in up to 9s, and print them finally */
1185 static void
1186 check_all_ports_link_status(uint32_t port_mask)
1187 {
1188 #define CHECK_INTERVAL 100 /* 100ms */
1189 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
1190 	uint16_t portid;
1191 	uint8_t count, all_ports_up, print_flag = 0;
1192 	struct rte_eth_link link;
1193 	int ret;
1194 	char link_status_text[RTE_ETH_LINK_MAX_STR_LEN];
1195 
1196 	printf("\nChecking link status");
1197 	fflush(stdout);
1198 	for (count = 0; count <= MAX_CHECK_TIME; count++) {
1199 		if (force_quit)
1200 			return;
1201 		all_ports_up = 1;
1202 		RTE_ETH_FOREACH_DEV(portid) {
1203 			if (force_quit)
1204 				return;
1205 			if ((port_mask & (1 << portid)) == 0)
1206 				continue;
1207 			memset(&link, 0, sizeof(link));
1208 			ret = rte_eth_link_get_nowait(portid, &link);
1209 			if (ret < 0) {
1210 				all_ports_up = 0;
1211 				if (print_flag == 1)
1212 					printf("Port %u link get failed: %s\n",
1213 						portid, rte_strerror(-ret));
1214 				continue;
1215 			}
1216 			/* print link status if flag set */
1217 			if (print_flag == 1) {
1218 				rte_eth_link_to_str(link_status_text,
1219 					sizeof(link_status_text), &link);
1220 				printf("Port %d %s\n", portid,
1221 				       link_status_text);
1222 				continue;
1223 			}
1224 			/* clear all_ports_up flag if any link down */
1225 			if (link.link_status == RTE_ETH_LINK_DOWN) {
1226 				all_ports_up = 0;
1227 				break;
1228 			}
1229 		}
1230 		/* after finally printing all link status, get out */
1231 		if (print_flag == 1)
1232 			break;
1233 
1234 		if (all_ports_up == 0) {
1235 			printf(".");
1236 			fflush(stdout);
1237 			rte_delay_ms(CHECK_INTERVAL);
1238 		}
1239 
1240 		/* set the print_flag if all ports up or timeout */
1241 		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
1242 			print_flag = 1;
1243 			printf("done\n");
1244 		}
1245 	}
1246 }
1247 
1248 static void
1249 signal_handler(int signum)
1250 {
1251 	if (signum == SIGINT || signum == SIGTERM) {
1252 		printf("\n\nSignal %d received, preparing to exit...\n",
1253 				signum);
1254 		force_quit = true;
1255 	}
1256 }
1257 
1258 int
1259 main(int argc, char **argv)
1260 {
1261 	struct l2fwd_macsec_options options = {0};
1262 	struct lcore_queue_conf *qconf;
1263 	int ret;
1264 	uint16_t nb_ports;
1265 	uint16_t nb_ports_available = 0;
1266 	uint16_t portid, last_port;
1267 	unsigned int lcore_id, rx_lcore_id;
1268 	unsigned int nb_ports_in_mask = 0;
1269 	unsigned int nb_lcores = 0;
1270 	unsigned int nb_mbufs;
1271 	uint16_t nb_sess = 512;
1272 	uint32_t sess_sz;
1273 	char s[64];
1274 
1275 	/* Init EAL. 8< */
1276 	ret = rte_eal_init(argc, argv);
1277 	if (ret < 0)
1278 		rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
1279 	argc -= ret;
1280 	argv += ret;
1281 
1282 	force_quit = false;
1283 	signal(SIGINT, signal_handler);
1284 	signal(SIGTERM, signal_handler);
1285 
1286 	/* parse application arguments (after the EAL ones) */
1287 	ret = l2fwd_parse_args(&options, argc, argv);
1288 	if (ret < 0)
1289 		rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
1290 	/* >8 End of init EAL. */
1291 
1292 	printf("MAC updating %s\n", mac_updating ? "enabled" : "disabled");
1293 
1294 	/* convert to number of cycles */
1295 	timer_period *= rte_get_timer_hz();
1296 
1297 	nb_ports = rte_eth_dev_count_avail();
1298 	if (nb_ports == 0)
1299 		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
1300 
1301 	if (port_pair_params != NULL) {
1302 		if (check_port_pair_config() < 0)
1303 			rte_exit(EXIT_FAILURE, "Invalid port pair config\n");
1304 	}
1305 
1306 	/* check port mask to possible port mask */
1307 	if (l2fwd_enabled_port_mask & ~((1 << nb_ports) - 1))
1308 		rte_exit(EXIT_FAILURE, "Invalid portmask; possible (0x%x)\n",
1309 			(1 << nb_ports) - 1);
1310 
1311 	/* Initialization of the driver. 8< */
1312 
1313 	/* reset l2fwd_dst_ports */
1314 	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
1315 		l2fwd_dst_ports[portid] = 0;
1316 	last_port = 0;
1317 
1318 	/* populate destination port details */
1319 	if (port_pair_params != NULL) {
1320 		uint16_t idx, p;
1321 
1322 		for (idx = 0; idx < (nb_port_pair_params << 1); idx++) {
1323 			p = idx & 1;
1324 			portid = port_pair_params[idx >> 1].port[p];
1325 			l2fwd_dst_ports[portid] =
1326 				port_pair_params[idx >> 1].port[p ^ 1];
1327 		}
1328 	} else {
1329 		RTE_ETH_FOREACH_DEV(portid) {
1330 			/* skip ports that are not enabled */
1331 			if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
1332 				continue;
1333 
1334 			if (nb_ports_in_mask % 2) {
1335 				l2fwd_dst_ports[portid] = last_port;
1336 				l2fwd_dst_ports[last_port] = portid;
1337 			} else {
1338 				last_port = portid;
1339 			}
1340 
1341 			nb_ports_in_mask++;
1342 		}
1343 		if (nb_ports_in_mask % 2) {
1344 			printf("Notice: odd number of ports in portmask.\n");
1345 			l2fwd_dst_ports[last_port] = last_port;
1346 		}
1347 	}
1348 	/* >8 End of initialization of the driver. */
1349 
1350 	rx_lcore_id = 0;
1351 	qconf = NULL;
1352 
1353 	/* Initialize the port/queue configuration of each logical core */
1354 	RTE_ETH_FOREACH_DEV(portid) {
1355 		/* skip ports that are not enabled */
1356 		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
1357 			continue;
1358 
1359 		/* get the lcore_id for this port */
1360 		while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
1361 		       lcore_queue_conf[rx_lcore_id].n_rx_port ==
1362 		       l2fwd_rx_queue_per_lcore) {
1363 			rx_lcore_id++;
1364 			if (rx_lcore_id >= RTE_MAX_LCORE)
1365 				rte_exit(EXIT_FAILURE, "Not enough cores\n");
1366 		}
1367 
1368 		if (qconf != &lcore_queue_conf[rx_lcore_id]) {
1369 			/* Assigned a new logical core in the loop above. */
1370 			qconf = &lcore_queue_conf[rx_lcore_id];
1371 			nb_lcores++;
1372 		}
1373 
1374 		qconf->rx_port_list[qconf->n_rx_port] = portid;
1375 		qconf->n_rx_port++;
1376 		printf("Lcore %u: RX port %u TX port %u\n", rx_lcore_id,
1377 		       portid, l2fwd_dst_ports[portid]);
1378 	}
1379 
1380 	nb_mbufs = RTE_MAX(nb_ports * (nb_rxd + nb_txd + MAX_PKT_BURST +
1381 		nb_lcores * MEMPOOL_CACHE_SIZE), 8192U);
1382 
1383 	/* Create the mbuf pool. 8< */
1384 	l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", nb_mbufs,
1385 		MEMPOOL_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE,
1386 		rte_socket_id());
1387 	if (l2fwd_pktmbuf_pool == NULL)
1388 		rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
1389 	/* >8 End of create the mbuf pool. */
1390 
1391 	/* Initialise each port */
1392 	RTE_ETH_FOREACH_DEV(portid) {
1393 		struct rte_eth_rxconf rxq_conf;
1394 		struct rte_eth_txconf txq_conf;
1395 		struct rte_eth_conf local_port_conf = port_conf;
1396 		struct rte_eth_dev_info dev_info;
1397 
1398 		/* skip ports that are not enabled */
1399 		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
1400 			printf("Skipping disabled port %u\n", portid);
1401 			continue;
1402 		}
1403 		nb_ports_available++;
1404 
1405 		/* init port */
1406 		printf("Initializing port %u... ", portid);
1407 		fflush(stdout);
1408 
1409 		ret = rte_eth_dev_info_get(portid, &dev_info);
1410 		if (ret != 0)
1411 			rte_exit(EXIT_FAILURE,
1412 				"Error during getting device (port %u) info: %s\n",
1413 				portid, strerror(-ret));
1414 
1415 		if (dev_info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE)
1416 			local_port_conf.txmode.offloads |=
1417 				RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE;
1418 		/* Configure the number of queues for a port. */
1419 		ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf);
1420 		if (ret < 0)
1421 			rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n",
1422 				  ret, portid);
1423 		/* >8 End of configuration of the number of queues for a port. */
1424 
1425 		ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd,
1426 						       &nb_txd);
1427 		if (ret < 0)
1428 			rte_exit(EXIT_FAILURE,
1429 				 "Cannot adjust number of descriptors: err=%d, port=%u\n",
1430 				 ret, portid);
1431 
1432 		ret = rte_eth_macaddr_get(portid,
1433 					  &l2fwd_ports_eth_addr[portid]);
1434 		if (ret < 0)
1435 			rte_exit(EXIT_FAILURE,
1436 				 "Cannot get MAC address: err=%d, port=%u\n",
1437 				 ret, portid);
1438 
1439 		/* init one RX queue */
1440 		fflush(stdout);
1441 		rxq_conf = dev_info.default_rxconf;
1442 		rxq_conf.offloads = local_port_conf.rxmode.offloads;
1443 		/* RX queue setup. 8< */
1444 		ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
1445 					     rte_eth_dev_socket_id(portid),
1446 					     &rxq_conf,
1447 					     l2fwd_pktmbuf_pool);
1448 		if (ret < 0)
1449 			rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n",
1450 				  ret, portid);
1451 		/* >8 End of RX queue setup. */
1452 
1453 		/* Init one TX queue on each port. 8< */
1454 		fflush(stdout);
1455 		txq_conf = dev_info.default_txconf;
1456 		txq_conf.offloads = local_port_conf.txmode.offloads;
1457 		ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
1458 				rte_eth_dev_socket_id(portid),
1459 				&txq_conf);
1460 		if (ret < 0)
1461 			rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n",
1462 				ret, portid);
1463 		/* >8 End of init one TX queue on each port. */
1464 
1465 		/* Initialize TX buffers */
1466 		tx_buffer[portid] = rte_zmalloc_socket("tx_buffer",
1467 				RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,
1468 				rte_eth_dev_socket_id(portid));
1469 		if (tx_buffer[portid] == NULL)
1470 			rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n",
1471 					portid);
1472 
1473 		rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST);
1474 
1475 		ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid],
1476 				rte_eth_tx_buffer_count_callback,
1477 				&port_statistics[portid].dropped);
1478 		if (ret < 0)
1479 			rte_exit(EXIT_FAILURE,
1480 			"Cannot set error callback for tx buffer on port %u\n",
1481 				 portid);
1482 
1483 		ret = rte_eth_dev_set_ptypes(portid, RTE_PTYPE_UNKNOWN, NULL,
1484 					     0);
1485 		if (ret < 0)
1486 			printf("Port %u, Failed to disable Ptype parsing\n",
1487 					portid);
1488 		/* Start device */
1489 		ret = rte_eth_dev_start(portid);
1490 		if (ret < 0)
1491 			rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n",
1492 				  ret, portid);
1493 
1494 		printf("done:\n");
1495 		if (promiscuous_on) {
1496 			ret = rte_eth_promiscuous_enable(portid);
1497 			if (ret != 0)
1498 				rte_exit(EXIT_FAILURE,
1499 					"rte_eth_promiscuous_enable:err=%s, port=%u\n",
1500 					rte_strerror(-ret), portid);
1501 		}
1502 
1503 		printf("Port %u, MAC address: " RTE_ETHER_ADDR_PRT_FMT "\n\n",
1504 			portid,
1505 			RTE_ETHER_ADDR_BYTES(&l2fwd_ports_eth_addr[portid]));
1506 
1507 		/* initialize port stats */
1508 		memset(&port_statistics, 0, sizeof(port_statistics));
1509 
1510 		mcs_port_params[portid].sec_ctx = rte_eth_dev_get_sec_ctx(portid);
1511 		if (mcs_port_params[portid].sec_ctx == NULL)
1512 			rte_exit(EXIT_FAILURE, "Device does not support Security ctx\n");
1513 
1514 		sess_sz = rte_security_session_get_size(mcs_port_params[portid].sec_ctx);
1515 		if (mcs_port_params[portid].sess_pool == NULL) {
1516 			snprintf(s, sizeof(s), "sess_pool_p%d", portid);
1517 			mcs_port_params[portid].sess_pool = rte_mempool_create(s,
1518 							nb_sess, sess_sz,
1519 							SESSION_POOL_CACHE_SIZE, 0,
1520 							NULL, NULL, NULL, NULL,
1521 							SOCKET_ID_ANY, 0);
1522 			if (mcs_port_params[portid].sess_pool == NULL)
1523 				rte_exit(EXIT_FAILURE, "Cannot init sess pool\n");
1524 
1525 			printf("Allocated sess pool\n");
1526 		}
1527 
1528 		if (((options.tx_portmask & (1 << portid)) != 0) ||
1529 				((options.rx_portmask & (1 << portid)) != 0)) {
1530 			ret = initialize_macsec_session(portid);
1531 			if (ret < 0)
1532 				rte_exit(EXIT_FAILURE,
1533 					"Failed to initialize MACsec session for port: %d\n",
1534 					portid);
1535 		}
1536 	}
1537 
1538 	if (!nb_ports_available) {
1539 		rte_exit(EXIT_FAILURE,
1540 			"All available ports are disabled. Please set portmask.\n");
1541 	}
1542 
1543 	check_all_ports_link_status(l2fwd_enabled_port_mask);
1544 
1545 	ret = 0;
1546 	/* launch per-lcore init on every lcore */
1547 	rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MAIN);
1548 	RTE_LCORE_FOREACH_WORKER(lcore_id) {
1549 		if (rte_eal_wait_lcore(lcore_id) < 0) {
1550 			ret = -1;
1551 			break;
1552 		}
1553 	}
1554 
1555 	RTE_ETH_FOREACH_DEV(portid) {
1556 		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
1557 			continue;
1558 		printf("Closing port %d...", portid);
1559 		ret = rte_eth_dev_stop(portid);
1560 		if (ret != 0)
1561 			printf("rte_eth_dev_stop: err=%d, port=%d\n",
1562 			       ret, portid);
1563 		rte_eth_dev_close(portid);
1564 		printf(" Done\n");
1565 	}
1566 
1567 	/* clean up the EAL */
1568 	rte_eal_cleanup();
1569 	printf("Bye...\n");
1570 
1571 	return ret;
1572 }
1573