From patchwork Wed Jun 21 08:38:36 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kumara Parameshwaran X-Patchwork-Id: 128885 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 955C142D12; Wed, 21 Jun 2023 10:38:53 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id A166C42D10; Wed, 21 Jun 2023 10:38:48 +0200 (CEST) Received: from mail-pf1-f172.google.com (mail-pf1-f172.google.com [209.85.210.172]) by mails.dpdk.org (Postfix) with ESMTP id 4EBCA42C54 for ; Wed, 21 Jun 2023 10:38:47 +0200 (CEST) Received: by mail-pf1-f172.google.com with SMTP id d2e1a72fcca58-6686c74183cso3397572b3a.1 for ; Wed, 21 Jun 2023 01:38:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20221208; t=1687336726; x=1689928726; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=NX19E9AtyEd6OeMd8NDWCezVEEQVOMvqKBSWxnC4+yk=; b=fMNNcOisHDS+Z5T0K9UatmxEcwV8ezeyqD817LqcAe1mWzN0DKGctL6Oikwh0rTFUI B3h7ezz2u31lllIPoEGwwxoVDzOywG5XyTP/jui/YjK1bXlHlydOzPE8+xlPcPC9TBMH dlIp9j9HAkxpyYB9nyYHbmgY3KvIRZw+NJ5Tj6RHWQ9PhTBisDvOXoHEc5706LuwN1xO B+dPPZRecqg34lzdeckUfVbWjVrrbza6W/WmhQ0iUk5jkt1RpDPeX23qS/WXh3aF5v2K ca/PGq7YkzqBbLQCkBHCD2WdglqTOBgYo0eMzQ/tg5pZmqdHgPP74BR2drOwQAhFM+GT FCsg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1687336726; x=1689928726; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=NX19E9AtyEd6OeMd8NDWCezVEEQVOMvqKBSWxnC4+yk=; b=bzUjGsexVcrDC+lqsIKvsDgYXI/DJvzayI32qD82Hl8+DEyAFSr1tEbERg/SbHb5vK c9HUYa2fyjLguyGsNCqxuFUKBlqMGGsxPaomkHuWGLdKXJ9V1/l7aHZ0KF6WXYXqdwIg Ja+YOH6A/jv9zE68DO580M/mxI/WSNjW4g1bDGhYAus4920AfxXD/57lA4xJuQjbsZ48 nAHpgHVplbFnc7pyU1iessxAOJZgLGbC7QReVmSg5jHy2sf1jeDuA8ZnFMDE5sbKys3J uEs3sX7bA2J3A/do8dOAaE7TNhJbqyLVcTE/6qPd8ySvuKMd2a1JD9ciq3lvJbnY4yHY FR0Q== X-Gm-Message-State: AC+VfDytl+/gyyewiZyZlOMeCkkOdM4PT2pZ2q546GWg2WUXawsxQsm3 dgqsdfsjML/QxqHNj5Gxw18= X-Google-Smtp-Source: ACHHUZ66V4kZZ/MqgotiGWZnPiRU59m3e77zC4TtoUumNnDbPBZqPOoOUIJw3evyXQWuhvNiVbSJlA== X-Received: by 2002:a05:6a00:240f:b0:64b:256:204c with SMTP id z15-20020a056a00240f00b0064b0256204cmr17869488pfh.20.1687336726151; Wed, 21 Jun 2023 01:38:46 -0700 (PDT) Received: from kparameshw7KFWX.vmware.com.com ([103.19.213.32]) by smtp.gmail.com with ESMTPSA id k10-20020aa792ca000000b00653dc27acadsm2436173pfa.205.2023.06.21.01.38.44 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Wed, 21 Jun 2023 01:38:45 -0700 (PDT) From: Kumara Parameshwaran To: jiayu.hu@intel.com Cc: dev@dpdk.org, Kumara Parameshwaran Subject: [PATCH v11 2/2] gro : add support for IPv6 GRO Date: Wed, 21 Jun 2023 14:08:36 +0530 Message-Id: <20230621083836.63060-2-kumaraparamesh92@gmail.com> X-Mailer: git-send-email 2.37.1 (Apple Git-137.1) In-Reply-To: <20230621083836.63060-1-kumaraparamesh92@gmail.com> References: <20221020181425.48006-1-kumaraparmesh92@gmail.com> <20230621083836.63060-1-kumaraparamesh92@gmail.com> MIME-Version: 1.0 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Add support for IPv6 GRO for TCP packets Signed-off-by: Kumara Parameshwaran --- v1: * Changes to support GRO for TCP/ipv6 packets. This does not include vxlan changes. * The GRO is performed only for ipv6 packets that does not contain extension headers. * The logic for the TCP coalescing remains the same, in ipv6 header the source address, destination address, flow label, version fields are expected to be the same. * Re-organised the code to reuse certain tcp functions for both ipv4 and ipv6 flows. v2: * Fix comments in gro_tcp6.h header file. v3: * Adderess review comments to fix code duplication for v4 and v6 v4: * Addresses review comments for v3, do not use callbacks v5: * Address review comments v6: * Fix warning and coding style issues v7: * Fix build compilation issue v8: * Use gro_tcp_internal.h for functions used for gro_tcp4 and gro_tcp6 and use gro_tcp.h for data structures and functions used across gro_vxlan_tcp4 v9: * Resolve merge conflict and add gro_tcp.h in proper path v10: * Refactor the code to contain 2 patches. This patch contains support for IPv6 GRO v11: * Fix commit to add missed files .../generic_receive_offload_lib.rst | 21 +- doc/guides/rel_notes/release_23_07.rst | 2 + lib/gro/gro_tcp6.c | 268 ++++++++++++++++++ lib/gro/gro_tcp6.h | 160 +++++++++++ lib/gro/meson.build | 1 + lib/gro/rte_gro.c | 81 +++++- lib/gro/rte_gro.h | 3 + 7 files changed, 513 insertions(+), 23 deletions(-) create mode 100644 lib/gro/gro_tcp6.c create mode 100644 lib/gro/gro_tcp6.h diff --git a/doc/guides/prog_guide/generic_receive_offload_lib.rst b/doc/guides/prog_guide/generic_receive_offload_lib.rst index 98a5d29bbc..533cda7f5c 100644 --- a/doc/guides/prog_guide/generic_receive_offload_lib.rst +++ b/doc/guides/prog_guide/generic_receive_offload_lib.rst @@ -138,20 +138,21 @@ The key-based algorithm has two characters: Key-based Reassembly Algorithm -TCP/IPv4 GRO ------------- +TCP-IPv4/IPv6 GRO +----------------- -The table structure used by TCP/IPv4 GRO contains two arrays: flow array +The table structure used by TCP-IPv4/IPv6 GRO contains two arrays: flow array and item array. The flow array keeps flow information, and the item array -keeps packet information. +keeps packet information. The flow array is different for IPv4 and IPv6 while +the item array is the same. -Header fields used to define a TCP/IPv4 flow include: +Header fields used to define a TCP-IPv4/IPv6 flow include: -- source and destination: Ethernet and IP address, TCP port +- common tcp key fields : Ethernet address, TCP port, TCP acknowledge number +- version specific IP address +- IPv6 flow label for IPv6 flow -- TCP acknowledge number - -TCP/IPv4 packets whose FIN, SYN, RST, URG, PSH, ECE or CWR bit is set +TCP packets whose FIN, SYN, RST, URG, PSH, ECE or CWR bit is set won't be processed. Header fields deciding if two packets are neighbors include: @@ -159,7 +160,7 @@ Header fields deciding if two packets are neighbors include: - TCP sequence number - IPv4 ID. The IPv4 ID fields of the packets, whose DF bit is 0, should - be increased by 1. + be increased by 1. This is applicable only for IPv4 VxLAN GRO --------- diff --git a/doc/guides/rel_notes/release_23_07.rst b/doc/guides/rel_notes/release_23_07.rst index 027ae7bd2d..7124cf45c7 100644 --- a/doc/guides/rel_notes/release_23_07.rst +++ b/doc/guides/rel_notes/release_23_07.rst @@ -170,6 +170,8 @@ New Features See :doc:`../prog_guide/pdcp_lib` for more information. +* **Added support for TCP/IPv6 GRO.** + * Enhanced the existing library to support GRO for TCP packets over IPv6 network. Removed Items ------------- diff --git a/lib/gro/gro_tcp6.c b/lib/gro/gro_tcp6.c new file mode 100644 index 0000000000..5aa39801e1 --- /dev/null +++ b/lib/gro/gro_tcp6.c @@ -0,0 +1,268 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Intel Corporation + */ + +#include +#include +#include + +#include "gro_tcp6.h" +#include "gro_tcp_internal.h" + +void * +gro_tcp6_tbl_create(uint16_t socket_id, + uint16_t max_flow_num, + uint16_t max_item_per_flow) +{ + struct gro_tcp6_tbl *tbl; + size_t size; + uint32_t entries_num, i; + + entries_num = max_flow_num * max_item_per_flow; + entries_num = RTE_MIN(entries_num, GRO_TCP6_TBL_MAX_ITEM_NUM); + + if (entries_num == 0) + return NULL; + + tbl = rte_zmalloc_socket(__func__, + sizeof(struct gro_tcp6_tbl), + RTE_CACHE_LINE_SIZE, + socket_id); + if (tbl == NULL) + return NULL; + + size = sizeof(struct gro_tcp_item) * entries_num; + tbl->items = rte_zmalloc_socket(__func__, + size, + RTE_CACHE_LINE_SIZE, + socket_id); + if (tbl->items == NULL) { + rte_free(tbl); + return NULL; + } + tbl->max_item_num = entries_num; + + size = sizeof(struct gro_tcp6_flow) * entries_num; + tbl->flows = rte_zmalloc_socket(__func__, + size, + RTE_CACHE_LINE_SIZE, + socket_id); + if (tbl->flows == NULL) { + rte_free(tbl->items); + rte_free(tbl); + return NULL; + } + /* INVALID_ARRAY_INDEX indicates an empty flow */ + for (i = 0; i < entries_num; i++) + tbl->flows[i].start_index = INVALID_ARRAY_INDEX; + tbl->max_flow_num = entries_num; + + return tbl; +} + +void +gro_tcp6_tbl_destroy(void *tbl) +{ + struct gro_tcp6_tbl *tcp_tbl = tbl; + + if (tcp_tbl) { + rte_free(tcp_tbl->items); + rte_free(tcp_tbl->flows); + } + rte_free(tcp_tbl); +} + +static inline uint32_t +find_an_empty_flow(struct gro_tcp6_tbl *tbl) +{ + uint32_t i; + uint32_t max_flow_num = tbl->max_flow_num; + + for (i = 0; i < max_flow_num; i++) + if (tbl->flows[i].start_index == INVALID_ARRAY_INDEX) + return i; + return INVALID_ARRAY_INDEX; +} + +static inline uint32_t +insert_new_flow(struct gro_tcp6_tbl *tbl, + struct tcp6_flow_key *src, + uint32_t item_idx) +{ + struct tcp6_flow_key *dst; + uint32_t flow_idx; + + flow_idx = find_an_empty_flow(tbl); + if (unlikely(flow_idx == INVALID_ARRAY_INDEX)) + return INVALID_ARRAY_INDEX; + + dst = &(tbl->flows[flow_idx].key); + + ASSIGN_COMMON_TCP_KEY((&src->cmn_key), (&dst->cmn_key)); + memcpy(&dst->src_addr[0], &src->src_addr[0], sizeof(dst->src_addr)); + memcpy(&dst->dst_addr[0], &src->dst_addr[0], sizeof(dst->dst_addr)); + dst->vtc_flow = src->vtc_flow; + + tbl->flows[flow_idx].start_index = item_idx; + tbl->flow_num++; + + return flow_idx; +} + +/* + * update the packet length for the flushed packet. + */ +static inline void +update_header(struct gro_tcp_item *item) +{ + struct rte_ipv6_hdr *ipv6_hdr; + struct rte_mbuf *pkt = item->firstseg; + + ipv6_hdr = (struct rte_ipv6_hdr *)(rte_pktmbuf_mtod(pkt, char *) + + pkt->l2_len); + ipv6_hdr->payload_len = rte_cpu_to_be_16(pkt->pkt_len - + pkt->l2_len - pkt->l3_len); +} + +int32_t +gro_tcp6_reassemble(struct rte_mbuf *pkt, + struct gro_tcp6_tbl *tbl, + uint64_t start_time) +{ + struct rte_ether_hdr *eth_hdr; + struct rte_ipv6_hdr *ipv6_hdr; + int32_t tcp_dl; + uint16_t ip_tlen; + struct tcp6_flow_key key; + uint32_t i, max_flow_num, remaining_flow_num; + uint32_t sent_seq; + struct rte_tcp_hdr *tcp_hdr; + uint8_t find; + uint32_t item_idx; + /* + * Don't process the packet whose TCP header length is greater + * than 60 bytes or less than 20 bytes. + */ + if (unlikely(INVALID_TCP_HDRLEN(pkt->l4_len))) + return -1; + + eth_hdr = rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *); + ipv6_hdr = (struct rte_ipv6_hdr *)((char *)eth_hdr + pkt->l2_len); + tcp_hdr = rte_pktmbuf_mtod_offset(pkt, struct rte_tcp_hdr *, pkt->l2_len + pkt->l3_len); + + /* + * Don't process the packet which has FIN, SYN, RST, PSH, URG, ECE + * or CWR set. + */ + if (tcp_hdr->tcp_flags != RTE_TCP_ACK_FLAG) + return -1; + + ip_tlen = rte_be_to_cpu_16(ipv6_hdr->payload_len); + /* + * Don't process the packet whose payload length is less than or + * equal to 0. + */ + tcp_dl = ip_tlen - pkt->l4_len; + if (tcp_dl <= 0) + return -1; + + rte_ether_addr_copy(&(eth_hdr->src_addr), &(key.cmn_key.eth_saddr)); + rte_ether_addr_copy(&(eth_hdr->dst_addr), &(key.cmn_key.eth_daddr)); + memcpy(&key.src_addr[0], &ipv6_hdr->src_addr, sizeof(key.src_addr)); + memcpy(&key.dst_addr[0], &ipv6_hdr->dst_addr, sizeof(key.dst_addr)); + key.cmn_key.src_port = tcp_hdr->src_port; + key.cmn_key.dst_port = tcp_hdr->dst_port; + key.cmn_key.recv_ack = tcp_hdr->recv_ack; + key.vtc_flow = ipv6_hdr->vtc_flow; + + /* Search for a matched flow. */ + max_flow_num = tbl->max_flow_num; + remaining_flow_num = tbl->flow_num; + find = 0; + for (i = 0; i < max_flow_num && remaining_flow_num; i++) { + if (tbl->flows[i].start_index != INVALID_ARRAY_INDEX) { + if (is_same_tcp6_flow(&tbl->flows[i].key, &key)) { + find = 1; + break; + } + remaining_flow_num--; + } + } + + if (find == 0) { + sent_seq = rte_be_to_cpu_32(tcp_hdr->sent_seq); + item_idx = insert_new_tcp_item(pkt, tbl->items, &tbl->item_num, + tbl->max_item_num, start_time, + INVALID_ARRAY_INDEX, sent_seq, 0, true); + if (item_idx == INVALID_ARRAY_INDEX) + return -1; + if (insert_new_flow(tbl, &key, item_idx) == + INVALID_ARRAY_INDEX) { + /* + * Fail to insert a new flow, so delete the + * stored packet. + */ + delete_tcp_item(tbl->items, item_idx, &tbl->item_num, INVALID_ARRAY_INDEX); + return -1; + } + return 0; + } + + return process_tcp_item(pkt, tcp_hdr, tcp_dl, tbl->items, tbl->flows[i].start_index, + &tbl->item_num, tbl->max_item_num, + 0, true, start_time); +} + +uint16_t +gro_tcp6_tbl_timeout_flush(struct gro_tcp6_tbl *tbl, + uint64_t flush_timestamp, + struct rte_mbuf **out, + uint16_t nb_out) +{ + uint16_t k = 0; + uint32_t i, j; + uint32_t max_flow_num = tbl->max_flow_num; + + for (i = 0; i < max_flow_num; i++) { + if (unlikely(tbl->flow_num == 0)) + return k; + + j = tbl->flows[i].start_index; + while (j != INVALID_ARRAY_INDEX) { + if (tbl->items[j].start_time <= flush_timestamp) { + out[k++] = tbl->items[j].firstseg; + if (tbl->items[j].nb_merged > 1) + update_header(&(tbl->items[j])); + /* + * Delete the packet and get the next + * packet in the flow. + */ + j = delete_tcp_item(tbl->items, j, + &tbl->item_num, INVALID_ARRAY_INDEX); + tbl->flows[i].start_index = j; + if (j == INVALID_ARRAY_INDEX) + tbl->flow_num--; + + if (unlikely(k == nb_out)) + return k; + } else + /* + * The left packets in this flow won't be + * timeout. Go to check other flows. + */ + break; + } + } + return k; +} + +uint32_t +gro_tcp6_tbl_pkt_count(void *tbl) +{ + struct gro_tcp6_tbl *gro_tbl = tbl; + + if (gro_tbl) + return gro_tbl->item_num; + + return 0; +} diff --git a/lib/gro/gro_tcp6.h b/lib/gro/gro_tcp6.h new file mode 100644 index 0000000000..073122f0ec --- /dev/null +++ b/lib/gro/gro_tcp6.h @@ -0,0 +1,160 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Intel Corporation + */ + +#ifndef _GRO_TCP6_H_ +#define _GRO_TCP6_H_ + +#include "gro_tcp.h" + +#define GRO_TCP6_TBL_MAX_ITEM_NUM (1024UL * 1024UL) + +/* Header fields representing a TCP/IPv6 flow */ +struct tcp6_flow_key { + struct cmn_tcp_key cmn_key; + uint8_t src_addr[16]; + uint8_t dst_addr[16]; + rte_be32_t vtc_flow; +}; + +struct gro_tcp6_flow { + struct tcp6_flow_key key; + /* + * The index of the first packet in the flow. + * INVALID_ARRAY_INDEX indicates an empty flow. + */ + uint32_t start_index; +}; + +/* + * TCP/IPv6 reassembly table structure. + */ +struct gro_tcp6_tbl { + /* item array */ + struct gro_tcp_item *items; + /* flow array */ + struct gro_tcp6_flow *flows; + /* current item number */ + uint32_t item_num; + /* current flow num */ + uint32_t flow_num; + /* item array size */ + uint32_t max_item_num; + /* flow array size */ + uint32_t max_flow_num; +}; + +/** + * This function creates a TCP/IPv6 reassembly table. + * + * @param socket_id + * Socket index for allocating the TCP/IPv6 reassemble table + * @param max_flow_num + * The maximum number of flows in the TCP/IPv6 GRO table + * @param max_item_per_flow + * The maximum number of packets per flow + * + * @return + * - Return the table pointer on success. + * - Return NULL on failure. + */ +void *gro_tcp6_tbl_create(uint16_t socket_id, + uint16_t max_flow_num, + uint16_t max_item_per_flow); + +/** + * This function destroys a TCP/IPv6 reassembly table. + * + * @param tbl + * Pointer pointing to the TCP/IPv6 reassembly table. + */ +void gro_tcp6_tbl_destroy(void *tbl); + +/** + * This function merges a TCP/IPv6 packet. It doesn't process the packet, + * which has SYN, FIN, RST, PSH, CWR, ECE or URG set, or doesn't have + * payload. + * + * This function doesn't check if the packet has correct checksums and + * doesn't re-calculate checksums for the merged packet. Additionally, + * it assumes the packets are complete (i.e., MF==0 && frag_off==0), + * when IP fragmentation is possible (i.e., DF==0). It returns the + * packet, if the packet has invalid parameters (e.g. SYN bit is set) + * or there is no available space in the table. + * + * @param pkt + * Packet to reassemble + * @param tbl + * Pointer pointing to the TCP/IPv6 reassembly table + * @start_time + * The time when the packet is inserted into the table + * + * @return + * - Return a positive value if the packet is merged. + * - Return zero if the packet isn't merged but stored in the table. + * - Return a negative value for invalid parameters or no available + * space in the table. + */ +int32_t gro_tcp6_reassemble(struct rte_mbuf *pkt, + struct gro_tcp6_tbl *tbl, + uint64_t start_time); + +/** + * This function flushes timeout packets in a TCP/IPv6 reassembly table, + * and without updating checksums. + * + * @param tbl + * TCP/IPv6 reassembly table pointer + * @param flush_timestamp + * Flush packets which are inserted into the table before or at the + * flush_timestamp. + * @param out + * Pointer array used to keep flushed packets + * @param nb_out + * The element number in 'out'. It also determines the maximum number of + * packets that can be flushed finally. + * + * @return + * The number of flushed packets + */ +uint16_t gro_tcp6_tbl_timeout_flush(struct gro_tcp6_tbl *tbl, + uint64_t flush_timestamp, + struct rte_mbuf **out, + uint16_t nb_out); + +/** + * This function returns the number of the packets in a TCP/IPv6 + * reassembly table. + * + * @param tbl + * TCP/IPv6 reassembly table pointer + * + * @return + * The number of packets in the table + */ +uint32_t gro_tcp6_tbl_pkt_count(void *tbl); + +/* + * Check if two TCP/IPv6 packets belong to the same flow. + */ +static inline int +is_same_tcp6_flow(struct tcp6_flow_key *k1, struct tcp6_flow_key *k2) +{ + rte_be32_t vtc_flow_diff; + + if (memcmp(&k1->src_addr, &k2->src_addr, 16)) + return 0; + if (memcmp(&k1->dst_addr, &k2->dst_addr, 16)) + return 0; + /* + * IP version (4) Traffic Class (8) Flow Label (20) + * All fields except Traffic class should be same + */ + vtc_flow_diff = (k1->vtc_flow ^ k2->vtc_flow); + if (vtc_flow_diff & htonl(0xF00FFFFF)) + return 0; + + return is_same_common_tcp_key(&k1->cmn_key, &k2->cmn_key); +} + +#endif diff --git a/lib/gro/meson.build b/lib/gro/meson.build index e4fa2958bd..dbce05220d 100644 --- a/lib/gro/meson.build +++ b/lib/gro/meson.build @@ -4,6 +4,7 @@ sources = files( 'rte_gro.c', 'gro_tcp4.c', + 'gro_tcp6.c', 'gro_udp4.c', 'gro_vxlan_tcp4.c', 'gro_vxlan_udp4.c', diff --git a/lib/gro/rte_gro.c b/lib/gro/rte_gro.c index ac3d1cdc94..d824eebd93 100644 --- a/lib/gro/rte_gro.c +++ b/lib/gro/rte_gro.c @@ -8,6 +8,7 @@ #include "rte_gro.h" #include "gro_tcp4.h" +#include "gro_tcp6.h" #include "gro_udp4.h" #include "gro_vxlan_tcp4.h" #include "gro_vxlan_udp4.h" @@ -20,14 +21,16 @@ typedef uint32_t (*gro_tbl_pkt_count_fn)(void *tbl); static gro_tbl_create_fn tbl_create_fn[RTE_GRO_TYPE_MAX_NUM] = { gro_tcp4_tbl_create, gro_vxlan_tcp4_tbl_create, - gro_udp4_tbl_create, gro_vxlan_udp4_tbl_create, NULL}; + gro_udp4_tbl_create, gro_vxlan_udp4_tbl_create, gro_tcp6_tbl_create, NULL}; static gro_tbl_destroy_fn tbl_destroy_fn[RTE_GRO_TYPE_MAX_NUM] = { gro_tcp4_tbl_destroy, gro_vxlan_tcp4_tbl_destroy, gro_udp4_tbl_destroy, gro_vxlan_udp4_tbl_destroy, + gro_tcp6_tbl_destroy, NULL}; static gro_tbl_pkt_count_fn tbl_pkt_count_fn[RTE_GRO_TYPE_MAX_NUM] = { gro_tcp4_tbl_pkt_count, gro_vxlan_tcp4_tbl_pkt_count, gro_udp4_tbl_pkt_count, gro_vxlan_udp4_tbl_pkt_count, + gro_tcp6_tbl_pkt_count, NULL}; #define IS_IPV4_TCP_PKT(ptype) (RTE_ETH_IS_IPV4_HDR(ptype) && \ @@ -35,6 +38,12 @@ static gro_tbl_pkt_count_fn tbl_pkt_count_fn[RTE_GRO_TYPE_MAX_NUM] = { ((ptype & RTE_PTYPE_L4_FRAG) != RTE_PTYPE_L4_FRAG) && \ (RTE_ETH_IS_TUNNEL_PKT(ptype) == 0)) +/* GRO with extension headers is not supported */ +#define IS_IPV6_TCP_PKT(ptype) (RTE_ETH_IS_IPV6_HDR(ptype) && \ + ((ptype & RTE_PTYPE_L4_TCP) == RTE_PTYPE_L4_TCP) && \ + ((ptype & RTE_PTYPE_L4_FRAG) != RTE_PTYPE_L4_FRAG) && \ + (RTE_ETH_IS_TUNNEL_PKT(ptype) == 0)) + #define IS_IPV4_UDP_PKT(ptype) (RTE_ETH_IS_IPV4_HDR(ptype) && \ ((ptype & RTE_PTYPE_L4_UDP) == RTE_PTYPE_L4_UDP) && \ (RTE_ETH_IS_TUNNEL_PKT(ptype) == 0)) @@ -149,6 +158,10 @@ rte_gro_reassemble_burst(struct rte_mbuf **pkts, struct gro_tcp4_flow tcp_flows[RTE_GRO_MAX_BURST_ITEM_NUM]; struct gro_tcp_item tcp_items[RTE_GRO_MAX_BURST_ITEM_NUM] = {{0} }; + struct gro_tcp6_tbl tcp6_tbl; + struct gro_tcp6_flow tcp6_flows[RTE_GRO_MAX_BURST_ITEM_NUM]; + struct gro_tcp_item tcp6_items[RTE_GRO_MAX_BURST_ITEM_NUM] = {{0} }; + /* allocate a reassembly table for UDP/IPv4 GRO */ struct gro_udp4_tbl udp_tbl; struct gro_udp4_flow udp_flows[RTE_GRO_MAX_BURST_ITEM_NUM]; @@ -171,10 +184,10 @@ rte_gro_reassemble_burst(struct rte_mbuf **pkts, int32_t ret; uint16_t i, unprocess_num = 0, nb_after_gro = nb_pkts; uint8_t do_tcp4_gro = 0, do_vxlan_tcp_gro = 0, do_udp4_gro = 0, - do_vxlan_udp_gro = 0; + do_vxlan_udp_gro = 0, do_tcp6_gro = 0; if (unlikely((param->gro_types & (RTE_GRO_IPV4_VXLAN_TCP_IPV4 | - RTE_GRO_TCP_IPV4 | + RTE_GRO_TCP_IPV4 | RTE_GRO_TCP_IPV6 | RTE_GRO_IPV4_VXLAN_UDP_IPV4 | RTE_GRO_UDP_IPV4)) == 0)) return nb_pkts; @@ -236,6 +249,18 @@ rte_gro_reassemble_burst(struct rte_mbuf **pkts, do_udp4_gro = 1; } + if (param->gro_types & RTE_GRO_TCP_IPV6) { + for (i = 0; i < item_num; i++) + tcp6_flows[i].start_index = INVALID_ARRAY_INDEX; + + tcp6_tbl.flows = tcp6_flows; + tcp6_tbl.items = tcp6_items; + tcp6_tbl.flow_num = 0; + tcp6_tbl.item_num = 0; + tcp6_tbl.max_flow_num = item_num; + tcp6_tbl.max_item_num = item_num; + do_tcp6_gro = 1; + } for (i = 0; i < nb_pkts; i++) { /* @@ -276,6 +301,14 @@ rte_gro_reassemble_burst(struct rte_mbuf **pkts, nb_after_gro--; else if (ret < 0) unprocess_pkts[unprocess_num++] = pkts[i]; + } else if (IS_IPV6_TCP_PKT(pkts[i]->packet_type) && + do_tcp6_gro) { + ret = gro_tcp6_reassemble(pkts[i], &tcp6_tbl, 0); + if (ret > 0) + /* merge successfully */ + nb_after_gro--; + else if (ret < 0) + unprocess_pkts[unprocess_num++] = pkts[i]; } else unprocess_pkts[unprocess_num++] = pkts[i]; } @@ -283,9 +316,17 @@ rte_gro_reassemble_burst(struct rte_mbuf **pkts, if ((nb_after_gro < nb_pkts) || (unprocess_num < nb_pkts)) { i = 0; + /* Copy unprocessed packets */ + if (unprocess_num > 0) { + memcpy(&pkts[i], unprocess_pkts, + sizeof(struct rte_mbuf *) * + unprocess_num); + i = unprocess_num; + } + /* Flush all packets from the tables */ if (do_vxlan_tcp_gro) { - i = gro_vxlan_tcp4_tbl_timeout_flush(&vxlan_tcp_tbl, + i += gro_vxlan_tcp4_tbl_timeout_flush(&vxlan_tcp_tbl, 0, pkts, nb_pkts); } @@ -304,13 +345,11 @@ rte_gro_reassemble_burst(struct rte_mbuf **pkts, i += gro_udp4_tbl_timeout_flush(&udp_tbl, 0, &pkts[i], nb_pkts - i); } - /* Copy unprocessed packets */ - if (unprocess_num > 0) { - memcpy(&pkts[i], unprocess_pkts, - sizeof(struct rte_mbuf *) * - unprocess_num); + + if (do_tcp6_gro) { + i += gro_tcp6_tbl_timeout_flush(&tcp6_tbl, 0, + &pkts[i], nb_pkts - i); } - nb_after_gro = i + unprocess_num; } return nb_after_gro; @@ -323,13 +362,13 @@ rte_gro_reassemble(struct rte_mbuf **pkts, { struct rte_mbuf *unprocess_pkts[nb_pkts]; struct gro_ctx *gro_ctx = ctx; - void *tcp_tbl, *udp_tbl, *vxlan_tcp_tbl, *vxlan_udp_tbl; + void *tcp_tbl, *udp_tbl, *vxlan_tcp_tbl, *vxlan_udp_tbl, *tcp6_tbl; uint64_t current_time; uint16_t i, unprocess_num = 0; - uint8_t do_tcp4_gro, do_vxlan_tcp_gro, do_udp4_gro, do_vxlan_udp_gro; + uint8_t do_tcp4_gro, do_vxlan_tcp_gro, do_udp4_gro, do_vxlan_udp_gro, do_tcp6_gro; if (unlikely((gro_ctx->gro_types & (RTE_GRO_IPV4_VXLAN_TCP_IPV4 | - RTE_GRO_TCP_IPV4 | + RTE_GRO_TCP_IPV4 | RTE_GRO_TCP_IPV6 | RTE_GRO_IPV4_VXLAN_UDP_IPV4 | RTE_GRO_UDP_IPV4)) == 0)) return nb_pkts; @@ -338,6 +377,7 @@ rte_gro_reassemble(struct rte_mbuf **pkts, vxlan_tcp_tbl = gro_ctx->tbls[RTE_GRO_IPV4_VXLAN_TCP_IPV4_INDEX]; udp_tbl = gro_ctx->tbls[RTE_GRO_UDP_IPV4_INDEX]; vxlan_udp_tbl = gro_ctx->tbls[RTE_GRO_IPV4_VXLAN_UDP_IPV4_INDEX]; + tcp6_tbl = gro_ctx->tbls[RTE_GRO_TCP_IPV6_INDEX]; do_tcp4_gro = (gro_ctx->gro_types & RTE_GRO_TCP_IPV4) == RTE_GRO_TCP_IPV4; @@ -347,6 +387,7 @@ rte_gro_reassemble(struct rte_mbuf **pkts, RTE_GRO_UDP_IPV4; do_vxlan_udp_gro = (gro_ctx->gro_types & RTE_GRO_IPV4_VXLAN_UDP_IPV4) == RTE_GRO_IPV4_VXLAN_UDP_IPV4; + do_tcp6_gro = (gro_ctx->gro_types & RTE_GRO_TCP_IPV6) == RTE_GRO_TCP_IPV6; current_time = rte_rdtsc(); @@ -371,6 +412,11 @@ rte_gro_reassemble(struct rte_mbuf **pkts, if (gro_udp4_reassemble(pkts[i], udp_tbl, current_time) < 0) unprocess_pkts[unprocess_num++] = pkts[i]; + } else if (IS_IPV6_TCP_PKT(pkts[i]->packet_type) && + do_tcp6_gro) { + if (gro_tcp6_reassemble(pkts[i], tcp6_tbl, + current_time) < 0) + unprocess_pkts[unprocess_num++] = pkts[i]; } else unprocess_pkts[unprocess_num++] = pkts[i]; } @@ -426,6 +472,15 @@ rte_gro_timeout_flush(void *ctx, gro_ctx->tbls[RTE_GRO_UDP_IPV4_INDEX], flush_timestamp, &out[num], left_nb_out); + left_nb_out = max_nb_out - num; + } + + if ((gro_types & RTE_GRO_TCP_IPV6) && left_nb_out > 0) { + num += gro_tcp6_tbl_timeout_flush( + gro_ctx->tbls[RTE_GRO_TCP_IPV6_INDEX], + flush_timestamp, + &out[num], left_nb_out); + } return num; diff --git a/lib/gro/rte_gro.h b/lib/gro/rte_gro.h index 9f9ed4935a..c83dfd9ad1 100644 --- a/lib/gro/rte_gro.h +++ b/lib/gro/rte_gro.h @@ -38,6 +38,9 @@ extern "C" { #define RTE_GRO_IPV4_VXLAN_UDP_IPV4_INDEX 3 #define RTE_GRO_IPV4_VXLAN_UDP_IPV4 (1ULL << RTE_GRO_IPV4_VXLAN_UDP_IPV4_INDEX) /**< VxLAN UDP/IPv4 GRO flag. */ +#define RTE_GRO_TCP_IPV6_INDEX 4 +#define RTE_GRO_TCP_IPV6 (1ULL << RTE_GRO_TCP_IPV6_INDEX) +/**< TCP/IPv6 GRO flag. */ /** * Structure used to create GRO context objects or used to pass