aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Horman <simon.horman@netronome.com>2015-08-28 20:02:21 -0400
committerDavid S. Miller <davem@davemloft.net>2015-08-29 16:39:59 -0400
commitc30da497893718abc6cec4f1d34d35875200edee (patch)
tree2c0719458035858da1c1779d5970b34b868c51ac
parentf5004a14fac0a71656340544c48a14c80a3afddf (diff)
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: Simon Horman <simon.horman@netronome.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/openvswitch/flow.c21
1 files changed, 15 insertions, 6 deletions
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c
index 9760dc43bdb9..9db87331e211 100644
--- a/net/openvswitch/flow.c
+++ b/net/openvswitch/flow.c
@@ -272,8 +272,6 @@ static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key)
272 key->ipv6.addr.dst = nh->daddr; 272 key->ipv6.addr.dst = nh->daddr;
273 273
274 payload_ofs = ipv6_skip_exthdr(skb, payload_ofs, &nexthdr, &frag_off); 274 payload_ofs = ipv6_skip_exthdr(skb, payload_ofs, &nexthdr, &frag_off);
275 if (unlikely(payload_ofs < 0))
276 return -EINVAL;
277 275
278 if (frag_off) { 276 if (frag_off) {
279 if (frag_off & htons(~0x7)) 277 if (frag_off & htons(~0x7))
@@ -284,6 +282,13 @@ static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key)
284 key->ip.frag = OVS_FRAG_TYPE_NONE; 282 key->ip.frag = OVS_FRAG_TYPE_NONE;
285 } 283 }
286 284
285 /* Delayed handling of error in ipv6_skip_exthdr() as it
286 * always sets frag_off to a valid value which may be
287 * used to set key->ip.frag above.
288 */
289 if (unlikely(payload_ofs < 0))
290 return -EPROTO;
291
287 nh_len = payload_ofs - nh_ofs; 292 nh_len = payload_ofs - nh_ofs;
288 skb_set_transport_header(skb, nh_ofs + nh_len); 293 skb_set_transport_header(skb, nh_ofs + nh_len);
289 key->ip.proto = nexthdr; 294 key->ip.proto = nexthdr;
@@ -623,12 +628,16 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
623 628
624 nh_len = parse_ipv6hdr(skb, key); 629 nh_len = parse_ipv6hdr(skb, key);
625 if (unlikely(nh_len < 0)) { 630 if (unlikely(nh_len < 0)) {
626 memset(&key->ip, 0, sizeof(key->ip)); 631 switch (nh_len) {
627 memset(&key->ipv6.addr, 0, sizeof(key->ipv6.addr)); 632 case -EINVAL:
628 if (nh_len == -EINVAL) { 633 memset(&key->ip, 0, sizeof(key->ip));
634 memset(&key->ipv6.addr, 0, sizeof(key->ipv6.addr));
635 /* fall-through */
636 case -EPROTO:
629 skb->transport_header = skb->network_header; 637 skb->transport_header = skb->network_header;
630 error = 0; 638 error = 0;
631 } else { 639 break;
640 default:
632 error = nh_len; 641 error = nh_len;
633 } 642 }
634 return error; 643 return error;