diff options
author | Pravin B Shelar <pshelar@nicira.com> | 2013-06-17 20:50:18 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-06-19 21:07:41 -0400 |
commit | 7d5437c709ded4f152cb8b305d17972d6707f20c (patch) | |
tree | d69da5004c4a65a0d4f60f5f8884f2aad120698f /net/openvswitch | |
parent | 74f84a5726c7d08c27745305e67474b8645c541d (diff) |
openvswitch: Add tunneling interface.
Add ovs tunnel interface for set tunnel action for userspace.
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Acked-by: Jesse Gross <jesse@nicira.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/openvswitch')
-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 |
9 files changed, 233 insertions, 7 deletions
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 |