diff options
author | Pravin B Shelar <pshelar@nicira.com> | 2013-08-19 14:23:34 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-08-20 03:15:44 -0400 |
commit | 58264848a5a7b91195f43c4729072e8cc980288d (patch) | |
tree | edf1ffa351402de61a4fe26e4443872c2d7b1dcb /net/openvswitch | |
parent | 1eaa81785a70082213d40de14ec13520b5c6fff2 (diff) |
openvswitch: Add vxlan tunneling support.
Following patch adds vxlan vport type for openvswitch using
vxlan api. So now there is vxlan dependency for openvswitch.
CC: Jesse Gross <jesse@nicira.com>
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/Kconfig | 13 | ||||
-rw-r--r-- | net/openvswitch/Makefile | 4 | ||||
-rw-r--r-- | net/openvswitch/vport-vxlan.c | 204 | ||||
-rw-r--r-- | net/openvswitch/vport.c | 3 | ||||
-rw-r--r-- | net/openvswitch/vport.h | 1 |
5 files changed, 225 insertions, 0 deletions
diff --git a/net/openvswitch/Kconfig b/net/openvswitch/Kconfig index 27ee56b688a3..bed30e69baa7 100644 --- a/net/openvswitch/Kconfig +++ b/net/openvswitch/Kconfig | |||
@@ -40,3 +40,16 @@ config OPENVSWITCH_GRE | |||
40 | Say N to exclude this support and reduce the binary size. | 40 | Say N to exclude this support and reduce the binary size. |
41 | 41 | ||
42 | If unsure, say Y. | 42 | If unsure, say Y. |
43 | |||
44 | config OPENVSWITCH_VXLAN | ||
45 | bool "Open vSwitch VXLAN tunneling support" | ||
46 | depends on INET | ||
47 | depends on OPENVSWITCH | ||
48 | depends on VXLAN && !(OPENVSWITCH=y && VXLAN=m) | ||
49 | default y | ||
50 | ---help--- | ||
51 | If you say Y here, then the Open vSwitch will be able create vxlan vport. | ||
52 | |||
53 | Say N to exclude this support and reduce the binary size. | ||
54 | |||
55 | If unsure, say Y. | ||
diff --git a/net/openvswitch/Makefile b/net/openvswitch/Makefile index 01bddb2991e3..82e4ee54a44b 100644 --- a/net/openvswitch/Makefile +++ b/net/openvswitch/Makefile | |||
@@ -13,3 +13,7 @@ openvswitch-y := \ | |||
13 | vport-gre.o \ | 13 | vport-gre.o \ |
14 | vport-internal_dev.o \ | 14 | vport-internal_dev.o \ |
15 | vport-netdev.o | 15 | vport-netdev.o |
16 | |||
17 | ifneq ($(CONFIG_OPENVSWITCH_VXLAN),) | ||
18 | openvswitch-y += vport-vxlan.o | ||
19 | endif | ||
diff --git a/net/openvswitch/vport-vxlan.c b/net/openvswitch/vport-vxlan.c new file mode 100644 index 000000000000..36848bd54a77 --- /dev/null +++ b/net/openvswitch/vport-vxlan.c | |||
@@ -0,0 +1,204 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013 Nicira, Inc. | ||
3 | * Copyright (c) 2013 Cisco Systems, Inc. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of version 2 of the GNU General Public | ||
7 | * License as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but | ||
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | * General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
17 | * 02110-1301, USA | ||
18 | */ | ||
19 | |||
20 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
21 | |||
22 | #include <linux/in.h> | ||
23 | #include <linux/ip.h> | ||
24 | #include <linux/net.h> | ||
25 | #include <linux/rculist.h> | ||
26 | #include <linux/udp.h> | ||
27 | |||
28 | #include <net/icmp.h> | ||
29 | #include <net/ip.h> | ||
30 | #include <net/udp.h> | ||
31 | #include <net/ip_tunnels.h> | ||
32 | #include <net/udp.h> | ||
33 | #include <net/rtnetlink.h> | ||
34 | #include <net/route.h> | ||
35 | #include <net/dsfield.h> | ||
36 | #include <net/inet_ecn.h> | ||
37 | #include <net/net_namespace.h> | ||
38 | #include <net/netns/generic.h> | ||
39 | #include <net/vxlan.h> | ||
40 | |||
41 | #include "datapath.h" | ||
42 | #include "vport.h" | ||
43 | |||
44 | /** | ||
45 | * struct vxlan_port - Keeps track of open UDP ports | ||
46 | * @vs: vxlan_sock created for the port. | ||
47 | * @name: vport name. | ||
48 | */ | ||
49 | struct vxlan_port { | ||
50 | struct vxlan_sock *vs; | ||
51 | char name[IFNAMSIZ]; | ||
52 | }; | ||
53 | |||
54 | static inline struct vxlan_port *vxlan_vport(const struct vport *vport) | ||
55 | { | ||
56 | return vport_priv(vport); | ||
57 | } | ||
58 | |||
59 | /* Called with rcu_read_lock and BH disabled. */ | ||
60 | static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, __be32 vx_vni) | ||
61 | { | ||
62 | struct ovs_key_ipv4_tunnel tun_key; | ||
63 | struct vport *vport = vs->data; | ||
64 | struct iphdr *iph; | ||
65 | __be64 key; | ||
66 | |||
67 | /* Save outer tunnel values */ | ||
68 | iph = ip_hdr(skb); | ||
69 | key = cpu_to_be64(ntohl(vx_vni) >> 8); | ||
70 | ovs_flow_tun_key_init(&tun_key, iph, key, TUNNEL_KEY); | ||
71 | |||
72 | ovs_vport_receive(vport, skb, &tun_key); | ||
73 | } | ||
74 | |||
75 | static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb) | ||
76 | { | ||
77 | struct vxlan_port *vxlan_port = vxlan_vport(vport); | ||
78 | __be16 dst_port = inet_sk(vxlan_port->vs->sock->sk)->inet_sport; | ||
79 | |||
80 | if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, ntohs(dst_port))) | ||
81 | return -EMSGSIZE; | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static void vxlan_tnl_destroy(struct vport *vport) | ||
86 | { | ||
87 | struct vxlan_port *vxlan_port = vxlan_vport(vport); | ||
88 | |||
89 | vxlan_sock_release(vxlan_port->vs); | ||
90 | |||
91 | ovs_vport_deferred_free(vport); | ||
92 | } | ||
93 | |||
94 | static struct vport *vxlan_tnl_create(const struct vport_parms *parms) | ||
95 | { | ||
96 | struct net *net = ovs_dp_get_net(parms->dp); | ||
97 | struct nlattr *options = parms->options; | ||
98 | struct vxlan_port *vxlan_port; | ||
99 | struct vxlan_sock *vs; | ||
100 | struct vport *vport; | ||
101 | struct nlattr *a; | ||
102 | u16 dst_port; | ||
103 | int err; | ||
104 | |||
105 | if (!options) { | ||
106 | err = -EINVAL; | ||
107 | goto error; | ||
108 | } | ||
109 | a = nla_find_nested(options, OVS_TUNNEL_ATTR_DST_PORT); | ||
110 | if (a && nla_len(a) == sizeof(u16)) { | ||
111 | dst_port = nla_get_u16(a); | ||
112 | } else { | ||
113 | /* Require destination port from userspace. */ | ||
114 | err = -EINVAL; | ||
115 | goto error; | ||
116 | } | ||
117 | |||
118 | vport = ovs_vport_alloc(sizeof(struct vxlan_port), | ||
119 | &ovs_vxlan_vport_ops, parms); | ||
120 | if (IS_ERR(vport)) | ||
121 | return vport; | ||
122 | |||
123 | vxlan_port = vxlan_vport(vport); | ||
124 | strncpy(vxlan_port->name, parms->name, IFNAMSIZ); | ||
125 | |||
126 | vs = vxlan_sock_add(net, htons(dst_port), vxlan_rcv, vport, true); | ||
127 | if (IS_ERR(vs)) { | ||
128 | ovs_vport_free(vport); | ||
129 | return (void *)vs; | ||
130 | } | ||
131 | vxlan_port->vs = vs; | ||
132 | |||
133 | return vport; | ||
134 | |||
135 | error: | ||
136 | return ERR_PTR(err); | ||
137 | } | ||
138 | |||
139 | static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) | ||
140 | { | ||
141 | struct net *net = ovs_dp_get_net(vport->dp); | ||
142 | struct vxlan_port *vxlan_port = vxlan_vport(vport); | ||
143 | __be16 dst_port = inet_sk(vxlan_port->vs->sock->sk)->inet_sport; | ||
144 | struct rtable *rt; | ||
145 | struct flowi4 fl; | ||
146 | __be16 src_port; | ||
147 | int port_min; | ||
148 | int port_max; | ||
149 | __be16 df; | ||
150 | int err; | ||
151 | |||
152 | if (unlikely(!OVS_CB(skb)->tun_key)) { | ||
153 | err = -EINVAL; | ||
154 | goto error; | ||
155 | } | ||
156 | |||
157 | /* Route lookup */ | ||
158 | memset(&fl, 0, sizeof(fl)); | ||
159 | fl.daddr = OVS_CB(skb)->tun_key->ipv4_dst; | ||
160 | fl.saddr = OVS_CB(skb)->tun_key->ipv4_src; | ||
161 | fl.flowi4_tos = RT_TOS(OVS_CB(skb)->tun_key->ipv4_tos); | ||
162 | fl.flowi4_mark = skb->mark; | ||
163 | fl.flowi4_proto = IPPROTO_UDP; | ||
164 | |||
165 | rt = ip_route_output_key(net, &fl); | ||
166 | if (IS_ERR(rt)) { | ||
167 | err = PTR_ERR(rt); | ||
168 | goto error; | ||
169 | } | ||
170 | |||
171 | df = OVS_CB(skb)->tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ? | ||
172 | htons(IP_DF) : 0; | ||
173 | |||
174 | skb->local_df = 1; | ||
175 | |||
176 | inet_get_local_port_range(&port_min, &port_max); | ||
177 | src_port = vxlan_src_port(port_min, port_max, skb); | ||
178 | |||
179 | err = vxlan_xmit_skb(net, vxlan_port->vs, rt, skb, | ||
180 | fl.saddr, OVS_CB(skb)->tun_key->ipv4_dst, | ||
181 | OVS_CB(skb)->tun_key->ipv4_tos, | ||
182 | OVS_CB(skb)->tun_key->ipv4_ttl, df, | ||
183 | src_port, dst_port, | ||
184 | htonl(be64_to_cpu(OVS_CB(skb)->tun_key->tun_id) << 8)); | ||
185 | if (err < 0) | ||
186 | ip_rt_put(rt); | ||
187 | error: | ||
188 | return err; | ||
189 | } | ||
190 | |||
191 | static const char *vxlan_get_name(const struct vport *vport) | ||
192 | { | ||
193 | struct vxlan_port *vxlan_port = vxlan_vport(vport); | ||
194 | return vxlan_port->name; | ||
195 | } | ||
196 | |||
197 | const struct vport_ops ovs_vxlan_vport_ops = { | ||
198 | .type = OVS_VPORT_TYPE_VXLAN, | ||
199 | .create = vxlan_tnl_create, | ||
200 | .destroy = vxlan_tnl_destroy, | ||
201 | .get_name = vxlan_get_name, | ||
202 | .get_options = vxlan_get_options, | ||
203 | .send = vxlan_tnl_send, | ||
204 | }; | ||
diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index d4c7fa04ce08..d69e0c06dfde 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c | |||
@@ -42,6 +42,9 @@ static const struct vport_ops *vport_ops_list[] = { | |||
42 | #ifdef CONFIG_OPENVSWITCH_GRE | 42 | #ifdef CONFIG_OPENVSWITCH_GRE |
43 | &ovs_gre_vport_ops, | 43 | &ovs_gre_vport_ops, |
44 | #endif | 44 | #endif |
45 | #ifdef CONFIG_OPENVSWITCH_VXLAN | ||
46 | &ovs_vxlan_vport_ops, | ||
47 | #endif | ||
45 | }; | 48 | }; |
46 | 49 | ||
47 | /* Protected by RCU read lock for reading, ovs_mutex for writing. */ | 50 | /* Protected by RCU read lock for reading, ovs_mutex for writing. */ |
diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h index 376045c42f8b..1a9fbcec6e1b 100644 --- a/net/openvswitch/vport.h +++ b/net/openvswitch/vport.h | |||
@@ -199,6 +199,7 @@ void ovs_vport_record_error(struct vport *, enum vport_err_type err_type); | |||
199 | extern const struct vport_ops ovs_netdev_vport_ops; | 199 | extern const struct vport_ops ovs_netdev_vport_ops; |
200 | extern const struct vport_ops ovs_internal_vport_ops; | 200 | extern const struct vport_ops ovs_internal_vport_ops; |
201 | extern const struct vport_ops ovs_gre_vport_ops; | 201 | extern const struct vport_ops ovs_gre_vport_ops; |
202 | extern const struct vport_ops ovs_vxlan_vport_ops; | ||
202 | 203 | ||
203 | static inline void ovs_skb_postpush_rcsum(struct sk_buff *skb, | 204 | static inline void ovs_skb_postpush_rcsum(struct sk_buff *skb, |
204 | const void *start, unsigned int len) | 205 | const void *start, unsigned int len) |