]> git.proxmox.com Git - mirror_ovs.git/blame - datapath/vport-vxlan.c
datapath: Initialize unmasked key and uid len.
[mirror_ovs.git] / datapath / vport-vxlan.c
CommitLineData
79f827fa 1/*
a109c9fb
PS
2 * Copyright (c) 2013 Nicira, Inc.
3 * Copyright (c) 2013 Cisco Systems, Inc.
79f827fa
KM
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/version.h>
79f827fa
KM
23
24#include <linux/in.h>
25#include <linux/ip.h>
79f827fa 26#include <linux/net.h>
85c9de19 27#include <linux/rculist.h>
79f827fa
KM
28#include <linux/udp.h>
29
30#include <net/icmp.h>
31#include <net/ip.h>
32#include <net/udp.h>
1b7ee51f 33#include <net/ip_tunnels.h>
1b7ee51f
PS
34#include <net/rtnetlink.h>
35#include <net/route.h>
36#include <net/dsfield.h>
37#include <net/inet_ecn.h>
38#include <net/net_namespace.h>
39#include <net/netns/generic.h>
40#include <net/vxlan.h>
79f827fa
KM
41
42#include "datapath.h"
79f827fa 43#include "vport.h"
0c7930a3 44#include "vport-vxlan.h"
79f827fa 45
79f827fa
KM
46/**
47 * struct vxlan_port - Keeps track of open UDP ports
a109c9fb 48 * @vs: vxlan_sock created for the port.
c405d282 49 * @name: vport name.
79f827fa
KM
50 */
51struct vxlan_port {
a109c9fb 52 struct vxlan_sock *vs;
c405d282 53 char name[IFNAMSIZ];
0c7930a3 54 u32 exts; /* VXLAN_F_* in <net/vxlan.h> */
79f827fa
KM
55};
56
c405d282
PS
57static inline struct vxlan_port *vxlan_vport(const struct vport *vport)
58{
59 return vport_priv(vport);
60}
61
3174a818
TG
62static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,
63 struct vxlan_metadata *md)
79f827fa 64{
f0cd669f 65 struct ovs_tunnel_info tun_info;
0c7930a3 66 struct vxlan_port *vxlan_port;
a109c9fb
PS
67 struct vport *vport = vs->data;
68 struct iphdr *iph;
0c7930a3
TG
69 struct ovs_vxlan_opts opts = {
70 .gbp = md->gbp,
71 };
79f827fa 72 __be64 key;
0c7930a3
TG
73 __be16 flags;
74
2d79a600 75 flags = TUNNEL_KEY | (udp_hdr(skb)->check != 0 ? TUNNEL_CSUM : 0);
0c7930a3
TG
76 vxlan_port = vxlan_vport(vport);
77 if (vxlan_port->exts & VXLAN_F_GBP && md->gbp)
78 flags |= TUNNEL_VXLAN_OPT;
85c9de19 79
79f827fa 80 /* Save outer tunnel values */
85c9de19 81 iph = ip_hdr(skb);
3174a818 82 key = cpu_to_be64(ntohl(md->vni) >> 8);
8b7ea2d4
WZ
83 ovs_flow_tun_info_init(&tun_info, iph,
84 udp_hdr(skb)->source, udp_hdr(skb)->dest,
0c7930a3 85 key, flags, &opts, sizeof(opts));
79f827fa 86
f0cd669f 87 ovs_vport_receive(vport, skb, &tun_info);
79f827fa
KM
88}
89
c405d282 90static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb)
85c9de19 91{
c405d282 92 struct vxlan_port *vxlan_port = vxlan_vport(vport);
a109c9fb 93 __be16 dst_port = inet_sport(vxlan_port->vs->sock->sk);
85c9de19 94
1b7ee51f 95 if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, ntohs(dst_port)))
c405d282 96 return -EMSGSIZE;
0c7930a3
TG
97
98 if (vxlan_port->exts) {
99 struct nlattr *exts;
100
101 exts = nla_nest_start(skb, OVS_TUNNEL_ATTR_EXTENSION);
102 if (!exts)
103 return -EMSGSIZE;
104
105 if (vxlan_port->exts & VXLAN_F_GBP &&
106 nla_put_flag(skb, OVS_VXLAN_EXT_GBP))
107 return -EMSGSIZE;
108
109 nla_nest_end(skb, exts);
110 }
111
c405d282 112 return 0;
85c9de19
PS
113}
114
c405d282 115static void vxlan_tnl_destroy(struct vport *vport)
79f827fa 116{
c405d282 117 struct vxlan_port *vxlan_port = vxlan_vport(vport);
79f827fa 118
a109c9fb 119 vxlan_sock_release(vxlan_port->vs);
c405d282
PS
120
121 ovs_vport_deferred_free(vport);
79f827fa 122}
85c9de19 123
0c7930a3
TG
124static const struct nla_policy exts_policy[OVS_VXLAN_EXT_MAX+1] = {
125 [OVS_VXLAN_EXT_GBP] = { .type = NLA_FLAG, },
126};
127
128static int vxlan_configure_exts(struct vport *vport, struct nlattr *attr)
129{
130 struct nlattr *exts[OVS_VXLAN_EXT_MAX+1];
131 struct vxlan_port *vxlan_port;
132 int err;
133
134 if (nla_len(attr) < sizeof(struct nlattr))
135 return -EINVAL;
136
137 err = nla_parse_nested(exts, OVS_VXLAN_EXT_MAX, attr, exts_policy);
138 if (err < 0)
139 return err;
140
141 vxlan_port = vxlan_vport(vport);
142
143 if (exts[OVS_VXLAN_EXT_GBP])
144 vxlan_port->exts |= VXLAN_F_GBP;
145
146 return 0;
147}
148
c405d282 149static struct vport *vxlan_tnl_create(const struct vport_parms *parms)
79f827fa 150{
c405d282
PS
151 struct net *net = ovs_dp_get_net(parms->dp);
152 struct nlattr *options = parms->options;
85c9de19 153 struct vxlan_port *vxlan_port;
a109c9fb 154 struct vxlan_sock *vs;
c405d282 155 struct vport *vport;
79f827fa 156 struct nlattr *a;
79f827fa 157 u16 dst_port;
1b7ee51f 158 int err;
79f827fa
KM
159
160 if (!options) {
161 err = -EINVAL;
c405d282 162 goto error;
79f827fa 163 }
79f827fa
KM
164 a = nla_find_nested(options, OVS_TUNNEL_ATTR_DST_PORT);
165 if (a && nla_len(a) == sizeof(u16)) {
166 dst_port = nla_get_u16(a);
167 } else {
168 /* Require destination port from userspace. */
169 err = -EINVAL;
c405d282 170 goto error;
79f827fa
KM
171 }
172
c405d282
PS
173 vport = ovs_vport_alloc(sizeof(struct vxlan_port),
174 &ovs_vxlan_vport_ops, parms);
175 if (IS_ERR(vport))
176 return vport;
79f827fa 177
c405d282 178 vxlan_port = vxlan_vport(vport);
c405d282 179 strncpy(vxlan_port->name, parms->name, IFNAMSIZ);
79f827fa 180
0c7930a3
TG
181 a = nla_find_nested(options, OVS_TUNNEL_ATTR_EXTENSION);
182 if (a) {
183 err = vxlan_configure_exts(vport, a);
184 if (err) {
185 ovs_vport_free(vport);
186 goto error;
187 }
188 }
189
190 vs = vxlan_sock_add(net, htons(dst_port), vxlan_rcv, vport, true,
191 vxlan_port->exts);
a109c9fb 192 if (IS_ERR(vs)) {
1b7ee51f 193 ovs_vport_free(vport);
a109c9fb 194 return (void *)vs;
1b7ee51f 195 }
a109c9fb 196 vxlan_port->vs = vs;
79f827fa 197
c405d282 198 return vport;
79f827fa
KM
199
200error:
c405d282 201 return ERR_PTR(err);
79f827fa
KM
202}
203
0c7930a3
TG
204static int vxlan_ext_gbp(struct sk_buff *skb)
205{
206 const struct ovs_tunnel_info *tun_info;
207 const struct ovs_vxlan_opts *opts;
208
209 tun_info = OVS_CB(skb)->egress_tun_info;
210 opts = tun_info->options;
211
212 if (tun_info->tunnel.tun_flags & TUNNEL_VXLAN_OPT &&
213 tun_info->options_len >= sizeof(*opts))
214 return opts->gbp;
215 else
216 return 0;
217}
218
c405d282 219static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)
79f827fa 220{
27914610 221 struct ovs_key_ipv4_tunnel *tun_key;
cb25142c 222 struct net *net = ovs_dp_get_net(vport->dp);
1b7ee51f 223 struct vxlan_port *vxlan_port = vxlan_vport(vport);
a109c9fb 224 __be16 dst_port = inet_sport(vxlan_port->vs->sock->sk);
3174a818 225 struct vxlan_metadata md = {0};
1b7ee51f
PS
226 struct rtable *rt;
227 __be16 src_port;
228 __be32 saddr;
229 __be16 df;
1b7ee51f 230 int err;
2d79a600 231 u32 vxflags;
1b7ee51f 232
fb66fbd1 233 if (unlikely(!OVS_CB(skb)->egress_tun_info)) {
1b7ee51f
PS
234 err = -EINVAL;
235 goto error;
236 }
79f827fa 237
fb66fbd1 238 tun_key = &OVS_CB(skb)->egress_tun_info->tunnel;
27914610 239
1b7ee51f 240 /* Route lookup */
f0cd669f 241 saddr = tun_key->ipv4_src;
1b7ee51f 242 rt = find_route(ovs_dp_get_net(vport->dp),
f0cd669f
JG
243 &saddr, tun_key->ipv4_dst,
244 IPPROTO_UDP, tun_key->ipv4_tos,
3025a772 245 skb->mark);
1b7ee51f
PS
246 if (IS_ERR(rt)) {
247 err = PTR_ERR(rt);
248 goto error;
249 }
250
f0cd669f 251 df = tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0;
f6a0c895 252 skb->ignore_df = 1;
1b7ee51f 253
f6a0c895 254 src_port = udp_flow_src_port(net, skb, 0, 0, true);
3174a818 255 md.vni = htonl(be64_to_cpu(tun_key->tun_id) << 8);
0c7930a3 256 md.gbp = vxlan_ext_gbp(skb);
2d79a600
JG
257 vxflags = vxlan_port->exts |
258 (tun_key->tun_flags & TUNNEL_CSUM ? VXLAN_F_UDP_CSUM : 0);
1b7ee51f 259
13beaf62 260 err = vxlan_xmit_skb(vxlan_port->vs, rt, skb,
f0cd669f
JG
261 saddr, tun_key->ipv4_dst,
262 tun_key->ipv4_tos,
263 tun_key->ipv4_ttl, df,
1b7ee51f 264 src_port, dst_port,
2d79a600 265 &md, false, vxflags);
1b7ee51f
PS
266 if (err < 0)
267 ip_rt_put(rt);
93258bd7 268 return err;
1b7ee51f 269error:
93258bd7 270 kfree_skb(skb);
1b7ee51f 271 return err;
79f827fa
KM
272}
273
8b7ea2d4
WZ
274static int vxlan_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
275 struct ovs_tunnel_info *egress_tun_info)
276{
277 struct net *net = ovs_dp_get_net(vport->dp);
278 struct vxlan_port *vxlan_port = vxlan_vport(vport);
279 __be16 dst_port = inet_sport(vxlan_port->vs->sock->sk);
280 __be16 src_port;
8b7ea2d4 281
f6a0c895 282 src_port = udp_flow_src_port(net, skb, 0, 0, true);
8b7ea2d4
WZ
283
284 return ovs_tunnel_get_egress_info(egress_tun_info, net,
285 OVS_CB(skb)->egress_tun_info,
286 IPPROTO_UDP, skb->mark,
287 src_port, dst_port);
288}
289
c405d282 290static const char *vxlan_get_name(const struct vport *vport)
79f827fa 291{
c405d282
PS
292 struct vxlan_port *vxlan_port = vxlan_vport(vport);
293 return vxlan_port->name;
79f827fa
KM
294}
295
296const struct vport_ops ovs_vxlan_vport_ops = {
8b7ea2d4
WZ
297 .type = OVS_VPORT_TYPE_VXLAN,
298 .create = vxlan_tnl_create,
299 .destroy = vxlan_tnl_destroy,
300 .get_name = vxlan_get_name,
301 .get_options = vxlan_get_options,
302 .send = vxlan_tnl_send,
303 .get_egress_tun_info = vxlan_get_egress_tun_info,
79f827fa 304};