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