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__device_from_nic(libxl__gc * gc,uint32_t domid,libxl_device_nic * nic,libxl__device * device)119 static int libxl__device_from_nic(libxl__gc *gc, uint32_t domid,
120                                   libxl_device_nic *nic,
121                                   libxl__device *device)
122 {
123     device->backend_devid    = nic->devid;
124     device->backend_domid    = nic->backend_domid;
125     device->backend_kind     = LIBXL__DEVICE_KIND_VIF;
126     device->devid            = nic->devid;
127     device->domid            = domid;
128     device->kind             = LIBXL__DEVICE_KIND_VIF;
129 
130     return 0;
131 }
132 
libxl__update_config_nic(libxl__gc * gc,libxl_device_nic * dst,const libxl_device_nic * src)133 static void libxl__update_config_nic(libxl__gc *gc, libxl_device_nic *dst,
134                                      const libxl_device_nic *src)
135 {
136     dst->devid = src->devid;
137     dst->nictype = src->nictype;
138     libxl_mac_copy(CTX, &dst->mac, &src->mac);
139 }
140 
141 static LIBXL_DEFINE_UPDATE_DEVID(nic, "vif")
142 
libxl__set_xenstore_nic(libxl__gc * gc,uint32_t domid,libxl_device_nic * nic,flexarray_t * back,flexarray_t * front,flexarray_t * ro_front)143 static int libxl__set_xenstore_nic(libxl__gc *gc, uint32_t domid,
144                                    libxl_device_nic *nic,
145                                    flexarray_t *back, flexarray_t *front,
146                                    flexarray_t *ro_front)
147 {
148     flexarray_grow(back, 2);
149 
150     if (nic->script)
151         flexarray_append_pair(back, "script",
152                               libxl__abs_path(gc, nic->script,
153                                               libxl__xen_script_dir_path()));
154 
155     if (nic->ifname) {
156         flexarray_append(back, "vifname");
157         flexarray_append(back, nic->ifname);
158     }
159 
160     if (nic->coloft_forwarddev) {
161         flexarray_append(back, "forwarddev");
162         flexarray_append(back, nic->coloft_forwarddev);
163     }
164 
165 #define MAYBE_ADD_COLO_ARGS(arg) ({                                       \
166     if (nic->colo_##arg) {                                                \
167         flexarray_append(back, "colo_"#arg);                              \
168         flexarray_append(back, nic->colo_##arg);                          \
169     }                                                                     \
170 })
171 
172     MAYBE_ADD_COLO_ARGS(sock_mirror_id);
173     MAYBE_ADD_COLO_ARGS(sock_mirror_ip);
174     MAYBE_ADD_COLO_ARGS(sock_mirror_port);
175     MAYBE_ADD_COLO_ARGS(sock_compare_pri_in_id);
176     MAYBE_ADD_COLO_ARGS(sock_compare_pri_in_ip);
177     MAYBE_ADD_COLO_ARGS(sock_compare_pri_in_port);
178     MAYBE_ADD_COLO_ARGS(sock_compare_sec_in_id);
179     MAYBE_ADD_COLO_ARGS(sock_compare_sec_in_ip);
180     MAYBE_ADD_COLO_ARGS(sock_compare_sec_in_port);
181     MAYBE_ADD_COLO_ARGS(sock_compare_notify_id);
182     MAYBE_ADD_COLO_ARGS(sock_compare_notify_ip);
183     MAYBE_ADD_COLO_ARGS(sock_compare_notify_port);
184     MAYBE_ADD_COLO_ARGS(sock_redirector0_id);
185     MAYBE_ADD_COLO_ARGS(sock_redirector0_ip);
186     MAYBE_ADD_COLO_ARGS(sock_redirector0_port);
187     MAYBE_ADD_COLO_ARGS(sock_redirector1_id);
188     MAYBE_ADD_COLO_ARGS(sock_redirector1_ip);
189     MAYBE_ADD_COLO_ARGS(sock_redirector1_port);
190     MAYBE_ADD_COLO_ARGS(sock_redirector2_id);
191     MAYBE_ADD_COLO_ARGS(sock_redirector2_ip);
192     MAYBE_ADD_COLO_ARGS(sock_redirector2_port);
193     MAYBE_ADD_COLO_ARGS(filter_mirror_queue);
194     MAYBE_ADD_COLO_ARGS(filter_mirror_outdev);
195     MAYBE_ADD_COLO_ARGS(filter_redirector0_queue);
196     MAYBE_ADD_COLO_ARGS(filter_redirector0_indev);
197     MAYBE_ADD_COLO_ARGS(filter_redirector0_outdev);
198     MAYBE_ADD_COLO_ARGS(filter_redirector1_queue);
199     MAYBE_ADD_COLO_ARGS(filter_redirector1_indev);
200     MAYBE_ADD_COLO_ARGS(filter_redirector1_outdev);
201     MAYBE_ADD_COLO_ARGS(compare_pri_in);
202     MAYBE_ADD_COLO_ARGS(compare_sec_in);
203     MAYBE_ADD_COLO_ARGS(compare_out);
204     MAYBE_ADD_COLO_ARGS(compare_notify_dev);
205 
206     MAYBE_ADD_COLO_ARGS(sock_sec_redirector0_id);
207     MAYBE_ADD_COLO_ARGS(sock_sec_redirector0_ip);
208     MAYBE_ADD_COLO_ARGS(sock_sec_redirector0_port);
209     MAYBE_ADD_COLO_ARGS(sock_sec_redirector1_id);
210     MAYBE_ADD_COLO_ARGS(sock_sec_redirector1_ip);
211     MAYBE_ADD_COLO_ARGS(sock_sec_redirector1_port);
212     MAYBE_ADD_COLO_ARGS(filter_sec_redirector0_queue);
213     MAYBE_ADD_COLO_ARGS(filter_sec_redirector0_indev);
214     MAYBE_ADD_COLO_ARGS(filter_sec_redirector0_outdev);
215     MAYBE_ADD_COLO_ARGS(filter_sec_redirector1_queue);
216     MAYBE_ADD_COLO_ARGS(filter_sec_redirector1_indev);
217     MAYBE_ADD_COLO_ARGS(filter_sec_redirector1_outdev);
218     MAYBE_ADD_COLO_ARGS(filter_sec_rewriter0_queue);
219     MAYBE_ADD_COLO_ARGS(checkpoint_host);
220     MAYBE_ADD_COLO_ARGS(checkpoint_port);
221 
222 #undef MAYBE_ADD_COLO_ARGS
223 
224     flexarray_append(back, "mac");
225     flexarray_append(back,GCSPRINTF(LIBXL_MAC_FMT, LIBXL_MAC_BYTES(nic->mac)));
226     if (nic->ip) {
227         flexarray_append(back, "ip");
228         flexarray_append(back, libxl__strdup(gc, nic->ip));
229     }
230     if (nic->gatewaydev) {
231         flexarray_append(back, "gatewaydev");
232         flexarray_append(back, libxl__strdup(gc, nic->gatewaydev));
233     }
234 
235     if (nic->rate_interval_usecs > 0) {
236         flexarray_append(back, "rate");
237         flexarray_append(back, GCSPRINTF("%"PRIu64",%"PRIu32"",
238                             nic->rate_bytes_per_interval,
239                             nic->rate_interval_usecs));
240     }
241 
242     flexarray_append(back, "bridge");
243     flexarray_append(back, libxl__strdup(gc, nic->bridge));
244     flexarray_append(back, "handle");
245     flexarray_append(back, GCSPRINTF("%d", nic->devid));
246     flexarray_append(back, "type");
247     flexarray_append(back, libxl__strdup(gc,
248                                      libxl_nic_type_to_string(nic->nictype)));
249 
250     flexarray_append(front, "handle");
251     flexarray_append(front, GCSPRINTF("%d", nic->devid));
252     flexarray_append(front, "mac");
253     flexarray_append(front, GCSPRINTF(
254                                     LIBXL_MAC_FMT, LIBXL_MAC_BYTES(nic->mac)));
255 
256     return 0;
257 }
258 
libxl__device_nic_add(libxl__egc * egc,uint32_t domid,libxl_device_nic * nic,libxl__ao_device * aodev)259 static void libxl__device_nic_add(libxl__egc *egc, uint32_t domid,
260                                   libxl_device_nic *nic,
261                                   libxl__ao_device *aodev)
262 {
263     libxl__device_add_async(egc, domid, &libxl__nic_devtype, nic, aodev);
264 }
265 
libxl__nic_from_xenstore(libxl__gc * gc,const char * libxl_path,libxl_devid devid,libxl_device_nic * nic)266 static int libxl__nic_from_xenstore(libxl__gc *gc, const char *libxl_path,
267                                     libxl_devid devid, libxl_device_nic *nic)
268 {
269     const char *tmp;
270     int rc;
271 
272     libxl_device_nic_init(nic);
273 
274     rc = libxl__xs_read_checked(gc, XBT_NULL,
275                                 GCSPRINTF("%s/handle", libxl_path), &tmp);
276     if (rc) goto out;
277     if (tmp)
278         nic->devid = atoi(tmp);
279     else
280         nic->devid = 0;
281 
282     rc = libxl__xs_read_checked(gc, XBT_NULL,
283                                 GCSPRINTF("%s/backend", libxl_path), &tmp);
284     if (rc) goto out;
285 
286     if (!tmp) {
287         LOG(ERROR, "nic %s does not exist (no backend path)", libxl_path);
288         rc = ERROR_FAIL;
289         goto out;
290     }
291     rc = libxl__backendpath_parse_domid(gc, tmp, &nic->backend_domid);
292     if (rc) goto out;
293 
294     /* nic->mtu = */
295 
296     rc = libxl__xs_read_checked(gc, XBT_NULL,
297                                 GCSPRINTF("%s/mac", libxl_path), &tmp);
298     if (rc) goto out;
299     if (tmp) {
300         rc = libxl__parse_mac(tmp, nic->mac);
301         if (rc) goto out;
302     } else {
303         memset(nic->mac, 0, sizeof(nic->mac));
304     }
305 
306     rc = libxl__xs_read_checked(NOGC, XBT_NULL,
307                                 GCSPRINTF("%s/ip", libxl_path),
308                                 (const char **)(&nic->ip));
309     if (rc) goto out;
310     rc = libxl__xs_read_checked(NOGC, XBT_NULL,
311                                 GCSPRINTF("%s/bridge", libxl_path),
312                                 (const char **)(&nic->bridge));
313     if (rc) goto out;
314     rc = libxl__xs_read_checked(NOGC, XBT_NULL,
315                                 GCSPRINTF("%s/script", libxl_path),
316                                 (const char **)(&nic->script));
317     if (rc) goto out;
318     rc = libxl__xs_read_checked(NOGC, XBT_NULL,
319                                 GCSPRINTF("%s/forwarddev", libxl_path),
320                                 (const char **)(&nic->coloft_forwarddev));
321     if (rc) goto out;
322 
323 #define CHECK_COLO_ARGS(arg) ({                                           \
324     rc = libxl__xs_read_checked(NOGC, XBT_NULL,                           \
325                                 GCSPRINTF("%s/colo_"#arg, libxl_path),    \
326                                 (const char **)(&nic->colo_##arg));       \
327     if (rc) goto out;                                                     \
328 })
329 
330     CHECK_COLO_ARGS(sock_mirror_id);
331     CHECK_COLO_ARGS(sock_mirror_ip);
332     CHECK_COLO_ARGS(sock_mirror_port);
333     CHECK_COLO_ARGS(sock_compare_pri_in_id);
334     CHECK_COLO_ARGS(sock_compare_pri_in_ip);
335     CHECK_COLO_ARGS(sock_compare_pri_in_port);
336     CHECK_COLO_ARGS(sock_compare_sec_in_id);
337     CHECK_COLO_ARGS(sock_compare_sec_in_ip);
338     CHECK_COLO_ARGS(sock_compare_sec_in_port);
339     CHECK_COLO_ARGS(sock_compare_notify_id);
340     CHECK_COLO_ARGS(sock_compare_notify_ip);
341     CHECK_COLO_ARGS(sock_compare_notify_port);
342     CHECK_COLO_ARGS(sock_redirector0_id);
343     CHECK_COLO_ARGS(sock_redirector0_ip);
344     CHECK_COLO_ARGS(sock_redirector0_port);
345     CHECK_COLO_ARGS(sock_redirector1_id);
346     CHECK_COLO_ARGS(sock_redirector1_ip);
347     CHECK_COLO_ARGS(sock_redirector1_port);
348     CHECK_COLO_ARGS(sock_redirector2_id);
349     CHECK_COLO_ARGS(sock_redirector2_ip);
350     CHECK_COLO_ARGS(sock_redirector2_port);
351     CHECK_COLO_ARGS(filter_mirror_queue);
352     CHECK_COLO_ARGS(filter_mirror_outdev);
353     CHECK_COLO_ARGS(filter_redirector0_queue);
354     CHECK_COLO_ARGS(filter_redirector0_indev);
355     CHECK_COLO_ARGS(filter_redirector0_outdev);
356     CHECK_COLO_ARGS(filter_redirector1_queue);
357     CHECK_COLO_ARGS(filter_redirector1_indev);
358     CHECK_COLO_ARGS(filter_redirector1_outdev);
359     CHECK_COLO_ARGS(compare_pri_in);
360     CHECK_COLO_ARGS(compare_sec_in);
361     CHECK_COLO_ARGS(compare_out);
362     CHECK_COLO_ARGS(compare_notify_dev);
363     CHECK_COLO_ARGS(sock_sec_redirector0_id);
364     CHECK_COLO_ARGS(sock_sec_redirector0_ip);
365     CHECK_COLO_ARGS(sock_sec_redirector0_port);
366     CHECK_COLO_ARGS(sock_sec_redirector1_id);
367     CHECK_COLO_ARGS(sock_sec_redirector1_ip);
368     CHECK_COLO_ARGS(sock_sec_redirector1_port);
369     CHECK_COLO_ARGS(filter_sec_redirector0_queue);
370     CHECK_COLO_ARGS(filter_sec_redirector0_indev);
371     CHECK_COLO_ARGS(filter_sec_redirector0_outdev);
372     CHECK_COLO_ARGS(filter_sec_redirector1_queue);
373     CHECK_COLO_ARGS(filter_sec_redirector1_indev);
374     CHECK_COLO_ARGS(filter_sec_redirector1_outdev);
375     CHECK_COLO_ARGS(filter_sec_rewriter0_queue);
376     CHECK_COLO_ARGS(checkpoint_host);
377     CHECK_COLO_ARGS(checkpoint_port);
378 
379 #undef CHECK_COLO_ARGS
380 
381     /* vif_ioemu nics use the same xenstore entries as vif interfaces */
382     rc = libxl__xs_read_checked(gc, XBT_NULL,
383                                 GCSPRINTF("%s/type", libxl_path), &tmp);
384     if (rc) goto out;
385     if (tmp) {
386         rc = libxl_nic_type_from_string(tmp, &nic->nictype);
387         if (rc) goto out;
388     } else {
389         nic->nictype = LIBXL_NIC_TYPE_VIF;
390     }
391     nic->model = NULL; /* XXX Only for TYPE_IOEMU */
392     nic->ifname = NULL; /* XXX Only for TYPE_IOEMU */
393 
394     rc = 0;
395  out:
396     return rc;
397 }
398 
libxl_devid_to_device_nic(libxl_ctx * ctx,uint32_t domid,int devid,libxl_device_nic * nic)399 int libxl_devid_to_device_nic(libxl_ctx *ctx, uint32_t domid,
400                               int devid, libxl_device_nic *nic)
401 {
402     GC_INIT(ctx);
403     char *libxl_dom_path, *libxl_path;
404     int rc = ERROR_FAIL;
405 
406     libxl_device_nic_init(nic);
407     libxl_dom_path = libxl__xs_libxl_path(gc, domid);
408     if (!libxl_dom_path)
409         goto out;
410 
411     libxl_path = GCSPRINTF("%s/device/vif/%d", libxl_dom_path, devid);
412 
413     rc = libxl__nic_from_xenstore(gc, libxl_path, devid, nic);
414     if (rc) goto out;
415 
416     rc = 0;
417 out:
418     GC_FREE;
419     return rc;
420 }
421 
libxl_device_nic_list(libxl_ctx * ctx,uint32_t domid,int * num)422 libxl_device_nic *libxl_device_nic_list(libxl_ctx *ctx, uint32_t domid, int *num)
423 {
424     libxl_device_nic *r;
425 
426     GC_INIT(ctx);
427 
428     r = libxl__device_list(gc, &libxl__nic_devtype, domid, num);
429 
430     GC_FREE;
431 
432     return r;
433 }
434 
libxl_device_nic_list_free(libxl_device_nic * list,int num)435 void libxl_device_nic_list_free(libxl_device_nic* list, int num)
436 {
437     libxl__device_list_free(&libxl__nic_devtype, list, num);
438 }
439 
libxl_device_nic_getinfo(libxl_ctx * ctx,uint32_t domid,libxl_device_nic * nic,libxl_nicinfo * nicinfo)440 int libxl_device_nic_getinfo(libxl_ctx *ctx, uint32_t domid,
441                               libxl_device_nic *nic, libxl_nicinfo *nicinfo)
442 {
443     GC_INIT(ctx);
444     char *dompath, *nicpath, *libxl_path;
445     char *val;
446     int rc;
447 
448     dompath = libxl__xs_get_dompath(gc, domid);
449     nicinfo->devid = nic->devid;
450 
451     nicpath = GCSPRINTF("%s/device/vif/%d", dompath, nicinfo->devid);
452     libxl_path = GCSPRINTF("%s/device/vif/%d",
453                            libxl__xs_libxl_path(gc, domid), nicinfo->devid);
454     nicinfo->backend = xs_read(ctx->xsh, XBT_NULL,
455                                 GCSPRINTF("%s/backend", libxl_path), NULL);
456     if (!nicinfo->backend) {
457         GC_FREE;
458         return ERROR_FAIL;
459     }
460     rc = libxl__backendpath_parse_domid(gc, nicinfo->backend,
461                                         &nicinfo->backend_id);
462     if (rc) goto out;
463 
464     val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/state", nicpath));
465     nicinfo->state = val ? strtoul(val, NULL, 10) : -1;
466     val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/event-channel", nicpath));
467     nicinfo->evtch = val ? strtoul(val, NULL, 10) : -1;
468     val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/tx-ring-ref", nicpath));
469     nicinfo->rref_tx = val ? strtoul(val, NULL, 10) : -1;
470     val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/rx-ring-ref", nicpath));
471     nicinfo->rref_rx = val ? strtoul(val, NULL, 10) : -1;
472     nicinfo->frontend = libxl__strdup(NOGC, nicpath);
473     nicinfo->frontend_id = domid;
474 
475     rc = 0;
476  out:
477     GC_FREE;
478     return rc;
479 }
480 
libxl__device_nic_devname(libxl__gc * gc,uint32_t domid,uint32_t devid,libxl_nic_type type)481 const char *libxl__device_nic_devname(libxl__gc *gc,
482                                       uint32_t domid,
483                                       uint32_t devid,
484                                       libxl_nic_type type)
485 {
486     switch (type) {
487     case LIBXL_NIC_TYPE_VIF:
488         return GCSPRINTF(NETBACK_NIC_NAME, domid, devid);
489     case LIBXL_NIC_TYPE_VIF_IOEMU:
490         return GCSPRINTF(NETBACK_NIC_NAME TAP_DEVICE_SUFFIX, domid, devid);
491     default:
492         abort();
493     }
494 }
495 
libxl_device_nic_compare(libxl_device_nic * d1,libxl_device_nic * d2)496 static int libxl_device_nic_compare(libxl_device_nic *d1,
497                                     libxl_device_nic *d2)
498 {
499     return COMPARE_DEVID(d1, d2);
500 }
501 
libxl_device_nic_update_config(libxl__gc * gc,void * d,void * s)502 static void libxl_device_nic_update_config(libxl__gc *gc, void *d, void *s)
503 {
504     libxl__update_config_nic(gc, d, s);
505 }
506 
libxl__device_nic_set_devids(libxl__gc * gc,libxl_domain_config * d_config,uint32_t domid)507 int libxl__device_nic_set_devids(libxl__gc *gc, libxl_domain_config *d_config,
508                                  uint32_t domid)
509 {
510     int ret = 0;
511     int i;
512     size_t last_devid = -1;
513 
514     for (i = 0; i < d_config->num_nics; i++) {
515         /* We have to init the nic here, because we still haven't
516          * called libxl_device_nic_add when domcreate_launch_dm gets called,
517          * but qemu needs the nic information to be complete.
518          */
519         ret = libxl__device_nic_setdefault(gc, domid, &d_config->nics[i],
520                                            false);
521         if (ret) {
522             LOGD(ERROR, domid, "Unable to set nic defaults for nic %d", i);
523             goto out;
524         }
525 
526         if (d_config->nics[i].devid > last_devid)
527             last_devid = d_config->nics[i].devid;
528     }
529     for (i = 0; i < d_config->num_nics; i++) {
530         if (d_config->nics[i].devid < 0)
531             d_config->nics[i].devid = ++last_devid;
532     }
533 
534 out:
535     return ret;
536 }
537 
538 LIBXL_DEFINE_DEVICE_ADD(nic)
539 LIBXL_DEFINE_DEVICES_ADD(nic)
540 LIBXL_DEFINE_DEVICE_REMOVE(nic)
541 
542 DEFINE_DEVICE_TYPE_STRUCT_X(nic, nic, vif,
543     .update_config = libxl_device_nic_update_config,
544     .from_xenstore = (device_from_xenstore_fn_t)libxl__nic_from_xenstore,
545     .set_xenstore_config = (device_set_xenstore_config_fn_t)
546                            libxl__set_xenstore_nic,
547 );
548 
549 /*
550  * Local variables:
551  * mode: C
552  * c-basic-offset: 4
553  * indent-tabs-mode: nil
554  * End:
555  */
556