aboutsummaryrefslogtreecommitdiffstats
path: root/net/openvswitch
diff options
context:
space:
mode:
Diffstat (limited to 'net/openvswitch')
-rw-r--r--net/openvswitch/Kconfig3
-rw-r--r--net/openvswitch/conntrack.c8
-rw-r--r--net/openvswitch/datapath.c4
-rw-r--r--net/openvswitch/flow_netlink.c82
-rw-r--r--net/openvswitch/flow_table.c23
-rw-r--r--net/openvswitch/flow_table.h2
6 files changed, 81 insertions, 41 deletions
diff --git a/net/openvswitch/Kconfig b/net/openvswitch/Kconfig
index 2a071f470d57..d143aa9f6654 100644
--- a/net/openvswitch/Kconfig
+++ b/net/openvswitch/Kconfig
@@ -5,7 +5,8 @@
5config OPENVSWITCH 5config OPENVSWITCH
6 tristate "Open vSwitch" 6 tristate "Open vSwitch"
7 depends on INET 7 depends on INET
8 depends on (!NF_CONNTRACK || NF_CONNTRACK) 8 depends on !NF_CONNTRACK || \
9 (NF_CONNTRACK && (!NF_DEFRAG_IPV6 || NF_DEFRAG_IPV6))
9 select LIBCRC32C 10 select LIBCRC32C
10 select MPLS 11 select MPLS
11 select NET_MPLS_GSO 12 select NET_MPLS_GSO
diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c
index e8e524ad8a01..002a755fa07e 100644
--- a/net/openvswitch/conntrack.c
+++ b/net/openvswitch/conntrack.c
@@ -275,13 +275,15 @@ static int ovs_ct_helper(struct sk_buff *skb, u16 proto)
275 case NFPROTO_IPV6: { 275 case NFPROTO_IPV6: {
276 u8 nexthdr = ipv6_hdr(skb)->nexthdr; 276 u8 nexthdr = ipv6_hdr(skb)->nexthdr;
277 __be16 frag_off; 277 __be16 frag_off;
278 int ofs;
278 279
279 protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), 280 ofs = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr,
280 &nexthdr, &frag_off); 281 &frag_off);
281 if (protoff < 0 || (frag_off & htons(~0x7)) != 0) { 282 if (ofs < 0 || (frag_off & htons(~0x7)) != 0) {
282 pr_debug("proto header not found\n"); 283 pr_debug("proto header not found\n");
283 return NF_ACCEPT; 284 return NF_ACCEPT;
284 } 285 }
286 protoff = ofs;
285 break; 287 break;
286 } 288 }
287 default: 289 default:
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index 6fbd2decb19e..b816ff871528 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -952,7 +952,7 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
952 if (error) 952 if (error)
953 goto err_kfree_flow; 953 goto err_kfree_flow;
954 954
955 ovs_flow_mask_key(&new_flow->key, &key, &mask); 955 ovs_flow_mask_key(&new_flow->key, &key, true, &mask);
956 956
957 /* Extract flow identifier. */ 957 /* Extract flow identifier. */
958 error = ovs_nla_get_identifier(&new_flow->id, a[OVS_FLOW_ATTR_UFID], 958 error = ovs_nla_get_identifier(&new_flow->id, a[OVS_FLOW_ATTR_UFID],
@@ -1080,7 +1080,7 @@ static struct sw_flow_actions *get_flow_actions(struct net *net,
1080 struct sw_flow_key masked_key; 1080 struct sw_flow_key masked_key;
1081 int error; 1081 int error;
1082 1082
1083 ovs_flow_mask_key(&masked_key, key, mask); 1083 ovs_flow_mask_key(&masked_key, key, true, mask);
1084 error = ovs_nla_copy_actions(net, a, &masked_key, &acts, log); 1084 error = ovs_nla_copy_actions(net, a, &masked_key, &acts, log);
1085 if (error) { 1085 if (error) {
1086 OVS_NLERR(log, 1086 OVS_NLERR(log,
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c
index c92d6a262bc5..5c030a4d7338 100644
--- a/net/openvswitch/flow_netlink.c
+++ b/net/openvswitch/flow_netlink.c
@@ -57,6 +57,7 @@ struct ovs_len_tbl {
57}; 57};
58 58
59#define OVS_ATTR_NESTED -1 59#define OVS_ATTR_NESTED -1
60#define OVS_ATTR_VARIABLE -2
60 61
61static void update_range(struct sw_flow_match *match, 62static void update_range(struct sw_flow_match *match,
62 size_t offset, size_t size, bool is_mask) 63 size_t offset, size_t size, bool is_mask)
@@ -304,6 +305,10 @@ size_t ovs_key_attr_size(void)
304 + nla_total_size(28); /* OVS_KEY_ATTR_ND */ 305 + nla_total_size(28); /* OVS_KEY_ATTR_ND */
305} 306}
306 307
308static const struct ovs_len_tbl ovs_vxlan_ext_key_lens[OVS_VXLAN_EXT_MAX + 1] = {
309 [OVS_VXLAN_EXT_GBP] = { .len = sizeof(u32) },
310};
311
307static const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1] = { 312static const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1] = {
308 [OVS_TUNNEL_KEY_ATTR_ID] = { .len = sizeof(u64) }, 313 [OVS_TUNNEL_KEY_ATTR_ID] = { .len = sizeof(u64) },
309 [OVS_TUNNEL_KEY_ATTR_IPV4_SRC] = { .len = sizeof(u32) }, 314 [OVS_TUNNEL_KEY_ATTR_IPV4_SRC] = { .len = sizeof(u32) },
@@ -315,8 +320,9 @@ static const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1]
315 [OVS_TUNNEL_KEY_ATTR_TP_SRC] = { .len = sizeof(u16) }, 320 [OVS_TUNNEL_KEY_ATTR_TP_SRC] = { .len = sizeof(u16) },
316 [OVS_TUNNEL_KEY_ATTR_TP_DST] = { .len = sizeof(u16) }, 321 [OVS_TUNNEL_KEY_ATTR_TP_DST] = { .len = sizeof(u16) },
317 [OVS_TUNNEL_KEY_ATTR_OAM] = { .len = 0 }, 322 [OVS_TUNNEL_KEY_ATTR_OAM] = { .len = 0 },
318 [OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = { .len = OVS_ATTR_NESTED }, 323 [OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = { .len = OVS_ATTR_VARIABLE },
319 [OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS] = { .len = OVS_ATTR_NESTED }, 324 [OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS] = { .len = OVS_ATTR_NESTED,
325 .next = ovs_vxlan_ext_key_lens },
320}; 326};
321 327
322/* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute. */ 328/* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute. */
@@ -349,6 +355,13 @@ static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
349 [OVS_KEY_ATTR_CT_LABEL] = { .len = sizeof(struct ovs_key_ct_label) }, 355 [OVS_KEY_ATTR_CT_LABEL] = { .len = sizeof(struct ovs_key_ct_label) },
350}; 356};
351 357
358static bool check_attr_len(unsigned int attr_len, unsigned int expected_len)
359{
360 return expected_len == attr_len ||
361 expected_len == OVS_ATTR_NESTED ||
362 expected_len == OVS_ATTR_VARIABLE;
363}
364
352static bool is_all_zero(const u8 *fp, size_t size) 365static bool is_all_zero(const u8 *fp, size_t size)
353{ 366{
354 int i; 367 int i;
@@ -388,7 +401,7 @@ static int __parse_flow_nlattrs(const struct nlattr *attr,
388 } 401 }
389 402
390 expected_len = ovs_key_lens[type].len; 403 expected_len = ovs_key_lens[type].len;
391 if (nla_len(nla) != expected_len && expected_len != OVS_ATTR_NESTED) { 404 if (!check_attr_len(nla_len(nla), expected_len)) {
392 OVS_NLERR(log, "Key %d has unexpected len %d expected %d", 405 OVS_NLERR(log, "Key %d has unexpected len %d expected %d",
393 type, nla_len(nla), expected_len); 406 type, nla_len(nla), expected_len);
394 return -EINVAL; 407 return -EINVAL;
@@ -473,29 +486,50 @@ static int genev_tun_opt_from_nlattr(const struct nlattr *a,
473 return 0; 486 return 0;
474} 487}
475 488
476static const struct nla_policy vxlan_opt_policy[OVS_VXLAN_EXT_MAX + 1] = { 489static int vxlan_tun_opt_from_nlattr(const struct nlattr *attr,
477 [OVS_VXLAN_EXT_GBP] = { .type = NLA_U32 },
478};
479
480static int vxlan_tun_opt_from_nlattr(const struct nlattr *a,
481 struct sw_flow_match *match, bool is_mask, 490 struct sw_flow_match *match, bool is_mask,
482 bool log) 491 bool log)
483{ 492{
484 struct nlattr *tb[OVS_VXLAN_EXT_MAX+1]; 493 struct nlattr *a;
494 int rem;
485 unsigned long opt_key_offset; 495 unsigned long opt_key_offset;
486 struct vxlan_metadata opts; 496 struct vxlan_metadata opts;
487 int err;
488 497
489 BUILD_BUG_ON(sizeof(opts) > sizeof(match->key->tun_opts)); 498 BUILD_BUG_ON(sizeof(opts) > sizeof(match->key->tun_opts));
490 499
491 err = nla_parse_nested(tb, OVS_VXLAN_EXT_MAX, a, vxlan_opt_policy);
492 if (err < 0)
493 return err;
494
495 memset(&opts, 0, sizeof(opts)); 500 memset(&opts, 0, sizeof(opts));
501 nla_for_each_nested(a, attr, rem) {
502 int type = nla_type(a);
496 503
497 if (tb[OVS_VXLAN_EXT_GBP]) 504 if (type > OVS_VXLAN_EXT_MAX) {
498 opts.gbp = nla_get_u32(tb[OVS_VXLAN_EXT_GBP]); 505 OVS_NLERR(log, "VXLAN extension %d out of range max %d",
506 type, OVS_VXLAN_EXT_MAX);
507 return -EINVAL;
508 }
509
510 if (!check_attr_len(nla_len(a),
511 ovs_vxlan_ext_key_lens[type].len)) {
512 OVS_NLERR(log, "VXLAN extension %d has unexpected len %d expected %d",
513 type, nla_len(a),
514 ovs_vxlan_ext_key_lens[type].len);
515 return -EINVAL;
516 }
517
518 switch (type) {
519 case OVS_VXLAN_EXT_GBP:
520 opts.gbp = nla_get_u32(a);
521 break;
522 default:
523 OVS_NLERR(log, "Unknown VXLAN extension attribute %d",
524 type);
525 return -EINVAL;
526 }
527 }
528 if (rem) {
529 OVS_NLERR(log, "VXLAN extension message has %d unknown bytes.",
530 rem);
531 return -EINVAL;
532 }
499 533
500 if (!is_mask) 534 if (!is_mask)
501 SW_FLOW_KEY_PUT(match, tun_opts_len, sizeof(opts), false); 535 SW_FLOW_KEY_PUT(match, tun_opts_len, sizeof(opts), false);
@@ -528,8 +562,8 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
528 return -EINVAL; 562 return -EINVAL;
529 } 563 }
530 564
531 if (ovs_tunnel_key_lens[type].len != nla_len(a) && 565 if (!check_attr_len(nla_len(a),
532 ovs_tunnel_key_lens[type].len != OVS_ATTR_NESTED) { 566 ovs_tunnel_key_lens[type].len)) {
533 OVS_NLERR(log, "Tunnel attr %d has unexpected len %d expected %d", 567 OVS_NLERR(log, "Tunnel attr %d has unexpected len %d expected %d",
534 type, nla_len(a), ovs_tunnel_key_lens[type].len); 568 type, nla_len(a), ovs_tunnel_key_lens[type].len);
535 return -EINVAL; 569 return -EINVAL;
@@ -1052,10 +1086,13 @@ static void nlattr_set(struct nlattr *attr, u8 val,
1052 1086
1053 /* The nlattr stream should already have been validated */ 1087 /* The nlattr stream should already have been validated */
1054 nla_for_each_nested(nla, attr, rem) { 1088 nla_for_each_nested(nla, attr, rem) {
1055 if (tbl && tbl[nla_type(nla)].len == OVS_ATTR_NESTED) 1089 if (tbl[nla_type(nla)].len == OVS_ATTR_NESTED) {
1056 nlattr_set(nla, val, tbl[nla_type(nla)].next); 1090 if (tbl[nla_type(nla)].next)
1057 else 1091 tbl = tbl[nla_type(nla)].next;
1092 nlattr_set(nla, val, tbl);
1093 } else {
1058 memset(nla_data(nla), val, nla_len(nla)); 1094 memset(nla_data(nla), val, nla_len(nla));
1095 }
1059 } 1096 }
1060} 1097}
1061 1098
@@ -1922,8 +1959,7 @@ static int validate_set(const struct nlattr *a,
1922 key_len /= 2; 1959 key_len /= 2;
1923 1960
1924 if (key_type > OVS_KEY_ATTR_MAX || 1961 if (key_type > OVS_KEY_ATTR_MAX ||
1925 (ovs_key_lens[key_type].len != key_len && 1962 !check_attr_len(key_len, ovs_key_lens[key_type].len))
1926 ovs_key_lens[key_type].len != OVS_ATTR_NESTED))
1927 return -EINVAL; 1963 return -EINVAL;
1928 1964
1929 if (masked && !validate_masked(nla_data(ovs_key), key_len)) 1965 if (masked && !validate_masked(nla_data(ovs_key), key_len))
diff --git a/net/openvswitch/flow_table.c b/net/openvswitch/flow_table.c
index d22d8e948d0f..f2ea83ba4763 100644
--- a/net/openvswitch/flow_table.c
+++ b/net/openvswitch/flow_table.c
@@ -57,20 +57,21 @@ static u16 range_n_bytes(const struct sw_flow_key_range *range)
57} 57}
58 58
59void ovs_flow_mask_key(struct sw_flow_key *dst, const struct sw_flow_key *src, 59void ovs_flow_mask_key(struct sw_flow_key *dst, const struct sw_flow_key *src,
60 const struct sw_flow_mask *mask) 60 bool full, const struct sw_flow_mask *mask)
61{ 61{
62 const long *m = (const long *)((const u8 *)&mask->key + 62 int start = full ? 0 : mask->range.start;
63 mask->range.start); 63 int len = full ? sizeof *dst : range_n_bytes(&mask->range);
64 const long *s = (const long *)((const u8 *)src + 64 const long *m = (const long *)((const u8 *)&mask->key + start);
65 mask->range.start); 65 const long *s = (const long *)((const u8 *)src + start);
66 long *d = (long *)((u8 *)dst + mask->range.start); 66 long *d = (long *)((u8 *)dst + start);
67 int i; 67 int i;
68 68
69 /* The memory outside of the 'mask->range' are not set since 69 /* If 'full' is true then all of 'dst' is fully initialized. Otherwise,
70 * further operations on 'dst' only uses contents within 70 * if 'full' is false the memory outside of the 'mask->range' is left
71 * 'mask->range'. 71 * uninitialized. This can be used as an optimization when further
72 * operations on 'dst' only use contents within 'mask->range'.
72 */ 73 */
73 for (i = 0; i < range_n_bytes(&mask->range); i += sizeof(long)) 74 for (i = 0; i < len; i += sizeof(long))
74 *d++ = *s++ & *m++; 75 *d++ = *s++ & *m++;
75} 76}
76 77
@@ -475,7 +476,7 @@ static struct sw_flow *masked_flow_lookup(struct table_instance *ti,
475 u32 hash; 476 u32 hash;
476 struct sw_flow_key masked_key; 477 struct sw_flow_key masked_key;
477 478
478 ovs_flow_mask_key(&masked_key, unmasked, mask); 479 ovs_flow_mask_key(&masked_key, unmasked, false, mask);
479 hash = flow_hash(&masked_key, &mask->range); 480 hash = flow_hash(&masked_key, &mask->range);
480 head = find_bucket(ti, hash); 481 head = find_bucket(ti, hash);
481 hlist_for_each_entry_rcu(flow, head, flow_table.node[ti->node_ver]) { 482 hlist_for_each_entry_rcu(flow, head, flow_table.node[ti->node_ver]) {
diff --git a/net/openvswitch/flow_table.h b/net/openvswitch/flow_table.h
index 616eda10d955..2dd9900f533d 100644
--- a/net/openvswitch/flow_table.h
+++ b/net/openvswitch/flow_table.h
@@ -86,5 +86,5 @@ struct sw_flow *ovs_flow_tbl_lookup_ufid(struct flow_table *,
86bool ovs_flow_cmp(const struct sw_flow *, const struct sw_flow_match *); 86bool ovs_flow_cmp(const struct sw_flow *, const struct sw_flow_match *);
87 87
88void ovs_flow_mask_key(struct sw_flow_key *dst, const struct sw_flow_key *src, 88void ovs_flow_mask_key(struct sw_flow_key *dst, const struct sw_flow_key *src,
89 const struct sw_flow_mask *mask); 89 bool full, const struct sw_flow_mask *mask);
90#endif /* flow_table.h */ 90#endif /* flow_table.h */