@@ -1589,11 +1589,12 @@ check_l4_icmp6(const struct conn_key *key, const void *data, size_t size,
}
static inline bool
-extract_l4_tcp(struct conn_key *key, const void *data, size_t size)
+extract_l4_tcp(struct conn_key *key, const void *data, size_t size,
+ size_t *chk_len)
{
const struct tcp_header *tcp = data;
- if (OVS_UNLIKELY(size < TCP_HEADER_LEN)) {
+ if (OVS_UNLIKELY(size < (chk_len ? *chk_len : TCP_HEADER_LEN))) {
return false;
}
@@ -1605,11 +1606,12 @@ extract_l4_tcp(struct conn_key *key, const void *data, size_t size)
}
static inline bool
-extract_l4_udp(struct conn_key *key, const void *data, size_t size)
+extract_l4_udp(struct conn_key *key, const void *data, size_t size,
+ size_t *chk_len)
{
const struct udp_header *udp = data;
- if (OVS_UNLIKELY(size < UDP_HEADER_LEN)) {
+ if (OVS_UNLIKELY(size < (chk_len ? *chk_len : UDP_HEADER_LEN))) {
return false;
}
@@ -1622,7 +1624,7 @@ extract_l4_udp(struct conn_key *key, const void *data, size_t size)
static inline bool extract_l4(struct conn_key *key, const void *data,
size_t size, bool *related, const void *l3,
- bool validate_checksum);
+ bool validate_checksum, size_t *chk_len);
static uint8_t
reverse_icmp_type(uint8_t type)
@@ -1654,11 +1656,11 @@ reverse_icmp_type(uint8_t type)
* possible */
static inline int
extract_l4_icmp(struct conn_key *key, const void *data, size_t size,
- bool *related)
+ bool *related, size_t *chk_len)
{
const struct icmp_header *icmp = data;
- if (OVS_UNLIKELY(size < ICMP_HEADER_LEN)) {
+ if (OVS_UNLIKELY(size < (chk_len ? *chk_len : ICMP_HEADER_LEN))) {
return false;
}
@@ -1708,8 +1710,9 @@ extract_l4_icmp(struct conn_key *key, const void *data, size_t size,
key->src = inner_key.src;
key->dst = inner_key.dst;
key->nw_proto = inner_key.nw_proto;
+ size_t check_len = ICMP_ERROR_DATA_L4_LEN;
- ok = extract_l4(key, l4, tail - l4, NULL, l3, false);
+ ok = extract_l4(key, l4, tail - l4, NULL, l3, false, &check_len);
if (ok) {
conn_key_reverse(key);
*related = true;
@@ -1797,7 +1800,7 @@ extract_l4_icmp6(struct conn_key *key, const void *data, size_t size,
key->dst = inner_key.dst;
key->nw_proto = inner_key.nw_proto;
- ok = extract_l4(key, l4, tail - l4, NULL, l3, false);
+ ok = extract_l4(key, l4, tail - l4, NULL, l3, false, NULL);
if (ok) {
conn_key_reverse(key);
*related = true;
@@ -1822,26 +1825,29 @@ extract_l4_icmp6(struct conn_key *key, const void *data, size_t size,
* an ICMP or ICMP6 header. **
*
* If 'related' is NULL, it means that we're already parsing a header nested
- * in an ICMP error. In this case, we skip checksum and length validation. */
+ * in an ICMP error. In this case, we skip the checksum and some length
+ * validations. */
static inline bool
extract_l4(struct conn_key *key, const void *data, size_t size, bool *related,
- const void *l3, bool validate_checksum)
+ const void *l3, bool validate_checksum, size_t *chk_len)
{
if (key->nw_proto == IPPROTO_TCP) {
return (!related || check_l4_tcp(key, data, size, l3,
- validate_checksum)) && extract_l4_tcp(key, data, size);
+ validate_checksum))
+ && extract_l4_tcp(key, data, size, chk_len);
} else if (key->nw_proto == IPPROTO_UDP) {
return (!related || check_l4_udp(key, data, size, l3,
- validate_checksum)) && extract_l4_udp(key, data, size);
+ validate_checksum))
+ && extract_l4_udp(key, data, size, chk_len);
} else if (key->dl_type == htons(ETH_TYPE_IP)
&& key->nw_proto == IPPROTO_ICMP) {
return (!related || check_l4_icmp(data, size, validate_checksum))
- && extract_l4_icmp(key, data, size, related);
+ && extract_l4_icmp(key, data, size, related, chk_len);
} else if (key->dl_type == htons(ETH_TYPE_IPV6)
&& key->nw_proto == IPPROTO_ICMPV6) {
return (!related || check_l4_icmp6(key, data, size, l3,
- validate_checksum)) && extract_l4_icmp6(key, data, size,
- related);
+ validate_checksum))
+ && extract_l4_icmp6(key, data, size, related);
} else {
return false;
}
@@ -1920,7 +1926,8 @@ conn_key_extract(struct conntrack *ct, struct dp_packet *pkt, ovs_be16 dl_type,
bool hwol_good_l4_csum = dp_packet_l4_checksum_valid(pkt);
/* Validate the checksum only when hwol is not supported. */
if (extract_l4(&ctx->key, l4, dp_packet_l4_size(pkt),
- &ctx->icmp_related, l3, !hwol_good_l4_csum)) {
+ &ctx->icmp_related, l3, !hwol_good_l4_csum,
+ NULL)) {
ctx->hash = conn_key_hash(&ctx->key, ct->hash_basis);
return true;
}
@@ -737,6 +737,9 @@ struct icmp_header {
};
BUILD_ASSERT_DECL(ICMP_HEADER_LEN == sizeof(struct icmp_header));
+/* ICMPV4 */
+#define ICMP_ERROR_DATA_L4_LEN 8
+
#define IGMP_HEADER_LEN 8
struct igmp_header {
uint8_t igmp_type;