xref: /dpdk/examples/l2fwd-macsec/main.c (revision d029f35384d0844e9aeb5dbc46fbe1b063d649f7)
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 port_pair_params {
76 #define NUM_PORTS	2
77 	uint16_t port[NUM_PORTS];
78 } __rte_cache_aligned;
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 lcore_queue_conf {
90 	unsigned int n_rx_port;
91 	unsigned int rx_port_list[MAX_RX_QUEUE_PER_LCORE];
92 } __rte_cache_aligned;
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 l2fwd_port_statistics {
109 	uint64_t tx;
110 	uint64_t rx;
111 	uint64_t dropped;
112 } __rte_cache_aligned;
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].xpn > 0)
450 			sc_conf->sc_tx.is_xpn = 1;
451 	} else {
452 		for (i = 0; i < RTE_SECURITY_MACSEC_NUM_AN; i++) {
453 			if (mcs_port_params[portid].sa_id[i] != 0xFFFF) {
454 				sc_conf->sc_rx.sa_id[i] = mcs_port_params[portid].sa_id[i];
455 				sc_conf->sc_rx.sa_in_use[i] = 1;
456 			}
457 		}
458 		sc_conf->sc_rx.active = 1;
459 		if (mcs_port_params[portid].xpn > 0)
460 			sc_conf->sc_rx.is_xpn = 1;
461 	}
462 }
463 
464 /* Create Inline MACsec session */
465 static int
466 fill_session_conf(uint16_t portid, struct rte_security_session_conf *sess_conf)
467 {
468 	sess_conf->action_type = RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL;
469 	sess_conf->protocol = RTE_SECURITY_PROTOCOL_MACSEC;
470 	sess_conf->macsec.dir = mcs_port_params[portid].dir;
471 	sess_conf->macsec.alg = mcs_port_params[portid].alg;
472 	sess_conf->macsec.cipher_off = 0;
473 	sess_conf->macsec.sci = mcs_port_params[portid].sci;
474 	sess_conf->macsec.sc_id = mcs_port_params[portid].sc_id;
475 	if (mcs_port_params[portid].dir == RTE_SECURITY_MACSEC_DIR_TX) {
476 		sess_conf->macsec.tx_secy.mtu = mcs_port_params[portid].mtu;
477 		sess_conf->macsec.tx_secy.sectag_off =
478 			(mcs_port_params[portid].sectag_insert_mode == 1) ?
479 					2 * RTE_ETHER_ADDR_LEN : RTE_VLAN_HLEN;
480 		sess_conf->macsec.tx_secy.sectag_insert_mode =
481 			mcs_port_params[portid].sectag_insert_mode;
482 		sess_conf->macsec.tx_secy.ctrl_port_enable = 1;
483 		sess_conf->macsec.tx_secy.sectag_version = 0;
484 		sess_conf->macsec.tx_secy.end_station = mcs_port_params[portid].end_station;
485 		sess_conf->macsec.tx_secy.send_sci = mcs_port_params[portid].send_sci;
486 		sess_conf->macsec.tx_secy.scb = mcs_port_params[portid].scb;
487 		sess_conf->macsec.tx_secy.encrypt = mcs_port_params[portid].encrypt;
488 		sess_conf->macsec.tx_secy.protect_frames = mcs_port_params[portid].protect_frames;
489 		sess_conf->macsec.tx_secy.icv_include_da_sa = 1;
490 	} else {
491 		sess_conf->macsec.rx_secy.replay_win_sz = mcs_port_params[portid].replay_win_sz;
492 		sess_conf->macsec.rx_secy.replay_protect = mcs_port_params[portid].replay_protect;
493 		sess_conf->macsec.rx_secy.icv_include_da_sa = 1;
494 		sess_conf->macsec.rx_secy.ctrl_port_enable = 1;
495 		sess_conf->macsec.rx_secy.preserve_sectag = 0;
496 		sess_conf->macsec.rx_secy.preserve_icv = 0;
497 		sess_conf->macsec.rx_secy.validate_frames = mcs_port_params[portid].val_frames;
498 	}
499 
500 	return 0;
501 }
502 
503 static int
504 create_default_flow(uint16_t portid)
505 {
506 	struct rte_flow_action action[2];
507 	struct rte_flow_item pattern[2];
508 	struct rte_flow_attr attr = {0};
509 	struct rte_flow_error err;
510 	struct rte_flow *flow;
511 	struct rte_flow_item_eth eth;
512 	static const struct rte_flow_item_eth eth_mask = {
513 		.hdr.dst_addr.addr_bytes = "\x00\x00\x00\x00\x00\x00",
514 		.hdr.src_addr.addr_bytes = "\x00\x00\x00\x00\x00\x00",
515 		.hdr.ether_type = RTE_BE16(0xFFFF),
516 	};
517 	int ret;
518 
519 	eth.has_vlan = 0;
520 	memcpy(&eth.hdr, mcs_port_params[portid].eth_hdr, RTE_ETHER_HDR_LEN);
521 
522 	printf("Creating flow on port %u with DST MAC address: " RTE_ETHER_ADDR_PRT_FMT
523 			", SRC MAC address: "RTE_ETHER_ADDR_PRT_FMT"\n\n",
524 			portid,
525 			RTE_ETHER_ADDR_BYTES(&eth.hdr.dst_addr),
526 			RTE_ETHER_ADDR_BYTES(&eth.hdr.src_addr));
527 
528 	pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
529 	pattern[0].spec = &eth;
530 	pattern[0].mask = &eth_mask;
531 	pattern[0].last = NULL;
532 	pattern[1].type = RTE_FLOW_ITEM_TYPE_END;
533 
534 	action[0].type = RTE_FLOW_ACTION_TYPE_SECURITY;
535 	action[0].conf = mcs_port_params[portid].sess;
536 	action[1].type = RTE_FLOW_ACTION_TYPE_END;
537 	action[1].conf = NULL;
538 
539 	attr.ingress = (mcs_port_params[portid].dir == RTE_SECURITY_MACSEC_DIR_RX) ? 1 : 0;
540 	attr.egress = (mcs_port_params[portid].dir == RTE_SECURITY_MACSEC_DIR_TX) ? 1 : 0;
541 
542 	ret = rte_flow_validate(portid, &attr, pattern, action, &err);
543 	if (ret) {
544 		printf("\nValidate flow failed, ret = %d\n", ret);
545 		return -1;
546 	}
547 	flow = rte_flow_create(portid, &attr, pattern, action, &err);
548 	if (flow == NULL) {
549 		printf("\nDefault flow rule create failed\n");
550 		return -1;
551 	}
552 
553 	if (mcs_port_params[portid].dir == RTE_SECURITY_MACSEC_DIR_TX)
554 		mcs_port_params[portid].tx_flow = flow;
555 	else
556 		mcs_port_params[portid].rx_flow = flow;
557 
558 	return 0;
559 }
560 
561 static void
562 destroy_default_flow(uint16_t portid)
563 {
564 	struct rte_flow_error err;
565 	int ret;
566 
567 	if (mcs_port_params[portid].tx_flow) {
568 		ret = rte_flow_destroy(portid, mcs_port_params[portid].tx_flow, &err);
569 		if (ret) {
570 			printf("\nDefault Tx flow rule destroy failed\n");
571 			return;
572 		}
573 		mcs_port_params[portid].tx_flow = NULL;
574 	}
575 	if (mcs_port_params[portid].rx_flow) {
576 		ret = rte_flow_destroy(portid, mcs_port_params[portid].rx_flow, &err);
577 		if (ret) {
578 			printf("\nDefault Rx flow rule destroy failed\n");
579 			return;
580 		}
581 		mcs_port_params[portid].rx_flow = NULL;
582 	}
583 }
584 
585 static void
586 clean_macsec_resources(uint16_t portid)
587 {
588 	uint8_t an;
589 
590 	destroy_default_flow(portid);
591 	rte_security_session_destroy(mcs_port_params[portid].sec_ctx,
592 				mcs_port_params[portid].sess);
593 	rte_security_macsec_sc_destroy(mcs_port_params[portid].sec_ctx,
594 				mcs_port_params[portid].sc_id,
595 				mcs_port_params[portid].dir);
596 	for (an = 0; an < RTE_SECURITY_MACSEC_NUM_AN; an++) {
597 		if (mcs_port_params[portid].sa_id[an] != 0xFFFF)
598 			rte_security_macsec_sa_destroy(mcs_port_params[portid].sec_ctx,
599 				mcs_port_params[portid].sa_id[an],
600 				mcs_port_params[portid].dir);
601 	}
602 }
603 
604 static int
605 initialize_macsec_session(uint8_t portid)
606 {
607 	struct rte_security_session_conf sess_conf = {0};
608 	struct rte_security_macsec_sa sa_conf = {0};
609 	struct rte_security_macsec_sc sc_conf = {0};
610 	int id, ret;
611 
612 	/* Create MACsec SA. */
613 	fill_macsec_sa_conf(portid, &sa_conf);
614 	id = rte_security_macsec_sa_create(mcs_port_params[portid].sec_ctx, &sa_conf);
615 	if (id < 0) {
616 		printf("MACsec SA create failed : %d.\n", id);
617 		return -1;
618 	}
619 	mcs_port_params[portid].sa_id[0] = (uint16_t)id;
620 	mcs_port_params[portid].sa_id[1] = 0xFFFF;
621 	mcs_port_params[portid].sa_id[2] = 0xFFFF;
622 	mcs_port_params[portid].sa_id[3] = 0xFFFF;
623 
624 	printf("\nsa_id %d created.\n", mcs_port_params[portid].sa_id[0]);
625 
626 	/* Create MACsec SC. */
627 	fill_macsec_sc_conf(portid, &sc_conf);
628 	id = rte_security_macsec_sc_create(mcs_port_params[portid].sec_ctx, &sc_conf);
629 	if (id < 0) {
630 		printf("MACsec SC create failed : %d.\n", id);
631 		goto out;
632 	}
633 	mcs_port_params[portid].sc_id = (uint16_t)id;
634 	printf("\nsc_id %d created.\n", mcs_port_params[portid].sc_id);
635 
636 	/* Create Inline MACsec session. */
637 	ret = fill_session_conf(portid, &sess_conf);
638 	if (ret) {
639 		printf("MACsec Session conf failed.\n");
640 		goto out;
641 	}
642 	mcs_port_params[portid].sess =
643 		rte_security_session_create(mcs_port_params[portid].sec_ctx,
644 				&sess_conf, mcs_port_params[portid].sess_pool);
645 	if (mcs_port_params[portid].sess == NULL) {
646 		printf("MACSEC Session init failed errno: %d.\n", rte_errno);
647 		goto out;
648 	}
649 
650 	/* Create MACsec flow. */
651 	ret = create_default_flow(portid);
652 	if (ret)
653 		goto out;
654 
655 	return 0;
656 out:
657 	clean_macsec_resources(portid);
658 	return -1;
659 }
660 
661 /* main processing loop */
662 static void
663 l2fwd_main_loop(void)
664 {
665 	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
666 	struct rte_mbuf *m;
667 	int sent;
668 	unsigned int lcore_id;
669 	uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
670 	unsigned int i, j, portid, nb_rx;
671 	struct lcore_queue_conf *qconf;
672 	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S *
673 			BURST_TX_DRAIN_US;
674 	struct rte_eth_dev_tx_buffer *buffer;
675 
676 	prev_tsc = 0;
677 	timer_tsc = 0;
678 
679 	lcore_id = rte_lcore_id();
680 	qconf = &lcore_queue_conf[lcore_id];
681 
682 	if (qconf->n_rx_port == 0) {
683 		RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
684 		return;
685 	}
686 
687 	RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
688 
689 	for (i = 0; i < qconf->n_rx_port; i++) {
690 
691 		portid = qconf->rx_port_list[i];
692 
693 		RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
694 			portid);
695 	}
696 
697 	while (!force_quit) {
698 
699 		/* Drains TX queue in its main loop. 8< */
700 		cur_tsc = rte_rdtsc();
701 
702 		/*
703 		 * TX burst queue drain
704 		 */
705 		diff_tsc = cur_tsc - prev_tsc;
706 		if (unlikely(diff_tsc > drain_tsc)) {
707 
708 			for (i = 0; i < qconf->n_rx_port; i++) {
709 
710 				portid = l2fwd_dst_ports[qconf->rx_port_list[i]];
711 				buffer = tx_buffer[portid];
712 
713 				sent = rte_eth_tx_buffer_flush(portid, 0, buffer);
714 				if (sent)
715 					port_statistics[portid].tx += sent;
716 
717 			}
718 
719 			/* if timer is enabled */
720 			if (timer_period > 0) {
721 
722 				/* advance the timer */
723 				timer_tsc += diff_tsc;
724 
725 				/* if timer has reached its timeout */
726 				if (unlikely(timer_tsc >= timer_period)) {
727 
728 					/* do this only on main core */
729 					if (lcore_id == rte_get_main_lcore()) {
730 						print_stats();
731 						/* reset the timer */
732 						timer_tsc = 0;
733 					}
734 				}
735 			}
736 
737 			prev_tsc = cur_tsc;
738 		}
739 		/* >8 End of draining TX queue. */
740 
741 		/* Read packet from RX queues. 8< */
742 		for (i = 0; i < qconf->n_rx_port; i++) {
743 
744 			portid = qconf->rx_port_list[i];
745 			nb_rx = rte_eth_rx_burst(portid, 0,
746 						 pkts_burst, MAX_PKT_BURST);
747 
748 			if (unlikely(nb_rx == 0))
749 				continue;
750 
751 			port_statistics[portid].rx += nb_rx;
752 
753 			for (j = 0; j < nb_rx; j++) {
754 				m = pkts_burst[j];
755 				rte_prefetch0(rte_pktmbuf_mtod(m, void *));
756 				l2fwd_simple_forward(m, portid);
757 			}
758 		}
759 		/* >8 End of read packet from RX queues. */
760 	}
761 	if (force_quit) {
762 		for (i = 0; i < qconf->n_rx_port; i++) {
763 			portid = qconf->rx_port_list[i];
764 			clean_macsec_resources(portid);
765 		}
766 	}
767 }
768 static int
769 l2fwd_launch_one_lcore(__rte_unused void *arg)
770 {
771 	l2fwd_main_loop();
772 	return 0;
773 }
774 
775 /* display usage */
776 static void
777 l2fwd_usage(const char *prgname)
778 {
779 	printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
780 	       "  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
781 	       "  -q NQ: number of queue (=ports) per lcore (default is 1)\n"
782 	       "  -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n"
783 	       "  --mcs-tx-portmask: Hexadecimal bitmask for MACsec Tx(Encap) ports\n"
784 	       "  --mcs-rx-portmask: Hexadecimal bitmask for MACsec Rx(Decap) ports\n"
785 	       "  --mcs-port-config '(<port>,<src-mac>,<dst-mac>)'\n"
786 	       "  --portmap: Configure forwarding port pair mapping\n"
787 	       "	      Default: alternate port pairs\n\n",
788 	       prgname);
789 }
790 
791 static int
792 l2fwd_parse_portmask(const char *portmask)
793 {
794 	char *end = NULL;
795 	unsigned long pm;
796 
797 	/* parse hexadecimal string */
798 	pm = strtoul(portmask, &end, 16);
799 	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
800 		return 0;
801 
802 	return pm;
803 }
804 
805 static int
806 l2fwd_parse_port_pair_config(const char *q_arg)
807 {
808 	enum fieldnames {
809 		FLD_PORT1 = 0,
810 		FLD_PORT2,
811 		_NUM_FLD
812 	};
813 	unsigned long int_fld[_NUM_FLD];
814 	const char *p, *p0 = q_arg;
815 	char *str_fld[_NUM_FLD];
816 	unsigned int size;
817 	char s[256];
818 	char *end;
819 	int i;
820 
821 	nb_port_pair_params = 0;
822 
823 	while ((p = strchr(p0, '(')) != NULL) {
824 		++p;
825 		p0 = strchr(p, ')');
826 		if (p0 == NULL)
827 			return -1;
828 
829 		size = p0 - p;
830 		if (size >= sizeof(s))
831 			return -1;
832 
833 		memcpy(s, p, size);
834 		s[size] = '\0';
835 		if (rte_strsplit(s, sizeof(s), str_fld,
836 				 _NUM_FLD, ',') != _NUM_FLD)
837 			return -1;
838 		for (i = 0; i < _NUM_FLD; i++) {
839 			errno = 0;
840 			int_fld[i] = strtoul(str_fld[i], &end, 0);
841 			if (errno != 0 || end == str_fld[i] ||
842 			    int_fld[i] >= RTE_MAX_ETHPORTS)
843 				return -1;
844 		}
845 		if (nb_port_pair_params >= RTE_MAX_ETHPORTS/2) {
846 			printf("exceeded max number of port pair params: %hu\n",
847 				nb_port_pair_params);
848 			return -1;
849 		}
850 		port_pair_params_array[nb_port_pair_params].port[0] =
851 				(uint16_t)int_fld[FLD_PORT1];
852 		port_pair_params_array[nb_port_pair_params].port[1] =
853 				(uint16_t)int_fld[FLD_PORT2];
854 		++nb_port_pair_params;
855 	}
856 	port_pair_params = port_pair_params_array;
857 	return 0;
858 }
859 
860 static int
861 l2fwd_parse_macsec_port_config(const char *q_arg)
862 {
863 	enum fieldnames {
864 		FLD_PORT = 0,
865 		FLD_SRC,
866 		FLD_DST,
867 		_NUM_FLD
868 	};
869 	unsigned int portid;
870 	struct rte_ether_addr src, dst;
871 	const char *p, *p0 = q_arg;
872 	char *str_fld[_NUM_FLD];
873 	unsigned int size;
874 	char s[256];
875 	char *end;
876 
877 	nb_port_pair_params = 0;
878 
879 	while ((p = strchr(p0, '(')) != NULL) {
880 		++p;
881 		p0 = strchr(p, ')');
882 		if (p0 == NULL)
883 			return -1;
884 
885 		size = p0 - p;
886 		if (size >= sizeof(s))
887 			return -1;
888 
889 		memcpy(s, p, size);
890 		s[size] = '\0';
891 		if (rte_strsplit(s, sizeof(s), str_fld,
892 				 _NUM_FLD, ',') != _NUM_FLD)
893 			return -1;
894 		errno = 0;
895 		portid = strtoul(str_fld[FLD_PORT], &end, 0);
896 		if (errno != 0 || end == str_fld[FLD_PORT] || portid >= RTE_MAX_ETHPORTS)
897 			return -1;
898 		if (port_ether_hdr_config[portid].ether_type == 0x0800) {
899 			printf("MACsec src-dst MAC addr already parsed for port: %d\n",
900 					portid);
901 			return -1;
902 		}
903 		if (rte_ether_unformat_addr(str_fld[FLD_SRC], &src) ||
904 				rte_ether_unformat_addr(str_fld[FLD_DST], &dst))
905 			return -1;
906 
907 		memcpy(&port_ether_hdr_config[portid].src_addr, &src, sizeof(src));
908 		memcpy(&port_ether_hdr_config[portid].dst_addr, &dst, sizeof(dst));
909 		port_ether_hdr_config[portid].ether_type = 0x0800;
910 	}
911 
912 	return 0;
913 }
914 
915 
916 static unsigned int
917 l2fwd_parse_nqueue(const char *q_arg)
918 {
919 	char *end = NULL;
920 	unsigned long n;
921 
922 	/* parse hexadecimal string */
923 	n = strtoul(q_arg, &end, 10);
924 	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
925 		return 0;
926 	if (n == 0)
927 		return 0;
928 	if (n >= MAX_RX_QUEUE_PER_LCORE)
929 		return 0;
930 
931 	return n;
932 }
933 
934 static int
935 l2fwd_parse_timer_period(const char *q_arg)
936 {
937 	char *end = NULL;
938 	int n;
939 
940 	/* parse number string */
941 	n = strtol(q_arg, &end, 10);
942 	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
943 		return -1;
944 	if (n >= MAX_TIMER_PERIOD)
945 		return -1;
946 
947 	return n;
948 }
949 
950 static const char short_options[] =
951 	"p:"  /* portmask */
952 	"P"   /* promiscuous */
953 	"q:"  /* number of queues */
954 	"T:"  /* timer period */
955 	;
956 
957 #define CMD_LINE_OPT_NO_MAC_UPDATING	"no-mac-updating"
958 #define CMD_LINE_OPT_PORTMAP_CONFIG	"portmap"
959 #define CMD_LINE_OPT_MACSEC_TX_PORTMASK	"mcs-tx-portmask"
960 #define CMD_LINE_OPT_MACSEC_RX_PORTMASK	"mcs-rx-portmask"
961 #define CMD_LINE_OPT_MACSEC_PORT_CONFIG	"mcs-port-config"
962 
963 enum {
964 	/* Long options mapped to a short option.
965 	 * First long only option value must be >= 256,
966 	 * so that we won't conflict with short options.
967 	 */
968 	CMD_LINE_OPT_NO_MAC_UPDATING_NUM = 256,
969 	CMD_LINE_OPT_PORTMAP_NUM,
970 	CMD_LINE_OPT_MACSEC_TX_PORTMASK_NUM,
971 	CMD_LINE_OPT_MACSEC_RX_PORTMASK_NUM,
972 	CMD_LINE_OPT_MACSEC_PORT_CFG_NUM,
973 };
974 
975 static const struct option lgopts[] = {
976 	{ CMD_LINE_OPT_NO_MAC_UPDATING, no_argument, 0,
977 		CMD_LINE_OPT_NO_MAC_UPDATING_NUM},
978 	{ CMD_LINE_OPT_PORTMAP_CONFIG, 1, 0, CMD_LINE_OPT_PORTMAP_NUM},
979 	{ CMD_LINE_OPT_MACSEC_TX_PORTMASK, required_argument, 0,
980 		CMD_LINE_OPT_MACSEC_TX_PORTMASK_NUM},
981 	{ CMD_LINE_OPT_MACSEC_RX_PORTMASK, required_argument, 0,
982 		CMD_LINE_OPT_MACSEC_RX_PORTMASK_NUM},
983 	{ CMD_LINE_OPT_MACSEC_PORT_CONFIG, 1, 0, CMD_LINE_OPT_MACSEC_PORT_CFG_NUM},
984 	{NULL, 0, 0, 0}
985 };
986 
987 /** Generate default options for application. */
988 static void
989 l2fwd_macsec_default_options(struct l2fwd_macsec_options *options)
990 {
991 	uint16_t portid;
992 	uint8_t salt[MCS_SALT_LEN] = {0};
993 	uint8_t key[16] = {
994 			0x07, 0x1B, 0x11, 0x3B, 0x0C, 0xA7, 0x43, 0xFE,
995 			0xCC, 0xCF, 0x3D, 0x05, 0x1F, 0x73, 0x73, 0x82
996 		};
997 
998 	options->portmask = 0xffffffff;
999 	options->nb_ports_per_lcore = 1;
1000 	options->single_lcore = 0;
1001 
1002 	RTE_ETH_FOREACH_DEV(portid) {
1003 		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
1004 			continue;
1005 		if ((options->tx_portmask & (1 << portid)) != 0)
1006 			mcs_port_params[portid].dir = RTE_SECURITY_MACSEC_DIR_TX;
1007 
1008 		if ((options->rx_portmask & (1 << portid)) != 0)
1009 			mcs_port_params[portid].dir = RTE_SECURITY_MACSEC_DIR_RX;
1010 
1011 		mcs_port_params[portid].alg = RTE_SECURITY_MACSEC_ALG_GCM_128;
1012 		memcpy(mcs_port_params[portid].sa_key.data, key, 16);
1013 		mcs_port_params[portid].sa_key.len = 16;
1014 		memcpy(mcs_port_params[portid].salt, salt, MCS_SALT_LEN);
1015 
1016 		memcpy(mcs_port_params[portid].eth_hdr, &port_ether_hdr_config[portid],
1017 				RTE_ETHER_HDR_LEN);
1018 
1019 		mcs_port_params[portid].ssci = 0;
1020 		mcs_port_params[portid].pn_threshold = 0xffffffffffffffff;
1021 		mcs_port_params[portid].xpn = 0;
1022 		mcs_port_params[portid].next_pn = 1;
1023 		mcs_port_params[portid].mtu = 1500;
1024 		mcs_port_params[portid].sectag_insert_mode = 1;
1025 		mcs_port_params[portid].encrypt = true;
1026 		mcs_port_params[portid].protect_frames = true;
1027 		mcs_port_params[portid].replay_protect = false;
1028 		mcs_port_params[portid].val_frames = RTE_SECURITY_MACSEC_VALIDATE_STRICT;
1029 		mcs_port_params[portid].send_sci = true;
1030 		mcs_port_params[portid].end_station = false;
1031 		mcs_port_params[portid].scb = false;
1032 	}
1033 }
1034 
1035 /* Parse the argument given in the command line of the application */
1036 static int
1037 l2fwd_parse_args(struct l2fwd_macsec_options *options,
1038 		int argc, char **argv)
1039 {
1040 	int opt, ret, timer_secs;
1041 	char **argvopt;
1042 	int option_index;
1043 	char *prgname = argv[0];
1044 
1045 	argvopt = argv;
1046 	port_pair_params = NULL;
1047 
1048 	while ((opt = getopt_long(argc, argvopt, short_options,
1049 				  lgopts, &option_index)) != EOF) {
1050 
1051 		switch (opt) {
1052 		/* portmask */
1053 		case 'p':
1054 			l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
1055 			if (l2fwd_enabled_port_mask == 0) {
1056 				printf("invalid portmask\n");
1057 				l2fwd_usage(prgname);
1058 				return -1;
1059 			}
1060 			break;
1061 		case 'P':
1062 			promiscuous_on = 1;
1063 			break;
1064 
1065 		/* nqueue */
1066 		case 'q':
1067 			l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
1068 			if (l2fwd_rx_queue_per_lcore == 0) {
1069 				printf("invalid queue number\n");
1070 				l2fwd_usage(prgname);
1071 				return -1;
1072 			}
1073 			break;
1074 
1075 		/* timer period */
1076 		case 'T':
1077 			timer_secs = l2fwd_parse_timer_period(optarg);
1078 			if (timer_secs < 0) {
1079 				printf("invalid timer period\n");
1080 				l2fwd_usage(prgname);
1081 				return -1;
1082 			}
1083 			timer_period = timer_secs;
1084 			break;
1085 
1086 		/* long options */
1087 		case CMD_LINE_OPT_PORTMAP_NUM:
1088 			ret = l2fwd_parse_port_pair_config(optarg);
1089 			if (ret) {
1090 				fprintf(stderr, "Invalid config\n");
1091 				l2fwd_usage(prgname);
1092 				return -1;
1093 			}
1094 			break;
1095 
1096 		case CMD_LINE_OPT_NO_MAC_UPDATING_NUM:
1097 			mac_updating = 0;
1098 			break;
1099 
1100 		case CMD_LINE_OPT_MACSEC_TX_PORTMASK_NUM:
1101 			options->tx_portmask = l2fwd_parse_portmask(optarg);
1102 			if (options->tx_portmask == 0) {
1103 				l2fwd_usage(prgname);
1104 				return -1;
1105 			}
1106 			break;
1107 
1108 		case CMD_LINE_OPT_MACSEC_RX_PORTMASK_NUM:
1109 			options->rx_portmask = l2fwd_parse_portmask(optarg);
1110 			if (options->rx_portmask == 0) {
1111 				l2fwd_usage(prgname);
1112 				return -1;
1113 			}
1114 			break;
1115 
1116 		case CMD_LINE_OPT_MACSEC_PORT_CFG_NUM:
1117 			ret = l2fwd_parse_macsec_port_config(optarg);
1118 			if (ret) {
1119 				fprintf(stderr, "Invalid MACsec port config\n");
1120 				l2fwd_usage(prgname);
1121 				return -1;
1122 			}
1123 			break;
1124 
1125 		default:
1126 			l2fwd_usage(prgname);
1127 			return -1;
1128 		}
1129 	}
1130 	l2fwd_macsec_default_options(options);
1131 
1132 	if (optind >= 0)
1133 		argv[optind-1] = prgname;
1134 
1135 	ret = optind-1;
1136 	optind = 1; /* reset getopt lib */
1137 	return ret;
1138 }
1139 
1140 /*
1141  * Check port pair config with enabled port mask,
1142  * and for valid port pair combinations.
1143  */
1144 static int
1145 check_port_pair_config(void)
1146 {
1147 	uint32_t port_pair_config_mask = 0;
1148 	uint32_t port_pair_mask = 0;
1149 	uint16_t index, i, portid;
1150 
1151 	for (index = 0; index < nb_port_pair_params; index++) {
1152 		port_pair_mask = 0;
1153 
1154 		for (i = 0; i < NUM_PORTS; i++)  {
1155 			portid = port_pair_params[index].port[i];
1156 			if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
1157 				printf("port %u is not enabled in port mask\n",
1158 				       portid);
1159 				return -1;
1160 			}
1161 			if (!rte_eth_dev_is_valid_port(portid)) {
1162 				printf("port %u is not present on the board\n",
1163 				       portid);
1164 				return -1;
1165 			}
1166 
1167 			port_pair_mask |= 1 << portid;
1168 		}
1169 
1170 		if (port_pair_config_mask & port_pair_mask) {
1171 			printf("port %u is used in other port pairs\n", portid);
1172 			return -1;
1173 		}
1174 		port_pair_config_mask |= port_pair_mask;
1175 	}
1176 
1177 	l2fwd_enabled_port_mask &= port_pair_config_mask;
1178 
1179 	return 0;
1180 }
1181 
1182 /* Check the link status of all ports in up to 9s, and print them finally */
1183 static void
1184 check_all_ports_link_status(uint32_t port_mask)
1185 {
1186 #define CHECK_INTERVAL 100 /* 100ms */
1187 #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
1188 	uint16_t portid;
1189 	uint8_t count, all_ports_up, print_flag = 0;
1190 	struct rte_eth_link link;
1191 	int ret;
1192 	char link_status_text[RTE_ETH_LINK_MAX_STR_LEN];
1193 
1194 	printf("\nChecking link status");
1195 	fflush(stdout);
1196 	for (count = 0; count <= MAX_CHECK_TIME; count++) {
1197 		if (force_quit)
1198 			return;
1199 		all_ports_up = 1;
1200 		RTE_ETH_FOREACH_DEV(portid) {
1201 			if (force_quit)
1202 				return;
1203 			if ((port_mask & (1 << portid)) == 0)
1204 				continue;
1205 			memset(&link, 0, sizeof(link));
1206 			ret = rte_eth_link_get_nowait(portid, &link);
1207 			if (ret < 0) {
1208 				all_ports_up = 0;
1209 				if (print_flag == 1)
1210 					printf("Port %u link get failed: %s\n",
1211 						portid, rte_strerror(-ret));
1212 				continue;
1213 			}
1214 			/* print link status if flag set */
1215 			if (print_flag == 1) {
1216 				rte_eth_link_to_str(link_status_text,
1217 					sizeof(link_status_text), &link);
1218 				printf("Port %d %s\n", portid,
1219 				       link_status_text);
1220 				continue;
1221 			}
1222 			/* clear all_ports_up flag if any link down */
1223 			if (link.link_status == RTE_ETH_LINK_DOWN) {
1224 				all_ports_up = 0;
1225 				break;
1226 			}
1227 		}
1228 		/* after finally printing all link status, get out */
1229 		if (print_flag == 1)
1230 			break;
1231 
1232 		if (all_ports_up == 0) {
1233 			printf(".");
1234 			fflush(stdout);
1235 			rte_delay_ms(CHECK_INTERVAL);
1236 		}
1237 
1238 		/* set the print_flag if all ports up or timeout */
1239 		if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
1240 			print_flag = 1;
1241 			printf("done\n");
1242 		}
1243 	}
1244 }
1245 
1246 static void
1247 signal_handler(int signum)
1248 {
1249 	if (signum == SIGINT || signum == SIGTERM) {
1250 		printf("\n\nSignal %d received, preparing to exit...\n",
1251 				signum);
1252 		force_quit = true;
1253 	}
1254 }
1255 
1256 int
1257 main(int argc, char **argv)
1258 {
1259 	struct l2fwd_macsec_options options = {0};
1260 	struct lcore_queue_conf *qconf;
1261 	int ret;
1262 	uint16_t nb_ports;
1263 	uint16_t nb_ports_available = 0;
1264 	uint16_t portid, last_port;
1265 	unsigned int lcore_id, rx_lcore_id;
1266 	unsigned int nb_ports_in_mask = 0;
1267 	unsigned int nb_lcores = 0;
1268 	unsigned int nb_mbufs;
1269 	uint16_t nb_sess = 512;
1270 	uint32_t sess_sz;
1271 	char s[64];
1272 
1273 	/* Init EAL. 8< */
1274 	ret = rte_eal_init(argc, argv);
1275 	if (ret < 0)
1276 		rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
1277 	argc -= ret;
1278 	argv += ret;
1279 
1280 	force_quit = false;
1281 	signal(SIGINT, signal_handler);
1282 	signal(SIGTERM, signal_handler);
1283 
1284 	/* parse application arguments (after the EAL ones) */
1285 	ret = l2fwd_parse_args(&options, argc, argv);
1286 	if (ret < 0)
1287 		rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
1288 	/* >8 End of init EAL. */
1289 
1290 	printf("MAC updating %s\n", mac_updating ? "enabled" : "disabled");
1291 
1292 	/* convert to number of cycles */
1293 	timer_period *= rte_get_timer_hz();
1294 
1295 	nb_ports = rte_eth_dev_count_avail();
1296 	if (nb_ports == 0)
1297 		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
1298 
1299 	if (port_pair_params != NULL) {
1300 		if (check_port_pair_config() < 0)
1301 			rte_exit(EXIT_FAILURE, "Invalid port pair config\n");
1302 	}
1303 
1304 	/* check port mask to possible port mask */
1305 	if (l2fwd_enabled_port_mask & ~((1 << nb_ports) - 1))
1306 		rte_exit(EXIT_FAILURE, "Invalid portmask; possible (0x%x)\n",
1307 			(1 << nb_ports) - 1);
1308 
1309 	/* Initialization of the driver. 8< */
1310 
1311 	/* reset l2fwd_dst_ports */
1312 	for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
1313 		l2fwd_dst_ports[portid] = 0;
1314 	last_port = 0;
1315 
1316 	/* populate destination port details */
1317 	if (port_pair_params != NULL) {
1318 		uint16_t idx, p;
1319 
1320 		for (idx = 0; idx < (nb_port_pair_params << 1); idx++) {
1321 			p = idx & 1;
1322 			portid = port_pair_params[idx >> 1].port[p];
1323 			l2fwd_dst_ports[portid] =
1324 				port_pair_params[idx >> 1].port[p ^ 1];
1325 		}
1326 	} else {
1327 		RTE_ETH_FOREACH_DEV(portid) {
1328 			/* skip ports that are not enabled */
1329 			if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
1330 				continue;
1331 
1332 			if (nb_ports_in_mask % 2) {
1333 				l2fwd_dst_ports[portid] = last_port;
1334 				l2fwd_dst_ports[last_port] = portid;
1335 			} else {
1336 				last_port = portid;
1337 			}
1338 
1339 			nb_ports_in_mask++;
1340 		}
1341 		if (nb_ports_in_mask % 2) {
1342 			printf("Notice: odd number of ports in portmask.\n");
1343 			l2fwd_dst_ports[last_port] = last_port;
1344 		}
1345 	}
1346 	/* >8 End of initialization of the driver. */
1347 
1348 	rx_lcore_id = 0;
1349 	qconf = NULL;
1350 
1351 	/* Initialize the port/queue configuration of each logical core */
1352 	RTE_ETH_FOREACH_DEV(portid) {
1353 		/* skip ports that are not enabled */
1354 		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
1355 			continue;
1356 
1357 		/* get the lcore_id for this port */
1358 		while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
1359 		       lcore_queue_conf[rx_lcore_id].n_rx_port ==
1360 		       l2fwd_rx_queue_per_lcore) {
1361 			rx_lcore_id++;
1362 			if (rx_lcore_id >= RTE_MAX_LCORE)
1363 				rte_exit(EXIT_FAILURE, "Not enough cores\n");
1364 		}
1365 
1366 		if (qconf != &lcore_queue_conf[rx_lcore_id]) {
1367 			/* Assigned a new logical core in the loop above. */
1368 			qconf = &lcore_queue_conf[rx_lcore_id];
1369 			nb_lcores++;
1370 		}
1371 
1372 		qconf->rx_port_list[qconf->n_rx_port] = portid;
1373 		qconf->n_rx_port++;
1374 		printf("Lcore %u: RX port %u TX port %u\n", rx_lcore_id,
1375 		       portid, l2fwd_dst_ports[portid]);
1376 	}
1377 
1378 	nb_mbufs = RTE_MAX(nb_ports * (nb_rxd + nb_txd + MAX_PKT_BURST +
1379 		nb_lcores * MEMPOOL_CACHE_SIZE), 8192U);
1380 
1381 	/* Create the mbuf pool. 8< */
1382 	l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", nb_mbufs,
1383 		MEMPOOL_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE,
1384 		rte_socket_id());
1385 	if (l2fwd_pktmbuf_pool == NULL)
1386 		rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
1387 	/* >8 End of create the mbuf pool. */
1388 
1389 	/* Initialise each port */
1390 	RTE_ETH_FOREACH_DEV(portid) {
1391 		struct rte_eth_rxconf rxq_conf;
1392 		struct rte_eth_txconf txq_conf;
1393 		struct rte_eth_conf local_port_conf = port_conf;
1394 		struct rte_eth_dev_info dev_info;
1395 
1396 		/* skip ports that are not enabled */
1397 		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
1398 			printf("Skipping disabled port %u\n", portid);
1399 			continue;
1400 		}
1401 		nb_ports_available++;
1402 
1403 		/* init port */
1404 		printf("Initializing port %u... ", portid);
1405 		fflush(stdout);
1406 
1407 		ret = rte_eth_dev_info_get(portid, &dev_info);
1408 		if (ret != 0)
1409 			rte_exit(EXIT_FAILURE,
1410 				"Error during getting device (port %u) info: %s\n",
1411 				portid, strerror(-ret));
1412 
1413 		if (dev_info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE)
1414 			local_port_conf.txmode.offloads |=
1415 				RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE;
1416 		/* Configure the number of queues for a port. */
1417 		ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf);
1418 		if (ret < 0)
1419 			rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n",
1420 				  ret, portid);
1421 		/* >8 End of configuration of the number of queues for a port. */
1422 
1423 		ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd,
1424 						       &nb_txd);
1425 		if (ret < 0)
1426 			rte_exit(EXIT_FAILURE,
1427 				 "Cannot adjust number of descriptors: err=%d, port=%u\n",
1428 				 ret, portid);
1429 
1430 		ret = rte_eth_macaddr_get(portid,
1431 					  &l2fwd_ports_eth_addr[portid]);
1432 		if (ret < 0)
1433 			rte_exit(EXIT_FAILURE,
1434 				 "Cannot get MAC address: err=%d, port=%u\n",
1435 				 ret, portid);
1436 
1437 		/* init one RX queue */
1438 		fflush(stdout);
1439 		rxq_conf = dev_info.default_rxconf;
1440 		rxq_conf.offloads = local_port_conf.rxmode.offloads;
1441 		/* RX queue setup. 8< */
1442 		ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
1443 					     rte_eth_dev_socket_id(portid),
1444 					     &rxq_conf,
1445 					     l2fwd_pktmbuf_pool);
1446 		if (ret < 0)
1447 			rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n",
1448 				  ret, portid);
1449 		/* >8 End of RX queue setup. */
1450 
1451 		/* Init one TX queue on each port. 8< */
1452 		fflush(stdout);
1453 		txq_conf = dev_info.default_txconf;
1454 		txq_conf.offloads = local_port_conf.txmode.offloads;
1455 		ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
1456 				rte_eth_dev_socket_id(portid),
1457 				&txq_conf);
1458 		if (ret < 0)
1459 			rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n",
1460 				ret, portid);
1461 		/* >8 End of init one TX queue on each port. */
1462 
1463 		/* Initialize TX buffers */
1464 		tx_buffer[portid] = rte_zmalloc_socket("tx_buffer",
1465 				RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,
1466 				rte_eth_dev_socket_id(portid));
1467 		if (tx_buffer[portid] == NULL)
1468 			rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n",
1469 					portid);
1470 
1471 		rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST);
1472 
1473 		ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid],
1474 				rte_eth_tx_buffer_count_callback,
1475 				&port_statistics[portid].dropped);
1476 		if (ret < 0)
1477 			rte_exit(EXIT_FAILURE,
1478 			"Cannot set error callback for tx buffer on port %u\n",
1479 				 portid);
1480 
1481 		ret = rte_eth_dev_set_ptypes(portid, RTE_PTYPE_UNKNOWN, NULL,
1482 					     0);
1483 		if (ret < 0)
1484 			printf("Port %u, Failed to disable Ptype parsing\n",
1485 					portid);
1486 		/* Start device */
1487 		ret = rte_eth_dev_start(portid);
1488 		if (ret < 0)
1489 			rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n",
1490 				  ret, portid);
1491 
1492 		printf("done:\n");
1493 		if (promiscuous_on) {
1494 			ret = rte_eth_promiscuous_enable(portid);
1495 			if (ret != 0)
1496 				rte_exit(EXIT_FAILURE,
1497 					"rte_eth_promiscuous_enable:err=%s, port=%u\n",
1498 					rte_strerror(-ret), portid);
1499 		}
1500 
1501 		printf("Port %u, MAC address: " RTE_ETHER_ADDR_PRT_FMT "\n\n",
1502 			portid,
1503 			RTE_ETHER_ADDR_BYTES(&l2fwd_ports_eth_addr[portid]));
1504 
1505 		/* initialize port stats */
1506 		memset(&port_statistics, 0, sizeof(port_statistics));
1507 
1508 		mcs_port_params[portid].sec_ctx = rte_eth_dev_get_sec_ctx(portid);
1509 		if (mcs_port_params[portid].sec_ctx == NULL)
1510 			rte_exit(EXIT_FAILURE, "Device does not support Security ctx\n");
1511 
1512 		sess_sz = rte_security_session_get_size(mcs_port_params[portid].sec_ctx);
1513 		if (mcs_port_params[portid].sess_pool == NULL) {
1514 			snprintf(s, sizeof(s), "sess_pool_p%d", portid);
1515 			mcs_port_params[portid].sess_pool = rte_mempool_create(s,
1516 							nb_sess, sess_sz,
1517 							SESSION_POOL_CACHE_SIZE, 0,
1518 							NULL, NULL, NULL, NULL,
1519 							SOCKET_ID_ANY, 0);
1520 			if (mcs_port_params[portid].sess_pool == NULL)
1521 				rte_exit(EXIT_FAILURE, "Cannot init sess pool\n");
1522 
1523 			printf("Allocated sess pool\n");
1524 		}
1525 
1526 		if (((options.tx_portmask & (1 << portid)) != 0) ||
1527 				((options.rx_portmask & (1 << portid)) != 0)) {
1528 			ret = initialize_macsec_session(portid);
1529 			if (ret < 0)
1530 				rte_exit(EXIT_FAILURE,
1531 					"Failed to initialize MACsec session for port: %d\n",
1532 					portid);
1533 		}
1534 	}
1535 
1536 	if (!nb_ports_available) {
1537 		rte_exit(EXIT_FAILURE,
1538 			"All available ports are disabled. Please set portmask.\n");
1539 	}
1540 
1541 	check_all_ports_link_status(l2fwd_enabled_port_mask);
1542 
1543 	ret = 0;
1544 	/* launch per-lcore init on every lcore */
1545 	rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MAIN);
1546 	RTE_LCORE_FOREACH_WORKER(lcore_id) {
1547 		if (rte_eal_wait_lcore(lcore_id) < 0) {
1548 			ret = -1;
1549 			break;
1550 		}
1551 	}
1552 
1553 	RTE_ETH_FOREACH_DEV(portid) {
1554 		if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
1555 			continue;
1556 		printf("Closing port %d...", portid);
1557 		ret = rte_eth_dev_stop(portid);
1558 		if (ret != 0)
1559 			printf("rte_eth_dev_stop: err=%d, port=%d\n",
1560 			       ret, portid);
1561 		rte_eth_dev_close(portid);
1562 		printf(" Done\n");
1563 	}
1564 
1565 	/* clean up the EAL */
1566 	rte_eal_cleanup();
1567 	printf("Bye...\n");
1568 
1569 	return ret;
1570 }
1571