liqinhuixm commented on code in PR #12493:
URL: https://github.com/apache/nuttx/pull/12493#discussion_r1639186751


##########
include/nuttx/net/offload.h:
##########
@@ -0,0 +1,474 @@
+/****************************************************************************
+ * include/nuttx/net/offload.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __INCLUDE_NUTTX_NET_OFFLOAD_H
+#define __INCLUDE_NUTTX_NET_OFFLOAD_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <nuttx/mm/iob.h>
+
+#ifdef CONFIG_NET_OFFLOAD
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define TCP_CWR 0x80
+#define TCP_ECE 0x40
+
+#define MAX_GSO_SEGS 17
+
+#define IOBDATA_OFFSET(iob, offset) ((FAR void *)(IOB_DATA(iob) + (offset)))
+#define ETHHDR(iob)  ((FAR struct eth_hdr_s *) \
+                   ((FAR uint8_t *)IOBDATA_OFFSET(iob, 0) - ETH_HDRLEN))
+
+#define IPV4HDR(iob) ((FAR struct ipv4_hdr_s *)IOBDATA_OFFSET(iob, 0))
+#define IPV6HDR(iob) ((FAR struct ipv6_hdr_s *)IOBDATA_OFFSET(iob, 0))
+
+/* ip_hdrlen: IPv4_HDRLEN, IPv6_HDRLEN */
+
+#define UDPHDR(iob, ip_hdrlen) ((FAR struct udp_hdr_s *) \
+                                 IOBDATA_OFFSET(iob, ip_hdrlen))
+#define TCPHDR(iob, ip_hdrlen) ((FAR struct tcp_hdr_s *) \
+                                 IOBDATA_OFFSET(iob, ip_hdrlen))
+
+#define GET_IPHDRLEN(pkt) \
+  (PKT_GSOINFO(pkt)->type == ETHTYPE_IP ? IPv4_HDRLEN : IPv6_HDRLEN)
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+struct gso_cb
+{
+  union
+  {
+    int             mac_offset;
+    int             data_offset;
+  };
+  uint16_t          type;        /* for L3 IPv4/IPv6 */
+  uint16_t          protocol;    /* for L4 TCP/UDP */
+  uint32_t          csum;
+  uint16_t          csum_start;
+
+  uint8_t           is_first:1;
+  uint8_t           is_ipv6:1;
+  uint8_t           is_fwd:1;
+  uint8_t           tx_flags;
+  uint16_t          gso_size;
+  uint16_t          gso_segs;
+  uint32_t          gso_type;
+  FAR struct iob_s *seg_list;
+  uint8_t           segs_num;
+};
+
+#define PKT_GSOINFO(pkt) (&(pkt->gso_info))
+
+enum GSO_TYPE_E
+{
+    PKT_GSO_TCPV4 = 1 << 0,
+    PKT_GSO_TCPV6 = 1 << 1,
+    PKT_GSO_UDPV4 = 1 << 2,
+    PKT_GSO_UDPV6 = 1 << 3,
+};
+
+struct gro_cb
+{
+  union
+  {
+    int             mac_offset;
+    int             data_offset;
+  };
+
+  uint8_t           is_first:1;
+  uint8_t           is_ipv6:1;
+  uint8_t           rx_flags;
+  uint16_t          gro_size;
+  uint8_t           segs_count;
+  uint16_t          proto;        /* tcp udp */
+  FAR struct iob_s *seg_list;     /* maybe use io_flink */
+};
+
+#define PKT_GROINFO(pkt) (&(pkt->gro_info))
+
+/****************************************************************************
+ * External structure Declaration
+ ****************************************************************************/
+
+struct net_driver_s; /* Forward reference */
+
+/****************************************************************************
+ * Name: devif_get_max_pktsize
+ *
+ * Description:
+ *   Get the maximum packet size value.
+ *
+ * Input Parameters:
+ *    dev -  The structure of the network driver.
+ *
+ * Returned Value:
+ *   The maximum packet size.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_GSO
+uint16_t devif_get_max_pktsize(FAR struct net_driver_s *dev);
+
+/****************************************************************************
+ * Name: netdev_enable_gso
+ *
+ * Description:
+ *   Enable the GSO function for the dev.
+ *   Set the features and GSO-related maximum value.
+ *
+ * Input Parameters:
+ *    dev -  The structure of the network driver that enables the GSO
+ *           function.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void netdev_enable_gso(FAR struct net_driver_s *dev);
+
+/****************************************************************************
+ * Name: devif_needs_gso
+ *
+ * Description:
+ *   Check whether the packet needs to be segmented.
+ *
+ * Input Parameters:
+ *    pkt  - the packet to be sent by the NIC driver.
+ *    features  - the features are supported by the target dev of the packet.
+ *
+ * Returned Value:
+ *    The false indicates that the packet does not to be divided.
+ *    The true indicates that the packet needs to be divided.
+ *
+ ****************************************************************************/
+
+bool devif_needs_gso(FAR struct iob_s *pkt, int features);
+
+/****************************************************************************
+ * Name: devif_gso_segment
+ *
+ * Description:
+ *   Divide the packet into multiple packets based on the features and
+ *   the GSO information of the packet.
+ *
+ * Input Parameters:
+ *   pkt  - the packet to be sent by the NIC driver.
+ *   features  - the features are supported by the target dev of the packet.
+ *
+ * Returned Value:
+ *   The NULL indicates that the devision is failure.
+ *   The segs is the head of the multiple packets.
+ *
+ ****************************************************************************/
+
+FAR struct iob_s *devif_gso_segment(FAR struct iob_s *pkt,
+                                    uint32_t features);
+
+/****************************************************************************
+ * Name: devif_gso_list_free
+ *
+ * Description:
+ *   Free the packet allocated by pkt_segment and
+ *   clear the GSO information of the fisrt packet.
+ *
+ * Input Parameters:
+ *    pkt  - The GSO packets includes the segments list.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void devif_gso_list_free(FAR struct iob_s *pkt);
+
+/****************************************************************************
+ * Name: pkt_segment
+ *
+ * Description:
+ *   Segment the packet to be divided, and add the header information for all
+ *   the segments.
+ *
+ * Input Parameters:
+ *   pkt  - the packet needs to be divided.
+ *   features  - the features are supported by the target dev of the packet.
+ *
+ * Returned Value:
+ *   The NULL indicates that the devision is failure.
+ *   The segs is the head of the multiple packets.
+ *
+ ****************************************************************************/
+
+FAR struct iob_s *pkt_segment(FAR struct iob_s *pkt, uint32_t features);
+
+/****************************************************************************
+ * Name: update_ipheader_length
+ *
+ * Description:
+ *    Update the (ipv4/ipv6) ipheader length based on the pkt->io_pktlen.
+ *
+ * Input Parameters:
+ *
+ *   pkt  - The data iob structure.
+ *   type  - The type of the packet.
+ *
+ ****************************************************************************/
+
+void update_ipheader_length(FAR struct iob_s *pkt, int type);

