2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-30 13:58:14 +00:00

netdev-native-tnl: Do not validate already checked checksum.

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.

Acked-by: Mike Pattrick <mkp@redhat.com>
Signed-off-by: David Marchand <david.marchand@redhat.com>
Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
This commit is contained in:
David Marchand
2025-03-13 13:43:35 +01:00
committed by Ilya Maximets
parent 71f3dd3e9c
commit c852a8c767
4 changed files with 129 additions and 26 deletions

View File

@@ -33,6 +33,7 @@
#include <sys/time.h> #include <sys/time.h>
#include "byte-order.h" #include "byte-order.h"
#include "coverage.h"
#include "csum.h" #include "csum.h"
#include "dp-packet.h" #include "dp-packet.h"
#include "netdev.h" #include "netdev.h"
@@ -49,6 +50,11 @@
VLOG_DEFINE_THIS_MODULE(native_tnl); VLOG_DEFINE_THIS_MODULE(native_tnl);
static struct vlog_rate_limit err_rl = VLOG_RATE_LIMIT_INIT(60, 5); static struct vlog_rate_limit err_rl = VLOG_RATE_LIMIT_INIT(60, 5);
COVERAGE_DEFINE(native_tnl_l3csum_checked);
COVERAGE_DEFINE(native_tnl_l3csum_err);
COVERAGE_DEFINE(native_tnl_l4csum_checked);
COVERAGE_DEFINE(native_tnl_l4csum_err);
#define VXLAN_HLEN (sizeof(struct udp_header) + \ #define VXLAN_HLEN (sizeof(struct udp_header) + \
sizeof(struct vxlanhdr)) sizeof(struct vxlanhdr))
@@ -82,8 +88,8 @@ netdev_tnl_get_src_port(struct dp_packet *packet)
return htons(hash + tnl_udp_port_min); return htons(hash + tnl_udp_port_min);
} }
void * static void *
netdev_tnl_ip_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl, ip_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl,
unsigned int *hlen) unsigned int *hlen)
{ {
void *nh; 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)); ((char *)nh - (char *)dp_packet_data(packet));
if (IP_VER(ip->ip_ihl_ver) == 4) { if (IP_VER(ip->ip_ihl_ver) == 4) {
bool bad_csum = dp_packet_ip_checksum_bad(packet);
ovs_be32 ip_src, ip_dst; ovs_be32 ip_src, ip_dst;
/* A packet coming from a network device might have the /* A packet coming from a network device might have the
* csum already checked. In this case, skip the check. */ * csum already checked. In this case, skip the check. */
if (OVS_UNLIKELY(!dp_packet_hwol_l3_csum_ipv4_ol(packet))) { if (OVS_UNLIKELY(!bad_csum
if (csum(ip, IP_IHL(ip->ip_ihl_ver) * 4)) { && !dp_packet_hwol_l3_csum_ipv4_ol(packet))) {
VLOG_WARN_RL(&err_rl, "ip packet has invalid checksum"); COVERAGE_INC(native_tnl_l3csum_checked);
return NULL; bad_csum = csum(ip, IP_IHL(ip->ip_ihl_ver) * 4);
} }
if (OVS_UNLIKELY(bad_csum)) {
COVERAGE_INC(native_tnl_l3csum_err);
VLOG_WARN_RL(&err_rl, "ip packet has invalid checksum");
return NULL;
} }
if (ntohs(ip->ip_tot_len) > l3_size) { if (ntohs(ip->ip_tot_len) > l3_size) {
@@ -227,15 +237,18 @@ udp_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl,
{ {
struct udp_header *udp; struct udp_header *udp;
udp = netdev_tnl_ip_extract_tnl_md(packet, tnl, hlen); udp = ip_extract_tnl_md(packet, tnl, hlen);
if (!udp) { if (!udp) {
return NULL; return NULL;
} }
if (udp->udp_csum) { if (udp->udp_csum) {
if (OVS_LIKELY(!dp_packet_ol_l4_csum_partial(packet)) && bool bad_csum = dp_packet_l4_checksum_bad(packet);
OVS_UNLIKELY(!dp_packet_l4_checksum_good(packet))) {
if (OVS_LIKELY(!bad_csum && !dp_packet_ol_l4_csum_partial(packet))
&& OVS_UNLIKELY(!dp_packet_l4_checksum_good(packet))) {
uint32_t csum; uint32_t csum;
COVERAGE_INC(native_tnl_l4csum_checked);
if (netdev_tnl_is_header_ipv6(dp_packet_data(packet))) { if (netdev_tnl_is_header_ipv6(dp_packet_data(packet))) {
csum = packet_csum_pseudoheader6(dp_packet_l3(packet)); csum = packet_csum_pseudoheader6(dp_packet_l3(packet));
} else { } else {
@@ -246,9 +259,11 @@ udp_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl,
((const unsigned char *)udp - ((const unsigned char *)udp -
(const unsigned char *)dp_packet_eth(packet) (const unsigned char *)dp_packet_eth(packet)
)); ));
if (csum_finish(csum)) { bad_csum = csum_finish(csum);
return NULL; }
} if (OVS_UNLIKELY(bad_csum)) {
COVERAGE_INC(native_tnl_l4csum_err);
return NULL;
} }
tnl->flags |= FLOW_TNL_F_CSUM; tnl->flags |= FLOW_TNL_F_CSUM;
} }
@@ -449,7 +464,7 @@ parse_gre_header(struct dp_packet *packet,
unsigned int ulen; unsigned int ulen;
uint16_t greh_protocol; uint16_t greh_protocol;
greh = netdev_tnl_ip_extract_tnl_md(packet, tnl, &ulen); greh = ip_extract_tnl_md(packet, tnl, &ulen);
if (!greh) { if (!greh) {
return -EINVAL; return -EINVAL;
} }
@@ -647,7 +662,7 @@ netdev_erspan_pop_header(struct dp_packet *packet)
goto err; goto err;
} }
greh = netdev_tnl_ip_extract_tnl_md(packet, tnl, &ulen); greh = ip_extract_tnl_md(packet, tnl, &ulen);
if (!greh) { if (!greh) {
goto err; goto err;
} }
@@ -1083,7 +1098,7 @@ netdev_srv6_pop_header(struct dp_packet *packet)
} }
pkt_metadata_init_tnl(md); 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; goto err;
} }

View File

@@ -125,9 +125,6 @@ extern uint16_t tnl_udp_port_max;
ovs_be16 netdev_tnl_get_src_port(struct dp_packet *); 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 * void *
netdev_tnl_push_ip_header(struct dp_packet *packet, const void *header, netdev_tnl_push_ip_header(struct dp_packet *packet, const void *header,
int size, int *ip_tot_size, ovs_be32 ipv6_label); int size, int *ip_tot_size, ovs_be32 ipv6_label);

View File

@@ -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 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-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))']) 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 [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 native_tnl_l3csum_err], [0], [0
])
AT_CHECK([ovs-appctl coverage/read-counter 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 native_tnl_l3csum_checked], [0], [0
])
AT_CHECK([ovs-appctl coverage/read-counter 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 native_tnl_l3csum_err], [0], [0
])
AT_CHECK([ovs-appctl coverage/read-counter native_tnl_l4csum_err], [0], [1
])
AT_CHECK([ovs-appctl coverage/read-counter native_tnl_l3csum_checked], [0], [0
])
AT_CHECK([ovs-appctl coverage/read-counter native_tnl_l4csum_checked], [0], [2
])
AT_CHECK([ovs-appctl tnl/arp/show | tail -n+3 | sort], [0], [dnl 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::92 f8:bc:12:44:ca:fe br0
2001:cafe::93 f8:bc:12:44:34:b7 br0 2001:cafe::93 f8:bc:12:44:34:b7 br0

View File

@@ -514,6 +514,30 @@ AT_CHECK([tail -1 stdout], [0],
]) ])
AT_CHECK([ovs-ofctl del-flows int-br]) 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 dnl Check decapsulation of GRE packet
AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6408004500007e79464000402fba550101025c0101025820006558000001c8fe71d883724fbeb6f4e1494a080045000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637']) AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6408004500007e79464000402fba550101025c0101025820006558000001c8fe71d883724fbeb6f4e1494a080045000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637'])
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=? 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 native_tnl_l3csum_err], [0], [0
])
AT_CHECK([ovs-appctl coverage/read-counter native_tnl_l4csum_err], [0], [0
])
dnl Yet csum validation happened on all previous packets.
AT_CHECK([ovs-appctl coverage/read-counter native_tnl_l3csum_checked], [0], [12
])
AT_CHECK([ovs-appctl coverage/read-counter 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 ovs-appctl time/warp 5000
AT_CHECK([ AT_CHECK([ovs-appctl coverage/read-counter datapath_drop_tunnel_pop_error], [0], [8
ovs-appctl coverage/read-counter datapath_drop_tunnel_pop_error ])
], [0], [dnl AT_CHECK([ovs-appctl coverage/read-counter native_tnl_l3csum_err], [0], [5
1 ])
AT_CHECK([ovs-appctl coverage/read-counter native_tnl_l4csum_err], [0], [3
])
AT_CHECK([ovs-appctl coverage/read-counter native_tnl_l3csum_checked], [0], [18
])
AT_CHECK([ovs-appctl coverage/read-counter native_tnl_l4csum_checked], [0], [5
]) ])
AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6408004503007079464000402fba600101025c0101025820000800000001c845000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637']) AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6408004503007079464000402fba600101025c0101025820000800000001c845000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637'])