xen-vtx-unstable

view linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c @ 6774:4d899a738d59

merge?
author cl349@firebug.cl.cam.ac.uk
date Tue Sep 13 15:05:49 2005 +0000 (2005-09-13)
parents 9ead08216805 291e816acbf4
children e7c7196fa329 8ca0f98ba8e2
line source
1 /* Xenbus code for netif backend
2 Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
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.
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.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 #include <stdarg.h>
19 #include <linux/module.h>
20 #include <asm-xen/xenbus.h>
21 #include "common.h"
23 struct backend_info
24 {
25 struct xenbus_device *dev;
27 /* our communications channel */
28 netif_t *netif;
30 long int frontend_id;
31 #if 0
32 long int pdev;
33 long int readonly;
34 #endif
36 /* watch back end for changes */
37 struct xenbus_watch backend_watch;
39 /* watch front end for changes */
40 struct xenbus_watch watch;
41 char *frontpath;
42 };
44 static int netback_remove(struct xenbus_device *dev)
45 {
46 struct backend_info *be = dev->data;
48 if (be->watch.node)
49 unregister_xenbus_watch(&be->watch);
50 unregister_xenbus_watch(&be->backend_watch);
51 if (be->netif)
52 netif_disconnect(be->netif);
53 if (be->frontpath)
54 kfree(be->frontpath);
55 kfree(be);
56 return 0;
57 }
59 /* Front end tells us frame. */
60 static void frontend_changed(struct xenbus_watch *watch, const char *node)
61 {
62 unsigned long tx_ring_ref, rx_ring_ref;
63 unsigned int evtchn;
64 int err;
65 struct backend_info *be
66 = container_of(watch, struct backend_info, watch);
67 char *mac, *e, *s;
68 int i;
70 /* If other end is gone, delete ourself. */
71 if (node && !xenbus_exists(be->frontpath, "")) {
72 xenbus_rm(be->dev->nodename, "");
73 device_unregister(&be->dev->dev);
74 return;
75 }
76 if (be->netif == NULL || be->netif->status == CONNECTED)
77 return;
79 mac = xenbus_read(be->frontpath, "mac", NULL);
80 if (IS_ERR(mac)) {
81 err = PTR_ERR(mac);
82 xenbus_dev_error(be->dev, err, "reading %s/mac",
83 be->dev->nodename);
84 return;
85 }
86 s = mac;
87 for (i = 0; i < ETH_ALEN; i++) {
88 be->netif->fe_dev_addr[i] = simple_strtoul(s, &e, 16);
89 if (s == e || (e[0] != ':' && e[0] != 0)) {
90 kfree(mac);
91 err = -ENOENT;
92 xenbus_dev_error(be->dev, err, "parsing %s/mac",
93 be->dev->nodename);
94 return;
95 }
96 s = &e[1];
97 }
98 kfree(mac);
100 err = xenbus_gather(be->frontpath, "tx-ring-ref", "%lu", &tx_ring_ref,
101 "rx-ring-ref", "%lu", &rx_ring_ref,
102 "event-channel", "%u", &evtchn, NULL);
103 if (err) {
104 xenbus_dev_error(be->dev, err,
105 "reading %s/ring-ref and event-channel",
106 be->frontpath);
107 return;
108 }
110 /* Map the shared frame, irq etc. */
111 err = netif_map(be->netif, tx_ring_ref, rx_ring_ref, evtchn);
112 if (err) {
113 xenbus_dev_error(be->dev, err,
114 "mapping shared-frames %lu/%lu port %u",
115 tx_ring_ref, rx_ring_ref, evtchn);
116 return;
117 }
119 xenbus_dev_ok(be->dev);
121 return;
122 }
124 /*
125 Setup supplies physical device.
126 We provide event channel and device details to front end.
127 Frontend supplies shared frame and event channel.
128 */
129 static void backend_changed(struct xenbus_watch *watch, const char *node)
130 {
131 int err;
132 long int handle;
133 struct backend_info *be
134 = container_of(watch, struct backend_info, backend_watch);
135 struct xenbus_device *dev = be->dev;
136 u8 be_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
138 err = xenbus_scanf(dev->nodename, "handle", "%li", &handle);
139 if (XENBUS_EXIST_ERR(err))
140 return;
141 if (err < 0) {
142 xenbus_dev_error(dev, err, "reading handle");
143 return;
144 }
146 if (be->netif == NULL) {
147 be->netif = alloc_netif(be->frontend_id, handle, be_mac);
148 if (IS_ERR(be->netif)) {
149 err = PTR_ERR(be->netif);
150 be->netif = NULL;
151 xenbus_dev_error(dev, err, "creating interface");
152 return;
153 }
155 #if 0
156 err = vbd_create(be->netif, handle, be->pdev, be->readonly);
157 if (err) {
158 xenbus_dev_error(dev, err, "creating vbd structure");
159 return;
160 }
161 #endif
163 kobject_hotplug(&dev->dev.kobj, KOBJ_ONLINE);
165 /* Pass in NULL node to skip exist test. */
166 frontend_changed(&be->watch, NULL);
167 }
168 }
170 static int netback_hotplug(struct xenbus_device *xdev, char **envp,
171 int num_envp, char *buffer, int buffer_size)
172 {
173 struct backend_info *be;
174 netif_t *netif;
175 char **key, *val;
176 int i = 0, length = 0;
177 static char *env_vars[] = { "script", "domain", "mac", "bridge", "ip",
178 NULL };
180 be = xdev->data;
181 netif = be->netif;
183 add_hotplug_env_var(envp, num_envp, &i,
184 buffer, buffer_size, &length,
185 "vif=%s", netif->dev->name);
187 key = env_vars;
188 while (*key != NULL) {
189 val = xenbus_read(xdev->nodename, *key, NULL);
190 if (!IS_ERR(val)) {
191 char buf[strlen(*key) + 4];
192 sprintf(buf, "%s=%%s", *key);
193 add_hotplug_env_var(envp, num_envp, &i,
194 buffer, buffer_size, &length,
195 buf, val);
196 kfree(val);
197 }
198 key++;
199 }
201 envp[i] = NULL;
203 return 0;
204 }
206 static int netback_probe(struct xenbus_device *dev,
207 const struct xenbus_device_id *id)
208 {
209 struct backend_info *be;
210 char *frontend;
211 int err;
213 be = kmalloc(sizeof(*be), GFP_KERNEL);
214 if (!be) {
215 xenbus_dev_error(dev, -ENOMEM, "allocating backend structure");
216 return -ENOMEM;
217 }
218 memset(be, 0, sizeof(*be));
220 frontend = NULL;
221 err = xenbus_gather(dev->nodename,
222 "frontend-id", "%li", &be->frontend_id,
223 "frontend", NULL, &frontend,
224 NULL);
225 if (XENBUS_EXIST_ERR(err))
226 goto free_be;
227 if (err < 0) {
228 xenbus_dev_error(dev, err,
229 "reading %s/frontend or frontend-id",
230 dev->nodename);
231 goto free_be;
232 }
233 if (strlen(frontend) == 0 || !xenbus_exists(frontend, "")) {
234 /* If we can't get a frontend path and a frontend-id,
235 * then our bus-id is no longer valid and we need to
236 * destroy the backend device.
237 */
238 err = -ENOENT;
239 goto free_be;
240 }
242 be->dev = dev;
243 be->backend_watch.node = dev->nodename;
244 be->backend_watch.callback = backend_changed;
245 err = register_xenbus_watch(&be->backend_watch);
246 if (err) {
247 be->backend_watch.node = NULL;
248 xenbus_dev_error(dev, err, "adding backend watch on %s",
249 dev->nodename);
250 goto free_be;
251 }
253 be->frontpath = frontend;
254 be->watch.node = be->frontpath;
255 be->watch.callback = frontend_changed;
256 err = register_xenbus_watch(&be->watch);
257 if (err) {
258 be->watch.node = NULL;
259 xenbus_dev_error(dev, err,
260 "adding frontend watch on %s",
261 be->frontpath);
262 goto free_be;
263 }
265 dev->data = be;
267 backend_changed(&be->backend_watch, dev->nodename);
268 return 0;
270 free_be:
271 if (be->backend_watch.node)
272 unregister_xenbus_watch(&be->backend_watch);
273 if (frontend)
274 kfree(frontend);
275 kfree(be);
276 return err;
277 }
279 static struct xenbus_device_id netback_ids[] = {
280 { "vif" },
281 { "" }
282 };
284 static struct xenbus_driver netback = {
285 .name = "vif",
286 .owner = THIS_MODULE,
287 .ids = netback_ids,
288 .probe = netback_probe,
289 .remove = netback_remove,
290 .hotplug = netback_hotplug,
291 };
293 void netif_xenbus_init(void)
294 {
295 xenbus_register_backend(&netback);
296 }