diff options
author | Thomas Graf <tgraf@suug.ch> | 2015-01-14 21:53:58 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-01-15 01:11:41 -0500 |
commit | 81bfe3c3cf153441588e50a57f53bc9816f37d37 (patch) | |
tree | 332d23a9c698cff308c8a140a886c5df45a3614d /net/openvswitch | |
parent | d91641d9b5047b0a0a4d223a0b87306e6dff8c02 (diff) |
openvswitch: Allow for any level of nesting in flow attributes
nlattr_set() is currently hardcoded to two levels of nesting. This change
introduces struct ovs_len_tbl to define minimal length requirements plus
next level nesting tables to traverse the key attributes to arbitrary depth.
Signed-off-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/openvswitch')
-rw-r--r-- | net/openvswitch/flow_netlink.c | 106 |
1 files changed, 56 insertions, 50 deletions
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index 2e8a9cd10802..518941c5bdf1 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c | |||
@@ -50,6 +50,13 @@ | |||
50 | 50 | ||
51 | #include "flow_netlink.h" | 51 | #include "flow_netlink.h" |
52 | 52 | ||
53 | struct ovs_len_tbl { | ||
54 | int len; | ||
55 | const struct ovs_len_tbl *next; | ||
56 | }; | ||
57 | |||
58 | #define OVS_ATTR_NESTED -1 | ||
59 | |||
53 | static void update_range(struct sw_flow_match *match, | 60 | static void update_range(struct sw_flow_match *match, |
54 | size_t offset, size_t size, bool is_mask) | 61 | size_t offset, size_t size, bool is_mask) |
55 | { | 62 | { |
@@ -289,29 +296,44 @@ size_t ovs_key_attr_size(void) | |||
289 | + nla_total_size(28); /* OVS_KEY_ATTR_ND */ | 296 | + nla_total_size(28); /* OVS_KEY_ATTR_ND */ |
290 | } | 297 | } |
291 | 298 | ||
299 | static const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1] = { | ||
300 | [OVS_TUNNEL_KEY_ATTR_ID] = { .len = sizeof(u64) }, | ||
301 | [OVS_TUNNEL_KEY_ATTR_IPV4_SRC] = { .len = sizeof(u32) }, | ||
302 | [OVS_TUNNEL_KEY_ATTR_IPV4_DST] = { .len = sizeof(u32) }, | ||
303 | [OVS_TUNNEL_KEY_ATTR_TOS] = { .len = 1 }, | ||
304 | [OVS_TUNNEL_KEY_ATTR_TTL] = { .len = 1 }, | ||
305 | [OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT] = { .len = 0 }, | ||
306 | [OVS_TUNNEL_KEY_ATTR_CSUM] = { .len = 0 }, | ||
307 | [OVS_TUNNEL_KEY_ATTR_TP_SRC] = { .len = sizeof(u16) }, | ||
308 | [OVS_TUNNEL_KEY_ATTR_TP_DST] = { .len = sizeof(u16) }, | ||
309 | [OVS_TUNNEL_KEY_ATTR_OAM] = { .len = 0 }, | ||
310 | [OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = { .len = OVS_ATTR_NESTED }, | ||
311 | }; | ||
312 | |||
292 | /* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute. */ | 313 | /* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute. */ |
293 | static const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = { | 314 | static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = { |
294 | [OVS_KEY_ATTR_ENCAP] = -1, | 315 | [OVS_KEY_ATTR_ENCAP] = { .len = OVS_ATTR_NESTED }, |
295 | [OVS_KEY_ATTR_PRIORITY] = sizeof(u32), | 316 | [OVS_KEY_ATTR_PRIORITY] = { .len = sizeof(u32) }, |
296 | [OVS_KEY_ATTR_IN_PORT] = sizeof(u32), | 317 | [OVS_KEY_ATTR_IN_PORT] = { .len = sizeof(u32) }, |
297 | [OVS_KEY_ATTR_SKB_MARK] = sizeof(u32), | 318 | [OVS_KEY_ATTR_SKB_MARK] = { .len = sizeof(u32) }, |
298 | [OVS_KEY_ATTR_ETHERNET] = sizeof(struct ovs_key_ethernet), | 319 | [OVS_KEY_ATTR_ETHERNET] = { .len = sizeof(struct ovs_key_ethernet) }, |
299 | [OVS_KEY_ATTR_VLAN] = sizeof(__be16), | 320 | [OVS_KEY_ATTR_VLAN] = { .len = sizeof(__be16) }, |
300 | [OVS_KEY_ATTR_ETHERTYPE] = sizeof(__be16), | 321 | [OVS_KEY_ATTR_ETHERTYPE] = { .len = sizeof(__be16) }, |
301 | [OVS_KEY_ATTR_IPV4] = sizeof(struct ovs_key_ipv4), | 322 | [OVS_KEY_ATTR_IPV4] = { .len = sizeof(struct ovs_key_ipv4) }, |
302 | [OVS_KEY_ATTR_IPV6] = sizeof(struct ovs_key_ipv6), | 323 | [OVS_KEY_ATTR_IPV6] = { .len = sizeof(struct ovs_key_ipv6) }, |
303 | [OVS_KEY_ATTR_TCP] = sizeof(struct ovs_key_tcp), | 324 | [OVS_KEY_ATTR_TCP] = { .len = sizeof(struct ovs_key_tcp) }, |
304 | [OVS_KEY_ATTR_TCP_FLAGS] = sizeof(__be16), | 325 | [OVS_KEY_ATTR_TCP_FLAGS] = { .len = sizeof(__be16) }, |
305 | [OVS_KEY_ATTR_UDP] = sizeof(struct ovs_key_udp), | 326 | [OVS_KEY_ATTR_UDP] = { .len = sizeof(struct ovs_key_udp) }, |
306 | [OVS_KEY_ATTR_SCTP] = sizeof(struct ovs_key_sctp), | 327 | [OVS_KEY_ATTR_SCTP] = { .len = sizeof(struct ovs_key_sctp) }, |
307 | [OVS_KEY_ATTR_ICMP] = sizeof(struct ovs_key_icmp), | 328 | [OVS_KEY_ATTR_ICMP] = { .len = sizeof(struct ovs_key_icmp) }, |
308 | [OVS_KEY_ATTR_ICMPV6] = sizeof(struct ovs_key_icmpv6), | 329 | [OVS_KEY_ATTR_ICMPV6] = { .len = sizeof(struct ovs_key_icmpv6) }, |
309 | [OVS_KEY_ATTR_ARP] = sizeof(struct ovs_key_arp), | 330 | [OVS_KEY_ATTR_ARP] = { .len = sizeof(struct ovs_key_arp) }, |
310 | [OVS_KEY_ATTR_ND] = sizeof(struct ovs_key_nd), | 331 | [OVS_KEY_ATTR_ND] = { .len = sizeof(struct ovs_key_nd) }, |
311 | [OVS_KEY_ATTR_RECIRC_ID] = sizeof(u32), | 332 | [OVS_KEY_ATTR_RECIRC_ID] = { .len = sizeof(u32) }, |
312 | [OVS_KEY_ATTR_DP_HASH] = sizeof(u32), | 333 | [OVS_KEY_ATTR_DP_HASH] = { .len = sizeof(u32) }, |
313 | [OVS_KEY_ATTR_TUNNEL] = -1, | 334 | [OVS_KEY_ATTR_TUNNEL] = { .len = OVS_ATTR_NESTED, |
314 | [OVS_KEY_ATTR_MPLS] = sizeof(struct ovs_key_mpls), | 335 | .next = ovs_tunnel_key_lens, }, |
336 | [OVS_KEY_ATTR_MPLS] = { .len = sizeof(struct ovs_key_mpls) }, | ||
315 | }; | 337 | }; |
316 | 338 | ||
317 | static bool is_all_zero(const u8 *fp, size_t size) | 339 | static bool is_all_zero(const u8 *fp, size_t size) |
@@ -352,8 +374,8 @@ static int __parse_flow_nlattrs(const struct nlattr *attr, | |||
352 | return -EINVAL; | 374 | return -EINVAL; |
353 | } | 375 | } |
354 | 376 | ||
355 | expected_len = ovs_key_lens[type]; | 377 | expected_len = ovs_key_lens[type].len; |
356 | if (nla_len(nla) != expected_len && expected_len != -1) { | 378 | if (nla_len(nla) != expected_len && expected_len != OVS_ATTR_NESTED) { |
357 | OVS_NLERR(log, "Key %d has unexpected len %d expected %d", | 379 | OVS_NLERR(log, "Key %d has unexpected len %d expected %d", |
358 | type, nla_len(nla), expected_len); | 380 | type, nla_len(nla), expected_len); |
359 | return -EINVAL; | 381 | return -EINVAL; |
@@ -451,30 +473,16 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr, | |||
451 | int type = nla_type(a); | 473 | int type = nla_type(a); |
452 | int err; | 474 | int err; |
453 | 475 | ||
454 | static const u32 ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1] = { | ||
455 | [OVS_TUNNEL_KEY_ATTR_ID] = sizeof(u64), | ||
456 | [OVS_TUNNEL_KEY_ATTR_IPV4_SRC] = sizeof(u32), | ||
457 | [OVS_TUNNEL_KEY_ATTR_IPV4_DST] = sizeof(u32), | ||
458 | [OVS_TUNNEL_KEY_ATTR_TOS] = 1, | ||
459 | [OVS_TUNNEL_KEY_ATTR_TTL] = 1, | ||
460 | [OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT] = 0, | ||
461 | [OVS_TUNNEL_KEY_ATTR_CSUM] = 0, | ||
462 | [OVS_TUNNEL_KEY_ATTR_TP_SRC] = sizeof(u16), | ||
463 | [OVS_TUNNEL_KEY_ATTR_TP_DST] = sizeof(u16), | ||
464 | [OVS_TUNNEL_KEY_ATTR_OAM] = 0, | ||
465 | [OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = -1, | ||
466 | }; | ||
467 | |||
468 | if (type > OVS_TUNNEL_KEY_ATTR_MAX) { | 476 | if (type > OVS_TUNNEL_KEY_ATTR_MAX) { |
469 | OVS_NLERR(log, "Tunnel attr %d out of range max %d", | 477 | OVS_NLERR(log, "Tunnel attr %d out of range max %d", |
470 | type, OVS_TUNNEL_KEY_ATTR_MAX); | 478 | type, OVS_TUNNEL_KEY_ATTR_MAX); |
471 | return -EINVAL; | 479 | return -EINVAL; |
472 | } | 480 | } |
473 | 481 | ||
474 | if (ovs_tunnel_key_lens[type] != nla_len(a) && | 482 | if (ovs_tunnel_key_lens[type].len != nla_len(a) && |
475 | ovs_tunnel_key_lens[type] != -1) { | 483 | ovs_tunnel_key_lens[type].len != OVS_ATTR_NESTED) { |
476 | OVS_NLERR(log, "Tunnel attr %d has unexpected len %d expected %d", | 484 | OVS_NLERR(log, "Tunnel attr %d has unexpected len %d expected %d", |
477 | type, nla_len(a), ovs_tunnel_key_lens[type]); | 485 | type, nla_len(a), ovs_tunnel_key_lens[type].len); |
478 | return -EINVAL; | 486 | return -EINVAL; |
479 | } | 487 | } |
480 | 488 | ||
@@ -912,18 +920,16 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs, | |||
912 | return 0; | 920 | return 0; |
913 | } | 921 | } |
914 | 922 | ||
915 | static void nlattr_set(struct nlattr *attr, u8 val, bool is_attr_mask_key) | 923 | static void nlattr_set(struct nlattr *attr, u8 val, |
924 | const struct ovs_len_tbl *tbl) | ||
916 | { | 925 | { |
917 | struct nlattr *nla; | 926 | struct nlattr *nla; |
918 | int rem; | 927 | int rem; |
919 | 928 | ||
920 | /* The nlattr stream should already have been validated */ | 929 | /* The nlattr stream should already have been validated */ |
921 | nla_for_each_nested(nla, attr, rem) { | 930 | nla_for_each_nested(nla, attr, rem) { |
922 | /* We assume that ovs_key_lens[type] == -1 means that type is a | 931 | if (tbl && tbl[nla_type(nla)].len == OVS_ATTR_NESTED) |
923 | * nested attribute | 932 | nlattr_set(nla, val, tbl[nla_type(nla)].next); |
924 | */ | ||
925 | if (is_attr_mask_key && ovs_key_lens[nla_type(nla)] == -1) | ||
926 | nlattr_set(nla, val, false); | ||
927 | else | 933 | else |
928 | memset(nla_data(nla), val, nla_len(nla)); | 934 | memset(nla_data(nla), val, nla_len(nla)); |
929 | } | 935 | } |
@@ -931,7 +937,7 @@ static void nlattr_set(struct nlattr *attr, u8 val, bool is_attr_mask_key) | |||
931 | 937 | ||
932 | static void mask_set_nlattr(struct nlattr *attr, u8 val) | 938 | static void mask_set_nlattr(struct nlattr *attr, u8 val) |
933 | { | 939 | { |
934 | nlattr_set(attr, val, true); | 940 | nlattr_set(attr, val, ovs_key_lens); |
935 | } | 941 | } |
936 | 942 | ||
937 | /** | 943 | /** |
@@ -1628,8 +1634,8 @@ static int validate_set(const struct nlattr *a, | |||
1628 | return -EINVAL; | 1634 | return -EINVAL; |
1629 | 1635 | ||
1630 | if (key_type > OVS_KEY_ATTR_MAX || | 1636 | if (key_type > OVS_KEY_ATTR_MAX || |
1631 | (ovs_key_lens[key_type] != nla_len(ovs_key) && | 1637 | (ovs_key_lens[key_type].len != nla_len(ovs_key) && |
1632 | ovs_key_lens[key_type] != -1)) | 1638 | ovs_key_lens[key_type].len != OVS_ATTR_NESTED)) |
1633 | return -EINVAL; | 1639 | return -EINVAL; |
1634 | 1640 | ||
1635 | switch (key_type) { | 1641 | switch (key_type) { |