1 /*
2 * Copyright (C) 2011
3 * Author Roger Pau Monne <roger.pau@entel.upc.edu>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published
7 * by the Free Software Foundation; version 2.1 only. with the special
8 * exception on linking described in file LICENSE.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 */
15
16 #include "libxl_osdeps.h" /* must come before any other headers */
17
18 #include "libxl_internal.h"
19
libxl__try_phy_backend(mode_t st_mode)20 int libxl__try_phy_backend(mode_t st_mode)
21 {
22 if (S_ISBLK(st_mode) || S_ISREG(st_mode)) {
23 return 1;
24 }
25
26 return 0;
27 }
28
libxl__devid_to_localdev(libxl__gc * gc,int devid)29 char *libxl__devid_to_localdev(libxl__gc *gc, int devid)
30 {
31 return libxl__devid_to_vdev(gc, devid);
32 }
33
34 /* Hotplug scripts helpers */
35
get_hotplug_env(libxl__gc * gc,char * script,libxl__device * dev)36 static char **get_hotplug_env(libxl__gc *gc,
37 char *script, libxl__device *dev)
38 {
39 const char *type = libxl__device_kind_to_string(dev->backend_kind);
40 char *be_path = libxl__device_backend_path(gc, dev);
41 char **env;
42 int nr = 0;
43
44 const int arraysize = 15;
45 GCNEW_ARRAY(env, arraysize);
46 env[nr++] = "script";
47 env[nr++] = script;
48 env[nr++] = "XENBUS_TYPE";
49 env[nr++] = (char *) type;
50 env[nr++] = "XENBUS_PATH";
51 env[nr++] = GCSPRINTF("backend/%s/%u/%d", type, dev->domid, dev->devid);
52 env[nr++] = "XENBUS_BASE_PATH";
53 env[nr++] = "backend";
54 if (dev->backend_kind == LIBXL__DEVICE_KIND_VIF) {
55 libxl_nic_type nictype;
56 char *gatewaydev;
57
58 gatewaydev = libxl__xs_read(gc, XBT_NULL,
59 GCSPRINTF("%s/%s", be_path, "gatewaydev"));
60 env[nr++] = "netdev";
61 env[nr++] = gatewaydev ? : "";
62
63 if (libxl__nic_type(gc, dev, &nictype)) {
64 LOGD(ERROR, dev->domid, "unable to get nictype");
65 return NULL;
66 }
67 switch (nictype) {
68 case LIBXL_NIC_TYPE_VIF_IOEMU:
69 env[nr++] = "INTERFACE";
70 env[nr++] = (char *) libxl__device_nic_devname(gc, dev->domid,
71 dev->devid,
72 LIBXL_NIC_TYPE_VIF_IOEMU);
73 /*
74 * We need to fall through because for PV_IOEMU nic types we need
75 * to execute both the vif and the tap hotplug script, and we
76 * don't know which one we are executing in this call, so provide
77 * both env variables.
78 */
79 case LIBXL_NIC_TYPE_VIF:
80 env[nr++] = "vif";
81 env[nr++] = (char *) libxl__device_nic_devname(gc, dev->domid,
82 dev->devid,
83 LIBXL_NIC_TYPE_VIF);
84 break;
85 default:
86 return NULL;
87 }
88 }
89
90 env[nr++] = NULL;
91 assert(nr <= arraysize);
92
93 return env;
94 }
95
96 /* Hotplug scripts caller functions */
97
libxl__hotplug_nic(libxl__gc * gc,libxl__device * dev,char *** args,char *** env,libxl__device_action action,int num_exec)98 static int libxl__hotplug_nic(libxl__gc *gc, libxl__device *dev,
99 char ***args, char ***env,
100 libxl__device_action action, int num_exec)
101 {
102 char *be_path = libxl__device_backend_path(gc, dev);
103 char *script;
104 int nr = 0, rc = 0;
105 libxl_nic_type nictype;
106
107 script = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/%s", be_path,
108 "script"));
109 if (!script) {
110 LOGED(ERROR, dev->domid,
111 "unable to read script from %s", be_path);
112 rc = ERROR_FAIL;
113 goto out;
114 }
115
116 rc = libxl__nic_type(gc, dev, &nictype);
117 if (rc) {
118 LOGD(ERROR, dev->domid, "error when fetching nic type");
119 rc = ERROR_FAIL;
120 goto out;
121 }
122 if (nictype == LIBXL_NIC_TYPE_VIF && num_exec != 0) {
123 rc = 0;
124 goto out;
125 }
126
127 *env = get_hotplug_env(gc, script, dev);
128 if (!*env) {
129 rc = ERROR_FAIL;
130 goto out;
131 }
132
133 const int arraysize = 4;
134 GCNEW_ARRAY(*args, arraysize);
135 (*args)[nr++] = script;
136
137 if (nictype == LIBXL_NIC_TYPE_VIF_IOEMU && num_exec) {
138 (*args)[nr++] = (char *) libxl__device_action_to_string(action);
139 (*args)[nr++] = "type_if=tap";
140 (*args)[nr++] = NULL;
141 } else {
142 (*args)[nr++] = action == LIBXL__DEVICE_ACTION_ADD ? "online" :
143 "offline";
144 (*args)[nr++] = "type_if=vif";
145 (*args)[nr++] = NULL;
146 }
147 assert(nr == arraysize);
148 rc = 1;
149
150 out:
151 return rc;
152 }
153
libxl__hotplug_disk(libxl__gc * gc,libxl__device * dev,char *** args,char *** env,libxl__device_action action)154 static int libxl__hotplug_disk(libxl__gc *gc, libxl__device *dev,
155 char ***args, char ***env,
156 libxl__device_action action)
157 {
158 char *be_path = libxl__device_backend_path(gc, dev);
159 char *script;
160 int nr = 0, rc = 0;
161
162 script = libxl__xs_read(gc, XBT_NULL,
163 GCSPRINTF("%s/%s", be_path, "script"));
164 if (!script) {
165 LOGEVD(ERROR, errno, dev->domid,
166 "unable to read script from %s", be_path);
167 rc = ERROR_FAIL;
168 goto error;
169 }
170
171 *env = get_hotplug_env(gc, script, dev);
172 if (!*env) {
173 LOGD(ERROR, dev->domid, "Failed to get hotplug environment");
174 rc = ERROR_FAIL;
175 goto error;
176 }
177
178 const int arraysize = 3;
179 GCNEW_ARRAY(*args, arraysize);
180 (*args)[nr++] = script;
181 (*args)[nr++] = (char *) libxl__device_action_to_string(action);
182 (*args)[nr++] = NULL;
183 assert(nr == arraysize);
184
185 LOGD(DEBUG, dev->domid, "Args and environment ready");
186 rc = 1;
187
188 error:
189 return rc;
190 }
191
libxl__get_hotplug_script_info(libxl__gc * gc,libxl__device * dev,char *** args,char *** env,libxl__device_action action,int num_exec)192 int libxl__get_hotplug_script_info(libxl__gc *gc, libxl__device *dev,
193 char ***args, char ***env,
194 libxl__device_action action,
195 int num_exec)
196 {
197 int rc;
198
199 switch (dev->backend_kind) {
200 case LIBXL__DEVICE_KIND_VBD:
201 if (num_exec != 0) {
202 LOGD(DEBUG, dev->domid,
203 "num_exec %d, not running hotplug scripts", num_exec);
204 rc = 0;
205 goto out;
206 }
207 rc = libxl__hotplug_disk(gc, dev, args, env, action);
208 break;
209 case LIBXL__DEVICE_KIND_VIF:
210 /*
211 * If domain has a stubdom we don't have to execute hotplug scripts
212 * for emulated interfaces
213 */
214 if ((num_exec > 1) ||
215 (libxl_get_stubdom_id(CTX, dev->domid) && num_exec)) {
216 LOGD(DEBUG, dev->domid,
217 "num_exec %d, not running hotplug scripts", num_exec);
218 rc = 0;
219 goto out;
220 }
221 rc = libxl__hotplug_nic(gc, dev, args, env, action, num_exec);
222 break;
223 default:
224 /* No need to execute any hotplug scripts */
225 LOGD(DEBUG, dev->domid,
226 "backend_kind %d, no need to execute scripts", dev->backend_kind);
227 rc = 0;
228 break;
229 }
230
231 out:
232 return rc;
233 }
234
libxl__default_device_model(libxl__gc * gc)235 libxl_device_model_version libxl__default_device_model(libxl__gc *gc)
236 {
237 return LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN;
238 }
239
libxl__pci_numdevs(libxl__gc * gc)240 int libxl__pci_numdevs(libxl__gc *gc)
241 {
242 DIR *dir;
243 struct dirent *entry;
244 int num_devs = 0;
245
246 dir = opendir("/sys/bus/pci/devices");
247 if (!dir) {
248 LOGE(ERROR, "Cannot open /sys/bus/pci/devices");
249 return ERROR_FAIL;
250 }
251
252 while ((entry = readdir(dir))) {
253 if (entry->d_name[0] == '.')
254 continue;
255 num_devs++;
256 }
257 closedir(dir);
258
259 return num_devs;
260 }
261
libxl__pci_topology_init(libxl__gc * gc,physdev_pci_device_t * devs,int num_devs)262 int libxl__pci_topology_init(libxl__gc *gc,
263 physdev_pci_device_t *devs,
264 int num_devs)
265 {
266
267 DIR *dir;
268 struct dirent *entry;
269 int i, err = 0;
270
271 dir = opendir("/sys/bus/pci/devices");
272 if (!dir) {
273 LOGE(ERROR, "Cannot open /sys/bus/pci/devices");
274 return ERROR_FAIL;
275 }
276
277 i = 0;
278 while ((entry = readdir(dir))) {
279 unsigned int dom, bus, dev, func;
280
281 if (entry->d_name[0] == '.')
282 continue;
283
284 if (i == num_devs) {
285 LOG(ERROR, "Too many devices");
286 err = ERROR_FAIL;
287 errno = -ENOSPC;
288 goto out;
289 }
290
291 if (sscanf(entry->d_name, "%x:%x:%x.%d", &dom, &bus, &dev, &func) < 4) {
292 LOGE(ERROR, "Error processing /sys/bus/pci/devices");
293 err = ERROR_FAIL;
294 goto out;
295 }
296
297 devs[i].seg = dom;
298 devs[i].bus = bus;
299 devs[i].devfn = ((dev & 0x1f) << 3) | (func & 7);
300
301 i++;
302 }
303
304 out:
305 closedir(dir);
306
307 return err;
308 }
309
310 /*
311 * Local variables:
312 * mode: C
313 * c-basic-offset: 4
314 * indent-tabs-mode: nil
315 * End:
316 */
317