]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/xen/pvcalls-back.c
xen/pvcalls: implement socket command
[mirror_ubuntu-bionic-kernel.git] / drivers / xen / pvcalls-back.c
CommitLineData
72e59c30
SS
1/*
2 * (c) 2017 Stefano Stabellini <stefano@aporeto.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
fb029875 15#include <linux/inet.h>
72e59c30
SS
16#include <linux/kthread.h>
17#include <linux/list.h>
18#include <linux/radix-tree.h>
19#include <linux/module.h>
20#include <linux/semaphore.h>
21#include <linux/wait.h>
fb029875
SS
22#include <net/sock.h>
23#include <net/inet_common.h>
24#include <net/inet_connection_sock.h>
25#include <net/request_sock.h>
72e59c30
SS
26
27#include <xen/events.h>
28#include <xen/grant_table.h>
29#include <xen/xen.h>
30#include <xen/xenbus.h>
31#include <xen/interface/io/pvcalls.h>
32
0a9c75c2
SS
33#define PVCALLS_VERSIONS "1"
34#define MAX_RING_ORDER XENBUS_MAX_RING_GRANT_ORDER
35
9be07334
SS
36struct pvcalls_back_global {
37 struct list_head frontends;
38 struct semaphore frontends_lock;
39} pvcalls_back_global;
40
d0e4d560
SS
41/*
42 * Per-frontend data structure. It contains pointers to the command
43 * ring, its event channel, a list of active sockets and a tree of
44 * passive sockets.
45 */
46struct pvcalls_fedata {
47 struct list_head list;
48 struct xenbus_device *dev;
49 struct xen_pvcalls_sring *sring;
50 struct xen_pvcalls_back_ring ring;
51 int irq;
52 struct list_head socket_mappings;
53 struct radix_tree_root socketpass_mappings;
54 struct semaphore socket_lock;
55};
56
b1efa693
SS
57static int pvcalls_back_socket(struct xenbus_device *dev,
58 struct xen_pvcalls_request *req)
59{
fb029875
SS
60 struct pvcalls_fedata *fedata;
61 int ret;
62 struct xen_pvcalls_response *rsp;
63
64 fedata = dev_get_drvdata(&dev->dev);
65
66 if (req->u.socket.domain != AF_INET ||
67 req->u.socket.type != SOCK_STREAM ||
68 (req->u.socket.protocol != IPPROTO_IP &&
69 req->u.socket.protocol != AF_INET))
70 ret = -EAFNOSUPPORT;
71 else
72 ret = 0;
73
74 /* leave the actual socket allocation for later */
75
76 rsp = RING_GET_RESPONSE(&fedata->ring, fedata->ring.rsp_prod_pvt++);
77 rsp->req_id = req->req_id;
78 rsp->cmd = req->cmd;
79 rsp->u.socket.id = req->u.socket.id;
80 rsp->ret = ret;
81
b1efa693
SS
82 return 0;
83}
84
85static int pvcalls_back_connect(struct xenbus_device *dev,
86 struct xen_pvcalls_request *req)
87{
88 return 0;
89}
90
91static int pvcalls_back_release(struct xenbus_device *dev,
92 struct xen_pvcalls_request *req)
93{
94 return 0;
95}
96
97static int pvcalls_back_bind(struct xenbus_device *dev,
98 struct xen_pvcalls_request *req)
99{
100 return 0;
101}
102
103static int pvcalls_back_listen(struct xenbus_device *dev,
104 struct xen_pvcalls_request *req)
105{
106 return 0;
107}
108
109static int pvcalls_back_accept(struct xenbus_device *dev,
110 struct xen_pvcalls_request *req)
111{
112 return 0;
113}
114
115static int pvcalls_back_poll(struct xenbus_device *dev,
116 struct xen_pvcalls_request *req)
117{
118 return 0;
119}
120
121static int pvcalls_back_handle_cmd(struct xenbus_device *dev,
122 struct xen_pvcalls_request *req)
123{
124 int ret = 0;
125
126 switch (req->cmd) {
127 case PVCALLS_SOCKET:
128 ret = pvcalls_back_socket(dev, req);
129 break;
130 case PVCALLS_CONNECT:
131 ret = pvcalls_back_connect(dev, req);
132 break;
133 case PVCALLS_RELEASE:
134 ret = pvcalls_back_release(dev, req);
135 break;
136 case PVCALLS_BIND:
137 ret = pvcalls_back_bind(dev, req);
138 break;
139 case PVCALLS_LISTEN:
140 ret = pvcalls_back_listen(dev, req);
141 break;
142 case PVCALLS_ACCEPT:
143 ret = pvcalls_back_accept(dev, req);
144 break;
145 case PVCALLS_POLL:
146 ret = pvcalls_back_poll(dev, req);
147 break;
148 default:
149 {
150 struct pvcalls_fedata *fedata;
151 struct xen_pvcalls_response *rsp;
152
153 fedata = dev_get_drvdata(&dev->dev);
154 rsp = RING_GET_RESPONSE(
155 &fedata->ring, fedata->ring.rsp_prod_pvt++);
156 rsp->req_id = req->req_id;
157 rsp->cmd = req->cmd;
158 rsp->ret = -ENOTSUPP;
159 break;
160 }
161 }
162 return ret;
163}
164
165static void pvcalls_back_work(struct pvcalls_fedata *fedata)
166{
167 int notify, notify_all = 0, more = 1;
168 struct xen_pvcalls_request req;
169 struct xenbus_device *dev = fedata->dev;
170
171 while (more) {
172 while (RING_HAS_UNCONSUMED_REQUESTS(&fedata->ring)) {
173 RING_COPY_REQUEST(&fedata->ring,
174 fedata->ring.req_cons++,
175 &req);
176
177 if (!pvcalls_back_handle_cmd(dev, &req)) {
178 RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(
179 &fedata->ring, notify);
180 notify_all += notify;
181 }
182 }
183
184 if (notify_all) {
185 notify_remote_via_irq(fedata->irq);
186 notify_all = 0;
187 }
188
189 RING_FINAL_CHECK_FOR_REQUESTS(&fedata->ring, more);
190 }
191}
192
d0e4d560
SS
193static irqreturn_t pvcalls_back_event(int irq, void *dev_id)
194{
b1efa693
SS
195 struct xenbus_device *dev = dev_id;
196 struct pvcalls_fedata *fedata = NULL;
197
198 if (dev == NULL)
199 return IRQ_HANDLED;
200
201 fedata = dev_get_drvdata(&dev->dev);
202 if (fedata == NULL)
203 return IRQ_HANDLED;
204
205 pvcalls_back_work(fedata);
d0e4d560
SS
206 return IRQ_HANDLED;
207}
208
0a9c75c2
SS
209static int backend_connect(struct xenbus_device *dev)
210{
d0e4d560
SS
211 int err, evtchn;
212 grant_ref_t ring_ref;
213 struct pvcalls_fedata *fedata = NULL;
214
215 fedata = kzalloc(sizeof(struct pvcalls_fedata), GFP_KERNEL);
216 if (!fedata)
217 return -ENOMEM;
218
219 fedata->irq = -1;
220 err = xenbus_scanf(XBT_NIL, dev->otherend, "port", "%u",
221 &evtchn);
222 if (err != 1) {
223 err = -EINVAL;
224 xenbus_dev_fatal(dev, err, "reading %s/event-channel",
225 dev->otherend);
226 goto error;
227 }
228
229 err = xenbus_scanf(XBT_NIL, dev->otherend, "ring-ref", "%u", &ring_ref);
230 if (err != 1) {
231 err = -EINVAL;
232 xenbus_dev_fatal(dev, err, "reading %s/ring-ref",
233 dev->otherend);
234 goto error;
235 }
236
237 err = bind_interdomain_evtchn_to_irq(dev->otherend_id, evtchn);
238 if (err < 0)
239 goto error;
240 fedata->irq = err;
241
242 err = request_threaded_irq(fedata->irq, NULL, pvcalls_back_event,
243 IRQF_ONESHOT, "pvcalls-back", dev);
244 if (err < 0)
245 goto error;
246
247 err = xenbus_map_ring_valloc(dev, &ring_ref, 1,
248 (void **)&fedata->sring);
249 if (err < 0)
250 goto error;
251
252 BACK_RING_INIT(&fedata->ring, fedata->sring, XEN_PAGE_SIZE * 1);
253 fedata->dev = dev;
254
255 INIT_LIST_HEAD(&fedata->socket_mappings);
256 INIT_RADIX_TREE(&fedata->socketpass_mappings, GFP_KERNEL);
257 sema_init(&fedata->socket_lock, 1);
258 dev_set_drvdata(&dev->dev, fedata);
259
260 down(&pvcalls_back_global.frontends_lock);
261 list_add_tail(&fedata->list, &pvcalls_back_global.frontends);
262 up(&pvcalls_back_global.frontends_lock);
263
0a9c75c2 264 return 0;
d0e4d560
SS
265
266 error:
267 if (fedata->irq >= 0)
268 unbind_from_irqhandler(fedata->irq, dev);
269 if (fedata->sring != NULL)
270 xenbus_unmap_ring_vfree(dev, fedata->sring);
271 kfree(fedata);
272 return err;
0a9c75c2
SS
273}
274
275static int backend_disconnect(struct xenbus_device *dev)
276{
277 return 0;
278}
279
72e59c30
SS
280static int pvcalls_back_probe(struct xenbus_device *dev,
281 const struct xenbus_device_id *id)
282{
0a9c75c2
SS
283 int err, abort;
284 struct xenbus_transaction xbt;
285
286again:
287 abort = 1;
288
289 err = xenbus_transaction_start(&xbt);
290 if (err) {
291 pr_warn("%s cannot create xenstore transaction\n", __func__);
292 return err;
293 }
294
295 err = xenbus_printf(xbt, dev->nodename, "versions", "%s",
296 PVCALLS_VERSIONS);
297 if (err) {
298 pr_warn("%s write out 'versions' failed\n", __func__);
299 goto abort;
300 }
301
302 err = xenbus_printf(xbt, dev->nodename, "max-page-order", "%u",
303 MAX_RING_ORDER);
304 if (err) {
305 pr_warn("%s write out 'max-page-order' failed\n", __func__);
306 goto abort;
307 }
308
309 err = xenbus_printf(xbt, dev->nodename, "function-calls",
310 XENBUS_FUNCTIONS_CALLS);
311 if (err) {
312 pr_warn("%s write out 'function-calls' failed\n", __func__);
313 goto abort;
314 }
315
316 abort = 0;
317abort:
318 err = xenbus_transaction_end(xbt, abort);
319 if (err) {
320 if (err == -EAGAIN && !abort)
321 goto again;
322 pr_warn("%s cannot complete xenstore transaction\n", __func__);
323 return err;
324 }
325
326 if (abort)
327 return -EFAULT;
328
329 xenbus_switch_state(dev, XenbusStateInitWait);
330
72e59c30
SS
331 return 0;
332}
333
0a9c75c2
SS
334static void set_backend_state(struct xenbus_device *dev,
335 enum xenbus_state state)
336{
337 while (dev->state != state) {
338 switch (dev->state) {
339 case XenbusStateClosed:
340 switch (state) {
341 case XenbusStateInitWait:
342 case XenbusStateConnected:
343 xenbus_switch_state(dev, XenbusStateInitWait);
344 break;
345 case XenbusStateClosing:
346 xenbus_switch_state(dev, XenbusStateClosing);
347 break;
348 default:
349 __WARN();
350 }
351 break;
352 case XenbusStateInitWait:
353 case XenbusStateInitialised:
354 switch (state) {
355 case XenbusStateConnected:
356 backend_connect(dev);
357 xenbus_switch_state(dev, XenbusStateConnected);
358 break;
359 case XenbusStateClosing:
360 case XenbusStateClosed:
361 xenbus_switch_state(dev, XenbusStateClosing);
362 break;
363 default:
364 __WARN();
365 }
366 break;
367 case XenbusStateConnected:
368 switch (state) {
369 case XenbusStateInitWait:
370 case XenbusStateClosing:
371 case XenbusStateClosed:
372 down(&pvcalls_back_global.frontends_lock);
373 backend_disconnect(dev);
374 up(&pvcalls_back_global.frontends_lock);
375 xenbus_switch_state(dev, XenbusStateClosing);
376 break;
377 default:
378 __WARN();
379 }
380 break;
381 case XenbusStateClosing:
382 switch (state) {
383 case XenbusStateInitWait:
384 case XenbusStateConnected:
385 case XenbusStateClosed:
386 xenbus_switch_state(dev, XenbusStateClosed);
387 break;
388 default:
389 __WARN();
390 }
391 break;
392 default:
393 __WARN();
394 }
395 }
396}
397
72e59c30
SS
398static void pvcalls_back_changed(struct xenbus_device *dev,
399 enum xenbus_state frontend_state)
400{
0a9c75c2
SS
401 switch (frontend_state) {
402 case XenbusStateInitialising:
403 set_backend_state(dev, XenbusStateInitWait);
404 break;
405
406 case XenbusStateInitialised:
407 case XenbusStateConnected:
408 set_backend_state(dev, XenbusStateConnected);
409 break;
410
411 case XenbusStateClosing:
412 set_backend_state(dev, XenbusStateClosing);
413 break;
414
415 case XenbusStateClosed:
416 set_backend_state(dev, XenbusStateClosed);
417 if (xenbus_dev_is_online(dev))
418 break;
419 device_unregister(&dev->dev);
420 break;
421 case XenbusStateUnknown:
422 set_backend_state(dev, XenbusStateClosed);
423 device_unregister(&dev->dev);
424 break;
425
426 default:
427 xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
428 frontend_state);
429 break;
430 }
72e59c30
SS
431}
432
433static int pvcalls_back_remove(struct xenbus_device *dev)
434{
435 return 0;
436}
437
438static int pvcalls_back_uevent(struct xenbus_device *xdev,
439 struct kobj_uevent_env *env)
440{
441 return 0;
442}
443
444static const struct xenbus_device_id pvcalls_back_ids[] = {
445 { "pvcalls" },
446 { "" }
447};
448
449static struct xenbus_driver pvcalls_back_driver = {
450 .ids = pvcalls_back_ids,
451 .probe = pvcalls_back_probe,
452 .remove = pvcalls_back_remove,
453 .uevent = pvcalls_back_uevent,
454 .otherend_changed = pvcalls_back_changed,
455};
9be07334
SS
456
457static int __init pvcalls_back_init(void)
458{
459 int ret;
460
461 if (!xen_domain())
462 return -ENODEV;
463
464 ret = xenbus_register_backend(&pvcalls_back_driver);
465 if (ret < 0)
466 return ret;
467
468 sema_init(&pvcalls_back_global.frontends_lock, 1);
469 INIT_LIST_HEAD(&pvcalls_back_global.frontends);
470 return 0;
471}
472module_init(pvcalls_back_init);