174080d7dSKumara Parameshwaran /* SPDX-License-Identifier: BSD-3-Clause 274080d7dSKumara Parameshwaran * Copyright(c) 2023 Intel Corporation 374080d7dSKumara Parameshwaran */ 474080d7dSKumara Parameshwaran 574080d7dSKumara Parameshwaran #include <rte_malloc.h> 674080d7dSKumara Parameshwaran #include <rte_mbuf.h> 774080d7dSKumara Parameshwaran #include <rte_ethdev.h> 874080d7dSKumara Parameshwaran 974080d7dSKumara Parameshwaran #include "gro_tcp6.h" 1074080d7dSKumara Parameshwaran #include "gro_tcp_internal.h" 1174080d7dSKumara Parameshwaran 1274080d7dSKumara Parameshwaran void * 1374080d7dSKumara Parameshwaran gro_tcp6_tbl_create(uint16_t socket_id, 1474080d7dSKumara Parameshwaran uint16_t max_flow_num, 1574080d7dSKumara Parameshwaran uint16_t max_item_per_flow) 1674080d7dSKumara Parameshwaran { 1774080d7dSKumara Parameshwaran struct gro_tcp6_tbl *tbl; 1874080d7dSKumara Parameshwaran size_t size; 1974080d7dSKumara Parameshwaran uint32_t entries_num, i; 2074080d7dSKumara Parameshwaran 2174080d7dSKumara Parameshwaran entries_num = max_flow_num * max_item_per_flow; 2274080d7dSKumara Parameshwaran entries_num = RTE_MIN(entries_num, GRO_TCP6_TBL_MAX_ITEM_NUM); 2374080d7dSKumara Parameshwaran 2474080d7dSKumara Parameshwaran if (entries_num == 0) 2574080d7dSKumara Parameshwaran return NULL; 2674080d7dSKumara Parameshwaran 2774080d7dSKumara Parameshwaran tbl = rte_zmalloc_socket(__func__, 2874080d7dSKumara Parameshwaran sizeof(struct gro_tcp6_tbl), 2974080d7dSKumara Parameshwaran RTE_CACHE_LINE_SIZE, 3074080d7dSKumara Parameshwaran socket_id); 3174080d7dSKumara Parameshwaran if (tbl == NULL) 3274080d7dSKumara Parameshwaran return NULL; 3374080d7dSKumara Parameshwaran 3474080d7dSKumara Parameshwaran size = sizeof(struct gro_tcp_item) * entries_num; 3574080d7dSKumara Parameshwaran tbl->items = rte_zmalloc_socket(__func__, 3674080d7dSKumara Parameshwaran size, 3774080d7dSKumara Parameshwaran RTE_CACHE_LINE_SIZE, 3874080d7dSKumara Parameshwaran socket_id); 3974080d7dSKumara Parameshwaran if (tbl->items == NULL) { 4074080d7dSKumara Parameshwaran rte_free(tbl); 4174080d7dSKumara Parameshwaran return NULL; 4274080d7dSKumara Parameshwaran } 4374080d7dSKumara Parameshwaran tbl->max_item_num = entries_num; 4474080d7dSKumara Parameshwaran 4574080d7dSKumara Parameshwaran size = sizeof(struct gro_tcp6_flow) * entries_num; 4674080d7dSKumara Parameshwaran tbl->flows = rte_zmalloc_socket(__func__, 4774080d7dSKumara Parameshwaran size, 4874080d7dSKumara Parameshwaran RTE_CACHE_LINE_SIZE, 4974080d7dSKumara Parameshwaran socket_id); 5074080d7dSKumara Parameshwaran if (tbl->flows == NULL) { 5174080d7dSKumara Parameshwaran rte_free(tbl->items); 5274080d7dSKumara Parameshwaran rte_free(tbl); 5374080d7dSKumara Parameshwaran return NULL; 5474080d7dSKumara Parameshwaran } 5574080d7dSKumara Parameshwaran /* INVALID_ARRAY_INDEX indicates an empty flow */ 5674080d7dSKumara Parameshwaran for (i = 0; i < entries_num; i++) 5774080d7dSKumara Parameshwaran tbl->flows[i].start_index = INVALID_ARRAY_INDEX; 5874080d7dSKumara Parameshwaran tbl->max_flow_num = entries_num; 5974080d7dSKumara Parameshwaran 6074080d7dSKumara Parameshwaran return tbl; 6174080d7dSKumara Parameshwaran } 6274080d7dSKumara Parameshwaran 6374080d7dSKumara Parameshwaran void 6474080d7dSKumara Parameshwaran gro_tcp6_tbl_destroy(void *tbl) 6574080d7dSKumara Parameshwaran { 6674080d7dSKumara Parameshwaran struct gro_tcp6_tbl *tcp_tbl = tbl; 6774080d7dSKumara Parameshwaran 6874080d7dSKumara Parameshwaran if (tcp_tbl) { 6974080d7dSKumara Parameshwaran rte_free(tcp_tbl->items); 7074080d7dSKumara Parameshwaran rte_free(tcp_tbl->flows); 7174080d7dSKumara Parameshwaran } 7274080d7dSKumara Parameshwaran rte_free(tcp_tbl); 7374080d7dSKumara Parameshwaran } 7474080d7dSKumara Parameshwaran 7574080d7dSKumara Parameshwaran static inline uint32_t 7674080d7dSKumara Parameshwaran find_an_empty_flow(struct gro_tcp6_tbl *tbl) 7774080d7dSKumara Parameshwaran { 7874080d7dSKumara Parameshwaran uint32_t i; 7974080d7dSKumara Parameshwaran uint32_t max_flow_num = tbl->max_flow_num; 8074080d7dSKumara Parameshwaran 8174080d7dSKumara Parameshwaran for (i = 0; i < max_flow_num; i++) 8274080d7dSKumara Parameshwaran if (tbl->flows[i].start_index == INVALID_ARRAY_INDEX) 8374080d7dSKumara Parameshwaran return i; 8474080d7dSKumara Parameshwaran return INVALID_ARRAY_INDEX; 8574080d7dSKumara Parameshwaran } 8674080d7dSKumara Parameshwaran 8774080d7dSKumara Parameshwaran static inline uint32_t 8874080d7dSKumara Parameshwaran insert_new_flow(struct gro_tcp6_tbl *tbl, 8974080d7dSKumara Parameshwaran struct tcp6_flow_key *src, 9074080d7dSKumara Parameshwaran uint32_t item_idx) 9174080d7dSKumara Parameshwaran { 9274080d7dSKumara Parameshwaran struct tcp6_flow_key *dst; 9374080d7dSKumara Parameshwaran uint32_t flow_idx; 9474080d7dSKumara Parameshwaran 9574080d7dSKumara Parameshwaran flow_idx = find_an_empty_flow(tbl); 9674080d7dSKumara Parameshwaran if (unlikely(flow_idx == INVALID_ARRAY_INDEX)) 9774080d7dSKumara Parameshwaran return INVALID_ARRAY_INDEX; 9874080d7dSKumara Parameshwaran 9974080d7dSKumara Parameshwaran dst = &(tbl->flows[flow_idx].key); 10074080d7dSKumara Parameshwaran 10174080d7dSKumara Parameshwaran ASSIGN_COMMON_TCP_KEY((&src->cmn_key), (&dst->cmn_key)); 102*41d71aebSRobin Jarry dst->src_addr = src->src_addr; 103*41d71aebSRobin Jarry dst->dst_addr = src->dst_addr; 10474080d7dSKumara Parameshwaran dst->vtc_flow = src->vtc_flow; 10574080d7dSKumara Parameshwaran 10674080d7dSKumara Parameshwaran tbl->flows[flow_idx].start_index = item_idx; 10774080d7dSKumara Parameshwaran tbl->flow_num++; 10874080d7dSKumara Parameshwaran 10974080d7dSKumara Parameshwaran return flow_idx; 11074080d7dSKumara Parameshwaran } 11174080d7dSKumara Parameshwaran 11274080d7dSKumara Parameshwaran /* 11374080d7dSKumara Parameshwaran * update the packet length for the flushed packet. 11474080d7dSKumara Parameshwaran */ 11574080d7dSKumara Parameshwaran static inline void 11674080d7dSKumara Parameshwaran update_header(struct gro_tcp_item *item) 11774080d7dSKumara Parameshwaran { 11874080d7dSKumara Parameshwaran struct rte_ipv6_hdr *ipv6_hdr; 11974080d7dSKumara Parameshwaran struct rte_mbuf *pkt = item->firstseg; 12074080d7dSKumara Parameshwaran 12163a98ffeSStephen Hemminger ipv6_hdr = rte_pktmbuf_mtod_offset(pkt, struct rte_ipv6_hdr *, 12274080d7dSKumara Parameshwaran pkt->l2_len); 12374080d7dSKumara Parameshwaran ipv6_hdr->payload_len = rte_cpu_to_be_16(pkt->pkt_len - 12474080d7dSKumara Parameshwaran pkt->l2_len - pkt->l3_len); 12574080d7dSKumara Parameshwaran } 12674080d7dSKumara Parameshwaran 12774080d7dSKumara Parameshwaran int32_t 12874080d7dSKumara Parameshwaran gro_tcp6_reassemble(struct rte_mbuf *pkt, 12974080d7dSKumara Parameshwaran struct gro_tcp6_tbl *tbl, 13074080d7dSKumara Parameshwaran uint64_t start_time) 13174080d7dSKumara Parameshwaran { 13274080d7dSKumara Parameshwaran struct rte_ether_hdr *eth_hdr; 13374080d7dSKumara Parameshwaran struct rte_ipv6_hdr *ipv6_hdr; 13474080d7dSKumara Parameshwaran int32_t tcp_dl; 13574080d7dSKumara Parameshwaran uint16_t ip_tlen; 13674080d7dSKumara Parameshwaran struct tcp6_flow_key key; 13774080d7dSKumara Parameshwaran uint32_t i, max_flow_num, remaining_flow_num; 13874080d7dSKumara Parameshwaran uint32_t sent_seq; 13974080d7dSKumara Parameshwaran struct rte_tcp_hdr *tcp_hdr; 14074080d7dSKumara Parameshwaran uint8_t find; 14174080d7dSKumara Parameshwaran uint32_t item_idx; 14274080d7dSKumara Parameshwaran /* 14374080d7dSKumara Parameshwaran * Don't process the packet whose TCP header length is greater 14474080d7dSKumara Parameshwaran * than 60 bytes or less than 20 bytes. 14574080d7dSKumara Parameshwaran */ 14674080d7dSKumara Parameshwaran if (unlikely(INVALID_TCP_HDRLEN(pkt->l4_len))) 14774080d7dSKumara Parameshwaran return -1; 14874080d7dSKumara Parameshwaran 14974080d7dSKumara Parameshwaran eth_hdr = rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *); 15074080d7dSKumara Parameshwaran ipv6_hdr = (struct rte_ipv6_hdr *)((char *)eth_hdr + pkt->l2_len); 15174080d7dSKumara Parameshwaran tcp_hdr = rte_pktmbuf_mtod_offset(pkt, struct rte_tcp_hdr *, pkt->l2_len + pkt->l3_len); 15274080d7dSKumara Parameshwaran 15374080d7dSKumara Parameshwaran /* 15474080d7dSKumara Parameshwaran * Don't process the packet which has FIN, SYN, RST, PSH, URG, ECE 15574080d7dSKumara Parameshwaran * or CWR set. 15674080d7dSKumara Parameshwaran */ 15774080d7dSKumara Parameshwaran if (tcp_hdr->tcp_flags != RTE_TCP_ACK_FLAG) 15874080d7dSKumara Parameshwaran return -1; 15974080d7dSKumara Parameshwaran 16074080d7dSKumara Parameshwaran ip_tlen = rte_be_to_cpu_16(ipv6_hdr->payload_len); 16174080d7dSKumara Parameshwaran /* 16274080d7dSKumara Parameshwaran * Don't process the packet whose payload length is less than or 16374080d7dSKumara Parameshwaran * equal to 0. 16474080d7dSKumara Parameshwaran */ 16574080d7dSKumara Parameshwaran tcp_dl = ip_tlen - pkt->l4_len; 16674080d7dSKumara Parameshwaran if (tcp_dl <= 0) 16774080d7dSKumara Parameshwaran return -1; 16874080d7dSKumara Parameshwaran 16974080d7dSKumara Parameshwaran rte_ether_addr_copy(&(eth_hdr->src_addr), &(key.cmn_key.eth_saddr)); 17074080d7dSKumara Parameshwaran rte_ether_addr_copy(&(eth_hdr->dst_addr), &(key.cmn_key.eth_daddr)); 171*41d71aebSRobin Jarry key.src_addr = ipv6_hdr->src_addr; 172*41d71aebSRobin Jarry key.dst_addr = ipv6_hdr->dst_addr; 17374080d7dSKumara Parameshwaran key.cmn_key.src_port = tcp_hdr->src_port; 17474080d7dSKumara Parameshwaran key.cmn_key.dst_port = tcp_hdr->dst_port; 17574080d7dSKumara Parameshwaran key.cmn_key.recv_ack = tcp_hdr->recv_ack; 17674080d7dSKumara Parameshwaran key.vtc_flow = ipv6_hdr->vtc_flow; 17774080d7dSKumara Parameshwaran 17874080d7dSKumara Parameshwaran /* Search for a matched flow. */ 17974080d7dSKumara Parameshwaran max_flow_num = tbl->max_flow_num; 18074080d7dSKumara Parameshwaran remaining_flow_num = tbl->flow_num; 18174080d7dSKumara Parameshwaran find = 0; 18274080d7dSKumara Parameshwaran for (i = 0; i < max_flow_num && remaining_flow_num; i++) { 18374080d7dSKumara Parameshwaran if (tbl->flows[i].start_index != INVALID_ARRAY_INDEX) { 18474080d7dSKumara Parameshwaran if (is_same_tcp6_flow(&tbl->flows[i].key, &key)) { 18574080d7dSKumara Parameshwaran find = 1; 18674080d7dSKumara Parameshwaran break; 18774080d7dSKumara Parameshwaran } 18874080d7dSKumara Parameshwaran remaining_flow_num--; 18974080d7dSKumara Parameshwaran } 19074080d7dSKumara Parameshwaran } 19174080d7dSKumara Parameshwaran 19274080d7dSKumara Parameshwaran if (find == 0) { 19374080d7dSKumara Parameshwaran sent_seq = rte_be_to_cpu_32(tcp_hdr->sent_seq); 19474080d7dSKumara Parameshwaran item_idx = insert_new_tcp_item(pkt, tbl->items, &tbl->item_num, 19574080d7dSKumara Parameshwaran tbl->max_item_num, start_time, 19674080d7dSKumara Parameshwaran INVALID_ARRAY_INDEX, sent_seq, 0, true); 19774080d7dSKumara Parameshwaran if (item_idx == INVALID_ARRAY_INDEX) 19874080d7dSKumara Parameshwaran return -1; 19974080d7dSKumara Parameshwaran if (insert_new_flow(tbl, &key, item_idx) == 20074080d7dSKumara Parameshwaran INVALID_ARRAY_INDEX) { 20174080d7dSKumara Parameshwaran /* 20274080d7dSKumara Parameshwaran * Fail to insert a new flow, so delete the 20374080d7dSKumara Parameshwaran * stored packet. 20474080d7dSKumara Parameshwaran */ 20574080d7dSKumara Parameshwaran delete_tcp_item(tbl->items, item_idx, &tbl->item_num, INVALID_ARRAY_INDEX); 20674080d7dSKumara Parameshwaran return -1; 20774080d7dSKumara Parameshwaran } 20874080d7dSKumara Parameshwaran return 0; 20974080d7dSKumara Parameshwaran } 21074080d7dSKumara Parameshwaran 21174080d7dSKumara Parameshwaran return process_tcp_item(pkt, tcp_hdr, tcp_dl, tbl->items, tbl->flows[i].start_index, 21274080d7dSKumara Parameshwaran &tbl->item_num, tbl->max_item_num, 21374080d7dSKumara Parameshwaran 0, true, start_time); 21474080d7dSKumara Parameshwaran } 21574080d7dSKumara Parameshwaran 21674080d7dSKumara Parameshwaran uint16_t 21774080d7dSKumara Parameshwaran gro_tcp6_tbl_timeout_flush(struct gro_tcp6_tbl *tbl, 21874080d7dSKumara Parameshwaran uint64_t flush_timestamp, 21974080d7dSKumara Parameshwaran struct rte_mbuf **out, 22074080d7dSKumara Parameshwaran uint16_t nb_out) 22174080d7dSKumara Parameshwaran { 22274080d7dSKumara Parameshwaran uint16_t k = 0; 22374080d7dSKumara Parameshwaran uint32_t i, j; 22474080d7dSKumara Parameshwaran uint32_t max_flow_num = tbl->max_flow_num; 22574080d7dSKumara Parameshwaran 22674080d7dSKumara Parameshwaran for (i = 0; i < max_flow_num; i++) { 22774080d7dSKumara Parameshwaran if (unlikely(tbl->flow_num == 0)) 22874080d7dSKumara Parameshwaran return k; 22974080d7dSKumara Parameshwaran 23074080d7dSKumara Parameshwaran j = tbl->flows[i].start_index; 23174080d7dSKumara Parameshwaran while (j != INVALID_ARRAY_INDEX) { 23274080d7dSKumara Parameshwaran if (tbl->items[j].start_time <= flush_timestamp) { 23374080d7dSKumara Parameshwaran out[k++] = tbl->items[j].firstseg; 23474080d7dSKumara Parameshwaran if (tbl->items[j].nb_merged > 1) 23574080d7dSKumara Parameshwaran update_header(&(tbl->items[j])); 23674080d7dSKumara Parameshwaran /* 23774080d7dSKumara Parameshwaran * Delete the packet and get the next 23874080d7dSKumara Parameshwaran * packet in the flow. 23974080d7dSKumara Parameshwaran */ 24074080d7dSKumara Parameshwaran j = delete_tcp_item(tbl->items, j, 24174080d7dSKumara Parameshwaran &tbl->item_num, INVALID_ARRAY_INDEX); 24274080d7dSKumara Parameshwaran tbl->flows[i].start_index = j; 24374080d7dSKumara Parameshwaran if (j == INVALID_ARRAY_INDEX) 24474080d7dSKumara Parameshwaran tbl->flow_num--; 24574080d7dSKumara Parameshwaran 24674080d7dSKumara Parameshwaran if (unlikely(k == nb_out)) 24774080d7dSKumara Parameshwaran return k; 24874080d7dSKumara Parameshwaran } else 24974080d7dSKumara Parameshwaran /* 25074080d7dSKumara Parameshwaran * The left packets in this flow won't be 25174080d7dSKumara Parameshwaran * timeout. Go to check other flows. 25274080d7dSKumara Parameshwaran */ 25374080d7dSKumara Parameshwaran break; 25474080d7dSKumara Parameshwaran } 25574080d7dSKumara Parameshwaran } 25674080d7dSKumara Parameshwaran return k; 25774080d7dSKumara Parameshwaran } 25874080d7dSKumara Parameshwaran 25974080d7dSKumara Parameshwaran uint32_t 26074080d7dSKumara Parameshwaran gro_tcp6_tbl_pkt_count(void *tbl) 26174080d7dSKumara Parameshwaran { 26274080d7dSKumara Parameshwaran struct gro_tcp6_tbl *gro_tbl = tbl; 26374080d7dSKumara Parameshwaran 26474080d7dSKumara Parameshwaran if (gro_tbl) 26574080d7dSKumara Parameshwaran return gro_tbl->item_num; 26674080d7dSKumara Parameshwaran 26774080d7dSKumara Parameshwaran return 0; 26874080d7dSKumara Parameshwaran } 269