Commit c30da497 authored by Simon Horman's avatar Simon Horman Committed by David S. Miller

openvswitch: retain parsed IPv6 header fields in flow on error skipping extension headers

When an error occurs skipping IPv6 extension headers retain the already
parsed IP protocol and IPv6 addresses in the flow. Also assume that the
packet is not a fragment in the absence of information to the contrary;
that is always use the frag_off value set by ipv6_skip_exthdr().

This allows matching on the IP protocol and IPv6 addresses of packets
with malformed extension headers.
Signed-off-by: default avatarSimon Horman <simon.horman@netronome.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f5004a14
...@@ -272,8 +272,6 @@ static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key) ...@@ -272,8 +272,6 @@ static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key)
key->ipv6.addr.dst = nh->daddr; key->ipv6.addr.dst = nh->daddr;
payload_ofs = ipv6_skip_exthdr(skb, payload_ofs, &nexthdr, &frag_off); payload_ofs = ipv6_skip_exthdr(skb, payload_ofs, &nexthdr, &frag_off);
if (unlikely(payload_ofs < 0))
return -EINVAL;
if (frag_off) { if (frag_off) {
if (frag_off & htons(~0x7)) if (frag_off & htons(~0x7))
...@@ -284,6 +282,13 @@ static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key) ...@@ -284,6 +282,13 @@ static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key)
key->ip.frag = OVS_FRAG_TYPE_NONE; key->ip.frag = OVS_FRAG_TYPE_NONE;
} }
/* Delayed handling of error in ipv6_skip_exthdr() as it
* always sets frag_off to a valid value which may be
* used to set key->ip.frag above.
*/
if (unlikely(payload_ofs < 0))
return -EPROTO;
nh_len = payload_ofs - nh_ofs; nh_len = payload_ofs - nh_ofs;
skb_set_transport_header(skb, nh_ofs + nh_len); skb_set_transport_header(skb, nh_ofs + nh_len);
key->ip.proto = nexthdr; key->ip.proto = nexthdr;
...@@ -623,12 +628,16 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) ...@@ -623,12 +628,16 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
nh_len = parse_ipv6hdr(skb, key); nh_len = parse_ipv6hdr(skb, key);
if (unlikely(nh_len < 0)) { if (unlikely(nh_len < 0)) {
switch (nh_len) {
case -EINVAL:
memset(&key->ip, 0, sizeof(key->ip)); memset(&key->ip, 0, sizeof(key->ip));
memset(&key->ipv6.addr, 0, sizeof(key->ipv6.addr)); memset(&key->ipv6.addr, 0, sizeof(key->ipv6.addr));
if (nh_len == -EINVAL) { /* fall-through */
case -EPROTO:
skb->transport_header = skb->network_header; skb->transport_header = skb->network_header;
error = 0; error = 0;
} else { break;
default:
error = nh_len; error = nh_len;
} }
return error; return error;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment