Now that IP and L4 checksum offloading don't require tweaking Tx flags,
update checksum status in parts of OVS that validate checksums (in case
of unknown status).

Signed-off-by: David Marchand <david.march...@redhat.com>
---
 lib/conntrack.c         | 107 ++++++++++++++++++++++++----------------
 lib/ipf.c               |   7 ++-
 lib/netdev-native-tnl.c |  14 +++++-
 3 files changed, 82 insertions(+), 46 deletions(-)

diff --git a/lib/conntrack.c b/lib/conntrack.c
index a17be27be2..fa09eb9f7e 100644
--- a/lib/conntrack.c
+++ b/lib/conntrack.c
@@ -125,8 +125,8 @@ reverse_icmp_type(uint8_t type);
 static uint8_t
 reverse_icmp6_type(uint8_t type);
 static inline bool
-extract_l3_ipv4(struct conn_key *key, const void *data, size_t size,
-                const char **new_data, bool validate_checksum);
+extract_l3_ipv4(struct dp_packet *pkt, struct conn_key *key, const void *data,
+                size_t size, const char **new_data);
 static inline bool
 extract_l3_ipv6(struct conn_key *key, const void *data, size_t size,
                 const char **new_data);
@@ -924,8 +924,8 @@ nat_inner_packet(struct dp_packet *pkt, struct conn_key 
*key,
      * 'extract_l4_icmp()'/'extract_l4_icmp6()'. */
     if (key->dl_type == htons(ETH_TYPE_IP)) {
         inner_l3 = (char *) l4 + sizeof(struct icmp_header);
-        extract_l3_ipv4(&inner_key, inner_l3, tail - ((char *) inner_l3) - pad,
-                        &inner_l4, false);
+        extract_l3_ipv4(NULL, &inner_key, inner_l3,
+                        tail - ((char *) inner_l3) - pad, &inner_l4);
     } else {
         inner_l3 = (char *) l4 + sizeof(struct icmp6_data_header);
         extract_l3_ipv6(&inner_key, inner_l3, tail - ((char *) inner_l3) - pad,
@@ -1688,8 +1688,8 @@ clean_thread_main(void *f_)
  * used to store a pointer to the first byte after the L3 header.  'Size' is
  * the size of the packet beyond the data pointer. */
 static inline bool
-extract_l3_ipv4(struct conn_key *key, const void *data, size_t size,
-                const char **new_data, bool validate_checksum)
+extract_l3_ipv4(struct dp_packet *pkt, struct conn_key *key, const void *data,
+                size_t size, const char **new_data)
 {
     if (OVS_UNLIKELY(size < IP_HEADER_LEN)) {
         return false;
@@ -1710,12 +1710,14 @@ extract_l3_ipv4(struct conn_key *key, const void *data, 
size_t size,
         return false;
     }
 
-    if (validate_checksum) {
+    if (pkt && dp_packet_ip_checksum_unknown(pkt)) {
         COVERAGE_INC(conntrack_l3csum_checked);
         if (csum(data, ip_len)) {
             COVERAGE_INC(conntrack_l3csum_err);
+            dp_packet_ip_checksum_set_bad(pkt);
             return false;
         }
+        dp_packet_ip_checksum_set_good(pkt);
     }
 
     if (new_data) {
@@ -1811,8 +1813,8 @@ sctp_checksum_valid(const void *data, size_t size)
 }
 
 static inline bool
-check_l4_tcp(const struct conn_key *key, const void *data, size_t size,
-             const void *l3, bool validate_checksum)
+check_l4_tcp(struct dp_packet *pkt, const struct conn_key *key,
+             const void *data, size_t size, const void *l3)
 {
     const struct tcp_header *tcp = data;
     if (size < sizeof *tcp) {
@@ -1824,12 +1826,20 @@ check_l4_tcp(const struct conn_key *key, const void 
*data, size_t size,
         return false;
     }
 
-    return validate_checksum ? checksum_valid(key, data, size, l3) : true;
+    if (pkt && dp_packet_l4_checksum_unknown(pkt)) {
+        if (!checksum_valid(key, data, size, l3)) {
+            dp_packet_l4_checksum_set_bad(pkt);
+            return false;
+        }
+        dp_packet_l4_checksum_set_good(pkt);
+        dp_packet_l4_proto_set_tcp(pkt);
+    }
+    return true;
 }
 
 static inline bool
-check_l4_udp(const struct conn_key *key, const void *data, size_t size,
-             const void *l3, bool validate_checksum)
+check_l4_udp(struct dp_packet *pkt, const struct conn_key *key,
+             const void *data, size_t size, const void *l3)
 {
     const struct udp_header *udp = data;
     if (size < sizeof *udp) {
@@ -1842,8 +1852,16 @@ check_l4_udp(const struct conn_key *key, const void 
*data, size_t size,
     }
 
     /* Validation must be skipped if checksum is 0 on IPv4 packets */
-    return (udp->udp_csum == 0 && key->dl_type == htons(ETH_TYPE_IP))
-           || (validate_checksum ? checksum_valid(key, data, size, l3) : true);
+    if (!(udp->udp_csum == 0 && key->dl_type == htons(ETH_TYPE_IP))
+        && (pkt && dp_packet_l4_checksum_unknown(pkt))) {
+        if (!checksum_valid(key, data, size, l3)) {
+            dp_packet_l4_checksum_set_bad(pkt);
+            return false;
+        }
+        dp_packet_l4_checksum_set_good(pkt);
+        dp_packet_l4_proto_set_udp(pkt);
+    }
+    return true;
 }
 
 static inline bool
@@ -1878,19 +1896,27 @@ sctp_check_len(const struct sctp_header *sh, size_t 
size)
 }
 
 static inline bool
-check_l4_sctp(const void *data, size_t size, bool validate_checksum)
+check_l4_sctp(struct dp_packet *pkt, const void *data, size_t size)
 {
     if (OVS_UNLIKELY(!sctp_check_len(data, size))) {
         return false;
     }
 
-    return validate_checksum ? sctp_checksum_valid(data, size) : true;
+    if (pkt && dp_packet_l4_checksum_unknown(pkt)) {
+        if (!sctp_checksum_valid(data, size)) {
+            dp_packet_l4_checksum_set_bad(pkt);
+            return false;
+        }
+        dp_packet_l4_checksum_set_good(pkt);
+        dp_packet_l4_proto_set_sctp(pkt);
+    }
+    return true;
 }
 
 static inline bool
-check_l4_icmp(const void *data, size_t size, bool validate_checksum)
+check_l4_icmp(struct dp_packet *pkt, const void *data, size_t size)
 {
-    if (validate_checksum) {
+    if (pkt) {
         COVERAGE_INC(conntrack_l4csum_checked);
         if (csum(data, size)) {
             COVERAGE_INC(conntrack_l4csum_err);
@@ -1902,10 +1928,10 @@ check_l4_icmp(const void *data, size_t size, bool 
validate_checksum)
 }
 
 static inline bool
-check_l4_icmp6(const struct conn_key *key, const void *data, size_t size,
-               const void *l3, bool validate_checksum)
+check_l4_icmp6(struct dp_packet *pkt, const struct conn_key *key,
+               const void *data, size_t size, const void *l3)
 {
-    return validate_checksum ? checksum_valid(key, data, size, l3) : true;
+    return pkt ? checksum_valid(key, data, size, l3) : true;
 }
 
 static inline bool
@@ -1955,9 +1981,9 @@ extract_l4_sctp(struct conn_key *key, const void *data, 
size_t size,
     return key->src.port && key->dst.port;
 }
 
-static inline bool extract_l4(struct conn_key *key, const void *data,
-                              size_t size, bool *related, const void *l3,
-                              bool validate_checksum, size_t *chk_len);
+static inline bool extract_l4(struct dp_packet *pkt, struct conn_key *key,
+                              const void *data, size_t size, bool *related,
+                              const void *l3, size_t *chk_len);
 
 static uint8_t
 reverse_icmp_type(uint8_t type)
@@ -2030,7 +2056,7 @@ extract_l4_icmp(struct conn_key *key, const void *data, 
size_t size,
 
         memset(&inner_key, 0, sizeof inner_key);
         inner_key.dl_type = htons(ETH_TYPE_IP);
-        bool ok = extract_l3_ipv4(&inner_key, l3, tail - l3, &l4, false);
+        bool ok = extract_l3_ipv4(NULL, &inner_key, l3, tail - l3, &l4);
         if (!ok) {
             return false;
         }
@@ -2044,7 +2070,7 @@ extract_l4_icmp(struct conn_key *key, const void *data, 
size_t size,
         key->nw_proto = inner_key.nw_proto;
         size_t check_len = ICMP_ERROR_DATA_L4_LEN;
 
-        ok = extract_l4(key, l4, tail - l4, NULL, l3, false, &check_len);
+        ok = extract_l4(NULL, key, l4, tail - l4, NULL, l3, &check_len);
         if (ok) {
             conn_key_reverse(key);
             *related = true;
@@ -2131,7 +2157,7 @@ extract_l4_icmp6(struct conn_key *key, const void *data, 
size_t size,
         key->dst = inner_key.dst;
         key->nw_proto = inner_key.nw_proto;
 
-        ok = extract_l4(key, l4, tail - l4, NULL, l3, false, NULL);
+        ok = extract_l4(NULL, key, l4, tail - l4, NULL, l3, NULL);
         if (ok) {
             conn_key_reverse(key);
             *related = true;
@@ -2159,28 +2185,25 @@ extract_l4_icmp6(struct conn_key *key, const void 
*data, size_t size,
  * in an ICMP error.  In this case, we skip the checksum and some length
  * validations. */
 static inline bool
-extract_l4(struct conn_key *key, const void *data, size_t size, bool *related,
-           const void *l3, bool validate_checksum, size_t *chk_len)
+extract_l4(struct dp_packet *pkt, struct conn_key *key, const void *data,
+           size_t size, bool *related, const void *l3, size_t *chk_len)
 {
     if (key->nw_proto == IPPROTO_TCP) {
-        return (!related || check_l4_tcp(key, data, size, l3,
-                validate_checksum))
+        return (!related || check_l4_tcp(pkt, key, data, size, l3))
                && extract_l4_tcp(key, data, size, chk_len);
     } else if (key->nw_proto == IPPROTO_UDP) {
-        return (!related || check_l4_udp(key, data, size, l3,
-                validate_checksum))
+        return (!related || check_l4_udp(pkt, key, data, size, l3))
                && extract_l4_udp(key, data, size, chk_len);
     } else if (key->nw_proto == IPPROTO_SCTP) {
-        return (!related || check_l4_sctp(data, size, validate_checksum))
+        return (!related || check_l4_sctp(pkt, data, size))
                && extract_l4_sctp(key, data, size, chk_len);
     } else if (key->dl_type == htons(ETH_TYPE_IP)
                && key->nw_proto == IPPROTO_ICMP) {
-        return (!related || check_l4_icmp(data, size, validate_checksum))
+        return (!related || check_l4_icmp(pkt, data, size))
                && extract_l4_icmp(key, data, size, related, chk_len);
     } else if (key->dl_type == htons(ETH_TYPE_IPV6)
                && key->nw_proto == IPPROTO_ICMPV6) {
-        return (!related || check_l4_icmp6(key, data, size, l3,
-                validate_checksum))
+        return (!related || check_l4_icmp6(pkt, key, data, size, l3))
                && extract_l4_icmp6(key, data, size, related);
     }
 
@@ -2246,8 +2269,8 @@ conn_key_extract(struct conntrack *ct, struct dp_packet 
*pkt, ovs_be16 dl_type,
         } else {
             /* Validate the checksum only when hwol is not supported and the
              * packet's checksum status is not known. */
-            ok = extract_l3_ipv4(&ctx->key, l3, dp_packet_l3_size(pkt), NULL,
-                                 dp_packet_ip_checksum_unknown(pkt));
+            ok = extract_l3_ipv4(pkt, &ctx->key, l3, dp_packet_l3_size(pkt),
+                                 NULL);
         }
     } else if (ctx->key.dl_type == htons(ETH_TYPE_IPV6)) {
         ok = extract_l3_ipv6(&ctx->key, l3, dp_packet_l3_size(pkt), NULL);
@@ -2258,10 +2281,8 @@ conn_key_extract(struct conntrack *ct, struct dp_packet 
*pkt, ovs_be16 dl_type,
     if (ok) {
         if (!dp_packet_l4_checksum_bad(pkt)) {
             /* Validate the checksum only when hwol is not supported. */
-            if (extract_l4(&ctx->key, l4, dp_packet_l4_size(pkt),
-                           &ctx->icmp_related, l3,
-                           dp_packet_l4_checksum_unknown(pkt),
-                           NULL)) {
+            if (extract_l4(pkt, &ctx->key, l4, dp_packet_l4_size(pkt),
+                           &ctx->icmp_related, l3, NULL)) {
                 ctx->hash = conn_key_hash(&ctx->key, ct->hash_basis);
                 return true;
             }
diff --git a/lib/ipf.c b/lib/ipf.c
index 0b7ca5bd28..6670ef5a99 100644
--- a/lib/ipf.c
+++ b/lib/ipf.c
@@ -618,7 +618,12 @@ ipf_is_valid_v4_frag(struct ipf *ipf, struct dp_packet 
*pkt)
     bool bad_csum = dp_packet_ip_checksum_bad(pkt);
     if (OVS_UNLIKELY(!bad_csum && dp_packet_ip_checksum_unknown(pkt))) {
         COVERAGE_INC(ipf_l3csum_checked);
-        bad_csum = csum(l3, ip_hdr_len);
+        if (csum(l3, ip_hdr_len)) {
+            dp_packet_ip_checksum_set_bad(pkt);
+            bad_csum = true;
+        } else {
+            dp_packet_ip_checksum_set_good(pkt);
+        }
     }
     if (OVS_UNLIKELY(bad_csum)) {
         COVERAGE_INC(ipf_l3csum_err);
diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c
index e070088259..86e46b173e 100644
--- a/lib/netdev-native-tnl.c
+++ b/lib/netdev-native-tnl.c
@@ -120,7 +120,12 @@ ip_extract_tnl_md(struct dp_packet *packet, struct 
flow_tnl *tnl,
          * csum already checked. In this case, skip the check. */
         if (OVS_UNLIKELY(!bad_csum && dp_packet_ip_checksum_unknown(packet))) {
             COVERAGE_INC(native_tnl_l3csum_checked);
-            bad_csum = csum(ip, IP_IHL(ip->ip_ihl_ver) * 4);
+            if (csum(ip, IP_IHL(ip->ip_ihl_ver) * 4)) {
+                dp_packet_ip_checksum_set_bad(packet);
+                bad_csum = true;
+            } else {
+                dp_packet_ip_checksum_set_good(packet);
+            }
         }
         if (OVS_UNLIKELY(bad_csum)) {
             COVERAGE_INC(native_tnl_l3csum_err);
@@ -246,7 +251,12 @@ udp_extract_tnl_md(struct dp_packet *packet, struct 
flow_tnl *tnl,
                                  ((const unsigned char *)udp -
                                   (const unsigned char *)dp_packet_eth(packet)
                                  ));
-            bad_csum = csum_finish(csum);
+            if (csum_finish(csum)) {
+                dp_packet_l4_checksum_set_bad(packet);
+                bad_csum = true;
+            } else {
+                dp_packet_l4_checksum_set_good(packet);
+            }
         }
         if (OVS_UNLIKELY(bad_csum)) {
             COVERAGE_INC(native_tnl_l4csum_err);
-- 
2.49.0

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to