Review Comment:
   rename to inet_update_iphdr_len



##########
net/devif/devif_offload.c:
##########
@@ -0,0 +1,653 @@
+/****************************************************************************
+ * net/devif/devif_offload.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <nuttx/net/netdev.h>
+#include <nuttx/net/ethernet.h>
+#include <nuttx/mm/iob.h>
+#include <nuttx/net/ip.h>
+#include <nuttx/net/tcp.h>
+#include <nuttx/net/udp.h>
+#include <nuttx/net/offload.h>
+
+#include "devif/devif.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
+
+/****************************************************************************
+ * External Function Prototypes
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv4
+FAR struct iob_s *inet_gso_segment(FAR struct iob_s *pkt, uint32_t features);
+#endif
+#ifdef CONFIG_NET_IPv6
+FAR struct iob_s *ipv6_gso_segment(FAR struct iob_s *pkt, uint32_t features);
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: pkt_segment
+ *
+ * Description:
+ *   Segment the packet to be divided, and add the header information for all
+ *   the segments.
+ *
+ * Input Parameters:
+ *   pkt  - the packet needs to be divided.
+ *   features  - the features are supported by the target dev of the packet.
+ *
+ * Returned Value:
+ *   The NULL indicates that the devision is failure.
+ *   The segs is the head of the multiple packets.
+ *
+ ****************************************************************************/
+
+FAR struct iob_s *pkt_segment(FAR struct iob_s *pkt, uint32_t features)
+{
+  FAR struct iob_s *segs;
+  FAR struct iob_s *tmp = NULL;
+  FAR struct iob_s *new_pkt = NULL;
+  int data_len;
+  bool need_alloc = true;
+  uint32_t mss;
+  uint16_t payload_len;
+  uint16_t size;
+  int segs_num = 0;
+  uint32_t header_len = PKT_GSOINFO(pkt)->data_offset;
+
+  /* check */
+
+  data_len = pkt->io_pktlen - header_len;
+
+  if (PKT_GSOINFO(pkt)->is_fwd == true)
+    {
+      /* The MTU is saved during forwarding, and the gso_size can be
+       * calculated based on the MTU value.
+       */
+
+      PKT_GSOINFO(pkt)->gso_size -= header_len;
+
+      if (PKT_GSOINFO(pkt)->gso_size == PKT_GROINFO(pkt)->gro_size)
+        {
+          need_alloc = false;
+        }
+    }
+
+  if (pkt->io_len == PKT_GSOINFO(pkt)->gso_size + header_len)
+    {
+      need_alloc = false;
+    }
+
+  mss = PKT_GSOINFO(pkt)->gso_size;
+  size = mss + header_len + CONFIG_NET_LL_GUARDSIZE;
+
+  if (data_len < mss)
+    {
+      return pkt;
+    }
+
+  if (CONFIG_IOB_BUFSIZE < mss)
+    {
+      nerr("CONFIG_IOB_BUFFERSIZE is smaller than mss.");
+      return NULL;
+    }
+
+  if (MAX_GSO_SEGS < PKT_GSOINFO(pkt)->gso_segs)
+    {
+      nerr("MAX_GSO_SEGS is smaller than gso_segs.");
+      return NULL;
+    }
+
+  /* Recalculate the gso segments. */
+
+  PKT_GSOINFO(pkt)->gso_segs = DIV_ROUND_UP(data_len, mss);
+
+  /* loop segment packet data and copy the header */
+
+  for (segs = NULL; segs_num < PKT_GSOINFO(pkt)->gso_segs;
+       data_len -= mss, segs_num++)
+    {
+      /* 1. create segment */
+
+      if (need_alloc == false)
+        {
+          /* The first segment. */
+
+          if (tmp == NULL)
+            {
+              tmp = pkt;
+              segs = pkt;
+            }
+          else
+            {
+              new_pkt = tmp->io_flink;
+            }
+        }
+      else
+        {
+          /* 1.1 malloc data as iob, alloc_iob */
+
+          new_pkt = iob_alloc_dynamic(size);
+          if (new_pkt == NULL)
+            {
+              nerr("ERROR: Failed to allocate an I/O buffer.");
+              iob_free_chain(segs);
+              return NULL;
+            }
+
+          new_pkt->io_flink = NULL;
+        }
+
+      /* need to init the iob and gso_info */
+
+      if (new_pkt)
+        {
+          /* 1.2copy header */
+
+          memcpy(new_pkt->io_data, pkt->io_data,
+                 header_len + pkt->io_offset);
+        }
+      else
+        {
+          new_pkt = segs;
+        }
+
+      /* 1.3 copy data */
+
+      payload_len = data_len > mss ? mss : data_len;
+      if (need_alloc)
+        {
+          /* pointer to data */
+
+          new_pkt->io_offset = header_len + pkt->io_offset;
+
+          iob_copyout(new_pkt->io_data + new_pkt->io_offset, pkt,
+                      payload_len, segs_num * mss);
+        }
+
+      /* 2. update left data_len */
+
+      new_pkt->io_offset = pkt->io_offset;
+      new_pkt->io_pktlen = header_len + payload_len;
+      new_pkt->io_len = new_pkt->io_pktlen;
+
+      if (need_alloc == true)
+        {
+          PKT_GSOINFO(new_pkt)->seg_list = NULL;
+          new_pkt->io_flink = NULL;
+
+          /* The first segment. */
+
+          if (segs == NULL)
+            {
+              segs = new_pkt;
+              tmp  = new_pkt;
+              memcpy(PKT_GSOINFO(tmp), PKT_GSOINFO(pkt),
+                     sizeof(struct gso_cb));
+            }
+        }
+
+      if (tmp != new_pkt)
+        {
+          PKT_GSOINFO(tmp)->seg_list = new_pkt;
+          tmp = new_pkt;
+        }
+    }
+
+  /* Assumption that a packet uses a single iob structure. */
+
+  if (need_alloc == false)
+    {
+      tmp = segs;
+      while (tmp)
+        {
+          new_pkt = tmp->io_flink;
+          tmp->io_flink = NULL;
+          tmp = new_pkt;
+        }
+    }
+  else
+    {
+      /* free the pkt */
+
+      iob_free_chain(pkt);
+    }
+
+  return segs;
+}
+
+/****************************************************************************
+ * Name: devif_prepare_gso_segments
+ *
+ * Description:
+ *   Allocate the iob for the GSO packet, based on the size and count.
+ *
+ * Input Parameters:
+ *   size  - the sum of L3 header length, L4 header length, and gso_size.
+ *   count  - the features are supported by the target dev of the packet.
+ *
+ * Returned Value:
+ *   The NULL indicates that the allocation is failure.
+ *   The segs is the head of the multiple iob.
+ *
+ ****************************************************************************/
+
+FAR struct iob_s *devif_prepare_gso_segments(uint16_t size, uint32_t count)
+{
+  FAR struct iob_s *segs = NULL;
+  FAR struct iob_s *pkt = NULL;
+  FAR struct iob_s *tmp = NULL;
+
+  while (count--)
+    {
+      pkt = iob_alloc_dynamic(size + CONFIG_NET_LL_GUARDSIZE);
+      if (pkt == NULL)
+        {
+          nerr("ERROR: Failed to allocate an I/O buffer.");
+          iob_free_chain(segs);
+          return NULL;
+        }
+
+      memset(PKT_GSOINFO(pkt), 0, sizeof(struct gso_cb));
+      memset(PKT_GROINFO(pkt), 0, sizeof(struct gro_cb));
+
+      if (segs)
+        {
+          tmp->io_flink = pkt;
+          tmp = pkt;
+        }
+      else
+        {
+          segs = pkt;
+          tmp = segs;
+        }
+    }
+
+  return segs;
+}
+
+/****************************************************************************
+ * Name: devif_send_gso_pkt
+ *
+ * Description:
+ *   Allocate the iob for the GSO packet, based on the size and count.
+ *
+ * Input Parameters:
+ *   pkt - The packet is to be sent.
+ *   sndlen - The length of the packet.
+ *   offset - The offset of data in the iob (packet).
+ *   hdrlen - The total header length of L3 and L4 in the packet.
+ *   gso_size - The size of each pachage when pre-segment.
+ *
+ * Returned Value:
+ *   The NULL indicates that the allocation is failure.
+ *   The segs is the head of the multiple iob.
+ *
+ ****************************************************************************/
+
+FAR struct iob_s *devif_send_gso_pkt(FAR struct iob_s *pkt,
+                       unsigned int sndlen, unsigned int offset,
+                       unsigned int hdrlen, uint16_t gso_size)
+{
+  FAR struct iob_s *segs = NULL;

Review Comment:
   Done



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscr...@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org

Reply via email to