Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
[linux-2.6-block.git] / net / openvswitch / vport-geneve.c
CommitLineData
f5796684
JG
1/*
2 * Copyright (c) 2014 Nicira, Inc.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 */
9
10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11
12#include <linux/version.h>
13
14#include <linux/in.h>
15#include <linux/ip.h>
16#include <linux/net.h>
17#include <linux/rculist.h>
18#include <linux/udp.h>
19#include <linux/if_vlan.h>
20
21#include <net/geneve.h>
22#include <net/icmp.h>
23#include <net/ip.h>
24#include <net/route.h>
25#include <net/udp.h>
26#include <net/xfrm.h>
27
28#include "datapath.h"
29#include "vport.h"
30
31/**
32 * struct geneve_port - Keeps track of open UDP ports
7e78cc46 33 * @gs: The socket created for this port number.
f5796684
JG
34 * @name: vport name.
35 */
36struct geneve_port {
37 struct geneve_sock *gs;
38 char name[IFNAMSIZ];
39};
40
41static LIST_HEAD(geneve_ports);
42
43static inline struct geneve_port *geneve_vport(const struct vport *vport)
44{
45 return vport_priv(vport);
46}
47
48static inline struct genevehdr *geneve_hdr(const struct sk_buff *skb)
49{
50 return (struct genevehdr *)(udp_hdr(skb) + 1);
51}
52
53/* Convert 64 bit tunnel ID to 24 bit VNI. */
54static void tunnel_id_to_vni(__be64 tun_id, __u8 *vni)
55{
56#ifdef __BIG_ENDIAN
57 vni[0] = (__force __u8)(tun_id >> 16);
58 vni[1] = (__force __u8)(tun_id >> 8);
59 vni[2] = (__force __u8)tun_id;
60#else
61 vni[0] = (__force __u8)((__force u64)tun_id >> 40);
62 vni[1] = (__force __u8)((__force u64)tun_id >> 48);
63 vni[2] = (__force __u8)((__force u64)tun_id >> 56);
64#endif
65}
66
67/* Convert 24 bit VNI to 64 bit tunnel ID. */
68static __be64 vni_to_tunnel_id(__u8 *vni)
69{
70#ifdef __BIG_ENDIAN
71 return (vni[0] << 16) | (vni[1] << 8) | vni[2];
72#else
73 return (__force __be64)(((__force u64)vni[0] << 40) |
74 ((__force u64)vni[1] << 48) |
75 ((__force u64)vni[2] << 56));
76#endif
77}
78
79static void geneve_rcv(struct geneve_sock *gs, struct sk_buff *skb)
80{
81 struct vport *vport = gs->rcv_data;
82 struct genevehdr *geneveh = geneve_hdr(skb);
83 int opts_len;
84 struct ovs_tunnel_info tun_info;
85 __be64 key;
86 __be16 flags;
87
88 opts_len = geneveh->opt_len * 4;
89
90 flags = TUNNEL_KEY | TUNNEL_OPTIONS_PRESENT |
91 (udp_hdr(skb)->check != 0 ? TUNNEL_CSUM : 0) |
92 (geneveh->oam ? TUNNEL_OAM : 0) |
93 (geneveh->critical ? TUNNEL_CRIT_OPT : 0);
94
95 key = vni_to_tunnel_id(geneveh->vni);
96
97 ovs_flow_tun_info_init(&tun_info, ip_hdr(skb), key, flags,
98 geneveh->options, opts_len);
99
100 ovs_vport_receive(vport, skb, &tun_info);
101}
102
103static int geneve_get_options(const struct vport *vport,
104 struct sk_buff *skb)
105{
106 struct geneve_port *geneve_port = geneve_vport(vport);
0a5d1c55 107 struct inet_sock *sk = inet_sk(geneve_port->gs->sock->sk);
f5796684 108
0a5d1c55 109 if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, ntohs(sk->inet_sport)))
f5796684
JG
110 return -EMSGSIZE;
111 return 0;
112}
113
114static void geneve_tnl_destroy(struct vport *vport)
115{
116 struct geneve_port *geneve_port = geneve_vport(vport);
117
118 geneve_sock_release(geneve_port->gs);
119
120 ovs_vport_deferred_free(vport);
121}
122
123static struct vport *geneve_tnl_create(const struct vport_parms *parms)
124{
125 struct net *net = ovs_dp_get_net(parms->dp);
126 struct nlattr *options = parms->options;
127 struct geneve_port *geneve_port;
128 struct geneve_sock *gs;
129 struct vport *vport;
130 struct nlattr *a;
131 int err;
132 u16 dst_port;
133
134 if (!options) {
135 err = -EINVAL;
136 goto error;
137 }
138
139 a = nla_find_nested(options, OVS_TUNNEL_ATTR_DST_PORT);
140 if (a && nla_len(a) == sizeof(u16)) {
141 dst_port = nla_get_u16(a);
142 } else {
143 /* Require destination port from userspace. */
144 err = -EINVAL;
145 goto error;
146 }
147
148 vport = ovs_vport_alloc(sizeof(struct geneve_port),
149 &ovs_geneve_vport_ops, parms);
150 if (IS_ERR(vport))
151 return vport;
152
153 geneve_port = geneve_vport(vport);
154 strncpy(geneve_port->name, parms->name, IFNAMSIZ);
155
156 gs = geneve_sock_add(net, htons(dst_port), geneve_rcv, vport, true, 0);
157 if (IS_ERR(gs)) {
158 ovs_vport_free(vport);
159 return (void *)gs;
160 }
161 geneve_port->gs = gs;
162
163 return vport;
164error:
165 return ERR_PTR(err);
166}
167
168static int geneve_tnl_send(struct vport *vport, struct sk_buff *skb)
169{
170 struct ovs_key_ipv4_tunnel *tun_key;
171 struct ovs_tunnel_info *tun_info;
172 struct net *net = ovs_dp_get_net(vport->dp);
173 struct geneve_port *geneve_port = geneve_vport(vport);
174 __be16 dport = inet_sk(geneve_port->gs->sock->sk)->inet_sport;
175 __be16 sport;
176 struct rtable *rt;
177 struct flowi4 fl;
178 u8 vni[3];
179 __be16 df;
180 int err;
181
182 tun_info = OVS_CB(skb)->egress_tun_info;
183 if (unlikely(!tun_info)) {
184 err = -EINVAL;
185 goto error;
186 }
187
188 tun_key = &tun_info->tunnel;
189
190 /* Route lookup */
191 memset(&fl, 0, sizeof(fl));
192 fl.daddr = tun_key->ipv4_dst;
193 fl.saddr = tun_key->ipv4_src;
194 fl.flowi4_tos = RT_TOS(tun_key->ipv4_tos);
195 fl.flowi4_mark = skb->mark;
196 fl.flowi4_proto = IPPROTO_UDP;
197
198 rt = ip_route_output_key(net, &fl);
199 if (IS_ERR(rt)) {
200 err = PTR_ERR(rt);
201 goto error;
202 }
203
204 df = tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0;
205 sport = udp_flow_src_port(net, skb, 1, USHRT_MAX, true);
206 tunnel_id_to_vni(tun_key->tun_id, vni);
207 skb->ignore_df = 1;
208
209 err = geneve_xmit_skb(geneve_port->gs, rt, skb, fl.saddr,
210 tun_key->ipv4_dst, tun_key->ipv4_tos,
211 tun_key->ipv4_ttl, df, sport, dport,
212 tun_key->tun_flags, vni,
213 tun_info->options_len, (u8 *)tun_info->options,
214 false);
215 if (err < 0)
216 ip_rt_put(rt);
217error:
218 return err;
219}
220
221static const char *geneve_get_name(const struct vport *vport)
222{
223 struct geneve_port *geneve_port = geneve_vport(vport);
224
225 return geneve_port->name;
226}
227
228const struct vport_ops ovs_geneve_vport_ops = {
229 .type = OVS_VPORT_TYPE_GENEVE,
230 .create = geneve_tnl_create,
231 .destroy = geneve_tnl_destroy,
232 .get_name = geneve_get_name,
233 .get_options = geneve_get_options,
234 .send = geneve_tnl_send,
235};