1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2016 Intel Corporation 3 * Copyright (C) 2020 Marvell International Ltd. 4 */ 5 #include <rte_acl.h> 6 #include <rte_event_eth_tx_adapter.h> 7 #include <rte_lpm.h> 8 #include <rte_lpm6.h> 9 10 #include "event_helper.h" 11 #include "ipsec.h" 12 #include "ipsec-secgw.h" 13 #include "ipsec_worker.h" 14 15 struct port_drv_mode_data { 16 struct rte_security_session *sess; 17 struct rte_security_ctx *ctx; 18 }; 19 20 static inline enum pkt_type 21 process_ipsec_get_pkt_type(struct rte_mbuf *pkt, uint8_t **nlp) 22 { 23 struct rte_ether_hdr *eth; 24 uint32_t ptype = pkt->packet_type; 25 26 eth = rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *); 27 rte_prefetch0(eth); 28 29 if (RTE_ETH_IS_IPV4_HDR(ptype)) { 30 *nlp = RTE_PTR_ADD(eth, RTE_ETHER_HDR_LEN + 31 offsetof(struct ip, ip_p)); 32 if ((ptype & RTE_PTYPE_TUNNEL_MASK) == RTE_PTYPE_TUNNEL_ESP) 33 return PKT_TYPE_IPSEC_IPV4; 34 else 35 return PKT_TYPE_PLAIN_IPV4; 36 } else if (RTE_ETH_IS_IPV6_HDR(ptype)) { 37 *nlp = RTE_PTR_ADD(eth, RTE_ETHER_HDR_LEN + 38 offsetof(struct ip6_hdr, ip6_nxt)); 39 if ((ptype & RTE_PTYPE_TUNNEL_MASK) == RTE_PTYPE_TUNNEL_ESP) 40 return PKT_TYPE_IPSEC_IPV6; 41 else 42 return PKT_TYPE_PLAIN_IPV6; 43 } 44 45 /* Unknown/Unsupported type */ 46 return PKT_TYPE_INVALID; 47 } 48 49 static inline void 50 update_mac_addrs(struct rte_mbuf *pkt, uint16_t portid) 51 { 52 struct rte_ether_hdr *ethhdr; 53 54 ethhdr = rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *); 55 memcpy(ðhdr->src_addr, ðaddr_tbl[portid].src, RTE_ETHER_ADDR_LEN); 56 memcpy(ðhdr->dst_addr, ðaddr_tbl[portid].dst, RTE_ETHER_ADDR_LEN); 57 } 58 59 static inline void 60 ipsec_event_pre_forward(struct rte_mbuf *m, unsigned int port_id) 61 { 62 /* Save the destination port in the mbuf */ 63 m->port = port_id; 64 65 /* Save eth queue for Tx */ 66 rte_event_eth_tx_adapter_txq_set(m, 0); 67 } 68 69 static inline void 70 ev_vector_attr_init(struct rte_event_vector *vec) 71 { 72 vec->attr_valid = 1; 73 vec->port = 0xFFFF; 74 vec->queue = 0; 75 } 76 77 static inline void 78 ev_vector_attr_update(struct rte_event_vector *vec, struct rte_mbuf *pkt) 79 { 80 if (vec->port == 0xFFFF) { 81 vec->port = pkt->port; 82 return; 83 } 84 if (vec->attr_valid && (vec->port != pkt->port)) 85 vec->attr_valid = 0; 86 } 87 88 static inline void 89 prepare_out_sessions_tbl(struct sa_ctx *sa_out, 90 struct port_drv_mode_data *data, 91 uint16_t size) 92 { 93 struct rte_ipsec_session *pri_sess; 94 struct ipsec_sa *sa; 95 uint32_t i; 96 97 if (!sa_out) 98 return; 99 100 for (i = 0; i < sa_out->nb_sa; i++) { 101 102 sa = &sa_out->sa[i]; 103 if (!sa) 104 continue; 105 106 pri_sess = ipsec_get_primary_session(sa); 107 if (!pri_sess) 108 continue; 109 110 if (pri_sess->type != 111 RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) { 112 113 RTE_LOG(ERR, IPSEC, "Invalid session type %d\n", 114 pri_sess->type); 115 continue; 116 } 117 118 if (sa->portid >= size) { 119 RTE_LOG(ERR, IPSEC, 120 "Port id >= than table size %d, %d\n", 121 sa->portid, size); 122 continue; 123 } 124 125 /* Use only first inline session found for a given port */ 126 if (data[sa->portid].sess) 127 continue; 128 data[sa->portid].sess = pri_sess->security.ses; 129 data[sa->portid].ctx = pri_sess->security.ctx; 130 } 131 } 132 133 static inline int 134 check_sp(struct sp_ctx *sp, const uint8_t *nlp, uint32_t *sa_idx) 135 { 136 uint32_t res; 137 138 if (unlikely(sp == NULL)) 139 return 0; 140 141 rte_acl_classify((struct rte_acl_ctx *)sp, &nlp, &res, 1, 142 DEFAULT_MAX_CATEGORIES); 143 144 if (unlikely(res == DISCARD)) 145 return 0; 146 else if (res == BYPASS) { 147 *sa_idx = -1; 148 return 1; 149 } 150 151 *sa_idx = res - 1; 152 return 1; 153 } 154 155 static inline void 156 check_sp_bulk(struct sp_ctx *sp, struct traffic_type *ip, 157 struct traffic_type *ipsec) 158 { 159 uint32_t i, j, res; 160 struct rte_mbuf *m; 161 162 if (unlikely(sp == NULL || ip->num == 0)) 163 return; 164 165 rte_acl_classify((struct rte_acl_ctx *)sp, ip->data, ip->res, ip->num, 166 DEFAULT_MAX_CATEGORIES); 167 168 j = 0; 169 for (i = 0; i < ip->num; i++) { 170 m = ip->pkts[i]; 171 res = ip->res[i]; 172 if (unlikely(res == DISCARD)) 173 free_pkts(&m, 1); 174 else if (res == BYPASS) 175 ip->pkts[j++] = m; 176 else { 177 ipsec->res[ipsec->num] = res - 1; 178 ipsec->pkts[ipsec->num++] = m; 179 } 180 } 181 ip->num = j; 182 } 183 184 static inline void 185 check_sp_sa_bulk(struct sp_ctx *sp, struct sa_ctx *sa_ctx, 186 struct traffic_type *ip) 187 { 188 struct ipsec_sa *sa; 189 uint32_t i, j, res; 190 struct rte_mbuf *m; 191 192 if (unlikely(sp == NULL || ip->num == 0)) 193 return; 194 195 rte_acl_classify((struct rte_acl_ctx *)sp, ip->data, ip->res, ip->num, 196 DEFAULT_MAX_CATEGORIES); 197 198 j = 0; 199 for (i = 0; i < ip->num; i++) { 200 m = ip->pkts[i]; 201 res = ip->res[i]; 202 if (unlikely(res == DISCARD)) 203 free_pkts(&m, 1); 204 else if (res == BYPASS) 205 ip->pkts[j++] = m; 206 else { 207 sa = *(struct ipsec_sa **)rte_security_dynfield(m); 208 if (sa == NULL) 209 free_pkts(&m, 1); 210 211 /* SPI on the packet should match with the one in SA */ 212 if (unlikely(sa->spi != sa_ctx->sa[res - 1].spi)) 213 free_pkts(&m, 1); 214 215 ip->pkts[j++] = m; 216 } 217 } 218 ip->num = j; 219 } 220 221 static inline uint16_t 222 route4_pkt(struct rte_mbuf *pkt, struct rt_ctx *rt_ctx) 223 { 224 uint32_t dst_ip; 225 uint16_t offset; 226 uint32_t hop; 227 int ret; 228 229 offset = RTE_ETHER_HDR_LEN + offsetof(struct ip, ip_dst); 230 dst_ip = *rte_pktmbuf_mtod_offset(pkt, uint32_t *, offset); 231 dst_ip = rte_be_to_cpu_32(dst_ip); 232 233 ret = rte_lpm_lookup((struct rte_lpm *)rt_ctx, dst_ip, &hop); 234 235 if (ret == 0) { 236 /* We have a hit */ 237 return hop; 238 } 239 240 /* else */ 241 return RTE_MAX_ETHPORTS; 242 } 243 244 /* TODO: To be tested */ 245 static inline uint16_t 246 route6_pkt(struct rte_mbuf *pkt, struct rt_ctx *rt_ctx) 247 { 248 uint8_t dst_ip[16]; 249 uint8_t *ip6_dst; 250 uint16_t offset; 251 uint32_t hop; 252 int ret; 253 254 offset = RTE_ETHER_HDR_LEN + offsetof(struct ip6_hdr, ip6_dst); 255 ip6_dst = rte_pktmbuf_mtod_offset(pkt, uint8_t *, offset); 256 memcpy(&dst_ip[0], ip6_dst, 16); 257 258 ret = rte_lpm6_lookup((struct rte_lpm6 *)rt_ctx, dst_ip, &hop); 259 260 if (ret == 0) { 261 /* We have a hit */ 262 return hop; 263 } 264 265 /* else */ 266 return RTE_MAX_ETHPORTS; 267 } 268 269 static inline uint16_t 270 get_route(struct rte_mbuf *pkt, struct route_table *rt, enum pkt_type type) 271 { 272 if (type == PKT_TYPE_PLAIN_IPV4 || type == PKT_TYPE_IPSEC_IPV4) 273 return route4_pkt(pkt, rt->rt4_ctx); 274 else if (type == PKT_TYPE_PLAIN_IPV6 || type == PKT_TYPE_IPSEC_IPV6) 275 return route6_pkt(pkt, rt->rt6_ctx); 276 277 return RTE_MAX_ETHPORTS; 278 } 279 280 static inline int 281 process_ipsec_ev_inbound(struct ipsec_ctx *ctx, struct route_table *rt, 282 struct rte_event *ev) 283 { 284 struct ipsec_sa *sa = NULL; 285 struct rte_mbuf *pkt; 286 uint16_t port_id = 0; 287 enum pkt_type type; 288 uint32_t sa_idx; 289 uint8_t *nlp; 290 291 /* Get pkt from event */ 292 pkt = ev->mbuf; 293 294 /* Check the packet type */ 295 type = process_ipsec_get_pkt_type(pkt, &nlp); 296 297 switch (type) { 298 case PKT_TYPE_PLAIN_IPV4: 299 if (pkt->ol_flags & RTE_MBUF_F_RX_SEC_OFFLOAD) { 300 if (unlikely(pkt->ol_flags & 301 RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED)) { 302 RTE_LOG(ERR, IPSEC, 303 "Inbound security offload failed\n"); 304 goto drop_pkt_and_exit; 305 } 306 sa = *(struct ipsec_sa **)rte_security_dynfield(pkt); 307 } 308 309 /* Check if we have a match */ 310 if (check_sp(ctx->sp4_ctx, nlp, &sa_idx) == 0) { 311 /* No valid match */ 312 goto drop_pkt_and_exit; 313 } 314 break; 315 316 case PKT_TYPE_PLAIN_IPV6: 317 if (pkt->ol_flags & RTE_MBUF_F_RX_SEC_OFFLOAD) { 318 if (unlikely(pkt->ol_flags & 319 RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED)) { 320 RTE_LOG(ERR, IPSEC, 321 "Inbound security offload failed\n"); 322 goto drop_pkt_and_exit; 323 } 324 sa = *(struct ipsec_sa **)rte_security_dynfield(pkt); 325 } 326 327 /* Check if we have a match */ 328 if (check_sp(ctx->sp6_ctx, nlp, &sa_idx) == 0) { 329 /* No valid match */ 330 goto drop_pkt_and_exit; 331 } 332 break; 333 334 default: 335 RTE_LOG(ERR, IPSEC, "Unsupported packet type = %d\n", type); 336 goto drop_pkt_and_exit; 337 } 338 339 /* Check if the packet has to be bypassed */ 340 if (sa_idx == BYPASS) 341 goto route_and_send_pkt; 342 343 /* Validate sa_idx */ 344 if (sa_idx >= ctx->sa_ctx->nb_sa) 345 goto drop_pkt_and_exit; 346 347 /* Else the packet has to be protected with SA */ 348 349 /* If the packet was IPsec processed, then SA pointer should be set */ 350 if (sa == NULL) 351 goto drop_pkt_and_exit; 352 353 /* SPI on the packet should match with the one in SA */ 354 if (unlikely(sa->spi != ctx->sa_ctx->sa[sa_idx].spi)) 355 goto drop_pkt_and_exit; 356 357 route_and_send_pkt: 358 port_id = get_route(pkt, rt, type); 359 if (unlikely(port_id == RTE_MAX_ETHPORTS)) { 360 /* no match */ 361 goto drop_pkt_and_exit; 362 } 363 /* else, we have a matching route */ 364 365 /* Update mac addresses */ 366 update_mac_addrs(pkt, port_id); 367 368 /* Update the event with the dest port */ 369 ipsec_event_pre_forward(pkt, port_id); 370 return PKT_FORWARDED; 371 372 drop_pkt_and_exit: 373 RTE_LOG(ERR, IPSEC, "Inbound packet dropped\n"); 374 rte_pktmbuf_free(pkt); 375 ev->mbuf = NULL; 376 return PKT_DROPPED; 377 } 378 379 static inline int 380 process_ipsec_ev_outbound(struct ipsec_ctx *ctx, struct route_table *rt, 381 struct rte_event *ev) 382 { 383 struct rte_ipsec_session *sess; 384 struct sa_ctx *sa_ctx; 385 struct rte_mbuf *pkt; 386 uint16_t port_id = 0; 387 struct ipsec_sa *sa; 388 enum pkt_type type; 389 uint32_t sa_idx; 390 uint8_t *nlp; 391 392 /* Get pkt from event */ 393 pkt = ev->mbuf; 394 395 /* Check the packet type */ 396 type = process_ipsec_get_pkt_type(pkt, &nlp); 397 398 switch (type) { 399 case PKT_TYPE_PLAIN_IPV4: 400 /* Check if we have a match */ 401 if (check_sp(ctx->sp4_ctx, nlp, &sa_idx) == 0) { 402 /* No valid match */ 403 goto drop_pkt_and_exit; 404 } 405 break; 406 case PKT_TYPE_PLAIN_IPV6: 407 /* Check if we have a match */ 408 if (check_sp(ctx->sp6_ctx, nlp, &sa_idx) == 0) { 409 /* No valid match */ 410 goto drop_pkt_and_exit; 411 } 412 break; 413 default: 414 /* 415 * Only plain IPv4 & IPv6 packets are allowed 416 * on protected port. Drop the rest. 417 */ 418 RTE_LOG(ERR, IPSEC, "Unsupported packet type = %d\n", type); 419 goto drop_pkt_and_exit; 420 } 421 422 /* Check if the packet has to be bypassed */ 423 if (sa_idx == BYPASS) { 424 port_id = get_route(pkt, rt, type); 425 if (unlikely(port_id == RTE_MAX_ETHPORTS)) { 426 /* no match */ 427 goto drop_pkt_and_exit; 428 } 429 /* else, we have a matching route */ 430 goto send_pkt; 431 } 432 433 /* Validate sa_idx */ 434 if (unlikely(sa_idx >= ctx->sa_ctx->nb_sa)) 435 goto drop_pkt_and_exit; 436 437 /* Else the packet has to be protected */ 438 439 /* Get SA ctx*/ 440 sa_ctx = ctx->sa_ctx; 441 442 /* Get SA */ 443 sa = &(sa_ctx->sa[sa_idx]); 444 445 /* Get IPsec session */ 446 sess = ipsec_get_primary_session(sa); 447 448 /* Allow only inline protocol for now */ 449 if (unlikely(sess->type != RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL)) { 450 RTE_LOG(ERR, IPSEC, "SA type not supported\n"); 451 goto drop_pkt_and_exit; 452 } 453 454 rte_security_set_pkt_metadata(sess->security.ctx, 455 sess->security.ses, pkt, NULL); 456 457 /* Mark the packet for Tx security offload */ 458 pkt->ol_flags |= RTE_MBUF_F_TX_SEC_OFFLOAD; 459 460 /* Get the port to which this pkt need to be submitted */ 461 port_id = sa->portid; 462 463 send_pkt: 464 /* Provide L2 len for Outbound processing */ 465 pkt->l2_len = RTE_ETHER_HDR_LEN; 466 467 /* Update mac addresses */ 468 update_mac_addrs(pkt, port_id); 469 470 /* Update the event with the dest port */ 471 ipsec_event_pre_forward(pkt, port_id); 472 return PKT_FORWARDED; 473 474 drop_pkt_and_exit: 475 RTE_LOG(ERR, IPSEC, "Outbound packet dropped\n"); 476 rte_pktmbuf_free(pkt); 477 ev->mbuf = NULL; 478 return PKT_DROPPED; 479 } 480 481 static inline int 482 ipsec_ev_route_pkts(struct rte_event_vector *vec, struct route_table *rt, 483 struct ipsec_traffic *t, struct sa_ctx *sa_ctx) 484 { 485 struct rte_ipsec_session *sess; 486 uint32_t sa_idx, i, j = 0; 487 uint16_t port_id = 0; 488 struct rte_mbuf *pkt; 489 struct ipsec_sa *sa; 490 491 /* Route IPv4 packets */ 492 for (i = 0; i < t->ip4.num; i++) { 493 pkt = t->ip4.pkts[i]; 494 port_id = route4_pkt(pkt, rt->rt4_ctx); 495 if (port_id != RTE_MAX_ETHPORTS) { 496 /* Update mac addresses */ 497 update_mac_addrs(pkt, port_id); 498 /* Update the event with the dest port */ 499 ipsec_event_pre_forward(pkt, port_id); 500 ev_vector_attr_update(vec, pkt); 501 vec->mbufs[j++] = pkt; 502 } else 503 free_pkts(&pkt, 1); 504 } 505 506 /* Route IPv6 packets */ 507 for (i = 0; i < t->ip6.num; i++) { 508 pkt = t->ip6.pkts[i]; 509 port_id = route6_pkt(pkt, rt->rt6_ctx); 510 if (port_id != RTE_MAX_ETHPORTS) { 511 /* Update mac addresses */ 512 update_mac_addrs(pkt, port_id); 513 /* Update the event with the dest port */ 514 ipsec_event_pre_forward(pkt, port_id); 515 ev_vector_attr_update(vec, pkt); 516 vec->mbufs[j++] = pkt; 517 } else 518 free_pkts(&pkt, 1); 519 } 520 521 /* Route ESP packets */ 522 for (i = 0; i < t->ipsec.num; i++) { 523 /* Validate sa_idx */ 524 sa_idx = t->ipsec.res[i]; 525 pkt = t->ipsec.pkts[i]; 526 if (unlikely(sa_idx >= sa_ctx->nb_sa)) 527 free_pkts(&pkt, 1); 528 else { 529 /* Else the packet has to be protected */ 530 sa = &(sa_ctx->sa[sa_idx]); 531 /* Get IPsec session */ 532 sess = ipsec_get_primary_session(sa); 533 /* Allow only inline protocol for now */ 534 if (unlikely(sess->type != 535 RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL)) { 536 RTE_LOG(ERR, IPSEC, "SA type not supported\n"); 537 free_pkts(&pkt, 1); 538 } 539 rte_security_set_pkt_metadata(sess->security.ctx, 540 sess->security.ses, pkt, NULL); 541 542 pkt->ol_flags |= RTE_MBUF_F_TX_SEC_OFFLOAD; 543 port_id = sa->portid; 544 update_mac_addrs(pkt, port_id); 545 ipsec_event_pre_forward(pkt, port_id); 546 ev_vector_attr_update(vec, pkt); 547 vec->mbufs[j++] = pkt; 548 } 549 } 550 551 return j; 552 } 553 554 static inline void 555 classify_pkt(struct rte_mbuf *pkt, struct ipsec_traffic *t) 556 { 557 enum pkt_type type; 558 uint8_t *nlp; 559 560 /* Check the packet type */ 561 type = process_ipsec_get_pkt_type(pkt, &nlp); 562 563 switch (type) { 564 case PKT_TYPE_PLAIN_IPV4: 565 t->ip4.data[t->ip4.num] = nlp; 566 t->ip4.pkts[(t->ip4.num)++] = pkt; 567 break; 568 case PKT_TYPE_PLAIN_IPV6: 569 t->ip6.data[t->ip6.num] = nlp; 570 t->ip6.pkts[(t->ip6.num)++] = pkt; 571 break; 572 default: 573 RTE_LOG(ERR, IPSEC, "Unsupported packet type = %d\n", type); 574 free_pkts(&pkt, 1); 575 break; 576 } 577 } 578 579 static inline int 580 process_ipsec_ev_inbound_vector(struct ipsec_ctx *ctx, struct route_table *rt, 581 struct rte_event_vector *vec) 582 { 583 struct ipsec_traffic t; 584 struct rte_mbuf *pkt; 585 int i; 586 587 t.ip4.num = 0; 588 t.ip6.num = 0; 589 t.ipsec.num = 0; 590 591 for (i = 0; i < vec->nb_elem; i++) { 592 /* Get pkt from event */ 593 pkt = vec->mbufs[i]; 594 595 if (pkt->ol_flags & RTE_MBUF_F_RX_SEC_OFFLOAD) { 596 if (unlikely(pkt->ol_flags & 597 RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED)) { 598 RTE_LOG(ERR, IPSEC, 599 "Inbound security offload failed\n"); 600 free_pkts(&pkt, 1); 601 continue; 602 } 603 } 604 605 classify_pkt(pkt, &t); 606 } 607 608 check_sp_sa_bulk(ctx->sp4_ctx, ctx->sa_ctx, &t.ip4); 609 check_sp_sa_bulk(ctx->sp6_ctx, ctx->sa_ctx, &t.ip6); 610 611 return ipsec_ev_route_pkts(vec, rt, &t, ctx->sa_ctx); 612 } 613 614 static inline int 615 process_ipsec_ev_outbound_vector(struct ipsec_ctx *ctx, struct route_table *rt, 616 struct rte_event_vector *vec) 617 { 618 struct ipsec_traffic t; 619 struct rte_mbuf *pkt; 620 uint32_t i; 621 622 t.ip4.num = 0; 623 t.ip6.num = 0; 624 t.ipsec.num = 0; 625 626 for (i = 0; i < vec->nb_elem; i++) { 627 /* Get pkt from event */ 628 pkt = vec->mbufs[i]; 629 630 classify_pkt(pkt, &t); 631 632 /* Provide L2 len for Outbound processing */ 633 pkt->l2_len = RTE_ETHER_HDR_LEN; 634 } 635 636 check_sp_bulk(ctx->sp4_ctx, &t.ip4, &t.ipsec); 637 check_sp_bulk(ctx->sp6_ctx, &t.ip6, &t.ipsec); 638 639 return ipsec_ev_route_pkts(vec, rt, &t, ctx->sa_ctx); 640 } 641 642 static inline int 643 process_ipsec_ev_drv_mode_outbound_vector(struct rte_event_vector *vec, 644 struct port_drv_mode_data *data) 645 { 646 struct rte_mbuf *pkt; 647 int16_t port_id; 648 uint32_t i; 649 int j = 0; 650 651 for (i = 0; i < vec->nb_elem; i++) { 652 pkt = vec->mbufs[i]; 653 port_id = pkt->port; 654 655 if (unlikely(!data[port_id].sess)) { 656 free_pkts(&pkt, 1); 657 continue; 658 } 659 ipsec_event_pre_forward(pkt, port_id); 660 /* Save security session */ 661 rte_security_set_pkt_metadata(data[port_id].ctx, 662 data[port_id].sess, pkt, 663 NULL); 664 665 /* Mark the packet for Tx security offload */ 666 pkt->ol_flags |= RTE_MBUF_F_TX_SEC_OFFLOAD; 667 668 /* Provide L2 len for Outbound processing */ 669 pkt->l2_len = RTE_ETHER_HDR_LEN; 670 671 vec->mbufs[j++] = pkt; 672 } 673 674 return j; 675 } 676 677 static inline void 678 ipsec_ev_vector_process(struct lcore_conf_ev_tx_int_port_wrkr *lconf, 679 struct eh_event_link_info *links, 680 struct rte_event *ev) 681 { 682 struct rte_event_vector *vec = ev->vec; 683 struct rte_mbuf *pkt; 684 int ret; 685 686 pkt = vec->mbufs[0]; 687 688 ev_vector_attr_init(vec); 689 if (is_unprotected_port(pkt->port)) 690 ret = process_ipsec_ev_inbound_vector(&lconf->inbound, 691 &lconf->rt, vec); 692 else 693 ret = process_ipsec_ev_outbound_vector(&lconf->outbound, 694 &lconf->rt, vec); 695 696 if (ret > 0) { 697 vec->nb_elem = ret; 698 rte_event_eth_tx_adapter_enqueue(links[0].eventdev_id, 699 links[0].event_port_id, 700 ev, 1, 0); 701 } 702 } 703 704 static inline void 705 ipsec_ev_vector_drv_mode_process(struct eh_event_link_info *links, 706 struct rte_event *ev, 707 struct port_drv_mode_data *data) 708 { 709 struct rte_event_vector *vec = ev->vec; 710 struct rte_mbuf *pkt; 711 712 pkt = vec->mbufs[0]; 713 714 if (!is_unprotected_port(pkt->port)) 715 vec->nb_elem = process_ipsec_ev_drv_mode_outbound_vector(vec, 716 data); 717 if (vec->nb_elem > 0) 718 rte_event_eth_tx_adapter_enqueue(links[0].eventdev_id, 719 links[0].event_port_id, 720 ev, 1, 0); 721 } 722 723 /* 724 * Event mode exposes various operating modes depending on the 725 * capabilities of the event device and the operating mode 726 * selected. 727 */ 728 729 /* Workers registered */ 730 #define IPSEC_EVENTMODE_WORKERS 2 731 732 /* 733 * Event mode worker 734 * Operating parameters : non-burst - Tx internal port - driver mode 735 */ 736 static void 737 ipsec_wrkr_non_burst_int_port_drv_mode(struct eh_event_link_info *links, 738 uint8_t nb_links) 739 { 740 struct port_drv_mode_data data[RTE_MAX_ETHPORTS]; 741 unsigned int nb_rx = 0; 742 struct rte_mbuf *pkt; 743 struct rte_event ev; 744 uint32_t lcore_id; 745 int32_t socket_id; 746 int16_t port_id; 747 748 /* Check if we have links registered for this lcore */ 749 if (nb_links == 0) { 750 /* No links registered - exit */ 751 return; 752 } 753 754 memset(&data, 0, sizeof(struct port_drv_mode_data)); 755 756 /* Get core ID */ 757 lcore_id = rte_lcore_id(); 758 759 /* Get socket ID */ 760 socket_id = rte_lcore_to_socket_id(lcore_id); 761 762 /* 763 * Prepare security sessions table. In outbound driver mode 764 * we always use first session configured for a given port 765 */ 766 prepare_out_sessions_tbl(socket_ctx[socket_id].sa_out, data, 767 RTE_MAX_ETHPORTS); 768 769 RTE_LOG(INFO, IPSEC, 770 "Launching event mode worker (non-burst - Tx internal port - " 771 "driver mode) on lcore %d\n", lcore_id); 772 773 /* We have valid links */ 774 775 /* Check if it's single link */ 776 if (nb_links != 1) { 777 RTE_LOG(INFO, IPSEC, 778 "Multiple links not supported. Using first link\n"); 779 } 780 781 RTE_LOG(INFO, IPSEC, " -- lcoreid=%u event_port_id=%u\n", lcore_id, 782 links[0].event_port_id); 783 while (!force_quit) { 784 /* Read packet from event queues */ 785 nb_rx = rte_event_dequeue_burst(links[0].eventdev_id, 786 links[0].event_port_id, 787 &ev, /* events */ 788 1, /* nb_events */ 789 0 /* timeout_ticks */); 790 791 if (nb_rx == 0) 792 continue; 793 794 switch (ev.event_type) { 795 case RTE_EVENT_TYPE_ETH_RX_ADAPTER_VECTOR: 796 case RTE_EVENT_TYPE_ETHDEV_VECTOR: 797 ipsec_ev_vector_drv_mode_process(links, &ev, data); 798 continue; 799 case RTE_EVENT_TYPE_ETHDEV: 800 break; 801 default: 802 RTE_LOG(ERR, IPSEC, "Invalid event type %u", 803 ev.event_type); 804 continue; 805 } 806 807 pkt = ev.mbuf; 808 port_id = pkt->port; 809 810 rte_prefetch0(rte_pktmbuf_mtod(pkt, void *)); 811 812 /* Process packet */ 813 ipsec_event_pre_forward(pkt, port_id); 814 815 if (!is_unprotected_port(port_id)) { 816 817 if (unlikely(!data[port_id].sess)) { 818 rte_pktmbuf_free(pkt); 819 continue; 820 } 821 822 /* Save security session */ 823 rte_security_set_pkt_metadata(data[port_id].ctx, 824 data[port_id].sess, pkt, 825 NULL); 826 827 /* Mark the packet for Tx security offload */ 828 pkt->ol_flags |= RTE_MBUF_F_TX_SEC_OFFLOAD; 829 830 /* Provide L2 len for Outbound processing */ 831 pkt->l2_len = RTE_ETHER_HDR_LEN; 832 } 833 834 /* 835 * Since tx internal port is available, events can be 836 * directly enqueued to the adapter and it would be 837 * internally submitted to the eth device. 838 */ 839 rte_event_eth_tx_adapter_enqueue(links[0].eventdev_id, 840 links[0].event_port_id, 841 &ev, /* events */ 842 1, /* nb_events */ 843 0 /* flags */); 844 } 845 } 846 847 /* 848 * Event mode worker 849 * Operating parameters : non-burst - Tx internal port - app mode 850 */ 851 static void 852 ipsec_wrkr_non_burst_int_port_app_mode(struct eh_event_link_info *links, 853 uint8_t nb_links) 854 { 855 struct lcore_conf_ev_tx_int_port_wrkr lconf; 856 unsigned int nb_rx = 0; 857 struct rte_event ev; 858 uint32_t lcore_id; 859 int32_t socket_id; 860 int ret; 861 862 /* Check if we have links registered for this lcore */ 863 if (nb_links == 0) { 864 /* No links registered - exit */ 865 return; 866 } 867 868 /* We have valid links */ 869 870 /* Get core ID */ 871 lcore_id = rte_lcore_id(); 872 873 /* Get socket ID */ 874 socket_id = rte_lcore_to_socket_id(lcore_id); 875 876 /* Save routing table */ 877 lconf.rt.rt4_ctx = socket_ctx[socket_id].rt_ip4; 878 lconf.rt.rt6_ctx = socket_ctx[socket_id].rt_ip6; 879 lconf.inbound.sp4_ctx = socket_ctx[socket_id].sp_ip4_in; 880 lconf.inbound.sp6_ctx = socket_ctx[socket_id].sp_ip6_in; 881 lconf.inbound.sa_ctx = socket_ctx[socket_id].sa_in; 882 lconf.inbound.session_pool = socket_ctx[socket_id].session_pool; 883 lconf.inbound.session_priv_pool = 884 socket_ctx[socket_id].session_priv_pool; 885 lconf.outbound.sp4_ctx = socket_ctx[socket_id].sp_ip4_out; 886 lconf.outbound.sp6_ctx = socket_ctx[socket_id].sp_ip6_out; 887 lconf.outbound.sa_ctx = socket_ctx[socket_id].sa_out; 888 lconf.outbound.session_pool = socket_ctx[socket_id].session_pool; 889 lconf.outbound.session_priv_pool = 890 socket_ctx[socket_id].session_priv_pool; 891 892 RTE_LOG(INFO, IPSEC, 893 "Launching event mode worker (non-burst - Tx internal port - " 894 "app mode) on lcore %d\n", lcore_id); 895 896 /* Check if it's single link */ 897 if (nb_links != 1) { 898 RTE_LOG(INFO, IPSEC, 899 "Multiple links not supported. Using first link\n"); 900 } 901 902 RTE_LOG(INFO, IPSEC, " -- lcoreid=%u event_port_id=%u\n", lcore_id, 903 links[0].event_port_id); 904 905 while (!force_quit) { 906 /* Read packet from event queues */ 907 nb_rx = rte_event_dequeue_burst(links[0].eventdev_id, 908 links[0].event_port_id, 909 &ev, /* events */ 910 1, /* nb_events */ 911 0 /* timeout_ticks */); 912 913 if (nb_rx == 0) 914 continue; 915 916 switch (ev.event_type) { 917 case RTE_EVENT_TYPE_ETH_RX_ADAPTER_VECTOR: 918 case RTE_EVENT_TYPE_ETHDEV_VECTOR: 919 ipsec_ev_vector_process(&lconf, links, &ev); 920 continue; 921 case RTE_EVENT_TYPE_ETHDEV: 922 break; 923 default: 924 RTE_LOG(ERR, IPSEC, "Invalid event type %u", 925 ev.event_type); 926 continue; 927 } 928 929 if (is_unprotected_port(ev.mbuf->port)) 930 ret = process_ipsec_ev_inbound(&lconf.inbound, 931 &lconf.rt, &ev); 932 else 933 ret = process_ipsec_ev_outbound(&lconf.outbound, 934 &lconf.rt, &ev); 935 if (ret != 1) 936 /* The pkt has been dropped */ 937 continue; 938 939 /* 940 * Since tx internal port is available, events can be 941 * directly enqueued to the adapter and it would be 942 * internally submitted to the eth device. 943 */ 944 rte_event_eth_tx_adapter_enqueue(links[0].eventdev_id, 945 links[0].event_port_id, 946 &ev, /* events */ 947 1, /* nb_events */ 948 0 /* flags */); 949 } 950 } 951 952 static uint8_t 953 ipsec_eventmode_populate_wrkr_params(struct eh_app_worker_params *wrkrs) 954 { 955 struct eh_app_worker_params *wrkr; 956 uint8_t nb_wrkr_param = 0; 957 958 /* Save workers */ 959 wrkr = wrkrs; 960 961 /* Non-burst - Tx internal port - driver mode */ 962 wrkr->cap.burst = EH_RX_TYPE_NON_BURST; 963 wrkr->cap.tx_internal_port = EH_TX_TYPE_INTERNAL_PORT; 964 wrkr->cap.ipsec_mode = EH_IPSEC_MODE_TYPE_DRIVER; 965 wrkr->worker_thread = ipsec_wrkr_non_burst_int_port_drv_mode; 966 wrkr++; 967 nb_wrkr_param++; 968 969 /* Non-burst - Tx internal port - app mode */ 970 wrkr->cap.burst = EH_RX_TYPE_NON_BURST; 971 wrkr->cap.tx_internal_port = EH_TX_TYPE_INTERNAL_PORT; 972 wrkr->cap.ipsec_mode = EH_IPSEC_MODE_TYPE_APP; 973 wrkr->worker_thread = ipsec_wrkr_non_burst_int_port_app_mode; 974 nb_wrkr_param++; 975 976 return nb_wrkr_param; 977 } 978 979 static void 980 ipsec_eventmode_worker(struct eh_conf *conf) 981 { 982 struct eh_app_worker_params ipsec_wrkr[IPSEC_EVENTMODE_WORKERS] = { 983 {{{0} }, NULL } }; 984 uint8_t nb_wrkr_param; 985 986 /* Populate l2fwd_wrkr params */ 987 nb_wrkr_param = ipsec_eventmode_populate_wrkr_params(ipsec_wrkr); 988 989 /* 990 * Launch correct worker after checking 991 * the event device's capabilities. 992 */ 993 eh_launch_worker(conf, ipsec_wrkr, nb_wrkr_param); 994 } 995 996 int ipsec_launch_one_lcore(void *args) 997 { 998 struct eh_conf *conf; 999 1000 conf = (struct eh_conf *)args; 1001 1002 if (conf->mode == EH_PKT_TRANSFER_MODE_POLL) { 1003 /* Run in poll mode */ 1004 ipsec_poll_mode_worker(); 1005 } else if (conf->mode == EH_PKT_TRANSFER_MODE_EVENT) { 1006 /* Run in event mode */ 1007 ipsec_eventmode_worker(conf); 1008 } 1009 return 0; 1010 } 1011