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