Commit 58264848a5a7b91195f43c4729072e8cc980288d
Committed by
David S. Miller
1 parent
1eaa81785a
Exists in
smarc-imx_3.14.28_1.0.0_ga
and in
1 other branch
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>
Showing 6 changed files with 236 additions and 0 deletions Side-by-side Diff
include/uapi/linux/openvswitch.h
... | ... | @@ -165,6 +165,7 @@ |
165 | 165 | OVS_VPORT_TYPE_NETDEV, /* network device */ |
166 | 166 | OVS_VPORT_TYPE_INTERNAL, /* network device implemented by datapath */ |
167 | 167 | OVS_VPORT_TYPE_GRE, /* GRE tunnel. */ |
168 | + OVS_VPORT_TYPE_VXLAN, /* VXLAN tunnel. */ | |
168 | 169 | __OVS_VPORT_TYPE_MAX |
169 | 170 | }; |
170 | 171 | |
... | ... | @@ -210,6 +211,16 @@ |
210 | 211 | }; |
211 | 212 | |
212 | 213 | #define OVS_VPORT_ATTR_MAX (__OVS_VPORT_ATTR_MAX - 1) |
214 | + | |
215 | +/* OVS_VPORT_ATTR_OPTIONS attributes for tunnels. | |
216 | + */ | |
217 | +enum { | |
218 | + OVS_TUNNEL_ATTR_UNSPEC, | |
219 | + OVS_TUNNEL_ATTR_DST_PORT, /* 16-bit UDP port, used by L4 tunnels. */ | |
220 | + __OVS_TUNNEL_ATTR_MAX | |
221 | +}; | |
222 | + | |
223 | +#define OVS_TUNNEL_ATTR_MAX (__OVS_TUNNEL_ATTR_MAX - 1) | |
213 | 224 | |
214 | 225 | /* Flows. */ |
215 | 226 |
net/openvswitch/Kconfig
... | ... | @@ -40,4 +40,17 @@ |
40 | 40 | Say N to exclude this support and reduce the binary size. |
41 | 41 | |
42 | 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. |
net/openvswitch/Makefile
net/openvswitch/vport-vxlan.c
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 | +}; |
net/openvswitch/vport.c
net/openvswitch/vport.h
... | ... | @@ -199,6 +199,7 @@ |
199 | 199 | extern const struct vport_ops ovs_netdev_vport_ops; |
200 | 200 | extern const struct vport_ops ovs_internal_vport_ops; |
201 | 201 | extern const struct vport_ops ovs_gre_vport_ops; |
202 | +extern const struct vport_ops ovs_vxlan_vport_ops; | |
202 | 203 | |
203 | 204 | static inline void ovs_skb_postpush_rcsum(struct sk_buff *skb, |
204 | 205 | const void *start, unsigned int len) |