Bad packets were still being validated in software when entering
conntrack.  Trust decision taken wrt IP checksum offloading (checking
dp_packet_hwol_l3_csum_ipv4_ol()) and avoid revalidating a known
bad checksum.

While at it, add coverage counters so that checksum validation impact
can be monitored, and unit tests.

Signed-off-by: David Marchand <david.march...@redhat.com>
---
 lib/conntrack.c      |  37 +++++++----
 tests/dpif-netdev.at | 154 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 177 insertions(+), 14 deletions(-)

diff --git a/lib/conntrack.c b/lib/conntrack.c
index f4b150bee5..08823234d4 100644
--- a/lib/conntrack.c
+++ b/lib/conntrack.c
@@ -47,7 +47,9 @@
 VLOG_DEFINE_THIS_MODULE(conntrack);
 
 COVERAGE_DEFINE(conntrack_full);
+COVERAGE_DEFINE(conntrack_l3csum_checked);
 COVERAGE_DEFINE(conntrack_l3csum_err);
+COVERAGE_DEFINE(conntrack_l4csum_checked);
 COVERAGE_DEFINE(conntrack_l4csum_err);
 COVERAGE_DEFINE(conntrack_lookup_natted_miss);
 COVERAGE_DEFINE(conntrack_zone_full);
@@ -1692,9 +1694,12 @@ extract_l3_ipv4(struct conn_key *key, const void *data, 
size_t size,
         return false;
     }
 
