]>
Commit | Line | Data |
---|---|---|
f942dc25 IC |
1 | /* |
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 | ||
24 | struct backend_info { | |
25 | struct xenbus_device *dev; | |
26 | struct xenvif *vif; | |
ea732dff PD |
27 | |
28 | /* This is the state that will be reflected in xenstore when any | |
29 | * active hotplug script completes. | |
30 | */ | |
31 | enum xenbus_state state; | |
32 | ||
f942dc25 IC |
33 | enum xenbus_state frontend_state; |
34 | struct xenbus_watch hotplug_status_watch; | |
17938a69 | 35 | u8 have_hotplug_status_watch:1; |
f942dc25 IC |
36 | }; |
37 | ||
38 | static int connect_rings(struct backend_info *); | |
39 | static void connect(struct backend_info *); | |
40 | static void backend_create_xenvif(struct backend_info *be); | |
41 | static void unregister_hotplug_status_watch(struct backend_info *be); | |
42 | ||
43 | static int netback_remove(struct xenbus_device *dev) | |
44 | { | |
45 | struct backend_info *be = dev_get_drvdata(&dev->dev); | |
46 | ||
47 | unregister_hotplug_status_watch(be); | |
48 | if (be->vif) { | |
49 | kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE); | |
50 | xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status"); | |
279f438e | 51 | xenvif_free(be->vif); |
f942dc25 IC |
52 | be->vif = NULL; |
53 | } | |
54 | kfree(be); | |
55 | dev_set_drvdata(&dev->dev, NULL); | |
56 | return 0; | |
57 | } | |
58 | ||
59 | ||
60 | /** | |
61 | * Entry point to this code when a new device is created. Allocate the basic | |
62 | * structures and switch to InitWait. | |
63 | */ | |
64 | static int netback_probe(struct xenbus_device *dev, | |
65 | const struct xenbus_device_id *id) | |
66 | { | |
67 | const char *message; | |
68 | struct xenbus_transaction xbt; | |
69 | int err; | |
70 | int sg; | |
71 | struct backend_info *be = kzalloc(sizeof(struct backend_info), | |
72 | GFP_KERNEL); | |
73 | if (!be) { | |
74 | xenbus_dev_fatal(dev, -ENOMEM, | |
75 | "allocating backend structure"); | |
76 | return -ENOMEM; | |
77 | } | |
78 | ||
79 | be->dev = dev; | |
80 | dev_set_drvdata(&dev->dev, be); | |
81 | ||
82 | sg = 1; | |
83 | ||
84 | do { | |
85 | err = xenbus_transaction_start(&xbt); | |
86 | if (err) { | |
87 | xenbus_dev_fatal(dev, err, "starting transaction"); | |
88 | goto fail; | |
89 | } | |
90 | ||
91 | err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", sg); | |
92 | if (err) { | |
93 | message = "writing feature-sg"; | |
94 | goto abort_transaction; | |
95 | } | |
96 | ||
97 | err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4", | |
98 | "%d", sg); | |
99 | if (err) { | |
100 | message = "writing feature-gso-tcpv4"; | |
101 | goto abort_transaction; | |
102 | } | |
103 | ||
104 | /* We support rx-copy path. */ | |
105 | err = xenbus_printf(xbt, dev->nodename, | |
106 | "feature-rx-copy", "%d", 1); | |
107 | if (err) { | |
108 | message = "writing feature-rx-copy"; | |
109 | goto abort_transaction; | |
110 | } | |
111 | ||
112 | /* | |
113 | * We don't support rx-flip path (except old guests who don't | |
114 | * grok this feature flag). | |
115 | */ | |
116 | err = xenbus_printf(xbt, dev->nodename, | |
117 | "feature-rx-flip", "%d", 0); | |
118 | if (err) { | |
119 | message = "writing feature-rx-flip"; | |
120 | goto abort_transaction; | |
121 | } | |
122 | ||
123 | err = xenbus_transaction_end(xbt, 0); | |
124 | } while (err == -EAGAIN); | |
125 | ||
126 | if (err) { | |
127 | xenbus_dev_fatal(dev, err, "completing transaction"); | |
128 | goto fail; | |
129 | } | |
130 | ||
e1f00a69 WL |
131 | /* |
132 | * Split event channels support, this is optional so it is not | |
133 | * put inside the above loop. | |
134 | */ | |
135 | err = xenbus_printf(XBT_NIL, dev->nodename, | |
136 | "feature-split-event-channels", | |
137 | "%u", separate_tx_rx_irq); | |
138 | if (err) | |
8ef2c3bc | 139 | pr_debug("Error writing feature-split-event-channels\n"); |
e1f00a69 | 140 | |
f942dc25 IC |
141 | err = xenbus_switch_state(dev, XenbusStateInitWait); |
142 | if (err) | |
143 | goto fail; | |
144 | ||
ea732dff PD |
145 | be->state = XenbusStateInitWait; |
146 | ||
f942dc25 IC |
147 | /* This kicks hotplug scripts, so do it immediately. */ |
148 | backend_create_xenvif(be); | |
149 | ||
150 | return 0; | |
151 | ||
152 | abort_transaction: | |
153 | xenbus_transaction_end(xbt, 1); | |
154 | xenbus_dev_fatal(dev, err, "%s", message); | |
155 | fail: | |
8ef2c3bc | 156 | pr_debug("failed\n"); |
f942dc25 IC |
157 | netback_remove(dev); |
158 | return err; | |
159 | } | |
160 | ||
161 | ||
162 | /* | |
163 | * Handle the creation of the hotplug script environment. We add the script | |
164 | * and vif variables to the environment, for the benefit of the vif-* hotplug | |
165 | * scripts. | |
166 | */ | |
167 | static int netback_uevent(struct xenbus_device *xdev, | |
168 | struct kobj_uevent_env *env) | |
169 | { | |
170 | struct backend_info *be = dev_get_drvdata(&xdev->dev); | |
171 | char *val; | |
172 | ||
173 | val = xenbus_read(XBT_NIL, xdev->nodename, "script", NULL); | |
174 | if (IS_ERR(val)) { | |
175 | int err = PTR_ERR(val); | |
176 | xenbus_dev_fatal(xdev, err, "reading script"); | |
177 | return err; | |
178 | } else { | |
179 | if (add_uevent_var(env, "script=%s", val)) { | |
180 | kfree(val); | |
181 | return -ENOMEM; | |
182 | } | |
183 | kfree(val); | |
184 | } | |
185 | ||
186 | if (!be || !be->vif) | |
187 | return 0; | |
188 | ||
189 | return add_uevent_var(env, "vif=%s", be->vif->dev->name); | |
190 | } | |
191 | ||
192 | ||
193 | static void backend_create_xenvif(struct backend_info *be) | |
194 | { | |
195 | int err; | |
196 | long handle; | |
197 | struct xenbus_device *dev = be->dev; | |
198 | ||
199 | if (be->vif != NULL) | |
200 | return; | |
201 | ||
202 | err = xenbus_scanf(XBT_NIL, dev->nodename, "handle", "%li", &handle); | |
203 | if (err != 1) { | |
204 | xenbus_dev_fatal(dev, err, "reading handle"); | |
205 | return; | |
206 | } | |
207 | ||
208 | be->vif = xenvif_alloc(&dev->dev, dev->otherend_id, handle); | |
209 | if (IS_ERR(be->vif)) { | |
210 | err = PTR_ERR(be->vif); | |
211 | be->vif = NULL; | |
212 | xenbus_dev_fatal(dev, err, "creating interface"); | |
213 | return; | |
214 | } | |
215 | ||
216 | kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE); | |
217 | } | |
218 | ||
ea732dff | 219 | static void backend_disconnect(struct backend_info *be) |
f942dc25 | 220 | { |
279f438e PD |
221 | if (be->vif) |
222 | xenvif_disconnect(be->vif); | |
223 | } | |
224 | ||
ea732dff | 225 | static void backend_connect(struct backend_info *be) |
279f438e | 226 | { |
ea732dff PD |
227 | if (be->vif) |
228 | connect(be); | |
229 | } | |
279f438e | 230 | |
ea732dff PD |
231 | static inline void backend_switch_state(struct backend_info *be, |
232 | enum xenbus_state state) | |
233 | { | |
234 | struct xenbus_device *dev = be->dev; | |
235 | ||
236 | pr_debug("%s -> %s\n", dev->nodename, xenbus_strstate(state)); | |
237 | be->state = state; | |
238 | ||
239 | /* If we are waiting for a hotplug script then defer the | |
240 | * actual xenbus state change. | |
241 | */ | |
242 | if (!be->have_hotplug_status_watch) | |
243 | xenbus_switch_state(dev, state); | |
244 | } | |
245 | ||
246 | /* Handle backend state transitions: | |
247 | * | |
248 | * The backend state starts in InitWait and the following transitions are | |
249 | * allowed. | |
250 | * | |
251 | * InitWait -> Connected | |
252 | * | |
253 | * ^ \ | | |
254 | * | \ | | |
255 | * | \ | | |
256 | * | \ | | |
257 | * | \ | | |
258 | * | \ | | |
259 | * | V V | |
260 | * | |
261 | * Closed <-> Closing | |
262 | * | |
263 | * The state argument specifies the eventual state of the backend and the | |
264 | * function transitions to that state via the shortest path. | |
265 | */ | |
266 | static void set_backend_state(struct backend_info *be, | |
267 | enum xenbus_state state) | |
268 | { | |
269 | while (be->state != state) { | |
270 | switch (be->state) { | |
271 | case XenbusStateClosed: | |
272 | switch (state) { | |
273 | case XenbusStateInitWait: | |
274 | case XenbusStateConnected: | |
275 | pr_info("%s: prepare for reconnect\n", | |
276 | be->dev->nodename); | |
277 | backend_switch_state(be, XenbusStateInitWait); | |
278 | break; | |
279 | case XenbusStateClosing: | |
280 | backend_switch_state(be, XenbusStateClosing); | |
281 | break; | |
282 | default: | |
283 | BUG(); | |
284 | } | |
285 | break; | |
286 | case XenbusStateInitWait: | |
287 | switch (state) { | |
288 | case XenbusStateConnected: | |
289 | backend_connect(be); | |
290 | backend_switch_state(be, XenbusStateConnected); | |
291 | break; | |
292 | case XenbusStateClosing: | |
293 | case XenbusStateClosed: | |
294 | backend_switch_state(be, XenbusStateClosing); | |
295 | break; | |
296 | default: | |
297 | BUG(); | |
298 | } | |
299 | break; | |
300 | case XenbusStateConnected: | |
301 | switch (state) { | |
302 | case XenbusStateInitWait: | |
303 | case XenbusStateClosing: | |
304 | case XenbusStateClosed: | |
305 | backend_disconnect(be); | |
306 | backend_switch_state(be, XenbusStateClosing); | |
307 | break; | |
308 | default: | |
309 | BUG(); | |
310 | } | |
311 | break; | |
312 | case XenbusStateClosing: | |
313 | switch (state) { | |
314 | case XenbusStateInitWait: | |
315 | case XenbusStateConnected: | |
316 | case XenbusStateClosed: | |
317 | backend_switch_state(be, XenbusStateClosed); | |
318 | break; | |
319 | default: | |
320 | BUG(); | |
321 | } | |
322 | break; | |
323 | default: | |
324 | BUG(); | |
325 | } | |
f942dc25 IC |
326 | } |
327 | } | |
328 | ||
329 | /** | |
330 | * Callback received when the frontend's state changes. | |
331 | */ | |
332 | static void frontend_changed(struct xenbus_device *dev, | |
333 | enum xenbus_state frontend_state) | |
334 | { | |
335 | struct backend_info *be = dev_get_drvdata(&dev->dev); | |
336 | ||
ea732dff | 337 | pr_debug("%s -> %s\n", dev->otherend, xenbus_strstate(frontend_state)); |
f942dc25 IC |
338 | |
339 | be->frontend_state = frontend_state; | |
340 | ||
341 | switch (frontend_state) { | |
342 | case XenbusStateInitialising: | |
ea732dff | 343 | set_backend_state(be, XenbusStateInitWait); |
f942dc25 IC |
344 | break; |
345 | ||
346 | case XenbusStateInitialised: | |
347 | break; | |
348 | ||
349 | case XenbusStateConnected: | |
ea732dff | 350 | set_backend_state(be, XenbusStateConnected); |
f942dc25 IC |
351 | break; |
352 | ||
353 | case XenbusStateClosing: | |
ea732dff | 354 | set_backend_state(be, XenbusStateClosing); |
f942dc25 IC |
355 | break; |
356 | ||
357 | case XenbusStateClosed: | |
ea732dff | 358 | set_backend_state(be, XenbusStateClosed); |
f942dc25 IC |
359 | if (xenbus_dev_is_online(dev)) |
360 | break; | |
361 | /* fall through if not online */ | |
362 | case XenbusStateUnknown: | |
ea732dff | 363 | set_backend_state(be, XenbusStateClosed); |
f942dc25 IC |
364 | device_unregister(&dev->dev); |
365 | break; | |
366 | ||
367 | default: | |
368 | xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend", | |
369 | frontend_state); | |
370 | break; | |
371 | } | |
372 | } | |
373 | ||
374 | ||
375 | static void xen_net_read_rate(struct xenbus_device *dev, | |
376 | unsigned long *bytes, unsigned long *usec) | |
377 | { | |
378 | char *s, *e; | |
379 | unsigned long b, u; | |
380 | char *ratestr; | |
381 | ||
382 | /* Default to unlimited bandwidth. */ | |
383 | *bytes = ~0UL; | |
384 | *usec = 0; | |
385 | ||
386 | ratestr = xenbus_read(XBT_NIL, dev->nodename, "rate", NULL); | |
387 | if (IS_ERR(ratestr)) | |
388 | return; | |
389 | ||
390 | s = ratestr; | |
391 | b = simple_strtoul(s, &e, 10); | |
392 | if ((s == e) || (*e != ',')) | |
393 | goto fail; | |
394 | ||
395 | s = e + 1; | |
396 | u = simple_strtoul(s, &e, 10); | |
397 | if ((s == e) || (*e != '\0')) | |
398 | goto fail; | |
399 | ||
400 | *bytes = b; | |
401 | *usec = u; | |
402 | ||
403 | kfree(ratestr); | |
404 | return; | |
405 | ||
406 | fail: | |
407 | pr_warn("Failed to parse network rate limit. Traffic unlimited.\n"); | |
408 | kfree(ratestr); | |
409 | } | |
410 | ||
411 | static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[]) | |
412 | { | |
413 | char *s, *e, *macstr; | |
414 | int i; | |
415 | ||
416 | macstr = s = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL); | |
417 | if (IS_ERR(macstr)) | |
418 | return PTR_ERR(macstr); | |
419 | ||
420 | for (i = 0; i < ETH_ALEN; i++) { | |
421 | mac[i] = simple_strtoul(s, &e, 16); | |
422 | if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) { | |
423 | kfree(macstr); | |
424 | return -ENOENT; | |
425 | } | |
426 | s = e+1; | |
427 | } | |
428 | ||
429 | kfree(macstr); | |
430 | return 0; | |
431 | } | |
432 | ||
433 | static void unregister_hotplug_status_watch(struct backend_info *be) | |
434 | { | |
435 | if (be->have_hotplug_status_watch) { | |
436 | unregister_xenbus_watch(&be->hotplug_status_watch); | |
437 | kfree(be->hotplug_status_watch.node); | |
438 | } | |
439 | be->have_hotplug_status_watch = 0; | |
440 | } | |
441 | ||
442 | static void hotplug_status_changed(struct xenbus_watch *watch, | |
443 | const char **vec, | |
444 | unsigned int vec_size) | |
445 | { | |
446 | struct backend_info *be = container_of(watch, | |
447 | struct backend_info, | |
448 | hotplug_status_watch); | |
449 | char *str; | |
450 | unsigned int len; | |
451 | ||
452 | str = xenbus_read(XBT_NIL, be->dev->nodename, "hotplug-status", &len); | |
453 | if (IS_ERR(str)) | |
454 | return; | |
455 | if (len == sizeof("connected")-1 && !memcmp(str, "connected", len)) { | |
ea732dff PD |
456 | /* Complete any pending state change */ |
457 | xenbus_switch_state(be->dev, be->state); | |
458 | ||
f942dc25 IC |
459 | /* Not interested in this watch anymore. */ |
460 | unregister_hotplug_status_watch(be); | |
461 | } | |
462 | kfree(str); | |
463 | } | |
464 | ||
465 | static void connect(struct backend_info *be) | |
466 | { | |
467 | int err; | |
468 | struct xenbus_device *dev = be->dev; | |
469 | ||
470 | err = connect_rings(be); | |
471 | if (err) | |
472 | return; | |
473 | ||
474 | err = xen_net_read_mac(dev, be->vif->fe_dev_addr); | |
475 | if (err) { | |
476 | xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename); | |
477 | return; | |
478 | } | |
479 | ||
480 | xen_net_read_rate(dev, &be->vif->credit_bytes, | |
481 | &be->vif->credit_usec); | |
482 | be->vif->remaining_credit = be->vif->credit_bytes; | |
483 | ||
484 | unregister_hotplug_status_watch(be); | |
485 | err = xenbus_watch_pathfmt(dev, &be->hotplug_status_watch, | |
486 | hotplug_status_changed, | |
487 | "%s/%s", dev->nodename, "hotplug-status"); | |
ea732dff | 488 | if (!err) |
f942dc25 | 489 | be->have_hotplug_status_watch = 1; |
f942dc25 IC |
490 | |
491 | netif_wake_queue(be->vif->dev); | |
492 | } | |
493 | ||
494 | ||
495 | static int connect_rings(struct backend_info *be) | |
496 | { | |
497 | struct xenvif *vif = be->vif; | |
498 | struct xenbus_device *dev = be->dev; | |
499 | unsigned long tx_ring_ref, rx_ring_ref; | |
e1f00a69 | 500 | unsigned int tx_evtchn, rx_evtchn, rx_copy; |
f942dc25 IC |
501 | int err; |
502 | int val; | |
503 | ||
504 | err = xenbus_gather(XBT_NIL, dev->otherend, | |
505 | "tx-ring-ref", "%lu", &tx_ring_ref, | |
e1f00a69 | 506 | "rx-ring-ref", "%lu", &rx_ring_ref, NULL); |
f942dc25 IC |
507 | if (err) { |
508 | xenbus_dev_fatal(dev, err, | |
e1f00a69 | 509 | "reading %s/ring-ref", |
f942dc25 IC |
510 | dev->otherend); |
511 | return err; | |
512 | } | |
513 | ||
e1f00a69 WL |
514 | /* Try split event channels first, then single event channel. */ |
515 | err = xenbus_gather(XBT_NIL, dev->otherend, | |
516 | "event-channel-tx", "%u", &tx_evtchn, | |
517 | "event-channel-rx", "%u", &rx_evtchn, NULL); | |
518 | if (err < 0) { | |
519 | err = xenbus_scanf(XBT_NIL, dev->otherend, | |
520 | "event-channel", "%u", &tx_evtchn); | |
521 | if (err < 0) { | |
522 | xenbus_dev_fatal(dev, err, | |
523 | "reading %s/event-channel(-tx/rx)", | |
524 | dev->otherend); | |
525 | return err; | |
526 | } | |
527 | rx_evtchn = tx_evtchn; | |
528 | } | |
529 | ||
f942dc25 IC |
530 | err = xenbus_scanf(XBT_NIL, dev->otherend, "request-rx-copy", "%u", |
531 | &rx_copy); | |
532 | if (err == -ENOENT) { | |
533 | err = 0; | |
534 | rx_copy = 0; | |
535 | } | |
536 | if (err < 0) { | |
537 | xenbus_dev_fatal(dev, err, "reading %s/request-rx-copy", | |
538 | dev->otherend); | |
539 | return err; | |
540 | } | |
541 | if (!rx_copy) | |
542 | return -EOPNOTSUPP; | |
543 | ||
544 | if (vif->dev->tx_queue_len != 0) { | |
545 | if (xenbus_scanf(XBT_NIL, dev->otherend, | |
546 | "feature-rx-notify", "%d", &val) < 0) | |
547 | val = 0; | |
548 | if (val) | |
549 | vif->can_queue = 1; | |
550 | else | |
551 | /* Must be non-zero for pfifo_fast to work. */ | |
552 | vif->dev->tx_queue_len = 1; | |
553 | } | |
554 | ||
555 | if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg", | |
556 | "%d", &val) < 0) | |
557 | val = 0; | |
558 | vif->can_sg = !!val; | |
559 | ||
560 | if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4", | |
561 | "%d", &val) < 0) | |
562 | val = 0; | |
563 | vif->gso = !!val; | |
564 | ||
565 | if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4-prefix", | |
566 | "%d", &val) < 0) | |
567 | val = 0; | |
568 | vif->gso_prefix = !!val; | |
569 | ||
570 | if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-no-csum-offload", | |
571 | "%d", &val) < 0) | |
572 | val = 0; | |
573 | vif->csum = !val; | |
574 | ||
575 | /* Map the shared frame, irq etc. */ | |
e1f00a69 WL |
576 | err = xenvif_connect(vif, tx_ring_ref, rx_ring_ref, |
577 | tx_evtchn, rx_evtchn); | |
f942dc25 IC |
578 | if (err) { |
579 | xenbus_dev_fatal(dev, err, | |
e1f00a69 WL |
580 | "mapping shared-frames %lu/%lu port tx %u rx %u", |
581 | tx_ring_ref, rx_ring_ref, | |
582 | tx_evtchn, rx_evtchn); | |
f942dc25 IC |
583 | return err; |
584 | } | |
585 | return 0; | |
586 | } | |
587 | ||
588 | ||
589 | /* ** Driver Registration ** */ | |
590 | ||
591 | ||
592 | static const struct xenbus_device_id netback_ids[] = { | |
593 | { "vif" }, | |
594 | { "" } | |
595 | }; | |
596 | ||
597 | ||
73db144b | 598 | static DEFINE_XENBUS_DRIVER(netback, , |
f942dc25 IC |
599 | .probe = netback_probe, |
600 | .remove = netback_remove, | |
601 | .uevent = netback_uevent, | |
602 | .otherend_changed = frontend_changed, | |
73db144b | 603 | ); |
f942dc25 IC |
604 | |
605 | int xenvif_xenbus_init(void) | |
606 | { | |
73db144b | 607 | return xenbus_register_backend(&netback_driver); |
f942dc25 | 608 | } |
b103f358 WL |
609 | |
610 | void xenvif_xenbus_fini(void) | |
611 | { | |
612 | return xenbus_unregister_driver(&netback_driver); | |
613 | } |