1 /*
2 * Copyright (C) 2014
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_ISREG(st_mode) || S_ISBLK(st_mode) || S_ISCHR(st_mode))
23 return 1;
24
25 return 0;
26 }
27
libxl__devid_to_localdev(libxl__gc * gc,int devid)28 char *libxl__devid_to_localdev(libxl__gc *gc, int devid)
29 {
30 /* This translation table has been copied from the FreeBSD blkfront code. */
31 const static struct vdev_info {
32 int major;
33 int shift;
34 int base;
35 const char *name;
36 } info[] = {
37 {3, 6, 0, "ada"}, /* ide0 */
38 {22, 6, 2, "ada"}, /* ide1 */
39 {33, 6, 4, "ada"}, /* ide2 */
40 {34, 6, 6, "ada"}, /* ide3 */
41 {56, 6, 8, "ada"}, /* ide4 */
42 {57, 6, 10, "ada"}, /* ide5 */
43 {88, 6, 12, "ada"}, /* ide6 */
44 {89, 6, 14, "ada"}, /* ide7 */
45 {90, 6, 16, "ada"}, /* ide8 */
46 {91, 6, 18, "ada"}, /* ide9 */
47
48 {8, 4, 0, "da"}, /* scsi disk0 */
49 {65, 4, 16, "da"}, /* scsi disk1 */
50 {66, 4, 32, "da"}, /* scsi disk2 */
51 {67, 4, 48, "da"}, /* scsi disk3 */
52 {68, 4, 64, "da"}, /* scsi disk4 */
53 {69, 4, 80, "da"}, /* scsi disk5 */
54 {70, 4, 96, "da"}, /* scsi disk6 */
55 {71, 4, 112, "da"}, /* scsi disk7 */
56 {128, 4, 128, "da"}, /* scsi disk8 */
57 {129, 4, 144, "da"}, /* scsi disk9 */
58 {130, 4, 160, "da"}, /* scsi disk10 */
59 {131, 4, 176, "da"}, /* scsi disk11 */
60 {132, 4, 192, "da"}, /* scsi disk12 */
61 {133, 4, 208, "da"}, /* scsi disk13 */
62 {134, 4, 224, "da"}, /* scsi disk14 */
63 {135, 4, 240, "da"}, /* scsi disk15 */
64
65 {202, 4, 0, "xbd"}, /* xbd */
66
67 {0, 0, 0, NULL},
68 };
69 int major = devid >> 8;
70 int minor = devid & 0xff;
71 int i;
72
73 if (devid & (1 << 28))
74 return GCSPRINTF("%s%d", "xbd", (devid & ((1 << 28) - 1)) >> 8);
75
76 for (i = 0; info[i].major; i++)
77 if (info[i].major == major)
78 return GCSPRINTF("%s%d", info[i].name,
79 info[i].base + (minor >> info[i].shift));
80
81 return GCSPRINTF("%s%d", "xbd", minor >> 4);
82 }
83
84 /* Hotplug scripts caller functions */
libxl__hotplug_env_nic(libxl__gc * gc,libxl__device * dev,char *** env,int num_exec)85 static int libxl__hotplug_env_nic(libxl__gc *gc, libxl__device *dev, char ***env,
86 int num_exec)
87 {
88 int nr = 0;
89 const int arraysize = 5;
90 libxl_nic_type type;
91
92 assert(dev->backend_kind == LIBXL__DEVICE_KIND_VIF);
93
94 /*
95 * On the first pass the PV interface is added to the bridge,
96 * on the second pass the tap interface will also be added.
97 */
98 type = num_exec == 0 ? LIBXL_NIC_TYPE_VIF : LIBXL_NIC_TYPE_VIF_IOEMU;
99
100 GCNEW_ARRAY(*env, arraysize);
101 (*env)[nr++] = "iface_dev";
102 (*env)[nr++] = (char *) libxl__device_nic_devname(gc, dev->domid,
103 dev->devid, type);
104 (*env)[nr++] = "emulated";
105 (*env)[nr++] = type == LIBXL_NIC_TYPE_VIF_IOEMU ? "1" : "0";
106 (*env)[nr++] = NULL;
107 assert(nr == arraysize);
108
109 return 0;
110 }
111
libxl__hotplug_nic(libxl__gc * gc,libxl__device * dev,char *** args,char *** env,libxl__device_action action,int num_exec)112 static int libxl__hotplug_nic(libxl__gc *gc, libxl__device *dev,
113 char ***args, char ***env,
114 libxl__device_action action,
115 int num_exec)
116 {
117 libxl_nic_type nictype;
118 char *be_path = libxl__device_backend_path(gc, dev);
119 char *script;
120 int nr = 0, rc;
121
122 rc = libxl__nic_type(gc, dev, &nictype);
123 if (rc) {
124 LOGD(ERROR, dev->domid, "error when fetching nic type");
125 rc = ERROR_FAIL;
126 goto out;
127 }
128
129 /*
130 * For PV domains only one pass is needed (because there's no emulated
131 * interface). For HVM domains two passes are needed in order to add
132 * both the PV and the tap interfaces to the bridge.
133 */
134 if (nictype == LIBXL_NIC_TYPE_VIF && num_exec != 0) {
135 rc = 0;
136 goto out;
137 }
138
139 rc = libxl__hotplug_env_nic(gc, dev, env, num_exec);
140 if (rc)
141 goto out;
142
143 script = libxl__xs_read(gc, XBT_NULL,
144 GCSPRINTF("%s/%s", be_path, "script"));
145 if (!script) {
146 LOGEVD(ERROR, errno, dev->domid,
147 "unable to read script from %s", be_path);
148 rc = ERROR_FAIL;
149 goto out;
150 }
151
152 const int arraysize = 4;
153 GCNEW_ARRAY(*args, arraysize);
154 (*args)[nr++] = script;
155 (*args)[nr++] = be_path;
156 (*args)[nr++] = (char *) libxl__device_action_to_string(action);
157 (*args)[nr++] = NULL;
158 assert(nr == arraysize);
159 rc = 1;
160
161 out:
162 return rc;
163 }
164
libxl__hotplug_disk(libxl__gc * gc,libxl__device * dev,char *** args,char *** env,libxl__device_action action)165 static int libxl__hotplug_disk(libxl__gc *gc, libxl__device *dev,
166 char ***args, char ***env,
167 libxl__device_action action)
168 {
169 char *be_path = libxl__device_backend_path(gc, dev);
170 char *script;
171 int nr = 0, rc;
172
173 script = libxl__xs_read(gc, XBT_NULL,
174 GCSPRINTF("%s/%s", be_path, "script"));
175 if (!script) {
176 LOGEVD(ERROR, errno, dev->domid,
177 "unable to read script from %s", be_path);
178 rc = ERROR_FAIL;
179 goto out;
180 }
181
182 const int arraysize = 4;
183 GCNEW_ARRAY(*args, arraysize);
184 (*args)[nr++] = script;
185 (*args)[nr++] = be_path;
186 (*args)[nr++] = (char *) libxl__device_action_to_string(action);
187 (*args)[nr++] = NULL;
188 assert(nr == arraysize);
189 rc = 1;
190
191 out:
192 return rc;
193 }
194
libxl__get_hotplug_script_info(libxl__gc * gc,libxl__device * dev,char *** args,char *** env,libxl__device_action action,int num_exec)195 int libxl__get_hotplug_script_info(libxl__gc *gc, libxl__device *dev,
196 char ***args, char ***env,
197 libxl__device_action action,
198 int num_exec)
199 {
200 int rc;
201
202 switch (dev->backend_kind) {
203 case LIBXL__DEVICE_KIND_VIF:
204 /*
205 * If domain has a stubdom we don't have to execute hotplug scripts
206 * for emulated interfaces
207 */
208 if ((num_exec > 1) ||
209 (libxl_get_stubdom_id(CTX, dev->domid) && num_exec)) {
210 rc = 0;
211 goto out;
212 }
213 rc = libxl__hotplug_nic(gc, dev, args, env, action, num_exec);
214 break;
215 case LIBXL__DEVICE_KIND_VBD:
216 if (num_exec != 0) {
217 rc = 0;
218 goto out;
219 }
220 rc = libxl__hotplug_disk(gc, dev, args, env, action);
221 break;
222 default:
223 /* No need to execute any hotplug scripts */
224 rc = 0;
225 break;
226 }
227
228 out:
229 return rc;
230 }
231
libxl__default_device_model(libxl__gc * gc)232 libxl_device_model_version libxl__default_device_model(libxl__gc *gc)
233 {
234 return LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN;
235 }
236
libxl__pci_numdevs(libxl__gc * gc)237 int libxl__pci_numdevs(libxl__gc *gc)
238 {
239 return ERROR_NI;
240 }
241
libxl__pci_topology_init(libxl__gc * gc,physdev_pci_device_t * devs,int num_devs)242 int libxl__pci_topology_init(libxl__gc *gc,
243 physdev_pci_device_t *devs,
244 int num_devs)
245 {
246 return ERROR_NI;
247 }
248
libxl__local_dm_preexec_restrict(libxl__gc * gc)249 int libxl__local_dm_preexec_restrict(libxl__gc *gc)
250 {
251 return 0;
252 }
253