ofp-util: Avoid use-after-free in ofputil_encode_flow_mod().
[openvswitch] / datapath / vport-patch.c
1 /*
2  * Copyright (c) 2007-2012 Nicira, Inc.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of version 2 of the GNU General Public
6  * License as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16  * 02110-1301, USA
17  */
18
19 #include <linux/kernel.h>
20 #include <linux/jhash.h>
21 #include <linux/list.h>
22 #include <linux/rtnetlink.h>
23 #include <net/net_namespace.h>
24
25 #include "compat.h"
26 #include "datapath.h"
27 #include "vport.h"
28 #include "vport-generic.h"
29
30 struct patch_config {
31         struct rcu_head rcu;
32
33         char peer_name[IFNAMSIZ];
34         unsigned char eth_addr[ETH_ALEN];
35 };
36
37 struct patch_vport {
38         struct rcu_head rcu;
39
40         char name[IFNAMSIZ];
41
42         /* Protected by RTNL lock. */
43         struct hlist_node hash_node;
44
45         struct vport __rcu *peer;
46         struct patch_config __rcu *patchconf;
47 };
48
49 /* Protected by RTNL lock. */
50 static struct hlist_head *peer_table;
51 #define PEER_HASH_BUCKETS 256
52
53 static void update_peers(struct net *, const char *name, struct vport *);
54
55 static struct patch_vport *patch_vport_priv(const struct vport *vport)
56 {
57         return vport_priv(vport);
58 }
59
60 /* RCU callback. */
61 static void free_config(struct rcu_head *rcu)
62 {
63         struct patch_config *c = container_of(rcu, struct patch_config, rcu);
64         kfree(c);
65 }
66
67 static void assign_config_rcu(struct vport *vport,
68                               struct patch_config *new_config)
69 {
70         struct patch_vport *patch_vport = patch_vport_priv(vport);
71         struct patch_config *old_config;
72
73         old_config = rtnl_dereference(patch_vport->patchconf);
74         rcu_assign_pointer(patch_vport->patchconf, new_config);
75         call_rcu(&old_config->rcu, free_config);
76 }
77
78 static struct hlist_head *hash_bucket(struct net *net, const char *name)
79 {
80         unsigned int hash = jhash(name, strlen(name), (unsigned long) net);
81         return &peer_table[hash & (PEER_HASH_BUCKETS - 1)];
82 }
83
84 static int patch_init(void)
85 {
86         peer_table = kzalloc(PEER_HASH_BUCKETS * sizeof(struct hlist_head),
87                             GFP_KERNEL);
88         if (!peer_table)
89                 return -ENOMEM;
90
91         return 0;
92 }
93
94 static void patch_exit(void)
95 {
96         kfree(peer_table);
97 }
98
99 static const struct nla_policy patch_policy[OVS_PATCH_ATTR_MAX + 1] = {
100 #ifdef HAVE_NLA_NUL_STRING
101         [OVS_PATCH_ATTR_PEER] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 },
102 #endif
103 };
104
105 static int patch_set_config(struct vport *vport, const struct nlattr *options,
106                             struct patch_config *patchconf)
107 {
108         struct patch_vport *patch_vport = patch_vport_priv(vport);
109         struct nlattr *a[OVS_PATCH_ATTR_MAX + 1];
110         const char *peer_name;
111         int err;
112
113         if (!options)
114                 return -EINVAL;
115
116         err = nla_parse_nested(a, OVS_PATCH_ATTR_MAX, options, patch_policy);
117         if (err)
118                 return err;
119
120         if (!a[OVS_PATCH_ATTR_PEER] ||
121             CHECK_NUL_STRING(a[OVS_PATCH_ATTR_PEER], IFNAMSIZ - 1))
122                 return -EINVAL;
123
124         peer_name = nla_data(a[OVS_PATCH_ATTR_PEER]);
125         if (!strcmp(patch_vport->name, peer_name))
126                 return -EINVAL;
127
128         strcpy(patchconf->peer_name, peer_name);
129
130         return 0;
131 }
132
133 static struct vport *patch_create(const struct vport_parms *parms)
134 {
135         struct vport *vport;
136         struct patch_vport *patch_vport;
137         const char *peer_name;
138         struct patch_config *patchconf;
139         struct net *net = ovs_dp_get_net(parms->dp);
140         int err;
141
142         vport = ovs_vport_alloc(sizeof(struct patch_vport),
143                                 &ovs_patch_vport_ops, parms);
144         if (IS_ERR(vport)) {
145                 err = PTR_ERR(vport);
146                 goto error;
147         }
148
149         patch_vport = patch_vport_priv(vport);
150
151         strcpy(patch_vport->name, parms->name);
152
153         patchconf = kmalloc(sizeof(struct patch_config), GFP_KERNEL);
154         if (!patchconf) {
155                 err = -ENOMEM;
156                 goto error_free_vport;
157         }
158
159         err = patch_set_config(vport, parms->options, patchconf);
160         if (err)
161                 goto error_free_patchconf;
162
163         random_ether_addr(patchconf->eth_addr);
164
165         rcu_assign_pointer(patch_vport->patchconf, patchconf);
166
167         peer_name = patchconf->peer_name;
168         hlist_add_head(&patch_vport->hash_node, hash_bucket(net, peer_name));
169         rcu_assign_pointer(patch_vport->peer, ovs_vport_locate(net, peer_name));
170         update_peers(net, patch_vport->name, vport);
171
172         return vport;
173
174 error_free_patchconf:
175         kfree(patchconf);
176 error_free_vport:
177         ovs_vport_free(vport);
178 error:
179         return ERR_PTR(err);
180 }
181
182 static void free_port_rcu(struct rcu_head *rcu)
183 {
184         struct patch_vport *patch_vport = container_of(rcu,
185                                           struct patch_vport, rcu);
186
187         kfree((struct patch_config __force *)patch_vport->patchconf);
188         ovs_vport_free(vport_from_priv(patch_vport));
189 }
190
191 static void patch_destroy(struct vport *vport)
192 {
193         struct patch_vport *patch_vport = patch_vport_priv(vport);
194
195         update_peers(ovs_dp_get_net(vport->dp), patch_vport->name, NULL);
196         hlist_del(&patch_vport->hash_node);
197         call_rcu(&patch_vport->rcu, free_port_rcu);
198 }
199
200 static int patch_set_options(struct vport *vport, struct nlattr *options)
201 {
202         struct patch_vport *patch_vport = patch_vport_priv(vport);
203         struct patch_config *patchconf;
204         int err;
205
206         patchconf = kmemdup(rtnl_dereference(patch_vport->patchconf),
207                           sizeof(struct patch_config), GFP_KERNEL);
208         if (!patchconf) {
209                 err = -ENOMEM;
210                 goto error;
211         }
212
213         err = patch_set_config(vport, options, patchconf);
214         if (err)
215                 goto error_free;
216
217         assign_config_rcu(vport, patchconf);
218
219         hlist_del(&patch_vport->hash_node);
220
221         rcu_assign_pointer(patch_vport->peer,
222                 ovs_vport_locate(ovs_dp_get_net(vport->dp), patchconf->peer_name));
223
224         hlist_add_head(&patch_vport->hash_node,
225                        hash_bucket(ovs_dp_get_net(vport->dp), patchconf->peer_name));
226
227         return 0;
228 error_free:
229         kfree(patchconf);
230 error:
231         return err;
232 }
233
234 static void update_peers(struct net *net, const char *name, struct vport *vport)
235 {
236         struct hlist_head *bucket = hash_bucket(net, name);
237         struct patch_vport *peer_vport;
238         struct hlist_node *node;
239
240         hlist_for_each_entry(peer_vport, node, bucket, hash_node) {
241                 struct vport *curr_vport = vport_from_priv(peer_vport);
242                 const char *peer_name;
243
244                 peer_name = rtnl_dereference(peer_vport->patchconf)->peer_name;
245                 if (!strcmp(peer_name, name) && net_eq(ovs_dp_get_net(curr_vport->dp), net))
246                         rcu_assign_pointer(peer_vport->peer, vport);
247         }
248 }
249
250 static int patch_set_addr(struct vport *vport, const unsigned char *addr)
251 {
252         struct patch_vport *patch_vport = patch_vport_priv(vport);
253         struct patch_config *patchconf;
254
255         patchconf = kmemdup(rtnl_dereference(patch_vport->patchconf),
256                           sizeof(struct patch_config), GFP_KERNEL);
257         if (!patchconf)
258                 return -ENOMEM;
259
260         memcpy(patchconf->eth_addr, addr, ETH_ALEN);
261         assign_config_rcu(vport, patchconf);
262
263         return 0;
264 }
265
266
267 static const char *patch_get_name(const struct vport *vport)
268 {
269         const struct patch_vport *patch_vport = patch_vport_priv(vport);
270         return patch_vport->name;
271 }
272
273 static const unsigned char *patch_get_addr(const struct vport *vport)
274 {
275         const struct patch_vport *patch_vport = patch_vport_priv(vport);
276         return rcu_dereference_rtnl(patch_vport->patchconf)->eth_addr;
277 }
278
279 static int patch_get_options(const struct vport *vport, struct sk_buff *skb)
280 {
281         struct patch_vport *patch_vport = patch_vport_priv(vport);
282         struct patch_config *patchconf = rcu_dereference_rtnl(patch_vport->patchconf);
283
284         return nla_put_string(skb, OVS_PATCH_ATTR_PEER, patchconf->peer_name);
285 }
286
287 static int patch_send(struct vport *vport, struct sk_buff *skb)
288 {
289         struct patch_vport *patch_vport = patch_vport_priv(vport);
290         struct vport *peer = rcu_dereference(patch_vport->peer);
291         int skb_len = skb->len;
292
293         if (!peer) {
294                 kfree_skb(skb);
295                 ovs_vport_record_error(vport, VPORT_E_TX_DROPPED);
296
297                 return 0;
298         }
299
300         ovs_vport_receive(peer, skb);
301         return skb_len;
302 }
303
304 const struct vport_ops ovs_patch_vport_ops = {
305         .type           = OVS_VPORT_TYPE_PATCH,
306         .init           = patch_init,
307         .exit           = patch_exit,
308         .create         = patch_create,
309         .destroy        = patch_destroy,
310         .set_addr       = patch_set_addr,
311         .get_name       = patch_get_name,
312         .get_addr       = patch_get_addr,
313         .get_options    = patch_get_options,
314         .set_options    = patch_set_options,
315         .get_dev_flags  = ovs_vport_gen_get_dev_flags,
316         .is_running     = ovs_vport_gen_is_running,
317         .get_operstate  = ovs_vport_gen_get_operstate,
318         .send           = patch_send,
319 };