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