We encountered a scenario where, if the received packet contains
padding bytes, and we then add Geneve tunnel encapsulation without
carrying the padding bytes, it results in checksum errors when sending
out.We need to remove the L2 pad immediately after receiving the
packet, rather than carrying it through the encapsulation.

For example, this type of packet format:
0000   06 6c 6a 71 e1 d3 6c e2 d3 8b ea 24 81 00 03 e9
0010   08 00 45 00 00 28 9d e5 40 00 3b 06 6e 64 0a 6f
0020   05 14 0a fe 19 06 01 bb 22 ae 59 c0 8c 61 8e 26
0030   14 e3 50 10 00 7f ce 3a 00 00 00 00 9e 38 cf 64

Fixes: 084c8087292c ("userspace: Support VXLAN and GENEVE TSO.")
Reported-by: Jun Wang <[email protected]>
Signed-off-by: Jun Wang <[email protected]>
---
v2: Remove the L2 pad immediately after receiving the packet.
---
 lib/dp-packet.h   | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/netdev-dpdk.c |  1 +
 2 files changed, 70 insertions(+)

diff --git a/lib/dp-packet.h b/lib/dp-packet.h
index a75b1c5..c3a2f43 100644
--- a/lib/dp-packet.h
+++ b/lib/dp-packet.h
@@ -726,6 +726,50 @@ dp_packet_set_tso_segsz(struct dp_packet *p, uint16_t s)
 {
     p->mbuf.tso_segsz = s;
 }
+
+static inline uint16_t
+dp_packet_get_total_length(struct dp_packet *p)
+{
+    struct rte_ether_hdr *eth_hdr;
+    struct rte_vlan_hdr *vlan_hdr;
+    struct rte_ipv4_hdr *ipv4_hdr;
+    struct rte_ipv6_hdr *ipv6_hdr;
+    uint16_t ether_type;
+    void *packet_data;
+    uint8_t vlan_count = 0;
+
+    packet_data = dp_packet_data(p);
+    eth_hdr = CONST_CAST(struct rte_ether_hdr *, packet_data);
+    ether_type = rte_be_to_cpu_16(eth_hdr->ether_type);
+    packet_data = CONST_CAST(char *, packet_data)
+                  + sizeof(struct rte_ether_hdr);
+
+    while (ether_type == RTE_ETHER_TYPE_VLAN) {
+        vlan_hdr = CONST_CAST(struct rte_vlan_hdr *, packet_data);
+        ether_type = rte_be_to_cpu_16(vlan_hdr->eth_proto);
+        packet_data = CONST_CAST(char *, packet_data)
+                     + sizeof(struct rte_vlan_hdr);
+        vlan_count++;
+    }
+
+    switch (ether_type) {
+    case RTE_ETHER_TYPE_IPV4:
+        ipv4_hdr = CONST_CAST(struct rte_ipv4_hdr *, packet_data);
+        return (rte_be_to_cpu_16(ipv4_hdr->total_length)
+                + sizeof(struct rte_ether_hdr)
+                + (vlan_count * sizeof(struct rte_vlan_hdr)));
+
+    case RTE_ETHER_TYPE_IPV6:
+        ipv6_hdr = CONST_CAST(struct rte_ipv6_hdr *, packet_data);
+        return (rte_be_to_cpu_16(ipv6_hdr->payload_len)
+                + sizeof(struct rte_ipv6_hdr)
+                + sizeof(struct rte_ether_hdr)
+                + (vlan_count * sizeof(struct rte_vlan_hdr)));
+
+    default:
+        return UINT16_MAX;
+    }
+}
 #else /* DPDK_NETDEV */
 
 static inline void
@@ -793,6 +837,12 @@ dp_packet_set_tso_segsz(struct dp_packet *p, uint16_t s)
 {
     p->tso_segsz = s;
 }
+
+static inline uint16_t
+dp_packet_get_total_length(struct dp_packet *b OVS_UNUSED)
+{
+    return UINT16_MAX;
+}
 #endif /* DPDK_NETDEV */
 
 static inline void
@@ -1011,6 +1061,25 @@ dp_packet_batch_reset_cutlen(struct dp_packet_batch 
*batch)
     }
 }
 
+static inline void
+dp_packet_cut_l2_pad(struct dp_packet_batch *batch)
+{
+    struct dp_packet *packet;
+    int total_len;
+    int padding_length;
+
+    DP_PACKET_BATCH_FOR_EACH (i, packet, batch) {
+        if (dp_packet_size(packet) == 64) {
+            total_len = dp_packet_get_total_length(packet);
+            if (UINT16_MAX != total_len) {
+                padding_length = dp_packet_size(packet) - total_len;
+                dp_packet_set_size(packet, dp_packet_size(packet)
+                                   - padding_length);
+            }
+        }
+    }
+}
+
 /* Returns the RSS hash of the packet 'p'.  Note that the returned value is
  * correct only if 'dp_packet_rss_valid(p)' returns 'true'. */
 static inline uint32_t
diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index 02cef6e..310533d 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -2982,6 +2982,7 @@ netdev_dpdk_rxq_recv(struct netdev_rxq *rxq, struct 
dp_packet_batch *batch,
 
     batch->count = nb_rx;
     dp_packet_batch_init_packet_fields(batch);
+    dp_packet_cut_l2_pad(batch);
 
     if (qfill) {
         if (nb_rx == NETDEV_MAX_BURST) {
-- 
1.8.3.1



_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to