2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-22 01:51:26 +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 "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(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) + \
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(native_tnl_l3csum_checked);
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) {
@ -227,15 +237,18 @@ 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_LIKELY(!bad_csum && !dp_packet_ol_l4_csum_partial(packet))
&& OVS_UNLIKELY(!dp_packet_l4_checksum_good(packet))) {
uint32_t csum;
COVERAGE_INC(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 +259,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(native_tnl_l4csum_err);
return NULL;
}
tnl->flags |= FLOW_TNL_F_CSUM;
}
@ -449,7 +464,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 +662,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 +1098,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;
}

View File

@ -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);

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
])
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 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
2001:cafe::92 f8:bc:12:44:ca:fe 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])
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 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
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 native_tnl_l3csum_err], [0], [5
])
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'])