mirror of
https://github.com/openvswitch/ovs
synced 2025-08-31 06:15:47 +00:00
flow: Count and dump invalid IP packets.
Skipping further processing of invalid IP packets helps avoid crashes but it does not help to figure out if the malformed packets are still present on the network. Add coverage counters for IPv4 and IPv6 sanity checks so that we know there are some invalid packets. Dump such whole packets in debug mode. Signed-off-by: David Marchand <david.marchand@redhat.com> Acked-by: Eelco Chaudron <echaudro@redhat.com> Acked-by: Flavio Leitner <fbl@sysclose.org> Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
This commit is contained in:
committed by
Ilya Maximets
parent
6545977cee
commit
15329b728b
42
lib/flow.c
42
lib/flow.c
@@ -44,8 +44,15 @@
|
||||
#include "openvswitch/nsh.h"
|
||||
#include "ovs-router.h"
|
||||
#include "lib/netdev-provider.h"
|
||||
#include "openvswitch/vlog.h"
|
||||
|
||||
VLOG_DEFINE_THIS_MODULE(flow);
|
||||
|
||||
COVERAGE_DEFINE(flow_extract);
|
||||
COVERAGE_DEFINE(miniflow_extract_ipv4_pkt_len_error);
|
||||
COVERAGE_DEFINE(miniflow_extract_ipv4_pkt_too_short);
|
||||
COVERAGE_DEFINE(miniflow_extract_ipv6_pkt_len_error);
|
||||
COVERAGE_DEFINE(miniflow_extract_ipv6_pkt_too_short);
|
||||
COVERAGE_DEFINE(miniflow_malloc);
|
||||
|
||||
/* U64 indices for segmented flow classification. */
|
||||
@@ -645,17 +652,20 @@ ipv4_sanity_check(const struct ip_header *nh, size_t size,
|
||||
uint16_t tot_len;
|
||||
|
||||
if (OVS_UNLIKELY(size < IP_HEADER_LEN)) {
|
||||
COVERAGE_INC(miniflow_extract_ipv4_pkt_too_short);
|
||||
return false;
|
||||
}
|
||||
ip_len = IP_IHL(nh->ip_ihl_ver) * 4;
|
||||
|
||||
if (OVS_UNLIKELY(ip_len < IP_HEADER_LEN || size < ip_len)) {
|
||||
COVERAGE_INC(miniflow_extract_ipv4_pkt_len_error);
|
||||
return false;
|
||||
}
|
||||
|
||||
tot_len = ntohs(nh->ip_tot_len);
|
||||
if (OVS_UNLIKELY(tot_len > size || ip_len > tot_len ||
|
||||
size - tot_len > UINT16_MAX)) {
|
||||
COVERAGE_INC(miniflow_extract_ipv4_pkt_len_error);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -686,21 +696,41 @@ ipv6_sanity_check(const struct ovs_16aligned_ip6_hdr *nh, size_t size)
|
||||
uint16_t plen;
|
||||
|
||||
if (OVS_UNLIKELY(size < sizeof *nh)) {
|
||||
COVERAGE_INC(miniflow_extract_ipv6_pkt_too_short);
|
||||
return false;
|
||||
}
|
||||
|
||||
plen = ntohs(nh->ip6_plen);
|
||||
if (OVS_UNLIKELY(plen + IPV6_HEADER_LEN > size)) {
|
||||
COVERAGE_INC(miniflow_extract_ipv6_pkt_len_error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (OVS_UNLIKELY(size - (plen + IPV6_HEADER_LEN) > UINT16_MAX)) {
|
||||
COVERAGE_INC(miniflow_extract_ipv6_pkt_len_error);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
dump_invalid_packet(struct dp_packet *packet, const char *reason)
|
||||
{
|
||||
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
|
||||
struct ds ds = DS_EMPTY_INITIALIZER;
|
||||
size_t size;
|
||||
|
||||
if (VLOG_DROP_DBG(&rl)) {
|
||||
return;
|
||||
}
|
||||
size = dp_packet_size(packet);
|
||||
ds_put_hex_dump(&ds, dp_packet_data(packet), size, 0, false);
|
||||
VLOG_DBG("invalid packet for %s: port %"PRIu32", size %"PRIuSIZE"\n%s",
|
||||
reason, packet->md.in_port.odp_port, size, ds_cstr(&ds));
|
||||
ds_destroy(&ds);
|
||||
}
|
||||
|
||||
/* Initializes 'dst' from 'packet' and 'md', taking the packet type into
|
||||
* account. 'dst' must have enough space for FLOW_U64S * 8 bytes.
|
||||
*
|
||||
@@ -850,6 +880,9 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
|
||||
uint16_t tot_len;
|
||||
|
||||
if (OVS_UNLIKELY(!ipv4_sanity_check(nh, size, &ip_len, &tot_len))) {
|
||||
if (OVS_UNLIKELY(VLOG_IS_DBG_ENABLED())) {
|
||||
dump_invalid_packet(packet, "ipv4_sanity_check");
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
dp_packet_set_l2_pad_size(packet, size - tot_len);
|
||||
@@ -880,6 +913,9 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
|
||||
uint16_t plen;
|
||||
|
||||
if (OVS_UNLIKELY(!ipv6_sanity_check(nh, size))) {
|
||||
if (OVS_UNLIKELY(VLOG_IS_DBG_ENABLED())) {
|
||||
dump_invalid_packet(packet, "ipv6_sanity_check");
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
data_pull(&data, &size, sizeof *nh);
|
||||
@@ -1114,6 +1150,9 @@ parse_tcp_flags(struct dp_packet *packet)
|
||||
uint16_t tot_len;
|
||||
|
||||
if (OVS_UNLIKELY(!ipv4_sanity_check(nh, size, &ip_len, &tot_len))) {
|
||||
if (OVS_UNLIKELY(VLOG_IS_DBG_ENABLED())) {
|
||||
dump_invalid_packet(packet, "ipv4_sanity_check");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
dp_packet_set_l2_pad_size(packet, size - tot_len);
|
||||
@@ -1127,6 +1166,9 @@ parse_tcp_flags(struct dp_packet *packet)
|
||||
uint16_t plen;
|
||||
|
||||
if (OVS_UNLIKELY(!ipv6_sanity_check(nh, size))) {
|
||||
if (OVS_UNLIKELY(VLOG_IS_DBG_ENABLED())) {
|
||||
dump_invalid_packet(packet, "ipv6_sanity_check");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
data_pull(&data, &size, sizeof *nh);
|
||||
|
Reference in New Issue
Block a user