diff options
| -rw-r--r-- | include/uapi/linux/openvswitch.h | 18 | ||||
| -rw-r--r-- | net/openvswitch/actions.c | 4 | ||||
| -rw-r--r-- | net/openvswitch/datapath.c | 78 | ||||
| -rw-r--r-- | net/openvswitch/datapath.h | 3 | ||||
| -rw-r--r-- | net/openvswitch/flow.c | 125 | ||||
| -rw-r--r-- | net/openvswitch/flow.h | 19 | ||||
| -rw-r--r-- | net/openvswitch/vport-internal_dev.c | 2 | ||||
| -rw-r--r-- | net/openvswitch/vport-netdev.c | 2 | ||||
| -rw-r--r-- | net/openvswitch/vport.c | 4 | ||||
| -rw-r--r-- | net/openvswitch/vport.h | 3 |
10 files changed, 251 insertions, 7 deletions
diff --git a/include/uapi/linux/openvswitch.h b/include/uapi/linux/openvswitch.h index 424672db7f12..b15a445927d6 100644 --- a/include/uapi/linux/openvswitch.h +++ b/include/uapi/linux/openvswitch.h | |||
| @@ -246,11 +246,29 @@ enum ovs_key_attr { | |||
| 246 | OVS_KEY_ATTR_ARP, /* struct ovs_key_arp */ | 246 | OVS_KEY_ATTR_ARP, /* struct ovs_key_arp */ |
| 247 | OVS_KEY_ATTR_ND, /* struct ovs_key_nd */ | 247 | OVS_KEY_ATTR_ND, /* struct ovs_key_nd */ |
| 248 | OVS_KEY_ATTR_SKB_MARK, /* u32 skb mark */ | 248 | OVS_KEY_ATTR_SKB_MARK, /* u32 skb mark */ |
| 249 | OVS_KEY_ATTR_TUNNEL, /* Nested set of ovs_tunnel attributes */ | ||
| 250 | |||
| 251 | #ifdef __KERNEL__ | ||
| 252 | OVS_KEY_ATTR_IPV4_TUNNEL, /* struct ovs_key_ipv4_tunnel */ | ||
| 253 | #endif | ||
| 249 | __OVS_KEY_ATTR_MAX | 254 | __OVS_KEY_ATTR_MAX |
| 250 | }; | 255 | }; |
| 251 | 256 | ||
| 252 | #define OVS_KEY_ATTR_MAX (__OVS_KEY_ATTR_MAX - 1) | 257 | #define OVS_KEY_ATTR_MAX (__OVS_KEY_ATTR_MAX - 1) |
| 253 | 258 | ||
| 259 | enum ovs_tunnel_key_attr { | ||
| 260 | OVS_TUNNEL_KEY_ATTR_ID, /* be64 Tunnel ID */ | ||
| 261 | OVS_TUNNEL_KEY_ATTR_IPV4_SRC, /* be32 src IP address. */ | ||
| 262 | OVS_TUNNEL_KEY_ATTR_IPV4_DST, /* be32 dst IP address. */ | ||
| 263 | OVS_TUNNEL_KEY_ATTR_TOS, /* u8 Tunnel IP ToS. */ | ||
| 264 | OVS_TUNNEL_KEY_ATTR_TTL, /* u8 Tunnel IP TTL. */ | ||
| 265 | OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT, /* No argument, set DF. */ | ||
| 266 | OVS_TUNNEL_KEY_ATTR_CSUM, /* No argument. CSUM packet. */ | ||
| 267 | __OVS_TUNNEL_KEY_ATTR_MAX | ||
| 268 | }; | ||
| 269 | |||
| 270 | #define OVS_TUNNEL_KEY_ATTR_MAX (__OVS_TUNNEL_KEY_ATTR_MAX - 1) | ||
| 271 | |||
| 254 | /** | 272 | /** |
| 255 | * enum ovs_frag_type - IPv4 and IPv6 fragment type | 273 | * enum ovs_frag_type - IPv4 and IPv6 fragment type |
| 256 | * @OVS_FRAG_TYPE_NONE: Packet is not a fragment. | 274 | * @OVS_FRAG_TYPE_NONE: Packet is not a fragment. |
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 596d6373399d..22c5f399f1cf 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c | |||
| @@ -436,6 +436,10 @@ static int execute_set_action(struct sk_buff *skb, | |||
| 436 | skb->mark = nla_get_u32(nested_attr); | 436 | skb->mark = nla_get_u32(nested_attr); |
| 437 | break; | 437 | break; |
| 438 | 438 | ||
| 439 | case OVS_KEY_ATTR_IPV4_TUNNEL: | ||
| 440 | OVS_CB(skb)->tun_key = nla_data(nested_attr); | ||
| 441 | break; | ||
| 442 | |||
| 439 | case OVS_KEY_ATTR_ETHERNET: | 443 | case OVS_KEY_ATTR_ETHERNET: |
| 440 | err = set_eth_addr(skb, nla_data(nested_attr)); | 444 | err = set_eth_addr(skb, nla_data(nested_attr)); |
| 441 | break; | 445 | break; |
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index f14816b80b80..bbd310646bc8 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c | |||
| @@ -362,6 +362,14 @@ static int queue_gso_packets(struct net *net, int dp_ifindex, | |||
| 362 | static size_t key_attr_size(void) | 362 | static size_t key_attr_size(void) |
| 363 | { | 363 | { |
| 364 | return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */ | 364 | return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */ |
| 365 | + nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */ | ||
| 366 | + nla_total_size(8) /* OVS_TUNNEL_KEY_ATTR_ID */ | ||
| 367 | + nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_IPV4_SRC */ | ||
| 368 | + nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_IPV4_DST */ | ||
| 369 | + nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TOS */ | ||
| 370 | + nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TTL */ | ||
| 371 | + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT */ | ||
| 372 | + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_CSUM */ | ||
| 365 | + nla_total_size(4) /* OVS_KEY_ATTR_IN_PORT */ | 373 | + nla_total_size(4) /* OVS_KEY_ATTR_IN_PORT */ |
| 366 | + nla_total_size(4) /* OVS_KEY_ATTR_SKB_MARK */ | 374 | + nla_total_size(4) /* OVS_KEY_ATTR_SKB_MARK */ |
| 367 | + nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */ | 375 | + nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */ |
| @@ -600,8 +608,30 @@ static int validate_tp_port(const struct sw_flow_key *flow_key) | |||
| 600 | return -EINVAL; | 608 | return -EINVAL; |
| 601 | } | 609 | } |
| 602 | 610 | ||
| 611 | static int validate_and_copy_set_tun(const struct nlattr *attr, | ||
| 612 | struct sw_flow_actions **sfa) | ||
| 613 | { | ||
| 614 | struct ovs_key_ipv4_tunnel tun_key; | ||
| 615 | int err, start; | ||
| 616 | |||
| 617 | err = ovs_ipv4_tun_from_nlattr(nla_data(attr), &tun_key); | ||
| 618 | if (err) | ||
| 619 | return err; | ||
| 620 | |||
| 621 | start = add_nested_action_start(sfa, OVS_ACTION_ATTR_SET); | ||
| 622 | if (start < 0) | ||
| 623 | return start; | ||
| 624 | |||
| 625 | err = add_action(sfa, OVS_KEY_ATTR_IPV4_TUNNEL, &tun_key, sizeof(tun_key)); | ||
| 626 | add_nested_action_end(*sfa, start); | ||
| 627 | |||
| 628 | return err; | ||
| 629 | } | ||
| 630 | |||
| 603 | static int validate_set(const struct nlattr *a, | 631 | static int validate_set(const struct nlattr *a, |
| 604 | const struct sw_flow_key *flow_key) | 632 | const struct sw_flow_key *flow_key, |
| 633 | struct sw_flow_actions **sfa, | ||
| 634 | bool *set_tun) | ||
| 605 | { | 635 | { |
| 606 | const struct nlattr *ovs_key = nla_data(a); | 636 | const struct nlattr *ovs_key = nla_data(a); |
| 607 | int key_type = nla_type(ovs_key); | 637 | int key_type = nla_type(ovs_key); |
| @@ -611,18 +641,27 @@ static int validate_set(const struct nlattr *a, | |||
| 611 | return -EINVAL; | 641 | return -EINVAL; |
| 612 | 642 | ||
| 613 | if (key_type > OVS_KEY_ATTR_MAX || | 643 | if (key_type > OVS_KEY_ATTR_MAX || |
| 614 | nla_len(ovs_key) != ovs_key_lens[key_type]) | 644 | (ovs_key_lens[key_type] != nla_len(ovs_key) && |
| 645 | ovs_key_lens[key_type] != -1)) | ||
| 615 | return -EINVAL; | 646 | return -EINVAL; |
| 616 | 647 | ||
| 617 | switch (key_type) { | 648 | switch (key_type) { |
| 618 | const struct ovs_key_ipv4 *ipv4_key; | 649 | const struct ovs_key_ipv4 *ipv4_key; |
| 619 | const struct ovs_key_ipv6 *ipv6_key; | 650 | const struct ovs_key_ipv6 *ipv6_key; |
| 651 | int err; | ||
| 620 | 652 | ||
| 621 | case OVS_KEY_ATTR_PRIORITY: | 653 | case OVS_KEY_ATTR_PRIORITY: |
| 622 | case OVS_KEY_ATTR_SKB_MARK: | 654 | case OVS_KEY_ATTR_SKB_MARK: |
| 623 | case OVS_KEY_ATTR_ETHERNET: | 655 | case OVS_KEY_ATTR_ETHERNET: |
| 624 | break; | 656 | break; |
| 625 | 657 | ||
| 658 | case OVS_KEY_ATTR_TUNNEL: | ||
| 659 | *set_tun = true; | ||
| 660 | err = validate_and_copy_set_tun(a, sfa); | ||
| 661 | if (err) | ||
| 662 | return err; | ||
| 663 | break; | ||
| 664 | |||
| 626 | case OVS_KEY_ATTR_IPV4: | 665 | case OVS_KEY_ATTR_IPV4: |
| 627 | if (flow_key->eth.type != htons(ETH_P_IP)) | 666 | if (flow_key->eth.type != htons(ETH_P_IP)) |
| 628 | return -EINVAL; | 667 | return -EINVAL; |
| @@ -771,7 +810,7 @@ static int validate_and_copy_actions(const struct nlattr *attr, | |||
| 771 | break; | 810 | break; |
| 772 | 811 | ||
| 773 | case OVS_ACTION_ATTR_SET: | 812 | case OVS_ACTION_ATTR_SET: |
| 774 | err = validate_set(a, key); | 813 | err = validate_set(a, key, sfa, &skip_copy); |
| 775 | if (err) | 814 | if (err) |
| 776 | return err; | 815 | return err; |
| 777 | break; | 816 | break; |
| @@ -993,6 +1032,33 @@ static int sample_action_to_attr(const struct nlattr *attr, struct sk_buff *skb) | |||
| 993 | return err; | 1032 | return err; |
| 994 | } | 1033 | } |
| 995 | 1034 | ||
| 1035 | static int set_action_to_attr(const struct nlattr *a, struct sk_buff *skb) | ||
| 1036 | { | ||
| 1037 | const struct nlattr *ovs_key = nla_data(a); | ||
| 1038 | int key_type = nla_type(ovs_key); | ||
| 1039 | struct nlattr *start; | ||
| 1040 | int err; | ||
| 1041 | |||
| 1042 | switch (key_type) { | ||
| 1043 | case OVS_KEY_ATTR_IPV4_TUNNEL: | ||
| 1044 | start = nla_nest_start(skb, OVS_ACTION_ATTR_SET); | ||
| 1045 | if (!start) | ||
| 1046 | return -EMSGSIZE; | ||
| 1047 | |||
| 1048 | err = ovs_ipv4_tun_to_nlattr(skb, nla_data(ovs_key)); | ||
| 1049 | if (err) | ||
| 1050 | return err; | ||
| 1051 | nla_nest_end(skb, start); | ||
| 1052 | break; | ||
| 1053 | default: | ||
| 1054 | if (nla_put(skb, OVS_ACTION_ATTR_SET, nla_len(a), ovs_key)) | ||
| 1055 | return -EMSGSIZE; | ||
| 1056 | break; | ||
| 1057 | } | ||
| 1058 | |||
| 1059 | return 0; | ||
| 1060 | } | ||
| 1061 | |||
| 996 | static int actions_to_attr(const struct nlattr *attr, int len, struct sk_buff *skb) | 1062 | static int actions_to_attr(const struct nlattr *attr, int len, struct sk_buff *skb) |
| 997 | { | 1063 | { |
| 998 | const struct nlattr *a; | 1064 | const struct nlattr *a; |
| @@ -1002,6 +1068,12 @@ static int actions_to_attr(const struct nlattr *attr, int len, struct sk_buff *s | |||
| 1002 | int type = nla_type(a); | 1068 | int type = nla_type(a); |
| 1003 | 1069 | ||
| 1004 | switch (type) { | 1070 | switch (type) { |
| 1071 | case OVS_ACTION_ATTR_SET: | ||
| 1072 | err = set_action_to_attr(a, skb); | ||
| 1073 | if (err) | ||
| 1074 | return err; | ||
| 1075 | break; | ||
| 1076 | |||
| 1005 | case OVS_ACTION_ATTR_SAMPLE: | 1077 | case OVS_ACTION_ATTR_SAMPLE: |
| 1006 | err = sample_action_to_attr(a, skb); | 1078 | err = sample_action_to_attr(a, skb); |
| 1007 | if (err) | 1079 | if (err) |
diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h index 16b840695216..e88ebc2f1c54 100644 --- a/net/openvswitch/datapath.h +++ b/net/openvswitch/datapath.h | |||
| @@ -88,9 +88,12 @@ struct datapath { | |||
| 88 | /** | 88 | /** |
| 89 | * struct ovs_skb_cb - OVS data in skb CB | 89 | * struct ovs_skb_cb - OVS data in skb CB |
| 90 | * @flow: The flow associated with this packet. May be %NULL if no flow. | 90 | * @flow: The flow associated with this packet. May be %NULL if no flow. |
| 91 | * @tun_key: Key for the tunnel that encapsulated this packet. NULL if the | ||
| 92 | * packet is not being tunneled. | ||
| 91 | */ | 93 | */ |
| 92 | struct ovs_skb_cb { | 94 | struct ovs_skb_cb { |
| 93 | struct sw_flow *flow; | 95 | struct sw_flow *flow; |
| 96 | struct ovs_key_ipv4_tunnel *tun_key; | ||
| 94 | }; | 97 | }; |
| 95 | #define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb) | 98 | #define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb) |
| 96 | 99 | ||
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index 940d4b803ff5..976a8b766a6a 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c | |||
| @@ -40,6 +40,7 @@ | |||
| 40 | #include <linux/icmpv6.h> | 40 | #include <linux/icmpv6.h> |
| 41 | #include <linux/rculist.h> | 41 | #include <linux/rculist.h> |
| 42 | #include <net/ip.h> | 42 | #include <net/ip.h> |
| 43 | #include <net/ip_tunnels.h> | ||
| 43 | #include <net/ipv6.h> | 44 | #include <net/ipv6.h> |
| 44 | #include <net/ndisc.h> | 45 | #include <net/ndisc.h> |
| 45 | 46 | ||
| @@ -603,6 +604,8 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key, | |||
| 603 | memset(key, 0, sizeof(*key)); | 604 | memset(key, 0, sizeof(*key)); |
| 604 | 605 | ||
| 605 | key->phy.priority = skb->priority; | 606 | key->phy.priority = skb->priority; |
| 607 | if (OVS_CB(skb)->tun_key) | ||
| 608 | memcpy(&key->tun_key, OVS_CB(skb)->tun_key, sizeof(key->tun_key)); | ||
| 606 | key->phy.in_port = in_port; | 609 | key->phy.in_port = in_port; |
| 607 | key->phy.skb_mark = skb->mark; | 610 | key->phy.skb_mark = skb->mark; |
| 608 | 611 | ||
| @@ -818,6 +821,7 @@ const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = { | |||
| 818 | [OVS_KEY_ATTR_ICMPV6] = sizeof(struct ovs_key_icmpv6), | 821 | [OVS_KEY_ATTR_ICMPV6] = sizeof(struct ovs_key_icmpv6), |
| 819 | [OVS_KEY_ATTR_ARP] = sizeof(struct ovs_key_arp), | 822 | [OVS_KEY_ATTR_ARP] = sizeof(struct ovs_key_arp), |
| 820 | [OVS_KEY_ATTR_ND] = sizeof(struct ovs_key_nd), | 823 | [OVS_KEY_ATTR_ND] = sizeof(struct ovs_key_nd), |
| 824 | [OVS_KEY_ATTR_TUNNEL] = -1, | ||
| 821 | }; | 825 | }; |
| 822 | 826 | ||
| 823 | static int ipv4_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_len, | 827 | static int ipv4_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_len, |
| @@ -955,6 +959,105 @@ static int parse_flow_nlattrs(const struct nlattr *attr, | |||
| 955 | return 0; | 959 | return 0; |
| 956 | } | 960 | } |
| 957 | 961 | ||
| 962 | int ovs_ipv4_tun_from_nlattr(const struct nlattr *attr, | ||
| 963 | struct ovs_key_ipv4_tunnel *tun_key) | ||
| 964 | { | ||
| 965 | struct nlattr *a; | ||
| 966 | int rem; | ||
| 967 | bool ttl = false; | ||
| 968 | |||
| 969 | memset(tun_key, 0, sizeof(*tun_key)); | ||
| 970 | |||
| 971 | nla_for_each_nested(a, attr, rem) { | ||
| 972 | int type = nla_type(a); | ||
| 973 | static const u32 ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1] = { | ||
| 974 | [OVS_TUNNEL_KEY_ATTR_ID] = sizeof(u64), | ||
| 975 | [OVS_TUNNEL_KEY_ATTR_IPV4_SRC] = sizeof(u32), | ||
| 976 | [OVS_TUNNEL_KEY_ATTR_IPV4_DST] = sizeof(u32), | ||
| 977 | [OVS_TUNNEL_KEY_ATTR_TOS] = 1, | ||
| 978 | [OVS_TUNNEL_KEY_ATTR_TTL] = 1, | ||
| 979 | [OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT] = 0, | ||
| 980 | [OVS_TUNNEL_KEY_ATTR_CSUM] = 0, | ||
| 981 | }; | ||
| 982 | |||
| 983 | if (type > OVS_TUNNEL_KEY_ATTR_MAX || | ||
| 984 | ovs_tunnel_key_lens[type] != nla_len(a)) | ||
| 985 | return -EINVAL; | ||
| 986 | |||
| 987 | switch (type) { | ||
| 988 | case OVS_TUNNEL_KEY_ATTR_ID: | ||
| 989 | tun_key->tun_id = nla_get_be64(a); | ||
| 990 | tun_key->tun_flags |= TUNNEL_KEY; | ||
| 991 | break; | ||
| 992 | case OVS_TUNNEL_KEY_ATTR_IPV4_SRC: | ||
| 993 | tun_key->ipv4_src = nla_get_be32(a); | ||
| 994 | break; | ||
| 995 | case OVS_TUNNEL_KEY_ATTR_IPV4_DST: | ||
| 996 | tun_key->ipv4_dst = nla_get_be32(a); | ||
| 997 | break; | ||
| 998 | case OVS_TUNNEL_KEY_ATTR_TOS: | ||
| 999 | tun_key->ipv4_tos = nla_get_u8(a); | ||
| 1000 | break; | ||
| 1001 | case OVS_TUNNEL_KEY_ATTR_TTL: | ||
| 1002 | tun_key->ipv4_ttl = nla_get_u8(a); | ||
| 1003 | ttl = true; | ||
| 1004 | break; | ||
| 1005 | case OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT: | ||
| 1006 | tun_key->tun_flags |= TUNNEL_DONT_FRAGMENT; | ||
| 1007 | break; | ||
| 1008 | case OVS_TUNNEL_KEY_ATTR_CSUM: | ||
| 1009 | tun_key->tun_flags |= TUNNEL_CSUM; | ||
| 1010 | break; | ||
| 1011 | default: | ||
| 1012 | return -EINVAL; | ||
| 1013 | |||
| 1014 | } | ||
| 1015 | } | ||
| 1016 | if (rem > 0) | ||
| 1017 | return -EINVAL; | ||
| 1018 | |||
| 1019 | if (!tun_key->ipv4_dst) | ||
| 1020 | return -EINVAL; | ||
| 1021 | |||
| 1022 | if (!ttl) | ||
| 1023 | return -EINVAL; | ||
| 1024 | |||
| 1025 | return 0; | ||
| 1026 | } | ||
| 1027 | |||
| 1028 | int ovs_ipv4_tun_to_nlattr(struct sk_buff *skb, | ||
| 1029 | const struct ovs_key_ipv4_tunnel *tun_key) | ||
| 1030 | { | ||
| 1031 | struct nlattr *nla; | ||
| 1032 | |||
| 1033 | nla = nla_nest_start(skb, OVS_KEY_ATTR_TUNNEL); | ||
| 1034 | if (!nla) | ||
| 1035 | return -EMSGSIZE; | ||
| 1036 | |||
| 1037 | if (tun_key->tun_flags & TUNNEL_KEY && | ||
| 1038 | nla_put_be64(skb, OVS_TUNNEL_KEY_ATTR_ID, tun_key->tun_id)) | ||
| 1039 | return -EMSGSIZE; | ||
| 1040 | if (tun_key->ipv4_src && | ||
| 1041 | nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_IPV4_SRC, tun_key->ipv4_src)) | ||
| 1042 | return -EMSGSIZE; | ||
| 1043 | if (nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_IPV4_DST, tun_key->ipv4_dst)) | ||
| 1044 | return -EMSGSIZE; | ||
| 1045 | if (tun_key->ipv4_tos && | ||
| 1046 | nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TOS, tun_key->ipv4_tos)) | ||
| 1047 | return -EMSGSIZE; | ||
| 1048 | if (nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TTL, tun_key->ipv4_ttl)) | ||
| 1049 | return -EMSGSIZE; | ||
| 1050 | if ((tun_key->tun_flags & TUNNEL_DONT_FRAGMENT) && | ||
| 1051 | nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT)) | ||
| 1052 | return -EMSGSIZE; | ||
| 1053 | if ((tun_key->tun_flags & TUNNEL_CSUM) && | ||
| 1054 | nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_CSUM)) | ||
| 1055 | return -EMSGSIZE; | ||
| 1056 | |||
| 1057 | nla_nest_end(skb, nla); | ||
| 1058 | return 0; | ||
| 1059 | } | ||
| 1060 | |||
| 958 | /** | 1061 | /** |
| 959 | * ovs_flow_from_nlattrs - parses Netlink attributes into a flow key. | 1062 | * ovs_flow_from_nlattrs - parses Netlink attributes into a flow key. |
| 960 | * @swkey: receives the extracted flow key. | 1063 | * @swkey: receives the extracted flow key. |
| @@ -997,6 +1100,14 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, | |||
| 997 | attrs &= ~(1 << OVS_KEY_ATTR_SKB_MARK); | 1100 | attrs &= ~(1 << OVS_KEY_ATTR_SKB_MARK); |
| 998 | } | 1101 | } |
| 999 | 1102 | ||
| 1103 | if (attrs & (1 << OVS_KEY_ATTR_TUNNEL)) { | ||
| 1104 | err = ovs_ipv4_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], &swkey->tun_key); | ||
| 1105 | if (err) | ||
| 1106 | return err; | ||
| 1107 | |||
| 1108 | attrs &= ~(1 << OVS_KEY_ATTR_TUNNEL); | ||
| 1109 | } | ||
| 1110 | |||
| 1000 | /* Data attributes. */ | 1111 | /* Data attributes. */ |
| 1001 | if (!(attrs & (1 << OVS_KEY_ATTR_ETHERNET))) | 1112 | if (!(attrs & (1 << OVS_KEY_ATTR_ETHERNET))) |
| 1002 | return -EINVAL; | 1113 | return -EINVAL; |
| @@ -1135,17 +1246,21 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, | |||
| 1135 | int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, | 1246 | int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, |
| 1136 | const struct nlattr *attr) | 1247 | const struct nlattr *attr) |
| 1137 | { | 1248 | { |
| 1249 | struct ovs_key_ipv4_tunnel *tun_key = &flow->key.tun_key; | ||
| 1138 | const struct nlattr *nla; | 1250 | const struct nlattr *nla; |
| 1139 | int rem; | 1251 | int rem; |
| 1140 | 1252 | ||
| 1141 | flow->key.phy.in_port = DP_MAX_PORTS; | 1253 | flow->key.phy.in_port = DP_MAX_PORTS; |
| 1142 | flow->key.phy.priority = 0; | 1254 | flow->key.phy.priority = 0; |
| 1143 | flow->key.phy.skb_mark = 0; | 1255 | flow->key.phy.skb_mark = 0; |
| 1256 | memset(tun_key, 0, sizeof(flow->key.tun_key)); | ||
| 1144 | 1257 | ||
| 1145 | nla_for_each_nested(nla, attr, rem) { | 1258 | nla_for_each_nested(nla, attr, rem) { |
| 1146 | int type = nla_type(nla); | 1259 | int type = nla_type(nla); |
| 1147 | 1260 | ||
| 1148 | if (type <= OVS_KEY_ATTR_MAX && ovs_key_lens[type] > 0) { | 1261 | if (type <= OVS_KEY_ATTR_MAX && ovs_key_lens[type] > 0) { |
| 1262 | int err; | ||
| 1263 | |||
| 1149 | if (nla_len(nla) != ovs_key_lens[type]) | 1264 | if (nla_len(nla) != ovs_key_lens[type]) |
| 1150 | return -EINVAL; | 1265 | return -EINVAL; |
| 1151 | 1266 | ||
| @@ -1154,6 +1269,12 @@ int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, | |||
| 1154 | flow->key.phy.priority = nla_get_u32(nla); | 1269 | flow->key.phy.priority = nla_get_u32(nla); |
| 1155 | break; | 1270 | break; |
| 1156 | 1271 | ||
| 1272 | case OVS_KEY_ATTR_TUNNEL: | ||
| 1273 | err = ovs_ipv4_tun_from_nlattr(nla, tun_key); | ||
| 1274 | if (err) | ||
| 1275 | return err; | ||
| 1276 | break; | ||
| 1277 | |||
| 1157 | case OVS_KEY_ATTR_IN_PORT: | 1278 | case OVS_KEY_ATTR_IN_PORT: |
| 1158 | if (nla_get_u32(nla) >= DP_MAX_PORTS) | 1279 | if (nla_get_u32(nla) >= DP_MAX_PORTS) |
| 1159 | return -EINVAL; | 1280 | return -EINVAL; |
| @@ -1180,6 +1301,10 @@ int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb) | |||
| 1180 | nla_put_u32(skb, OVS_KEY_ATTR_PRIORITY, swkey->phy.priority)) | 1301 | nla_put_u32(skb, OVS_KEY_ATTR_PRIORITY, swkey->phy.priority)) |
| 1181 | goto nla_put_failure; | 1302 | goto nla_put_failure; |
| 1182 | 1303 | ||
| 1304 | if (swkey->tun_key.ipv4_dst && | ||
| 1305 | ovs_ipv4_tun_to_nlattr(skb, &swkey->tun_key)) | ||
| 1306 | goto nla_put_failure; | ||
| 1307 | |||
| 1183 | if (swkey->phy.in_port != DP_MAX_PORTS && | 1308 | if (swkey->phy.in_port != DP_MAX_PORTS && |
| 1184 | nla_put_u32(skb, OVS_KEY_ATTR_IN_PORT, swkey->phy.in_port)) | 1309 | nla_put_u32(skb, OVS_KEY_ATTR_IN_PORT, swkey->phy.in_port)) |
| 1185 | goto nla_put_failure; | 1310 | goto nla_put_failure; |
diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h index e370f6246ee9..aec5e43f690b 100644 --- a/net/openvswitch/flow.h +++ b/net/openvswitch/flow.h | |||
| @@ -40,7 +40,22 @@ struct sw_flow_actions { | |||
| 40 | struct nlattr actions[]; | 40 | struct nlattr actions[]; |
| 41 | }; | 41 | }; |
| 42 | 42 | ||
| 43 | /* Used to memset ovs_key_ipv4_tunnel padding. */ | ||
| 44 | #define OVS_TUNNEL_KEY_SIZE \ | ||
| 45 | (offsetof(struct ovs_key_ipv4_tunnel, ipv4_ttl) + \ | ||
| 46 | FIELD_SIZEOF(struct ovs_key_ipv4_tunnel, ipv4_ttl)) | ||
| 47 | |||
| 48 | struct ovs_key_ipv4_tunnel { | ||
| 49 | __be64 tun_id; | ||
| 50 | __be32 ipv4_src; | ||
| 51 | __be32 ipv4_dst; | ||
| 52 | u16 tun_flags; | ||
| 53 | u8 ipv4_tos; | ||
| 54 | u8 ipv4_ttl; | ||
| 55 | }; | ||
| 56 | |||
| 43 | struct sw_flow_key { | 57 | struct sw_flow_key { |
| 58 | struct ovs_key_ipv4_tunnel tun_key; /* Encapsulating tunnel key. */ | ||
| 44 | struct { | 59 | struct { |
| 45 | u32 priority; /* Packet QoS priority. */ | 60 | u32 priority; /* Packet QoS priority. */ |
| 46 | u32 skb_mark; /* SKB mark. */ | 61 | u32 skb_mark; /* SKB mark. */ |
| @@ -179,5 +194,9 @@ u32 ovs_flow_hash(const struct sw_flow_key *key, int key_len); | |||
| 179 | 194 | ||
| 180 | struct sw_flow *ovs_flow_tbl_next(struct flow_table *table, u32 *bucket, u32 *idx); | 195 | struct sw_flow *ovs_flow_tbl_next(struct flow_table *table, u32 *bucket, u32 *idx); |
| 181 | extern const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1]; | 196 | extern const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1]; |
| 197 | int ovs_ipv4_tun_from_nlattr(const struct nlattr *attr, | ||
| 198 | struct ovs_key_ipv4_tunnel *tun_key); | ||
| 199 | int ovs_ipv4_tun_to_nlattr(struct sk_buff *skb, | ||
| 200 | const struct ovs_key_ipv4_tunnel *tun_key); | ||
| 182 | 201 | ||
| 183 | #endif /* flow.h */ | 202 | #endif /* flow.h */ |
diff --git a/net/openvswitch/vport-internal_dev.c b/net/openvswitch/vport-internal_dev.c index e284c7e1fec4..98d3edbbc235 100644 --- a/net/openvswitch/vport-internal_dev.c +++ b/net/openvswitch/vport-internal_dev.c | |||
| @@ -67,7 +67,7 @@ static struct rtnl_link_stats64 *internal_dev_get_stats(struct net_device *netde | |||
| 67 | static int internal_dev_xmit(struct sk_buff *skb, struct net_device *netdev) | 67 | static int internal_dev_xmit(struct sk_buff *skb, struct net_device *netdev) |
| 68 | { | 68 | { |
| 69 | rcu_read_lock(); | 69 | rcu_read_lock(); |
| 70 | ovs_vport_receive(internal_dev_priv(netdev)->vport, skb); | 70 | ovs_vport_receive(internal_dev_priv(netdev)->vport, skb, NULL); |
| 71 | rcu_read_unlock(); | 71 | rcu_read_unlock(); |
| 72 | return 0; | 72 | return 0; |
| 73 | } | 73 | } |
diff --git a/net/openvswitch/vport-netdev.c b/net/openvswitch/vport-netdev.c index 40de815b4213..5982f3f62835 100644 --- a/net/openvswitch/vport-netdev.c +++ b/net/openvswitch/vport-netdev.c | |||
| @@ -51,7 +51,7 @@ static void netdev_port_receive(struct vport *vport, struct sk_buff *skb) | |||
| 51 | skb_push(skb, ETH_HLEN); | 51 | skb_push(skb, ETH_HLEN); |
| 52 | ovs_skb_postpush_rcsum(skb, skb->data, ETH_HLEN); | 52 | ovs_skb_postpush_rcsum(skb, skb->data, ETH_HLEN); |
| 53 | 53 | ||
| 54 | ovs_vport_receive(vport, skb); | 54 | ovs_vport_receive(vport, skb, NULL); |
| 55 | return; | 55 | return; |
| 56 | 56 | ||
| 57 | error: | 57 | error: |
diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index 176d449351eb..413287a1877f 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c | |||
| @@ -325,7 +325,8 @@ int ovs_vport_get_options(const struct vport *vport, struct sk_buff *skb) | |||
| 325 | * Must be called with rcu_read_lock. The packet cannot be shared and | 325 | * Must be called with rcu_read_lock. The packet cannot be shared and |
| 326 | * skb->data should point to the Ethernet header. | 326 | * skb->data should point to the Ethernet header. |
| 327 | */ | 327 | */ |
| 328 | void ovs_vport_receive(struct vport *vport, struct sk_buff *skb) | 328 | void ovs_vport_receive(struct vport *vport, struct sk_buff *skb, |
| 329 | struct ovs_key_ipv4_tunnel *tun_key) | ||
| 329 | { | 330 | { |
| 330 | struct pcpu_tstats *stats; | 331 | struct pcpu_tstats *stats; |
| 331 | 332 | ||
| @@ -335,6 +336,7 @@ void ovs_vport_receive(struct vport *vport, struct sk_buff *skb) | |||
| 335 | stats->rx_bytes += skb->len; | 336 | stats->rx_bytes += skb->len; |
| 336 | u64_stats_update_end(&stats->syncp); | 337 | u64_stats_update_end(&stats->syncp); |
| 337 | 338 | ||
| 339 | OVS_CB(skb)->tun_key = tun_key; | ||
| 338 | ovs_dp_process_received_packet(vport, skb); | 340 | ovs_dp_process_received_packet(vport, skb); |
| 339 | } | 341 | } |
| 340 | 342 | ||
diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h index 293278c4c2df..2d961aedd71d 100644 --- a/net/openvswitch/vport.h +++ b/net/openvswitch/vport.h | |||
| @@ -184,7 +184,8 @@ static inline struct vport *vport_from_priv(const void *priv) | |||
| 184 | return (struct vport *)(priv - ALIGN(sizeof(struct vport), VPORT_ALIGN)); | 184 | return (struct vport *)(priv - ALIGN(sizeof(struct vport), VPORT_ALIGN)); |
| 185 | } | 185 | } |
| 186 | 186 | ||
| 187 | void ovs_vport_receive(struct vport *, struct sk_buff *); | 187 | void ovs_vport_receive(struct vport *, struct sk_buff *, |
| 188 | struct ovs_key_ipv4_tunnel *); | ||
| 188 | void ovs_vport_record_error(struct vport *, enum vport_err_type err_type); | 189 | void ovs_vport_record_error(struct vport *, enum vport_err_type err_type); |
| 189 | 190 | ||
| 190 | /* List of statically compiled vport implementations. Don't forget to also | 191 | /* List of statically compiled vport implementations. Don't forget to also |
