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) { |
