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 = ð->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], ð->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(ð.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(ð.hdr.dst_addr), 528 RTE_ETHER_ADDR_BYTES(ð.hdr.src_addr)); 529 530 pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH; 531 pattern[0].spec = ð 532 pattern[0].mask = ð_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