-    if (validate_checksum && csum(data, ip_len) != 0) {
-        COVERAGE_INC(conntrack_l3csum_err);
-        return false;
+    if (validate_checksum) {
+        COVERAGE_INC(conntrack_l3csum_checked);
+        if (csum(data, ip_len)) {
+            COVERAGE_INC(conntrack_l3csum_err);
+            return false;
+        }
     }
 
     if (new_data) {
@@ -1761,6 +1766,7 @@ checksum_valid(const struct conn_key *key, const void 
*data, size_t size,
         valid = false;
     }
 
+    COVERAGE_INC(conntrack_l4csum_checked);
     if (!valid) {
         COVERAGE_INC(conntrack_l4csum_err);
     }
@@ -1773,19 +1779,19 @@ sctp_checksum_valid(const void *data, size_t size)
 {
     struct sctp_header *sctp = (struct sctp_header *) data;
     ovs_be32 rcvd_csum, csum;
-    bool ret;
 
     rcvd_csum = get_16aligned_be32(&sctp->sctp_csum);
     put_16aligned_be32(&sctp->sctp_csum, 0);
     csum = crc32c(data, size);
     put_16aligned_be32(&sctp->sctp_csum, rcvd_csum);
 
-    ret = (rcvd_csum == csum);
-    if (!ret) {
+    COVERAGE_INC(conntrack_l4csum_checked);
+    if (rcvd_csum != csum) {
         COVERAGE_INC(conntrack_l4csum_err);
+        return false;
     }
 
-    return ret;
+    return true;
 }
 
 static inline bool
@@ -1868,12 +1874,15 @@ check_l4_sctp(const void *data, size_t size, bool 
validate_checksum)
 static inline bool
 check_l4_icmp(const void *data, size_t size, bool validate_checksum)
 {
-    if (validate_checksum && csum(data, size) != 0) {
-        COVERAGE_INC(conntrack_l4csum_err);
-        return false;
-    } else {
-        return true;
+    if (validate_checksum) {
+        COVERAGE_INC(conntrack_l4csum_checked);
+        if (csum(data, size)) {
+            COVERAGE_INC(conntrack_l4csum_err);
+            return false;
+        }
     }
+
+    return true;
 }
 
 static inline bool
@@ -2222,8 +2231,8 @@ conn_key_extract(struct conntrack *ct, struct dp_packet 
*pkt, ovs_be16 dl_type,
             /* 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_hwol_is_ipv4(pkt) &&
-                                 !dp_packet_ip_checksum_good(pkt));
+                                 !dp_packet_hwol_l3_csum_ipv4_ol(pkt)
+                                 && !dp_packet_ip_checksum_good(pkt));
         }
     } else if (ctx->key.dl_type == htons(ETH_TYPE_IPV6)) {
         ok = extract_l3_ipv6(&ctx->key, l3, dp_packet_l3_size(pkt), NULL);
diff --git a/tests/dpif-netdev.at b/tests/dpif-netdev.at
index 58977b8fa1..36acd7c0bc 100644
--- a/tests/dpif-netdev.at
+++ b/tests/dpif-netdev.at
@@ -1609,6 +1609,160 @@ AT_CHECK([ovs-vsctl set Interface p1 
options:ol_l4_rx_csum_set_good=false])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+AT_SETUP([userspace offload - conntrack])
+OVS_VSWITCHD_START(
+  [add-br br1 -- set bridge br1 datapath-type=dummy -- \
+   add-port br1 p1 -- \
+       set Interface p1 type=dummy -- \
+   add-port br1 p2 -- \
+       set Interface p2 type=dummy --])
+
+AT_CHECK([ovs-appctl vlog/set netdev_dummy:file:dbg])
+
+dnl Modify the ip_dst addr to force changing the IP csum.
+AT_CHECK([ovs-ofctl add-flow br1 
'in_port=p1,ip,ct_state=-trk,actions=ct(commit,nat(dst=192.168.1.1),table=0),p2'])
+
+flow_s="\
+  eth_src=8a:bf:7e:2f:05:84,eth_dst=0a:8f:39:4f:e0:73,\
+  tcp,ip_src=192.168.123.2,ip_dst=192.168.123.1,ip_frag=no,\
+  tcp_src=54392,tcp_dst=5201,tcp_flags=ack"
+
+good_frame=$(ovs-ofctl compose-packet --bare "${flow_s}")
+
+AT_CHECK([ovs-vsctl set Interface p2 options:tx_pcap=p2.pcap])
+
+AT_CHECK([ovs-appctl coverage/read-counter conntrack_l3csum_checked], [0], [0
+])
+AT_CHECK([ovs-appctl coverage/read-counter conntrack_l3csum_err], [0], [0
+])
+
+dnl Checks for good packet (Tx offloads disabled).
+flow_expected=$(echo "${flow_s}" | sed 's/192.168.123.1/192.168.1.1/g')
+good_expected=$(ovs-ofctl compose-packet --bare "${flow_expected}")
+
+dnl No Rx flag.
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 ${good_frame}])
+AT_CHECK([ovs-appctl coverage/read-counter conntrack_l3csum_checked], [0], [1
+])
+AT_CHECK([ovs-appctl coverage/read-counter conntrack_l3csum_err], [0], [0
+])
+AT_CHECK([ovs-pcap p2.pcap > p2.pcap.txt 2>&1])
+AT_CHECK_UNQUOTED([tail -n 1 p2.pcap.txt], [0], [${good_expected}
+])
+
+dnl Flag as Rx good.
+AT_CHECK([ovs-vsctl set Interface p1 options:ol_ip_rx_csum_set_good=true])
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 ${good_frame}])
+AT_CHECK([ovs-pcap p2.pcap > p2.pcap.txt 2>&1])
+AT_CHECK_UNQUOTED([tail -n 1 p2.pcap.txt], [0], [${good_expected}
+])
+AT_CHECK([ovs-vsctl set Interface p1 options:ol_ip_rx_csum_set_good=false])
+
+dnl Flag as Rx bad.
+AT_CHECK([ovs-vsctl set Interface p1 options:ol_ip_rx_csum_set_bad=true])
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 ${good_frame}])
+AT_CHECK([ovs-appctl coverage/read-counter conntrack_l3csum_checked], [0], [1
+])
+AT_CHECK([ovs-appctl coverage/read-counter conntrack_l3csum_err], [0], [1
+])
+AT_CHECK([ovs-vsctl set Interface p1 options:ol_ip_rx_csum_set_bad=false])
+
+dnl Checks for bad packet (Tx offloads disabled).
+bad_frame=$(ovs-ofctl compose-packet --bare --bad-csum "${flow_s}")
+
+dnl No Rx flag.
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 ${bad_frame}])
+AT_CHECK([ovs-appctl coverage/read-counter conntrack_l3csum_checked], [0], [2
+])
+AT_CHECK([ovs-appctl coverage/read-counter conntrack_l3csum_err], [0], [2
+])
+
+dnl Flag as Rx good.
+AT_CHECK([ovs-vsctl set Interface p1 options:ol_ip_rx_csum_set_good=true])
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 ${bad_frame}])
+AT_CHECK([ovs-pcap p2.pcap > p2.pcap.txt 2>&1])
+dnl In this case, datapath will fix the csum as it trusts the Rx status.
+AT_CHECK_UNQUOTED([tail -n 1 p2.pcap.txt], [0], [${good_expected}
+])
+AT_CHECK([ovs-vsctl set Interface p1 options:ol_ip_rx_csum_set_good=false])
+
+dnl Flag as Rx bad.
+AT_CHECK([ovs-vsctl set Interface p1 options:ol_ip_rx_csum_set_bad=true])
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 ${bad_frame}])
+AT_CHECK([ovs-appctl coverage/read-counter conntrack_l3csum_checked], [0], [2
+])
+AT_CHECK([ovs-appctl coverage/read-counter conntrack_l3csum_err], [0], [3
+])
+AT_CHECK([ovs-vsctl set Interface p1 options:ol_ip_rx_csum_set_bad=false])
+
+dnl Checks for good packet (Tx offloads enabled).
+AT_CHECK([ovs-vsctl set Interface p2 options:ol_ip_tx_csum=true])
+
+dnl No Rx flag.
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 ${good_frame}])
+AT_CHECK([ovs-appctl coverage/read-counter conntrack_l3csum_checked], [0], [3
+])
+AT_CHECK([ovs-appctl coverage/read-counter conntrack_l3csum_err], [0], [3
+])
+AT_CHECK([ovs-pcap p2.pcap > p2.pcap.txt 2>&1])
+AT_CHECK_UNQUOTED([tail -n 1 p2.pcap.txt], [0], [${good_expected}
+])
+
+dnl Flag as Rx good.
+AT_CHECK([ovs-vsctl set Interface p1 options:ol_ip_rx_csum_set_good=true])
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 ${good_frame}])
+AT_CHECK([ovs-appctl coverage/read-counter conntrack_l3csum_checked], [0], [3
+])
+AT_CHECK([ovs-appctl coverage/read-counter conntrack_l3csum_err], [0], [3
+])
+AT_CHECK([ovs-pcap p2.pcap > p2.pcap.txt 2>&1])
+AT_CHECK_UNQUOTED([tail -n 1 p2.pcap.txt], [0], [${good_expected}
+])
+AT_CHECK([ovs-vsctl set Interface p1 options:ol_ip_rx_csum_set_good=false])
+
+dnl Flag as Rx bad.
+AT_CHECK([ovs-vsctl set Interface p1 options:ol_ip_rx_csum_set_bad=true])
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 ${good_frame}])
+AT_CHECK([ovs-appctl coverage/read-counter conntrack_l3csum_checked], [0], [3
+])
+AT_CHECK([ovs-appctl coverage/read-counter conntrack_l3csum_err], [0], [4
+])
+AT_CHECK([ovs-vsctl set Interface p1 options:ol_ip_rx_csum_set_bad=false])
+
+dnl Checks for bad packet (Tx offloads enabled).
+
+dnl No Rx flag.
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 ${bad_frame}])
+AT_CHECK([ovs-appctl coverage/read-counter conntrack_l3csum_checked], [0], [4
+])
+AT_CHECK([ovs-appctl coverage/read-counter conntrack_l3csum_err], [0], [5
+])
+
+dnl Flag as Rx good.
+AT_CHECK([ovs-vsctl set Interface p1 options:ol_ip_rx_csum_set_good=true])
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 ${bad_frame}])
+AT_CHECK([ovs-appctl coverage/read-counter conntrack_l3csum_checked], [0], [4
+])
+AT_CHECK([ovs-appctl coverage/read-counter conntrack_l3csum_err], [0], [5
+])
+AT_CHECK([ovs-pcap p2.pcap > p2.pcap.txt 2>&1])
+dnl In this case, datapath will fix the csum as it trusts the Rx status.
+AT_CHECK_UNQUOTED([tail -n 1 p2.pcap.txt], [0], [${good_expected}
+])
+AT_CHECK([ovs-vsctl set Interface p1 options:ol_ip_rx_csum_set_good=false])
+
+dnl Flag as Rx bad.
+AT_CHECK([ovs-vsctl set Interface p1 options:ol_ip_rx_csum_set_bad=true])
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 ${bad_frame}])
+AT_CHECK([ovs-appctl coverage/read-counter conntrack_l3csum_checked], [0], [4
+])
+AT_CHECK([ovs-appctl coverage/read-counter conntrack_l3csum_err], [0], [6
+])
+AT_CHECK([ovs-vsctl set Interface p1 options:ol_ip_rx_csum_set_bad=false])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
 AT_SETUP([userspace offload - tso])
 OVS_VSWITCHD_START(
   [set Open_vSwitch . other_config:userspace-tso-enable=true -- \
-- 
2.48.1

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

Reply via email to