Bad packets were still being validated in software when decapsulating a IP header. 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/netdev-native-tnl.c | 50 ++++++++++++++++-------- lib/netdev-native-tnl.h | 3 -- tests/tunnel-push-pop-ipv6.at | 30 +++++++++++++- tests/tunnel-push-pop.at | 73 ++++++++++++++++++++++++++++++++--- 4 files changed, 130 insertions(+), 26 deletions(-) diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c index 62e1a0c870..cbb875bd26 100644 --- a/lib/netdev-native-tnl.c +++ b/lib/netdev-native-tnl.c @@ -33,6 +33,7 @@ #include <sys/time.h> #include "byte-order.h" +#include "coverage.h" #include "csum.h" #include "dp-packet.h" #include "netdev.h" @@ -49,6 +50,11 @@ VLOG_DEFINE_THIS_MODULE(native_tnl); static struct vlog_rate_limit err_rl = VLOG_RATE_LIMIT_INIT(60, 5); +COVERAGE_DEFINE(netdev_native_tnl_l3csum_checked); +COVERAGE_DEFINE(netdev_native_tnl_l3csum_err); +COVERAGE_DEFINE(netdev_native_tnl_l4csum_checked); +COVERAGE_DEFINE(netdev_native_tnl_l4csum_err); + #define VXLAN_HLEN (sizeof(struct udp_header) + \ sizeof(struct vxlanhdr)) @@ -82,8 +88,8 @@ netdev_tnl_get_src_port(struct dp_packet *packet) return htons(hash + tnl_udp_port_min); } -void * -netdev_tnl_ip_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl, +static void * +ip_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl, unsigned int *hlen) { void *nh; @@ -107,16 +113,20 @@ netdev_tnl_ip_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl, ((char *)nh - (char *)dp_packet_data(packet)); if (IP_VER(ip->ip_ihl_ver) == 4) { - + bool bad_csum = dp_packet_ip_checksum_bad(packet); ovs_be32 ip_src, ip_dst; /* A packet coming from a network device might have the * csum already checked. In this case, skip the check. */ - if (OVS_UNLIKELY(!dp_packet_hwol_l3_csum_ipv4_ol(packet))) { - if (csum(ip, IP_IHL(ip->ip_ihl_ver) * 4)) { - VLOG_WARN_RL(&err_rl, "ip packet has invalid checksum"); - return NULL; - } + if (OVS_UNLIKELY(!bad_csum + && !dp_packet_hwol_l3_csum_ipv4_ol(packet))) { + COVERAGE_INC(netdev_native_tnl_l3csum_checked); + bad_csum = csum(ip, IP_IHL(ip->ip_ihl_ver) * 4); + } + if (OVS_UNLIKELY(bad_csum)) { + COVERAGE_INC(netdev_native_tnl_l3csum_err); + VLOG_WARN_RL(&err_rl, "ip packet has invalid checksum"); + return NULL; } if (ntohs(ip->ip_tot_len) > l3_size) { @@ -227,15 +237,19 @@ udp_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl, { struct udp_header *udp; - udp = netdev_tnl_ip_extract_tnl_md(packet, tnl, hlen); + udp = ip_extract_tnl_md(packet, tnl, hlen); if (!udp) { return NULL; } if (udp->udp_csum) { - if (OVS_LIKELY(!dp_packet_ol_l4_csum_partial(packet)) && - OVS_UNLIKELY(!dp_packet_l4_checksum_good(packet))) { + bool bad_csum = dp_packet_l4_checksum_bad(packet); + + if (OVS_UNLIKELY(!bad_csum) + && OVS_LIKELY(!dp_packet_ol_l4_csum_partial(packet)) + && OVS_UNLIKELY(!dp_packet_l4_checksum_good(packet))) { uint32_t csum; + COVERAGE_INC(netdev_native_tnl_l4csum_checked); if (netdev_tnl_is_header_ipv6(dp_packet_data(packet))) { csum = packet_csum_pseudoheader6(dp_packet_l3(packet)); } else { @@ -246,9 +260,11 @@ udp_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl, ((const unsigned char *)udp - (const unsigned char *)dp_packet_eth(packet) )); - if (csum_finish(csum)) { - return NULL; - } + bad_csum = csum_finish(csum); + } + if (OVS_UNLIKELY(bad_csum)) { + COVERAGE_INC(netdev_native_tnl_l4csum_err); + return NULL; } tnl->flags |= FLOW_TNL_F_CSUM; } @@ -449,7 +465,7 @@ parse_gre_header(struct dp_packet *packet, unsigned int ulen; uint16_t greh_protocol; - greh = netdev_tnl_ip_extract_tnl_md(packet, tnl, &ulen); + greh = ip_extract_tnl_md(packet, tnl, &ulen); if (!greh) { return -EINVAL; } @@ -647,7 +663,7 @@ netdev_erspan_pop_header(struct dp_packet *packet) goto err; } - greh = netdev_tnl_ip_extract_tnl_md(packet, tnl, &ulen); + greh = ip_extract_tnl_md(packet, tnl, &ulen); if (!greh) { goto err; } @@ -1083,7 +1099,7 @@ netdev_srv6_pop_header(struct dp_packet *packet) } pkt_metadata_init_tnl(md); - if (!netdev_tnl_ip_extract_tnl_md(packet, tnl, &hlen)) { + if (!ip_extract_tnl_md(packet, tnl, &hlen)) { goto err; } diff --git a/lib/netdev-native-tnl.h b/lib/netdev-native-tnl.h index 5d8f1672a8..47d6b6bbcf 100644 --- a/lib/netdev-native-tnl.h +++ b/lib/netdev-native-tnl.h @@ -125,9 +125,6 @@ extern uint16_t tnl_udp_port_max; ovs_be16 netdev_tnl_get_src_port(struct dp_packet *); -void * -netdev_tnl_ip_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl, - unsigned int *hlen); void * netdev_tnl_push_ip_header(struct dp_packet *packet, const void *header, int size, int *ip_tot_size, ovs_be32 ipv6_label); diff --git a/tests/tunnel-push-pop-ipv6.at b/tests/tunnel-push-pop-ipv6.at index 824a226b21..4934b97259 100644 --- a/tests/tunnel-push-pop-ipv6.at +++ b/tests/tunnel-push-pop-ipv6.at @@ -402,7 +402,7 @@ AT_CHECK([ovs-appctl tnl/arp/show | tail -n+3 | sort], [0], [dnl 2001:cafe::92 f8:bc:12:44:34:c8 br0 ]) -dnl Receiving Neighbot Advertisement with incorrect VLAN id should not alter tunnel neighbor cache +dnl Receiving Neighbor Advertisement with incorrect VLAN id should not alter tunnel neighbor cache AT_CHECK([ovs-vsctl set port br0 tag=10]) AT_CHECK([ovs-appctl netdev-dummy/receive p0 'in_port(1),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x8100),vlan(vid=99,pcp=7),encap(eth_type(0x86dd),ipv6(src=2001:cafe::92,dst=2001:cafe::88,label=0,proto=58,tclass=0,hlimit=255,frag=no),icmpv6(type=136,code=0),nd(target=2001:cafe::92,sll=00:00:00:00:00:00,tll=f8:bc:12:44:34:b6))']) @@ -587,6 +587,34 @@ AT_CHECK([tail -1 stdout], [0], [Datapath actions: tnl_push(tnl_port(4789),header(size=70,type=4,eth(dst=f8:bc:12:44:ca:fe,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=4789,csum=0xffff),vxlan(flags=0x8000000,vni=0x7b)),out_port(100)),1 ]) +dnl No drop so far. +AT_CHECK([ovs-appctl coverage/read-counter datapath_drop_tunnel_pop_error], [0], [0 +]) +AT_CHECK([ovs-appctl coverage/read-counter netdev_native_tnl_l3csum_err], [0], [0 +]) +AT_CHECK([ovs-appctl coverage/read-counter netdev_native_tnl_l4csum_err], [0], [0 +]) +dnl Yet csum validation happened on all previous packets (with non null checksums). +AT_CHECK([ovs-appctl coverage/read-counter netdev_native_tnl_l3csum_checked], [0], [0 +]) +AT_CHECK([ovs-appctl coverage/read-counter netdev_native_tnl_l4csum_checked], [0], [1 +]) + + +dnl Send a VXLAN packet with bad UDP checksum. +AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000f8bc1244cafe86dd60000000003a11402001cafe0000000000000000000000922001cafe000000000000000000000088c85312b5003aDEAD0c00000300007b00ffffffffffff00000000000008004500001c0001000040117cce7f0000017f0000010035003500080172']) + +AT_CHECK([ovs-appctl coverage/read-counter datapath_drop_tunnel_pop_error], [0], [1 +]) +AT_CHECK([ovs-appctl coverage/read-counter netdev_native_tnl_l3csum_err], [0], [0 +]) +AT_CHECK([ovs-appctl coverage/read-counter netdev_native_tnl_l4csum_err], [0], [1 +]) +AT_CHECK([ovs-appctl coverage/read-counter netdev_native_tnl_l3csum_checked], [0], [0 +]) +AT_CHECK([ovs-appctl coverage/read-counter netdev_native_tnl_l4csum_checked], [0], [2 +]) + AT_CHECK([ovs-appctl tnl/arp/show | tail -n+3 | sort], [0], [dnl 2001:cafe::92 f8:bc:12:44:ca:fe br0 2001:cafe::93 f8:bc:12:44:34:b7 br0 diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at index cf4e622014..35a9dc4944 100644 --- a/tests/tunnel-push-pop.at +++ b/tests/tunnel-push-pop.at @@ -514,6 +514,30 @@ AT_CHECK([tail -1 stdout], [0], ]) AT_CHECK([ovs-ofctl del-flows int-br]) +dnl Check decapsulation of VXLAN packet +AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6408004500004e00010000401173e90101025c0101025812b512b5003a00000800000000007b00fe71d883724fbeb6f4e1494a08004500001c0001000040013ede1e0000011e0000020000ffff00000000']) +AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6408004500004e00010000401173e90101025c0101025812b512b5003a02320800000000007b00fe71d883724fbeb6f4e1494a08004500001c0001000040013ede1e0000011e0000020000ffff00000000']) +AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6408004500004e00010000401173e90101025c0101025812b512b5003a202e0c00000300015900fe71d883724fbeb6f4e1494a08004500001c0001000040013ede1e0000011e0000020000ffff00000000']) +ovs-appctl time/warp 1000 +AT_CHECK([ovs-ofctl dump-ports int-br | grep -E 'port [[248]]:' | sort], [0], [dnl + port 2: rx pkts=2, bytes=84, drop=?, errs=?, frame=?, over=?, crc=? + port 4: rx pkts=0, bytes=0, drop=?, errs=?, frame=?, over=?, crc=? + port 8: rx pkts=1, bytes=42, drop=?, errs=?, frame=?, over=?, crc=? +]) + +dnl Idem, with Rx cksum good +AT_CHECK([ovs-vsctl set interface p0 options:ol_ip_rx_csum_set_good=true]) +AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6408004500004e00010000401173e90101025c0101025812b512b5003a00000800000000007b00fe71d883724fbeb6f4e1494a08004500001c0001000040013ede1e0000011e0000020000ffff00000000']) +AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6408004500004e00010000401173e90101025c0101025812b512b5003a02320800000000007b00fe71d883724fbeb6f4e1494a08004500001c0001000040013ede1e0000011e0000020000ffff00000000']) +AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6408004500004e00010000401173e90101025c0101025812b512b5003a202e0c00000300015900fe71d883724fbeb6f4e1494a08004500001c0001000040013ede1e0000011e0000020000ffff00000000']) +AT_CHECK([ovs-vsctl set interface p0 options:ol_ip_rx_csum_set_good=false]) +ovs-appctl time/warp 1000 +AT_CHECK([ovs-ofctl dump-ports int-br | grep -E 'port [[248]]:' | sort], [0], [dnl + port 2: rx pkts=4, bytes=168, drop=?, errs=?, frame=?, over=?, crc=? + port 4: rx pkts=0, bytes=0, drop=?, errs=?, frame=?, over=?, crc=? + port 8: rx pkts=2, bytes=84, drop=?, errs=?, frame=?, over=?, crc=? +]) + dnl Check decapsulation of GRE packet AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6408004500007e79464000402fba550101025c0101025820006558000001c8fe71d883724fbeb6f4e1494a080045000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637']) AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6408004500007e79464000402fba550101025c0101025820006558000001c8fe71d883724fbeb6f4e1494a080045000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637']) @@ -535,14 +559,53 @@ AT_CHECK([ovs-ofctl dump-ports int-br | grep 'port 7'], [0], [dnl port 7: rx pkts=3, bytes=252, drop=?, errs=?, frame=?, over=?, crc=? ]) -AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6408004500007079464000402fba600101025c0101025820000800000001c845000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637']) +dnl No drop so far. +AT_CHECK([ovs-appctl coverage/read-counter datapath_drop_tunnel_pop_error], [0], [0 +]) +AT_CHECK([ovs-appctl coverage/read-counter netdev_native_tnl_l3csum_err], [0], [0 +]) +AT_CHECK([ovs-appctl coverage/read-counter netdev_native_tnl_l4csum_err], [0], [0 +]) +dnl Yet csum validation happened on all previous packets. +AT_CHECK([ovs-appctl coverage/read-counter netdev_native_tnl_l3csum_checked], [0], [12 +]) +AT_CHECK([ovs-appctl coverage/read-counter netdev_native_tnl_l4csum_checked], [0], [4 +]) + +dnl Send various incorrect bad IP checksum packets. +dnl GRE +AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6408004500007079464000402fDEAD0101025c0101025820000800000001c845000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637']) +dnl VxLAN +AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6408004500004e000100004011DEAD0101025c0101025812b512b5003a00000800000000007b00fe71d883724fbeb6f4e1494a08004500001c0001000040013ede1e0000011e0000020000ffff00000000']) +dnl VxLAN-GPE +AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6408004500004e000100004011DEAD0101025c0101025812b512b5003a202e0c00000300015900fe71d883724fbeb6f4e1494a08004500001c0001000040013ede1e0000011e0000020000ffff00000000']) + +dnl Idem, with Rx cksum bad but with a valid and an invalid packet. +AT_CHECK([ovs-vsctl set interface p0 options:ol_ip_rx_csum_set_bad=true]) +AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6408004500004e00010000401173e90101025c0101025812b512b5003a02320800000000007b00fe71d883724fbeb6f4e1494a08004500001c0001000040013ede1e0000011e0000020000ffff00000000']) +AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6408004500007079464000402fDEAD0101025c0101025820000800000001c845000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637']) +AT_CHECK([ovs-vsctl set interface p0 options:ol_ip_rx_csum_set_bad=false]) + +dnl Send various incorrect bad UDP checksum packets. +AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6408004500004e00010000401173e90101025c0101025812b512b5003aDEAD0800000000007b00fe71d883724fbeb6f4e1494a08004500001c0001000040013ede1e0000011e0000020000ffff00000000']) + +dnl Idem, with Rx cksum bad but with a valid and an invalid packet. +AT_CHECK([ovs-vsctl set interface p0 options:ol_l4_rx_csum_set_bad=true]) +AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6408004500004e00010000401173e90101025c0101025812b512b5003a02320800000000007b00fe71d883724fbeb6f4e1494a08004500001c0001000040013ede1e0000011e0000020000ffff00000000']) +AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6408004500004e00010000401173e90101025c0101025812b512b5003aDEAD0800000000007b00fe71d883724fbeb6f4e1494a08004500001c0001000040013ede1e0000011e0000020000ffff00000000']) +AT_CHECK([ovs-vsctl set interface p0 options:ol_l4_rx_csum_set_bad=false]) ovs-appctl time/warp 5000 -AT_CHECK([ -ovs-appctl coverage/read-counter datapath_drop_tunnel_pop_error -], [0], [dnl -1 +AT_CHECK([ovs-appctl coverage/read-counter datapath_drop_tunnel_pop_error], [0], [8 +]) +AT_CHECK([ovs-appctl coverage/read-counter netdev_native_tnl_l3csum_err], [0], [5 +]) +AT_CHECK([ovs-appctl coverage/read-counter netdev_native_tnl_l4csum_err], [0], [3 +]) +AT_CHECK([ovs-appctl coverage/read-counter netdev_native_tnl_l3csum_checked], [0], [18 +]) +AT_CHECK([ovs-appctl coverage/read-counter netdev_native_tnl_l4csum_checked], [0], [5 ]) AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6408004503007079464000402fba600101025c0101025820000800000001c845000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637']) -- 2.48.1 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev