datapath: Remove vport MAC address configuration.
[sliver-openvswitch.git] / 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
29 struct patch_config {
30         struct rcu_head rcu;
31
32         char peer_name[IFNAMSIZ];
33 };
34
35 struct patch_vport {
36         struct rcu_head rcu;
37
38         char name[IFNAMSIZ];
39
40         /* Protected by RTNL lock. */
41         struct hlist_node hash_node;
42
43         struct vport __rcu *peer;
44         struct patch_config __rcu *patchconf;
45 };
46
47 /* Protected by RTNL lock. */
48 static struct hlist_head *peer_table;
49 #define PEER_HASH_BUCKETS 256
50
51 static void update_peers(struct net *, const char *name, struct vport *);
52
53 static struct patch_vport *patch_vport_priv(const struct vport *vport)
54 {
55         return vport_priv(vport);
56 }
57
58 /* RCU callback. */
59 static void free_config(struct rcu_head *rcu)
60 {
61         struct patch_config *c = container_of(rcu, struct patch_config, rcu);
62         kfree(c);
63 }
64
65 static void assign_config_rcu(struct vport *vport,
66                               struct patch_config *new_config)
67 {
68         struct patch_vport *patch_vport = patch_vport_priv(vport);
69         struct patch_config *old_config;
70
71         old_config = rtnl_dereference(patch_vport->patchconf);
72         rcu_assign_pointer(patch_vport->patchconf, new_config);
73         call_rcu(&old_config->rcu, free_config);
74 }
75
76 static struct hlist_head *hash_bucket(struct net *net, const char *name)
77 {
78         unsigned int hash = jhash(name, strlen(name), (unsigned long) net);
79         return &peer_table[hash & (PEER_HASH_BUCKETS - 1)];
80 }
81
82 static int patch_init(void)
83 {
84         peer_table = kzalloc(PEER_HASH_BUCKETS * sizeof(struct hlist_head),
85                             GFP_KERNEL);
86         if (!peer_table)
87                 return -ENOMEM;
88
89         return 0;
90 }
91
92 static void patch_exit(void)
93 {
94         kfree(peer_table);
95 }
96
97 static const struct nla_policy patch_policy[OVS_PATCH_ATTR_MAX + 1] = {
98 #ifdef HAVE_NLA_NUL_STRING
99         [OVS_PATCH_ATTR_PEER] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 },
100 #endif
101 };
102
103 static int patch_set_config(struct vport *vport, const struct nlattr *options,
104                             struct patch_config *patchconf)
105 {
106         struct patch_vport *patch_vport = patch_vport_priv(vport);
107         struct nlattr *a[OVS_PATCH_ATTR_MAX + 1];
108         const char *peer_name;
109         int err;
110
111         if (!options)
112                 return -EINVAL;
113
114         err = nla_parse_nested(a, OVS_PATCH_ATTR_MAX, options, patch_policy);
115         if (err)
116                 return err;
117
118         if (!a[OVS_PATCH_ATTR_PEER] ||
119             CHECK_NUL_STRING(a[OVS_PATCH_ATTR_PEER], IFNAMSIZ - 1))
120                 return -EINVAL;
121
122         peer_name = nla_data(a[OVS_PATCH_ATTR_PEER]);
123         if (!strcmp(patch_vport->name, peer_name))
124                 return -EINVAL;
125
126         strcpy(patchconf->peer_name, peer_name);
127
128         return 0;
129 }
130
131 static struct vport *patch_create(const struct vport_parms *parms)
132 {
133         struct vport *vport;
134         struct patch_vport *patch_vport;
135         const char *peer_name;
136         struct patch_config *patchconf;
137         struct net *net = ovs_dp_get_net(parms->dp);
138         int err;
139
140         vport = ovs_vport_alloc(sizeof(struct patch_vport),
141                                 &ovs_patch_vport_ops, parms);
142         if (IS_ERR(vport)) {
143                 err = PTR_ERR(vport);
144                 goto error;
145         }
146
147         patch_vport = patch_vport_priv(vport);
148
149         strcpy(patch_vport->name, parms->name);
150
151         patchconf = kmalloc(sizeof(struct patch_config), GFP_KERNEL);
152         if (!patchconf) {
153                 err = -ENOMEM;
154                 goto error_free_vport;
155         }
156
157         err = patch_set_config(vport, parms->options, patchconf);
158         if (err)
159                 goto error_free_patchconf;
160
161         rcu_assign_pointer(patch_vport->patchconf, patchconf);
162
163         peer_name = patchconf->peer_name;
164         hlist_add_head(&patch_vport->hash_node, hash_bucket(net, peer_name));
165         rcu_assign_pointer(patch_vport->peer, ovs_vport_locate(net, peer_name));
166         update_peers(net, patch_vport->name, vport);
167
168         return vport;
169
170 error_free_patchconf:
171         kfree(patchconf);
172 error_free_vport:
173         ovs_vport_free(vport);
174 error:
175         return ERR_PTR(err);
176 }
177
178 static void free_port_rcu(struct rcu_head *rcu)
179 {
180         struct patch_vport *patch_vport = container_of(rcu,
181                                           struct patch_vport, rcu);
182
183         kfree((struct patch_config __force *)patch_vport->patchconf);
184         ovs_vport_free(vport_from_priv(patch_vport));
185 }
186
187 static void patch_destroy(struct vport *vport)
188 {
189         struct patch_vport *patch_vport = patch_vport_priv(vport);
190
191         update_peers(ovs_dp_get_net(vport->dp), patch_vport->name, NULL);
192         hlist_del(&patch_vport->hash_node);
193         call_rcu(&patch_vport->rcu, free_port_rcu);
194 }
195
196 static int patch_set_options(struct vport *vport, struct nlattr *options)
197 {
198         struct patch_vport *patch_vport = patch_vport_priv(vport);
199         struct patch_config *patchconf;
200         int err;
201
202         patchconf = kmemdup(rtnl_dereference(patch_vport->patchconf),
203                           sizeof(struct patch_config), GFP_KERNEL);
204         if (!patchconf) {
205                 err = -ENOMEM;
206                 goto error;
207         }
208
209         err = patch_set_config(vport, options, patchconf);
210         if (err)
211                 goto error_free;
212
213         assign_config_rcu(vport, patchconf);
214
215         hlist_del(&patch_vport->hash_node);
216
217         rcu_assign_pointer(patch_vport->peer,
218                 ovs_vport_locate(ovs_dp_get_net(vport->dp), patchconf->peer_name));
219
220         hlist_add_head(&patch_vport->hash_node,
221                        hash_bucket(ovs_dp_get_net(vport->dp), patchconf->peer_name));
222
223         return 0;
224 error_free:
225         kfree(patchconf);
226 error:
227         return err;
228 }
229
230 static void update_peers(struct net *net, const char *name, struct vport *vport)
231 {
232         struct hlist_head *bucket = hash_bucket(net, name);
233         struct patch_vport *peer_vport;
234         struct hlist_node *node;
235
236         hlist_for_each_entry(peer_vport, node, bucket, hash_node) {
237                 struct vport *curr_vport = vport_from_priv(peer_vport);
238                 const char *peer_name;
239
240                 peer_name = rtnl_dereference(peer_vport->patchconf)->peer_name;
241                 if (!strcmp(peer_name, name) && net_eq(ovs_dp_get_net(curr_vport->dp), net))
242                         rcu_assign_pointer(peer_vport->peer, vport);
243         }
244 }
245
246 static const char *patch_get_name(const struct vport *vport)
247 {
248         const struct patch_vport *patch_vport = patch_vport_priv(vport);
249         return patch_vport->name;
250 }
251
252 static int patch_get_options(const struct vport *vport, struct sk_buff *skb)
253 {
254         struct patch_vport *patch_vport = patch_vport_priv(vport);
255         struct patch_config *patchconf = rcu_dereference_rtnl(patch_vport->patchconf);
256
257         return nla_put_string(skb, OVS_PATCH_ATTR_PEER, patchconf->peer_name);
258 }
259
260 static int patch_send(struct vport *vport, struct sk_buff *skb)
261 {
262         struct patch_vport *patch_vport = patch_vport_priv(vport);
263         struct vport *peer = rcu_dereference(patch_vport->peer);
264         int skb_len = skb->len;
265
266         if (!peer) {
267                 kfree_skb(skb);
268                 ovs_vport_record_error(vport, VPORT_E_TX_DROPPED);
269
270                 return 0;
271         }
272
273         ovs_vport_receive(peer, skb);
274         return skb_len;
275 }
276
277 const struct vport_ops ovs_patch_vport_ops = {
278         .type           = OVS_VPORT_TYPE_PATCH,
279         .init           = patch_init,
280         .exit           = patch_exit,
281         .create         = patch_create,
282         .destroy        = patch_destroy,
283         .get_name       = patch_get_name,
284         .get_options    = patch_get_options,
285         .set_options    = patch_set_options,
286         .send           = patch_send,
287 };