1 /*
2 * Copyright (C) 2016 SUSE Linux GmbH
3 * Author Juergen Gross <jgross@suse.com>
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"
17
18 #include "libxl_internal.h"
19
libxl_mac_to_device_nic(libxl_ctx * ctx,uint32_t domid,const char * mac,libxl_device_nic * nic)20 int libxl_mac_to_device_nic(libxl_ctx *ctx, uint32_t domid,
21 const char *mac, libxl_device_nic *nic)
22 {
23 GC_INIT(ctx);
24 libxl_device_nic *nics;
25 int nb, rc, i;
26 libxl_mac mac_n;
27
28 rc = libxl__parse_mac(mac, mac_n);
29 if (rc)
30 return rc;
31
32 nics = libxl__device_list(gc, &libxl__nic_devtype, domid, &nb);
33 if (!nics)
34 return ERROR_FAIL;
35
36 memset(nic, 0, sizeof (libxl_device_nic));
37
38 rc = ERROR_INVAL;
39 for (i = 0; i < nb; ++i) {
40 if (!libxl__compare_macs(&mac_n, &nics[i].mac)) {
41 *nic = nics[i];
42 rc = 0;
43 i++; /* Do not dispose this NIC on exit path */
44 break;
45 }
46 libxl_device_nic_dispose(&nics[i]);
47 }
48
49 for (; i<nb; i++)
50 libxl_device_nic_dispose(&nics[i]);
51
52 free(nics);
53 return rc;
54 }
55
libxl__device_nic_setdefault(libxl__gc * gc,uint32_t domid,libxl_device_nic * nic,bool hotplug)56 static int libxl__device_nic_setdefault(libxl__gc *gc, uint32_t domid,
57 libxl_device_nic *nic, bool hotplug)
58 {
59 int rc;
60
61 if (!nic->mtu)
62 nic->mtu = 1492;
63 if (!nic->model) {
64 nic->model = strdup("rtl8139");
65 if (!nic->model) return ERROR_NOMEM;
66 }
67 if (libxl__mac_is_default(&nic->mac)) {
68 const uint8_t *r;
69 libxl_uuid uuid;
70
71 libxl_uuid_generate(&uuid);
72 r = libxl_uuid_bytearray(&uuid);
73
74 nic->mac[0] = 0x00;
75 nic->mac[1] = 0x16;
76 nic->mac[2] = 0x3e;
77 nic->mac[3] = r[0] & 0x7f;
78 nic->mac[4] = r[1];
79 nic->mac[5] = r[2];
80 }
81 if (!nic->bridge) {
82 nic->bridge = strdup("xenbr0");
83 if (!nic->bridge) return ERROR_NOMEM;
84 }
85 if ( !nic->script && asprintf(&nic->script, "%s/vif-bridge",
86 libxl__xen_script_dir_path()) < 0 )
87 return ERROR_FAIL;
88
89 rc = libxl__resolve_domid(gc, nic->backend_domname, &nic->backend_domid);
90 if (rc < 0) return rc;
91
92 switch (libxl__domain_type(gc, domid)) {
93 case LIBXL_DOMAIN_TYPE_HVM:
94 if (!nic->nictype) {
95 if (hotplug)
96 nic->nictype = LIBXL_NIC_TYPE_VIF;
97 else
98 nic->nictype = LIBXL_NIC_TYPE_VIF_IOEMU;
99 }
100 break;
101 case LIBXL_DOMAIN_TYPE_PVH:
102 case LIBXL_DOMAIN_TYPE_PV:
103 if (nic->nictype == LIBXL_NIC_TYPE_VIF_IOEMU) {
104 LOGD(ERROR, domid,
105 "trying to create PV or PVH guest with an emulated interface");
106 return ERROR_INVAL;
107 }
108 nic->nictype = LIBXL_NIC_TYPE_VIF;
109 break;
110 case LIBXL_DOMAIN_TYPE_INVALID:
111 return ERROR_FAIL;
112 default:
113 abort();
114 }
115
116 return rc;
117 }
118
libxl__update_config_nic(libxl__gc * gc,libxl_device_nic * dst,const libxl_device_nic * src)119 static void libxl__update_config_nic(libxl__gc *gc, libxl_device_nic *dst,
120 const libxl_device_nic *src)
121 {
122 dst->devid = src->devid;
123 dst->nictype = src->nictype;
124 libxl_mac_copy(CTX, &dst->mac, &src->mac);
125 }
126
libxl__set_xenstore_nic(libxl__gc * gc,uint32_t domid,libxl_device_nic * nic,flexarray_t * back,flexarray_t * front,flexarray_t * ro_front)127 static int libxl__set_xenstore_nic(libxl__gc *gc, uint32_t domid,
128 libxl_device_nic *nic,
129 flexarray_t *back, flexarray_t *front,
130 flexarray_t *ro_front)
131 {
132 flexarray_grow(back, 2);
133
134 if (nic->script)
135 flexarray_append_pair(back, "script",
136 libxl__abs_path(gc, nic->script,
137 libxl__xen_script_dir_path()));
138
139 if (nic->ifname) {
140 flexarray_append(back, "vifname");
141 flexarray_append(back, nic->ifname);
142 }
143
144 if (nic->coloft_forwarddev) {
145 flexarray_append(back, "forwarddev");
146 flexarray_append(back, nic->coloft_forwarddev);
147 }
148
149 #define MAYBE_ADD_COLO_ARGS(arg) ({ \
150 if (nic->colo_##arg) { \
151 flexarray_append(back, "colo_"#arg); \
152 flexarray_append(back, nic->colo_##arg); \
153 } \
154 })
155
156 MAYBE_ADD_COLO_ARGS(sock_mirror_id);
157 MAYBE_ADD_COLO_ARGS(sock_mirror_ip);
158 MAYBE_ADD_COLO_ARGS(sock_mirror_port);
159 MAYBE_ADD_COLO_ARGS(sock_compare_pri_in_id);
160 MAYBE_ADD_COLO_ARGS(sock_compare_pri_in_ip);
161 MAYBE_ADD_COLO_ARGS(sock_compare_pri_in_port);
162 MAYBE_ADD_COLO_ARGS(sock_compare_sec_in_id);
163 MAYBE_ADD_COLO_ARGS(sock_compare_sec_in_ip);
164 MAYBE_ADD_COLO_ARGS(sock_compare_sec_in_port);
165 MAYBE_ADD_COLO_ARGS(sock_compare_notify_id);
166 MAYBE_ADD_COLO_ARGS(sock_compare_notify_ip);
167 MAYBE_ADD_COLO_ARGS(sock_compare_notify_port);
168 MAYBE_ADD_COLO_ARGS(sock_redirector0_id);
169 MAYBE_ADD_COLO_ARGS(sock_redirector0_ip);
170 MAYBE_ADD_COLO_ARGS(sock_redirector0_port);
171 MAYBE_ADD_COLO_ARGS(sock_redirector1_id);
172 MAYBE_ADD_COLO_ARGS(sock_redirector1_ip);
173 MAYBE_ADD_COLO_ARGS(sock_redirector1_port);
174 MAYBE_ADD_COLO_ARGS(sock_redirector2_id);
175 MAYBE_ADD_COLO_ARGS(sock_redirector2_ip);
176 MAYBE_ADD_COLO_ARGS(sock_redirector2_port);
177 MAYBE_ADD_COLO_ARGS(filter_mirror_queue);
178 MAYBE_ADD_COLO_ARGS(filter_mirror_outdev);
179 MAYBE_ADD_COLO_ARGS(filter_redirector0_queue);
180 MAYBE_ADD_COLO_ARGS(filter_redirector0_indev);
181 MAYBE_ADD_COLO_ARGS(filter_redirector0_outdev);
182 MAYBE_ADD_COLO_ARGS(filter_redirector1_queue);
183 MAYBE_ADD_COLO_ARGS(filter_redirector1_indev);
184 MAYBE_ADD_COLO_ARGS(filter_redirector1_outdev);
185 MAYBE_ADD_COLO_ARGS(compare_pri_in);
186 MAYBE_ADD_COLO_ARGS(compare_sec_in);
187 MAYBE_ADD_COLO_ARGS(compare_out);
188 MAYBE_ADD_COLO_ARGS(compare_notify_dev);
189
190 MAYBE_ADD_COLO_ARGS(sock_sec_redirector0_id);
191 MAYBE_ADD_COLO_ARGS(sock_sec_redirector0_ip);
192 MAYBE_ADD_COLO_ARGS(sock_sec_redirector0_port);
193 MAYBE_ADD_COLO_ARGS(sock_sec_redirector1_id);
194 MAYBE_ADD_COLO_ARGS(sock_sec_redirector1_ip);
195 MAYBE_ADD_COLO_ARGS(sock_sec_redirector1_port);
196 MAYBE_ADD_COLO_ARGS(filter_sec_redirector0_queue);
197 MAYBE_ADD_COLO_ARGS(filter_sec_redirector0_indev);
198 MAYBE_ADD_COLO_ARGS(filter_sec_redirector0_outdev);
199 MAYBE_ADD_COLO_ARGS(filter_sec_redirector1_queue);
200 MAYBE_ADD_COLO_ARGS(filter_sec_redirector1_indev);
201 MAYBE_ADD_COLO_ARGS(filter_sec_redirector1_outdev);
202 MAYBE_ADD_COLO_ARGS(filter_sec_rewriter0_queue);
203 MAYBE_ADD_COLO_ARGS(checkpoint_host);
204 MAYBE_ADD_COLO_ARGS(checkpoint_port);
205
206 #undef MAYBE_ADD_COLO_ARGS
207
208 flexarray_append(back, "mac");
209 flexarray_append(back,GCSPRINTF(LIBXL_MAC_FMT, LIBXL_MAC_BYTES(nic->mac)));
210 if (nic->ip) {
211 flexarray_append(back, "ip");
212 flexarray_append(back, libxl__strdup(gc, nic->ip));
213 }
214 if (nic->gatewaydev) {
215 flexarray_append(back, "gatewaydev");
216 flexarray_append(back, libxl__strdup(gc, nic->gatewaydev));
217 }
218
219 if (nic->rate_interval_usecs > 0) {
220 flexarray_append(back, "rate");
221 flexarray_append(back, GCSPRINTF("%"PRIu64",%"PRIu32"",
222 nic->rate_bytes_per_interval,
223 nic->rate_interval_usecs));
224 }
225
226 flexarray_append(back, "bridge");
227 flexarray_append(back, libxl__strdup(gc, nic->bridge));
228 flexarray_append(back, "handle");
229 flexarray_append(back, GCSPRINTF("%d", nic->devid));
230 flexarray_append(back, "type");
231 flexarray_append(back, libxl__strdup(gc,
232 libxl_nic_type_to_string(nic->nictype)));
233
234 flexarray_append(front, "handle");
235 flexarray_append(front, GCSPRINTF("%d", nic->devid));
236 flexarray_append(front, "mac");
237 flexarray_append(front, GCSPRINTF(
238 LIBXL_MAC_FMT, LIBXL_MAC_BYTES(nic->mac)));
239
240 return 0;
241 }
242
libxl__device_nic_add(libxl__egc * egc,uint32_t domid,libxl_device_nic * nic,libxl__ao_device * aodev)243 static void libxl__device_nic_add(libxl__egc *egc, uint32_t domid,
244 libxl_device_nic *nic,
245 libxl__ao_device *aodev)
246 {
247 libxl__device_add_async(egc, domid, &libxl__nic_devtype, nic, aodev);
248 }
249
libxl__nic_from_xenstore(libxl__gc * gc,const char * libxl_path,libxl_devid devid,libxl_device_nic * nic)250 static int libxl__nic_from_xenstore(libxl__gc *gc, const char *libxl_path,
251 libxl_devid devid, libxl_device_nic *nic)
252 {
253 const char *tmp;
254 int rc;
255
256 libxl_device_nic_init(nic);
257
258 rc = libxl__xs_read_checked(gc, XBT_NULL,
259 GCSPRINTF("%s/handle", libxl_path), &tmp);
260 if (rc) goto out;
261 if (tmp)
262 nic->devid = atoi(tmp);
263 else
264 nic->devid = 0;
265
266 rc = libxl__xs_read_checked(gc, XBT_NULL,
267 GCSPRINTF("%s/backend", libxl_path), &tmp);
268 if (rc) goto out;
269
270 if (!tmp) {
271 LOG(ERROR, "nic %s does not exist (no backend path)", libxl_path);
272 rc = ERROR_FAIL;
273 goto out;
274 }
275 rc = libxl__backendpath_parse_domid(gc, tmp, &nic->backend_domid);
276 if (rc) goto out;
277
278 /* nic->mtu = */
279
280 rc = libxl__xs_read_checked(gc, XBT_NULL,
281 GCSPRINTF("%s/mac", libxl_path), &tmp);
282 if (rc) goto out;
283 if (tmp) {
284 rc = libxl__parse_mac(tmp, nic->mac);
285 if (rc) goto out;
286 } else {
287 memset(nic->mac, 0, sizeof(nic->mac));
288 }
289
290 rc = libxl__xs_read_checked(NOGC, XBT_NULL,
291 GCSPRINTF("%s/ip", libxl_path),
292 (const char **)(&nic->ip));
293 if (rc) goto out;
294 rc = libxl__xs_read_checked(NOGC, XBT_NULL,
295 GCSPRINTF("%s/bridge", libxl_path),
296 (const char **)(&nic->bridge));
297 if (rc) goto out;
298 rc = libxl__xs_read_checked(NOGC, XBT_NULL,
299 GCSPRINTF("%s/script", libxl_path),
300 (const char **)(&nic->script));
301 if (rc) goto out;
302 rc = libxl__xs_read_checked(NOGC, XBT_NULL,
303 GCSPRINTF("%s/forwarddev", libxl_path),
304 (const char **)(&nic->coloft_forwarddev));
305 if (rc) goto out;
306
307 #define CHECK_COLO_ARGS(arg) ({ \
308 rc = libxl__xs_read_checked(NOGC, XBT_NULL, \
309 GCSPRINTF("%s/colo_"#arg, libxl_path), \
310 (const char **)(&nic->colo_##arg)); \
311 if (rc) goto out; \
312 })
313
314 CHECK_COLO_ARGS(sock_mirror_id);
315 CHECK_COLO_ARGS(sock_mirror_ip);
316 CHECK_COLO_ARGS(sock_mirror_port);
317 CHECK_COLO_ARGS(sock_compare_pri_in_id);
318 CHECK_COLO_ARGS(sock_compare_pri_in_ip);
319 CHECK_COLO_ARGS(sock_compare_pri_in_port);
320 CHECK_COLO_ARGS(sock_compare_sec_in_id);
321 CHECK_COLO_ARGS(sock_compare_sec_in_ip);
322 CHECK_COLO_ARGS(sock_compare_sec_in_port);
323 CHECK_COLO_ARGS(sock_compare_notify_id);
324 CHECK_COLO_ARGS(sock_compare_notify_ip);
325 CHECK_COLO_ARGS(sock_compare_notify_port);
326 CHECK_COLO_ARGS(sock_redirector0_id);
327 CHECK_COLO_ARGS(sock_redirector0_ip);
328 CHECK_COLO_ARGS(sock_redirector0_port);
329 CHECK_COLO_ARGS(sock_redirector1_id);
330 CHECK_COLO_ARGS(sock_redirector1_ip);
331 CHECK_COLO_ARGS(sock_redirector1_port);
332 CHECK_COLO_ARGS(sock_redirector2_id);
333 CHECK_COLO_ARGS(sock_redirector2_ip);
334 CHECK_COLO_ARGS(sock_redirector2_port);
335 CHECK_COLO_ARGS(filter_mirror_queue);
336 CHECK_COLO_ARGS(filter_mirror_outdev);
337 CHECK_COLO_ARGS(filter_redirector0_queue);
338 CHECK_COLO_ARGS(filter_redirector0_indev);
339 CHECK_COLO_ARGS(filter_redirector0_outdev);
340 CHECK_COLO_ARGS(filter_redirector1_queue);
341 CHECK_COLO_ARGS(filter_redirector1_indev);
342 CHECK_COLO_ARGS(filter_redirector1_outdev);
343 CHECK_COLO_ARGS(compare_pri_in);
344 CHECK_COLO_ARGS(compare_sec_in);
345 CHECK_COLO_ARGS(compare_out);
346 CHECK_COLO_ARGS(compare_notify_dev);
347 CHECK_COLO_ARGS(sock_sec_redirector0_id);
348 CHECK_COLO_ARGS(sock_sec_redirector0_ip);
349 CHECK_COLO_ARGS(sock_sec_redirector0_port);
350 CHECK_COLO_ARGS(sock_sec_redirector1_id);
351 CHECK_COLO_ARGS(sock_sec_redirector1_ip);
352 CHECK_COLO_ARGS(sock_sec_redirector1_port);
353 CHECK_COLO_ARGS(filter_sec_redirector0_queue);
354 CHECK_COLO_ARGS(filter_sec_redirector0_indev);
355 CHECK_COLO_ARGS(filter_sec_redirector0_outdev);
356 CHECK_COLO_ARGS(filter_sec_redirector1_queue);
357 CHECK_COLO_ARGS(filter_sec_redirector1_indev);
358 CHECK_COLO_ARGS(filter_sec_redirector1_outdev);
359 CHECK_COLO_ARGS(filter_sec_rewriter0_queue);
360 CHECK_COLO_ARGS(checkpoint_host);
361 CHECK_COLO_ARGS(checkpoint_port);
362
363 #undef CHECK_COLO_ARGS
364
365 /* vif_ioemu nics use the same xenstore entries as vif interfaces */
366 rc = libxl__xs_read_checked(gc, XBT_NULL,
367 GCSPRINTF("%s/type", libxl_path), &tmp);
368 if (rc) goto out;
369 if (tmp) {
370 rc = libxl_nic_type_from_string(tmp, &nic->nictype);
371 if (rc) goto out;
372 } else {
373 nic->nictype = LIBXL_NIC_TYPE_VIF;
374 }
375 nic->model = NULL; /* XXX Only for TYPE_IOEMU */
376 nic->ifname = NULL; /* XXX Only for TYPE_IOEMU */
377
378 rc = 0;
379 out:
380 return rc;
381 }
382
libxl_device_nic_list(libxl_ctx * ctx,uint32_t domid,int * num)383 libxl_device_nic *libxl_device_nic_list(libxl_ctx *ctx, uint32_t domid, int *num)
384 {
385 libxl_device_nic *r;
386
387 GC_INIT(ctx);
388
389 r = libxl__device_list(gc, &libxl__nic_devtype, domid, num);
390
391 GC_FREE;
392
393 return r;
394 }
395
libxl_device_nic_list_free(libxl_device_nic * list,int num)396 void libxl_device_nic_list_free(libxl_device_nic* list, int num)
397 {
398 libxl__device_list_free(&libxl__nic_devtype, list, num);
399 }
400
libxl_device_nic_getinfo(libxl_ctx * ctx,uint32_t domid,const libxl_device_nic * nic,libxl_nicinfo * nicinfo)401 int libxl_device_nic_getinfo(libxl_ctx *ctx, uint32_t domid,
402 const libxl_device_nic *nic,
403 libxl_nicinfo *nicinfo)
404 {
405 GC_INIT(ctx);
406 char *nicpath, *libxl_path;
407 char *val;
408 int rc;
409
410 nicinfo->devid = nic->devid;
411
412 nicpath = libxl__domain_device_frontend_path(gc, domid, nicinfo->devid,
413 LIBXL__DEVICE_KIND_VIF);
414 libxl_path = libxl__domain_device_libxl_path(gc, domid, nicinfo->devid,
415 LIBXL__DEVICE_KIND_VIF);
416 nicinfo->backend = xs_read(ctx->xsh, XBT_NULL,
417 GCSPRINTF("%s/backend", libxl_path), NULL);
418 if (!nicinfo->backend) {
419 GC_FREE;
420 return ERROR_FAIL;
421 }
422 rc = libxl__backendpath_parse_domid(gc, nicinfo->backend,
423 &nicinfo->backend_id);
424 if (rc) goto out;
425
426 val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/state", nicpath));
427 nicinfo->state = val ? strtoul(val, NULL, 10) : -1;
428 val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/event-channel", nicpath));
429 nicinfo->evtch = val ? strtoul(val, NULL, 10) : -1;
430 val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/tx-ring-ref", nicpath));
431 nicinfo->rref_tx = val ? strtoul(val, NULL, 10) : -1;
432 val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/rx-ring-ref", nicpath));
433 nicinfo->rref_rx = val ? strtoul(val, NULL, 10) : -1;
434 nicinfo->frontend = libxl__strdup(NOGC, nicpath);
435 nicinfo->frontend_id = domid;
436
437 rc = 0;
438 out:
439 GC_FREE;
440 return rc;
441 }
442
libxl__device_nic_devname(libxl__gc * gc,uint32_t domid,uint32_t devid,libxl_nic_type type)443 const char *libxl__device_nic_devname(libxl__gc *gc,
444 uint32_t domid,
445 uint32_t devid,
446 libxl_nic_type type)
447 {
448 switch (type) {
449 case LIBXL_NIC_TYPE_VIF:
450 return GCSPRINTF(NETBACK_NIC_NAME, domid, devid);
451 case LIBXL_NIC_TYPE_VIF_IOEMU:
452 return GCSPRINTF(NETBACK_NIC_NAME TAP_DEVICE_SUFFIX, domid, devid);
453 default:
454 abort();
455 }
456 }
457
libxl_device_nic_compare(const libxl_device_nic * d1,const libxl_device_nic * d2)458 static int libxl_device_nic_compare(const libxl_device_nic *d1,
459 const libxl_device_nic *d2)
460 {
461 return COMPARE_DEVID(d1, d2);
462 }
463
libxl_device_nic_update_config(libxl__gc * gc,void * d,void * s)464 static void libxl_device_nic_update_config(libxl__gc *gc, void *d, void *s)
465 {
466 libxl__update_config_nic(gc, d, s);
467 }
468
libxl__device_nic_set_devids(libxl__gc * gc,libxl_domain_config * d_config,uint32_t domid)469 int libxl__device_nic_set_devids(libxl__gc *gc, libxl_domain_config *d_config,
470 uint32_t domid)
471 {
472 int ret = 0;
473 int i;
474 size_t last_devid = -1;
475
476 for (i = 0; i < d_config->num_nics; i++) {
477 /* We have to init the nic here, because we still haven't
478 * called libxl_device_nic_add when domcreate_launch_dm gets called,
479 * but qemu needs the nic information to be complete.
480 */
481 ret = libxl__device_nic_setdefault(gc, domid, &d_config->nics[i],
482 false);
483 if (ret) {
484 LOGD(ERROR, domid, "Unable to set nic defaults for nic %d", i);
485 goto out;
486 }
487
488 if (d_config->nics[i].devid > last_devid)
489 last_devid = d_config->nics[i].devid;
490 }
491 for (i = 0; i < d_config->num_nics; i++) {
492 if (d_config->nics[i].devid < 0)
493 d_config->nics[i].devid = ++last_devid;
494 }
495
496 out:
497 return ret;
498 }
499
500 static LIBXL_DEFINE_UPDATE_DEVID(nic)
501 static LIBXL_DEFINE_DEVICE_FROM_TYPE(nic)
502
503 LIBXL_DEFINE_DEVID_TO_DEVICE(nic)
504 LIBXL_DEFINE_DEVICE_ADD(nic)
505 LIBXL_DEFINE_DEVICES_ADD(nic)
506 LIBXL_DEFINE_DEVICE_REMOVE(nic)
507
508 DEFINE_DEVICE_TYPE_STRUCT(nic, VIF,
509 .update_config = libxl_device_nic_update_config,
510 .from_xenstore = (device_from_xenstore_fn_t)libxl__nic_from_xenstore,
511 .set_xenstore_config = (device_set_xenstore_config_fn_t)
512 libxl__set_xenstore_nic,
513 );
514
515 /*
516 * Local variables:
517 * mode: C
518 * c-basic-offset: 4
519 * indent-tabs-mode: nil
520 * End:
521 */
522