blob: bad4ee30728a2202029118cb87226f677ccd6ffa [file] [log] [blame]
yuezonghe824eb0c2024-06-27 02:32:26 -07001/*
2 * Xenbus code for netif backend
3 *
4 * Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
5 * Copyright (C) 2005 XenSource Ltd
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20*/
21
22#include "common.h"
23
24struct backend_info {
25 struct xenbus_device *dev;
26 struct xenvif *vif;
27 enum xenbus_state frontend_state;
28 struct xenbus_watch hotplug_status_watch;
29 u8 have_hotplug_status_watch:1;
30
31 const char *hotplug_script;
32};
33
34static int connect_rings(struct backend_info *);
35static void connect(struct backend_info *);
36static void backend_create_xenvif(struct backend_info *be);
37static void unregister_hotplug_status_watch(struct backend_info *be);
38
39static int netback_remove(struct xenbus_device *dev)
40{
41 struct backend_info *be = dev_get_drvdata(&dev->dev);
42
43 unregister_hotplug_status_watch(be);
44 if (be->vif) {
45 kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
46 xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
47 xenvif_disconnect(be->vif);
48 be->vif = NULL;
49 }
50 kfree(be->hotplug_script);
51 kfree(be);
52 dev_set_drvdata(&dev->dev, NULL);
53 return 0;
54}
55
56
57/**
58 * Entry point to this code when a new device is created. Allocate the basic
59 * structures and switch to InitWait.
60 */
61static int netback_probe(struct xenbus_device *dev,
62 const struct xenbus_device_id *id)
63{
64 const char *message;
65 struct xenbus_transaction xbt;
66 int err;
67 int sg;
68 const char *script;
69 struct backend_info *be = kzalloc(sizeof(struct backend_info),
70 GFP_KERNEL);
71 if (!be) {
72 xenbus_dev_fatal(dev, -ENOMEM,
73 "allocating backend structure");
74 return -ENOMEM;
75 }
76
77 be->dev = dev;
78 dev_set_drvdata(&dev->dev, be);
79
80 sg = 1;
81
82 do {
83 err = xenbus_transaction_start(&xbt);
84 if (err) {
85 xenbus_dev_fatal(dev, err, "starting transaction");
86 goto fail;
87 }
88
89 err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", sg);
90 if (err) {
91 message = "writing feature-sg";
92 goto abort_transaction;
93 }
94
95 err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4",
96 "%d", sg);
97 if (err) {
98 message = "writing feature-gso-tcpv4";
99 goto abort_transaction;
100 }
101
102 /* We support rx-copy path. */
103 err = xenbus_printf(xbt, dev->nodename,
104 "feature-rx-copy", "%d", 1);
105 if (err) {
106 message = "writing feature-rx-copy";
107 goto abort_transaction;
108 }
109
110 /*
111 * We don't support rx-flip path (except old guests who don't
112 * grok this feature flag).
113 */
114 err = xenbus_printf(xbt, dev->nodename,
115 "feature-rx-flip", "%d", 0);
116 if (err) {
117 message = "writing feature-rx-flip";
118 goto abort_transaction;
119 }
120
121 err = xenbus_transaction_end(xbt, 0);
122 } while (err == -EAGAIN);
123
124 if (err) {
125 xenbus_dev_fatal(dev, err, "completing transaction");
126 goto fail;
127 }
128
129 script = xenbus_read(XBT_NIL, dev->nodename, "script", NULL);
130 if (IS_ERR(script)) {
131 err = PTR_ERR(script);
132 xenbus_dev_fatal(dev, err, "reading script");
133 goto fail;
134 }
135
136 be->hotplug_script = script;
137
138 err = xenbus_switch_state(dev, XenbusStateInitWait);
139 if (err)
140 goto fail;
141
142 /* This kicks hotplug scripts, so do it immediately. */
143 backend_create_xenvif(be);
144
145 return 0;
146
147abort_transaction:
148 xenbus_transaction_end(xbt, 1);
149 xenbus_dev_fatal(dev, err, "%s", message);
150fail:
151 pr_debug("failed");
152 netback_remove(dev);
153 return err;
154}
155
156
157/*
158 * Handle the creation of the hotplug script environment. We add the script
159 * and vif variables to the environment, for the benefit of the vif-* hotplug
160 * scripts.
161 */
162static int netback_uevent(struct xenbus_device *xdev,
163 struct kobj_uevent_env *env)
164{
165 struct backend_info *be = dev_get_drvdata(&xdev->dev);
166
167 if (!be)
168 return 0;
169
170 if (add_uevent_var(env, "script=%s", be->hotplug_script))
171 return -ENOMEM;
172
173 if (!be->vif)
174 return 0;
175
176 return add_uevent_var(env, "vif=%s", be->vif->dev->name);
177}
178
179
180static void backend_create_xenvif(struct backend_info *be)
181{
182 int err;
183 long handle;
184 struct xenbus_device *dev = be->dev;
185
186 if (be->vif != NULL)
187 return;
188
189 err = xenbus_scanf(XBT_NIL, dev->nodename, "handle", "%li", &handle);
190 if (err != 1) {
191 xenbus_dev_fatal(dev, err, "reading handle");
192 return;
193 }
194
195 be->vif = xenvif_alloc(&dev->dev, dev->otherend_id, handle);
196 if (IS_ERR(be->vif)) {
197 err = PTR_ERR(be->vif);
198 be->vif = NULL;
199 xenbus_dev_fatal(dev, err, "creating interface");
200 return;
201 }
202
203 kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE);
204}
205
206
207static void disconnect_backend(struct xenbus_device *dev)
208{
209 struct backend_info *be = dev_get_drvdata(&dev->dev);
210
211 if (be->vif) {
212 xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
213 xenvif_disconnect(be->vif);
214 be->vif = NULL;
215 }
216}
217
218/**
219 * Callback received when the frontend's state changes.
220 */
221static void frontend_changed(struct xenbus_device *dev,
222 enum xenbus_state frontend_state)
223{
224 struct backend_info *be = dev_get_drvdata(&dev->dev);
225
226 pr_debug("frontend state %s", xenbus_strstate(frontend_state));
227
228 be->frontend_state = frontend_state;
229
230 switch (frontend_state) {
231 case XenbusStateInitialising:
232 if (dev->state == XenbusStateClosed) {
233 printk(KERN_INFO "%s: %s: prepare for reconnect\n",
234 __func__, dev->nodename);
235 xenbus_switch_state(dev, XenbusStateInitWait);
236 }
237 break;
238
239 case XenbusStateInitialised:
240 break;
241
242 case XenbusStateConnected:
243 if (dev->state == XenbusStateConnected)
244 break;
245 backend_create_xenvif(be);
246 if (be->vif)
247 connect(be);
248 break;
249
250 case XenbusStateClosing:
251 if (be->vif)
252 kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
253 disconnect_backend(dev);
254 xenbus_switch_state(dev, XenbusStateClosing);
255 break;
256
257 case XenbusStateClosed:
258 xenbus_switch_state(dev, XenbusStateClosed);
259 if (xenbus_dev_is_online(dev))
260 break;
261 /* fall through if not online */
262 case XenbusStateUnknown:
263 device_unregister(&dev->dev);
264 break;
265
266 default:
267 xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
268 frontend_state);
269 break;
270 }
271}
272
273
274static void xen_net_read_rate(struct xenbus_device *dev,
275 unsigned long *bytes, unsigned long *usec)
276{
277 char *s, *e;
278 unsigned long b, u;
279 char *ratestr;
280
281 /* Default to unlimited bandwidth. */
282 *bytes = ~0UL;
283 *usec = 0;
284
285 ratestr = xenbus_read(XBT_NIL, dev->nodename, "rate", NULL);
286 if (IS_ERR(ratestr))
287 return;
288
289 s = ratestr;
290 b = simple_strtoul(s, &e, 10);
291 if ((s == e) || (*e != ','))
292 goto fail;
293
294 s = e + 1;
295 u = simple_strtoul(s, &e, 10);
296 if ((s == e) || (*e != '\0'))
297 goto fail;
298
299 *bytes = b;
300 *usec = u;
301
302 kfree(ratestr);
303 return;
304
305 fail:
306 pr_warn("Failed to parse network rate limit. Traffic unlimited.\n");
307 kfree(ratestr);
308}
309
310static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
311{
312 char *s, *e, *macstr;
313 int i;
314
315 macstr = s = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL);
316 if (IS_ERR(macstr))
317 return PTR_ERR(macstr);
318
319 for (i = 0; i < ETH_ALEN; i++) {
320 mac[i] = simple_strtoul(s, &e, 16);
321 if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
322 kfree(macstr);
323 return -ENOENT;
324 }
325 s = e+1;
326 }
327
328 kfree(macstr);
329 return 0;
330}
331
332static void unregister_hotplug_status_watch(struct backend_info *be)
333{
334 if (be->have_hotplug_status_watch) {
335 unregister_xenbus_watch(&be->hotplug_status_watch);
336 kfree(be->hotplug_status_watch.node);
337 }
338 be->have_hotplug_status_watch = 0;
339}
340
341static void hotplug_status_changed(struct xenbus_watch *watch,
342 const char **vec,
343 unsigned int vec_size)
344{
345 struct backend_info *be = container_of(watch,
346 struct backend_info,
347 hotplug_status_watch);
348 char *str;
349 unsigned int len;
350
351 str = xenbus_read(XBT_NIL, be->dev->nodename, "hotplug-status", &len);
352 if (IS_ERR(str))
353 return;
354 if (len == sizeof("connected")-1 && !memcmp(str, "connected", len)) {
355 xenbus_switch_state(be->dev, XenbusStateConnected);
356 /* Not interested in this watch anymore. */
357 unregister_hotplug_status_watch(be);
358 }
359 kfree(str);
360}
361
362static void connect(struct backend_info *be)
363{
364 int err;
365 struct xenbus_device *dev = be->dev;
366
367 err = connect_rings(be);
368 if (err)
369 return;
370
371 err = xen_net_read_mac(dev, be->vif->fe_dev_addr);
372 if (err) {
373 xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
374 return;
375 }
376
377 xen_net_read_rate(dev, &be->vif->credit_bytes,
378 &be->vif->credit_usec);
379 be->vif->remaining_credit = be->vif->credit_bytes;
380
381 unregister_hotplug_status_watch(be);
382 err = xenbus_watch_pathfmt(dev, &be->hotplug_status_watch,
383 hotplug_status_changed,
384 "%s/%s", dev->nodename, "hotplug-status");
385 if (err) {
386 /* Switch now, since we can't do a watch. */
387 xenbus_switch_state(dev, XenbusStateConnected);
388 } else {
389 be->have_hotplug_status_watch = 1;
390 }
391
392 netif_wake_queue(be->vif->dev);
393}
394
395
396static int connect_rings(struct backend_info *be)
397{
398 struct xenvif *vif = be->vif;
399 struct xenbus_device *dev = be->dev;
400 unsigned long tx_ring_ref, rx_ring_ref;
401 unsigned int evtchn, rx_copy;
402 int err;
403 int val;
404
405 err = xenbus_gather(XBT_NIL, dev->otherend,
406 "tx-ring-ref", "%lu", &tx_ring_ref,
407 "rx-ring-ref", "%lu", &rx_ring_ref,
408 "event-channel", "%u", &evtchn, NULL);
409 if (err) {
410 xenbus_dev_fatal(dev, err,
411 "reading %s/ring-ref and event-channel",
412 dev->otherend);
413 return err;
414 }
415
416 err = xenbus_scanf(XBT_NIL, dev->otherend, "request-rx-copy", "%u",
417 &rx_copy);
418 if (err == -ENOENT) {
419 err = 0;
420 rx_copy = 0;
421 }
422 if (err < 0) {
423 xenbus_dev_fatal(dev, err, "reading %s/request-rx-copy",
424 dev->otherend);
425 return err;
426 }
427 if (!rx_copy)
428 return -EOPNOTSUPP;
429
430 if (vif->dev->tx_queue_len != 0) {
431 if (xenbus_scanf(XBT_NIL, dev->otherend,
432 "feature-rx-notify", "%d", &val) < 0)
433 val = 0;
434 if (val)
435 vif->can_queue = 1;
436 else
437 /* Must be non-zero for pfifo_fast to work. */
438 vif->dev->tx_queue_len = 1;
439 }
440
441 if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg",
442 "%d", &val) < 0)
443 val = 0;
444 vif->can_sg = !!val;
445
446 if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4",
447 "%d", &val) < 0)
448 val = 0;
449 vif->gso = !!val;
450
451 if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4-prefix",
452 "%d", &val) < 0)
453 val = 0;
454 vif->gso_prefix = !!val;
455
456 if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-no-csum-offload",
457 "%d", &val) < 0)
458 val = 0;
459 vif->csum = !val;
460
461 /* Map the shared frame, irq etc. */
462 err = xenvif_connect(vif, tx_ring_ref, rx_ring_ref, evtchn);
463 if (err) {
464 xenbus_dev_fatal(dev, err,
465 "mapping shared-frames %lu/%lu port %u",
466 tx_ring_ref, rx_ring_ref, evtchn);
467 return err;
468 }
469 return 0;
470}
471
472
473/* ** Driver Registration ** */
474
475
476static const struct xenbus_device_id netback_ids[] = {
477 { "vif" },
478 { "" }
479};
480
481
482static DEFINE_XENBUS_DRIVER(netback, ,
483 .probe = netback_probe,
484 .remove = netback_remove,
485 .uevent = netback_uevent,
486 .otherend_changed = frontend_changed,
487);
488
489int xenvif_xenbus_init(void)
490{
491 return xenbus_register_backend(&netback_driver);
492}