1 /*
2 * virnetworkobj.c: handle network objects
3 * (derived from network_conf.c)
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library 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 GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library. If not, see
17 * <http://www.gnu.org/licenses/>.
18 */
19
20 #include <config.h>
21 #include <dirent.h>
22
23 #include "datatypes.h"
24 #include "virnetworkobj.h"
25
26 #include "viralloc.h"
27 #include "virerror.h"
28 #include "virfile.h"
29 #include "virhash.h"
30 #include "virlog.h"
31 #include "virstring.h"
32
33 #define VIR_FROM_THIS VIR_FROM_NETWORK
34
35 VIR_LOG_INIT("conf.virnetworkobj");
36
37 /* Currently, /sbin/tc implementation allows up to 16 bits for
38 * minor class size. But the initial bitmap doesn't have to be
39 * that big. */
40 #define INIT_CLASS_ID_BITMAP_SIZE (1<<4)
41
42 struct _virNetworkObj {
43 virObjectLockable parent;
44
45 pid_t dnsmasqPid;
46 pid_t radvdPid;
47 bool active;
48 bool autostart;
49 bool persistent;
50
51 virNetworkDef *def; /* The current definition */
52 virNetworkDef *newDef; /* New definition to activate at shutdown */
53
54 virBitmap *classIdMap; /* bitmap of class IDs for QoS */
55 unsigned long long floor_sum; /* sum of all 'floor'-s of attached NICs */
56
57 unsigned int taint;
58
59 /* Immutable pointer, self locking APIs */
60 virMacMap *macmap;
61
62 GHashTable *ports; /* uuid -> virNetworkPortDef **/
63 };
64
65 struct _virNetworkObjList {
66 virObjectRWLockable parent;
67
68 GHashTable *objs;
69 };
70
71 static virClass *virNetworkObjClass;
72 static virClass *virNetworkObjListClass;
73 static void virNetworkObjDispose(void *obj);
74 static void virNetworkObjListDispose(void *obj);
75
76 static int
virNetworkObjOnceInit(void)77 virNetworkObjOnceInit(void)
78 {
79 if (!VIR_CLASS_NEW(virNetworkObj, virClassForObjectLockable()))
80 return -1;
81
82 if (!VIR_CLASS_NEW(virNetworkObjList, virClassForObjectRWLockable()))
83 return -1;
84
85 return 0;
86 }
87
88
89 VIR_ONCE_GLOBAL_INIT(virNetworkObj);
90
91 static int
92 virNetworkObjLoadAllPorts(virNetworkObj *net,
93 const char *stateDir);
94
95
96 static void
virNetworkObjPortFree(void * val)97 virNetworkObjPortFree(void *val)
98 {
99 virNetworkPortDefFree(val);
100 }
101
102 virNetworkObj *
virNetworkObjNew(void)103 virNetworkObjNew(void)
104 {
105 virNetworkObj *obj;
106
107 if (virNetworkObjInitialize() < 0)
108 return NULL;
109
110 if (!(obj = virObjectLockableNew(virNetworkObjClass)))
111 return NULL;
112
113 obj->classIdMap = virBitmapNew(INIT_CLASS_ID_BITMAP_SIZE);
114
115 /* The first three class IDs are already taken. */
116 ignore_value(virBitmapSetBit(obj->classIdMap, 0));
117 ignore_value(virBitmapSetBit(obj->classIdMap, 1));
118 ignore_value(virBitmapSetBit(obj->classIdMap, 2));
119
120 obj->ports = virHashNew(virNetworkObjPortFree);
121
122 virObjectLock(obj);
123
124 return obj;
125 }
126
127
128 void
virNetworkObjEndAPI(virNetworkObj ** obj)129 virNetworkObjEndAPI(virNetworkObj **obj)
130 {
131 if (!*obj)
132 return;
133
134 virObjectUnlock(*obj);
135 virObjectUnref(*obj);
136 *obj = NULL;
137 }
138
139
140 virNetworkDef *
virNetworkObjGetDef(virNetworkObj * obj)141 virNetworkObjGetDef(virNetworkObj *obj)
142 {
143 return obj->def;
144 }
145
146
147 void
virNetworkObjSetDef(virNetworkObj * obj,virNetworkDef * def)148 virNetworkObjSetDef(virNetworkObj *obj,
149 virNetworkDef *def)
150 {
151 obj->def = def;
152 }
153
154
155 virNetworkDef *
virNetworkObjGetNewDef(virNetworkObj * obj)156 virNetworkObjGetNewDef(virNetworkObj *obj)
157 {
158 return obj->newDef;
159 }
160
161
162 bool
virNetworkObjIsActive(virNetworkObj * obj)163 virNetworkObjIsActive(virNetworkObj *obj)
164 {
165 return obj->active;
166 }
167
168
169 void
virNetworkObjSetActive(virNetworkObj * obj,bool active)170 virNetworkObjSetActive(virNetworkObj *obj,
171 bool active)
172 {
173 obj->active = active;
174 }
175
176
177 bool
virNetworkObjIsPersistent(virNetworkObj * obj)178 virNetworkObjIsPersistent(virNetworkObj *obj)
179 {
180 return obj->persistent;
181 }
182
183
184 bool
virNetworkObjIsAutostart(virNetworkObj * obj)185 virNetworkObjIsAutostart(virNetworkObj *obj)
186 {
187 return obj->autostart;
188 }
189
190
191 void
virNetworkObjSetAutostart(virNetworkObj * obj,bool autostart)192 virNetworkObjSetAutostart(virNetworkObj *obj,
193 bool autostart)
194 {
195 obj->autostart = autostart;
196 }
197
198
199 pid_t
virNetworkObjGetDnsmasqPid(virNetworkObj * obj)200 virNetworkObjGetDnsmasqPid(virNetworkObj *obj)
201 {
202 return obj->dnsmasqPid;
203 }
204
205
206 void
virNetworkObjSetDnsmasqPid(virNetworkObj * obj,pid_t dnsmasqPid)207 virNetworkObjSetDnsmasqPid(virNetworkObj *obj,
208 pid_t dnsmasqPid)
209 {
210 obj->dnsmasqPid = dnsmasqPid;
211 }
212
213
214 pid_t
virNetworkObjGetRadvdPid(virNetworkObj * obj)215 virNetworkObjGetRadvdPid(virNetworkObj *obj)
216 {
217 return obj->radvdPid;
218 }
219
220
221 void
virNetworkObjSetRadvdPid(virNetworkObj * obj,pid_t radvdPid)222 virNetworkObjSetRadvdPid(virNetworkObj *obj,
223 pid_t radvdPid)
224 {
225 obj->radvdPid = radvdPid;
226 }
227
228
229 virBitmap *
virNetworkObjGetClassIdMap(virNetworkObj * obj)230 virNetworkObjGetClassIdMap(virNetworkObj *obj)
231 {
232 return obj->classIdMap;
233 }
234
235
236 virMacMap *
virNetworkObjGetMacMap(virNetworkObj * obj)237 virNetworkObjGetMacMap(virNetworkObj *obj)
238 {
239 return obj->macmap;
240 }
241
242
243 unsigned long long
virNetworkObjGetFloorSum(virNetworkObj * obj)244 virNetworkObjGetFloorSum(virNetworkObj *obj)
245 {
246 return obj->floor_sum;
247 }
248
249
250 void
virNetworkObjSetFloorSum(virNetworkObj * obj,unsigned long long floor_sum)251 virNetworkObjSetFloorSum(virNetworkObj *obj,
252 unsigned long long floor_sum)
253 {
254 obj->floor_sum = floor_sum;
255 }
256
257
258 void
virNetworkObjSetMacMap(virNetworkObj * obj,virMacMap * macmap)259 virNetworkObjSetMacMap(virNetworkObj *obj,
260 virMacMap *macmap)
261 {
262 obj->macmap = macmap;
263 }
264
265
266 void
virNetworkObjUnrefMacMap(virNetworkObj * obj)267 virNetworkObjUnrefMacMap(virNetworkObj *obj)
268 {
269 virObjectUnref(obj->macmap);
270 obj->macmap = NULL;
271 }
272
273
274 int
virNetworkObjMacMgrAdd(virNetworkObj * obj,const char * dnsmasqStateDir,const char * domain,const virMacAddr * mac)275 virNetworkObjMacMgrAdd(virNetworkObj *obj,
276 const char *dnsmasqStateDir,
277 const char *domain,
278 const virMacAddr *mac)
279 {
280 char macStr[VIR_MAC_STRING_BUFLEN];
281 char *file = NULL;
282 int ret = -1;
283
284 if (!obj->macmap)
285 return 0;
286
287 virMacAddrFormat(mac, macStr);
288
289 if (!(file = virMacMapFileName(dnsmasqStateDir, obj->def->bridge)))
290 goto cleanup;
291
292 if (virMacMapAdd(obj->macmap, domain, macStr) < 0)
293 goto cleanup;
294
295 if (virMacMapWriteFile(obj->macmap, file) < 0)
296 goto cleanup;
297
298 ret = 0;
299 cleanup:
300 VIR_FREE(file);
301 return ret;
302 }
303
304
305 int
virNetworkObjMacMgrDel(virNetworkObj * obj,const char * dnsmasqStateDir,const char * domain,const virMacAddr * mac)306 virNetworkObjMacMgrDel(virNetworkObj *obj,
307 const char *dnsmasqStateDir,
308 const char *domain,
309 const virMacAddr *mac)
310 {
311 char macStr[VIR_MAC_STRING_BUFLEN];
312 char *file = NULL;
313 int ret = -1;
314
315 if (!obj->macmap)
316 return 0;
317
318 virMacAddrFormat(mac, macStr);
319
320 if (!(file = virMacMapFileName(dnsmasqStateDir, obj->def->bridge)))
321 goto cleanup;
322
323 if (virMacMapRemove(obj->macmap, domain, macStr) < 0)
324 goto cleanup;
325
326 if (virMacMapWriteFile(obj->macmap, file) < 0)
327 goto cleanup;
328
329 ret = 0;
330 cleanup:
331 VIR_FREE(file);
332 return ret;
333 }
334
335
336 virNetworkObjList *
virNetworkObjListNew(void)337 virNetworkObjListNew(void)
338 {
339 virNetworkObjList *nets;
340
341 if (virNetworkObjInitialize() < 0)
342 return NULL;
343
344 if (!(nets = virObjectRWLockableNew(virNetworkObjListClass)))
345 return NULL;
346
347 nets->objs = virHashNew(virObjectFreeHashData);
348
349 return nets;
350 }
351
352
353 static virNetworkObj *
virNetworkObjFindByUUIDLocked(virNetworkObjList * nets,const unsigned char * uuid)354 virNetworkObjFindByUUIDLocked(virNetworkObjList *nets,
355 const unsigned char *uuid)
356 {
357 virNetworkObj *obj = NULL;
358 char uuidstr[VIR_UUID_STRING_BUFLEN];
359
360 virUUIDFormat(uuid, uuidstr);
361
362 obj = virHashLookup(nets->objs, uuidstr);
363 if (obj)
364 virObjectRef(obj);
365 return obj;
366 }
367
368
369 /**
370 * virNetworkObjFindByUUID:
371 * @nets: list of network objects
372 * @uuid: network uuid to find
373 *
374 * This functions locks @nets and find network object which
375 * corresponds to @uuid.
376 *
377 * Returns: locked and ref'd network object.
378 */
379 virNetworkObj *
virNetworkObjFindByUUID(virNetworkObjList * nets,const unsigned char * uuid)380 virNetworkObjFindByUUID(virNetworkObjList *nets,
381 const unsigned char *uuid)
382 {
383 virNetworkObj *obj;
384
385 virObjectRWLockRead(nets);
386 obj = virNetworkObjFindByUUIDLocked(nets, uuid);
387 virObjectRWUnlock(nets);
388 if (obj)
389 virObjectLock(obj);
390 return obj;
391 }
392
393
394 static int
virNetworkObjSearchName(const void * payload,const char * name G_GNUC_UNUSED,const void * data)395 virNetworkObjSearchName(const void *payload,
396 const char *name G_GNUC_UNUSED,
397 const void *data)
398 {
399 virNetworkObj *obj = (virNetworkObj *) payload;
400 int want = 0;
401
402 virObjectLock(obj);
403 if (STREQ(obj->def->name, (const char *)data))
404 want = 1;
405 virObjectUnlock(obj);
406 return want;
407 }
408
409
410 static virNetworkObj *
virNetworkObjFindByNameLocked(virNetworkObjList * nets,const char * name)411 virNetworkObjFindByNameLocked(virNetworkObjList *nets,
412 const char *name)
413 {
414 virNetworkObj *obj = NULL;
415
416 obj = virHashSearch(nets->objs, virNetworkObjSearchName, name, NULL);
417 if (obj)
418 virObjectRef(obj);
419 return obj;
420 }
421
422
423 /**
424 * virNetworkObjFindByName:
425 * @nets: list of network objects
426 * @name: network name to find
427 *
428 * This functions locks @nets and find network object which
429 * corresponds to @name.
430 *
431 * Returns: locked and ref'd network object.
432 */
433 virNetworkObj *
virNetworkObjFindByName(virNetworkObjList * nets,const char * name)434 virNetworkObjFindByName(virNetworkObjList *nets,
435 const char *name)
436 {
437 virNetworkObj *obj;
438
439 virObjectRWLockRead(nets);
440 obj = virNetworkObjFindByNameLocked(nets, name);
441 virObjectRWUnlock(nets);
442 if (obj)
443 virObjectLock(obj);
444 return obj;
445 }
446
447
448 bool
virNetworkObjTaint(virNetworkObj * obj,virNetworkTaintFlags taint)449 virNetworkObjTaint(virNetworkObj *obj,
450 virNetworkTaintFlags taint)
451 {
452 unsigned int flag = (1 << taint);
453
454 if (obj->taint & flag)
455 return false;
456
457 obj->taint |= flag;
458 return true;
459 }
460
461
462 static void
virNetworkObjDispose(void * opaque)463 virNetworkObjDispose(void *opaque)
464 {
465 virNetworkObj *obj = opaque;
466
467 virHashFree(obj->ports);
468 virNetworkDefFree(obj->def);
469 virNetworkDefFree(obj->newDef);
470 virBitmapFree(obj->classIdMap);
471 virObjectUnref(obj->macmap);
472 }
473
474
475 static void
virNetworkObjListDispose(void * opaque)476 virNetworkObjListDispose(void *opaque)
477 {
478 virNetworkObjList *nets = opaque;
479
480 virHashFree(nets->objs);
481 }
482
483
484 /*
485 * virNetworkObjUpdateAssignDef:
486 * @network: the network object to update
487 * @def: the new NetworkDef (will be consumed by this function)
488 * @live: is this new def the "live" version, or the "persistent" version
489 *
490 * Replace the appropriate copy of the given network's def or newDef
491 * with def. Use "live" and current state of the network to determine
492 * which to replace and what to do with the old defs. When a non-live
493 * def is set, indicate that the network is now persistent.
494 *
495 * NB: a persistent network can be made transient by calling with:
496 * virNetworkObjAssignDef(network, NULL, false) (i.e. set the
497 * persistent def to NULL)
498 *
499 */
500 void
virNetworkObjUpdateAssignDef(virNetworkObj * obj,virNetworkDef * def,bool live)501 virNetworkObjUpdateAssignDef(virNetworkObj *obj,
502 virNetworkDef *def,
503 bool live)
504 {
505 if (live) {
506 /* before setting new live def, save (into newDef) any
507 * existing persistent (!live) def to be restored when the
508 * network is destroyed, unless there is one already saved.
509 */
510 if (obj->persistent && !obj->newDef)
511 obj->newDef = obj->def;
512 else
513 virNetworkDefFree(obj->def);
514 obj->def = def;
515 } else { /* !live */
516 virNetworkDefFree(obj->newDef);
517 if (virNetworkObjIsActive(obj)) {
518 /* save new configuration to be restored on network
519 * shutdown, leaving current live def alone
520 */
521 obj->newDef = def;
522 } else { /* !live and !active */
523 if (obj->def && !obj->persistent) {
524 /* network isn't (yet) marked active or persistent,
525 * but already has a "live" def set. This means we are
526 * currently setting the persistent def as a part of
527 * the process of starting the network, so we need to
528 * preserve the "not yet live" def in network->def.
529 */
530 obj->newDef = def;
531 } else {
532 /* either there is no live def set, or this network
533 * was already set as persistent, so the proper thing
534 * is to overwrite network->def.
535 */
536 obj->newDef = NULL;
537 virNetworkDefFree(obj->def);
538 obj->def = def;
539 }
540 }
541 obj->persistent = !!def;
542 }
543 }
544
545
546 /*
547 * If flags & VIR_NETWORK_OBJ_LIST_ADD_CHECK_LIVE then this will
548 * refuse updating an existing def if the current def is live
549 *
550 * If flags & VIR_NETWORK_OBJ_LIST_ADD_LIVE then the @def being
551 * added is assumed to represent a live config, not a future
552 * inactive config
553 *
554 * If flags is zero, network is considered as inactive and persistent.
555 */
556 static virNetworkObj *
virNetworkObjAssignDefLocked(virNetworkObjList * nets,virNetworkDef * def,unsigned int flags)557 virNetworkObjAssignDefLocked(virNetworkObjList *nets,
558 virNetworkDef *def,
559 unsigned int flags)
560 {
561 virNetworkObj *obj;
562 virNetworkObj *ret = NULL;
563 char uuidstr[VIR_UUID_STRING_BUFLEN];
564
565 /* See if a network with matching UUID already exists */
566 if ((obj = virNetworkObjFindByUUIDLocked(nets, def->uuid))) {
567 virObjectLock(obj);
568 /* UUID matches, but if names don't match, refuse it */
569 if (STRNEQ(obj->def->name, def->name)) {
570 virUUIDFormat(obj->def->uuid, uuidstr);
571 virReportError(VIR_ERR_OPERATION_FAILED,
572 _("network '%s' is already defined with uuid %s"),
573 obj->def->name, uuidstr);
574 goto cleanup;
575 }
576
577 if (flags & VIR_NETWORK_OBJ_LIST_ADD_CHECK_LIVE) {
578 /* UUID & name match, but if network is already active, refuse it */
579 if (virNetworkObjIsActive(obj)) {
580 virReportError(VIR_ERR_OPERATION_INVALID,
581 _("network is already active as '%s'"),
582 obj->def->name);
583 goto cleanup;
584 }
585 }
586
587 virNetworkObjUpdateAssignDef(obj, def,
588 !!(flags & VIR_NETWORK_OBJ_LIST_ADD_LIVE));
589 } else {
590 /* UUID does not match, but if a name matches, refuse it */
591 if ((obj = virNetworkObjFindByNameLocked(nets, def->name))) {
592 virObjectLock(obj);
593 virUUIDFormat(obj->def->uuid, uuidstr);
594 virReportError(VIR_ERR_OPERATION_FAILED,
595 _("network '%s' already exists with uuid %s"),
596 def->name, uuidstr);
597 goto cleanup;
598 }
599
600 if (!(obj = virNetworkObjNew()))
601 goto cleanup;
602
603 virUUIDFormat(def->uuid, uuidstr);
604 if (virHashAddEntry(nets->objs, uuidstr, obj) < 0)
605 goto cleanup;
606 virObjectRef(obj);
607
608 obj->def = def;
609 obj->persistent = !(flags & VIR_NETWORK_OBJ_LIST_ADD_LIVE);
610 }
611
612 ret = g_steal_pointer(&obj);
613
614 cleanup:
615 virNetworkObjEndAPI(&obj);
616 return ret;
617 }
618
619
620 /*
621 * virNetworkObjAssignDef:
622 * @nets: list of all networks
623 * @def: the new NetworkDef (will be consumed by this function iff successful)
624 * @flags: bitwise-OR of VIR_NETWORK_OBJ_LIST_ADD_* flags
625 *
626 * Either replace the appropriate copy of the NetworkDef with name
627 * matching def->name or, if not found, create a new NetworkObj with
628 * def. For an existing network, use "live" and current state of the
629 * network to determine which to replace.
630 *
631 * Look at virNetworkObjAssignDefLocked() for @flags description.
632 *
633 * Returns NULL on error, virNetworkObj *on success.
634 */
635 virNetworkObj *
virNetworkObjAssignDef(virNetworkObjList * nets,virNetworkDef * def,unsigned int flags)636 virNetworkObjAssignDef(virNetworkObjList *nets,
637 virNetworkDef *def,
638 unsigned int flags)
639 {
640 virNetworkObj *obj;
641
642 virObjectRWLockWrite(nets);
643 obj = virNetworkObjAssignDefLocked(nets, def, flags);
644 virObjectRWUnlock(nets);
645 return obj;
646 }
647
648
649 /*
650 * virNetworkObjSetDefTransient:
651 * @network: network object pointer
652 * @live: if true, run this operation even for an inactive network.
653 * this allows freely updated network->def with runtime defaults
654 * before starting the network, which will be discarded on network
655 * shutdown. Any cleanup paths need to be sure to handle newDef if
656 * the network is never started.
657 *
658 * Mark the active network config as transient. Ensures live-only update
659 * operations do not persist past network destroy.
660 *
661 * Returns 0 on success, -1 on failure
662 */
663 int
virNetworkObjSetDefTransient(virNetworkObj * obj,bool live,virNetworkXMLOption * xmlopt)664 virNetworkObjSetDefTransient(virNetworkObj *obj,
665 bool live,
666 virNetworkXMLOption *xmlopt)
667 {
668 if (!virNetworkObjIsActive(obj) && !live)
669 return 0;
670
671 if (!obj->persistent || obj->newDef)
672 return 0;
673
674 obj->newDef = virNetworkDefCopy(obj->def,
675 xmlopt,
676 VIR_NETWORK_XML_INACTIVE);
677 return obj->newDef ? 0 : -1;
678 }
679
680
681 /* virNetworkObjUnsetDefTransient:
682 *
683 * This *undoes* what virNetworkObjSetDefTransient did.
684 */
685 void
virNetworkObjUnsetDefTransient(virNetworkObj * obj)686 virNetworkObjUnsetDefTransient(virNetworkObj *obj)
687 {
688 if (obj->newDef) {
689 virNetworkDefFree(obj->def);
690 obj->def = g_steal_pointer(&obj->newDef);
691 }
692 }
693
694
695 /*
696 * virNetworkObjGetPersistentDef:
697 * @network: network object pointer
698 *
699 * Return the persistent network configuration. If network is transient,
700 * return the running config.
701 *
702 * Returns NULL on error, virNetworkDef *on success.
703 */
704 virNetworkDef *
virNetworkObjGetPersistentDef(virNetworkObj * obj)705 virNetworkObjGetPersistentDef(virNetworkObj *obj)
706 {
707 if (obj->newDef)
708 return obj->newDef;
709 else
710 return obj->def;
711 }
712
713
714 /*
715 * virNetworkObjReplacePersistentDef:
716 * @network: network object pointer
717 * @def: new virNetworkDef to replace current persistent config
718 *
719 * Replace the "persistent" network configuration with the given new
720 * virNetworkDef. This pays attention to whether or not the network
721 * is active.
722 *
723 * Returns -1 on error, 0 on success
724 */
725 int
virNetworkObjReplacePersistentDef(virNetworkObj * obj,virNetworkDef * def)726 virNetworkObjReplacePersistentDef(virNetworkObj *obj,
727 virNetworkDef *def)
728 {
729 if (virNetworkObjIsActive(obj)) {
730 virNetworkDefFree(obj->newDef);
731 obj->newDef = def;
732 } else {
733 virNetworkDefFree(obj->def);
734 obj->def = def;
735 }
736 return 0;
737 }
738
739
740 /*
741 * virNetworkObjConfigChangeSetup:
742 *
743 * 1) checks whether network state is consistent with the requested
744 * type of modification.
745 *
746 * 3) make sure there are separate "def" and "newDef" copies of
747 * networkDef if appropriate.
748 *
749 * Returns 0 on success, -1 on error.
750 */
751 static int
virNetworkObjConfigChangeSetup(virNetworkObj * obj,virNetworkXMLOption * xmlopt,unsigned int flags)752 virNetworkObjConfigChangeSetup(virNetworkObj *obj,
753 virNetworkXMLOption *xmlopt,
754 unsigned int flags)
755 {
756 bool isActive;
757
758 isActive = virNetworkObjIsActive(obj);
759
760 if (!isActive && (flags & VIR_NETWORK_UPDATE_AFFECT_LIVE)) {
761 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
762 _("network is not running"));
763 return -1;
764 }
765
766 if (flags & VIR_NETWORK_UPDATE_AFFECT_CONFIG) {
767 if (!obj->persistent) {
768 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
769 _("cannot change persistent config of a "
770 "transient network"));
771 return -1;
772 }
773 /* this should already have been done by the driver, but do it
774 * anyway just in case.
775 */
776 if (isActive && (virNetworkObjSetDefTransient(obj, false, xmlopt) < 0))
777 return -1;
778 }
779
780 return 0;
781 }
782
783
784 void
virNetworkObjRemoveInactive(virNetworkObjList * nets,virNetworkObj * obj)785 virNetworkObjRemoveInactive(virNetworkObjList *nets,
786 virNetworkObj *obj)
787 {
788 char uuidstr[VIR_UUID_STRING_BUFLEN];
789
790 virUUIDFormat(obj->def->uuid, uuidstr);
791 virObjectRef(obj);
792 virObjectUnlock(obj);
793 virObjectRWLockWrite(nets);
794 virObjectLock(obj);
795 virHashRemoveEntry(nets->objs, uuidstr);
796 virObjectRWUnlock(nets);
797 virObjectUnref(obj);
798 }
799
800
801 static char *
virNetworkObjFormat(virNetworkObj * obj,virNetworkXMLOption * xmlopt,unsigned int flags)802 virNetworkObjFormat(virNetworkObj *obj,
803 virNetworkXMLOption *xmlopt,
804 unsigned int flags)
805 {
806 g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
807 char *classIdStr = virBitmapFormat(obj->classIdMap);
808 size_t i;
809
810 if (!classIdStr)
811 return NULL;
812
813 virBufferAddLit(&buf, "<networkstatus>\n");
814 virBufferAdjustIndent(&buf, 2);
815 virBufferAsprintf(&buf, "<class_id bitmap='%s'/>\n", classIdStr);
816 virBufferAsprintf(&buf, "<floor sum='%llu'/>\n", obj->floor_sum);
817 VIR_FREE(classIdStr);
818
819 for (i = 0; i < VIR_NETWORK_TAINT_LAST; i++) {
820 if (obj->taint & (1 << i))
821 virBufferAsprintf(&buf, "<taint flag='%s'/>\n",
822 virNetworkTaintTypeToString(i));
823 }
824
825 if (virNetworkDefFormatBuf(&buf, obj->def, xmlopt, flags) < 0)
826 return NULL;
827
828 virBufferAdjustIndent(&buf, -2);
829 virBufferAddLit(&buf, "</networkstatus>");
830
831 return virBufferContentAndReset(&buf);
832 }
833
834
835 int
virNetworkObjSaveStatus(const char * statusDir,virNetworkObj * obj,virNetworkXMLOption * xmlopt)836 virNetworkObjSaveStatus(const char *statusDir,
837 virNetworkObj *obj,
838 virNetworkXMLOption *xmlopt)
839 {
840 int ret = -1;
841 int flags = 0;
842 char *xml;
843
844 if (!(xml = virNetworkObjFormat(obj, xmlopt, flags)))
845 goto cleanup;
846
847 if (virNetworkSaveXML(statusDir, obj->def, xml))
848 goto cleanup;
849
850 ret = 0;
851 cleanup:
852 VIR_FREE(xml);
853 return ret;
854 }
855
856
857 static virNetworkObj *
virNetworkLoadState(virNetworkObjList * nets,const char * stateDir,const char * name,virNetworkXMLOption * xmlopt)858 virNetworkLoadState(virNetworkObjList *nets,
859 const char *stateDir,
860 const char *name,
861 virNetworkXMLOption *xmlopt)
862 {
863 g_autofree char *configFile = NULL;
864 virNetworkDef *def = NULL;
865 virNetworkObj *obj = NULL;
866 g_autoptr(xmlDoc) xml = NULL;
867 xmlNodePtr node = NULL;
868 g_autoptr(xmlXPathContext) ctxt = NULL;
869 g_autoptr(virBitmap) classIdMap = NULL;
870 unsigned long long floor_sum_val = 0;
871 unsigned int taint = 0;
872 int n;
873 size_t i;
874
875
876 if ((configFile = virNetworkConfigFile(stateDir, name)) == NULL)
877 goto error;
878
879 if (!(xml = virXMLParseCtxt(configFile, NULL, _("(network status)"), &ctxt)))
880 goto error;
881
882 if (!(node = virXPathNode("//network", ctxt))) {
883 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
884 _("Could not find any 'network' element in status file"));
885 goto error;
886 }
887
888 /* parse the definition first */
889 ctxt->node = node;
890 if (!(def = virNetworkDefParseXML(ctxt, xmlopt)))
891 goto error;
892
893 if (STRNEQ(name, def->name)) {
894 virReportError(VIR_ERR_INTERNAL_ERROR,
895 _("Network config filename '%s'"
896 " does not match network name '%s'"),
897 configFile, def->name);
898 goto error;
899 }
900
901 /* now parse possible status data */
902 node = xmlDocGetRootElement(xml);
903 if (virXMLNodeNameEqual(node, "networkstatus")) {
904 /* Newer network status file. Contains useful
905 * info which are not to be found in bare config XML */
906 g_autofree char *classIdStr = NULL;
907 g_autofree char *floor_sum = NULL;
908 g_autofree xmlNodePtr *nodes = NULL;
909
910 ctxt->node = node;
911 if ((classIdStr = virXPathString("string(./class_id[1]/@bitmap)",
912 ctxt))) {
913 if (!(classIdMap = virBitmapParseUnlimited(classIdStr)))
914 goto error;
915 }
916
917 floor_sum = virXPathString("string(./floor[1]/@sum)", ctxt);
918 if (floor_sum &&
919 virStrToLong_ull(floor_sum, NULL, 10, &floor_sum_val) < 0) {
920 virReportError(VIR_ERR_INTERNAL_ERROR,
921 _("Malformed 'floor_sum' attribute: %s"),
922 floor_sum);
923 goto error;
924 }
925
926 if ((n = virXPathNodeSet("./taint", ctxt, &nodes)) < 0)
927 goto error;
928
929 for (i = 0; i < n; i++) {
930 g_autofree char *str = virXMLPropString(nodes[i], "flag");
931 if (str) {
932 int flag = virNetworkTaintTypeFromString(str);
933 if (flag < 0) {
934 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
935 _("Unknown taint flag %s"), str);
936 goto error;
937 }
938 /* Compute taint mask here. The network object does not
939 * exist yet, so we can't use virNetworkObjtTaint. */
940 taint |= (1 << flag);
941 }
942 }
943 }
944
945 /* create the object */
946 if (!(obj = virNetworkObjAssignDef(nets, def,
947 VIR_NETWORK_OBJ_LIST_ADD_LIVE)))
948 goto error;
949 /* do not put any "goto error" below this comment */
950
951 /* assign status data stored in the network object */
952 if (classIdMap) {
953 virBitmapFree(obj->classIdMap);
954 obj->classIdMap = g_steal_pointer(&classIdMap);
955 }
956
957 if (floor_sum_val > 0)
958 obj->floor_sum = floor_sum_val;
959
960 obj->taint = taint;
961 obj->active = true; /* network with a state file is by definition active */
962
963 return obj;
964
965 error:
966 virNetworkDefFree(def);
967 return NULL;
968 }
969
970
971 static virNetworkObj *
virNetworkLoadConfig(virNetworkObjList * nets,const char * configDir,const char * autostartDir,const char * name,virNetworkXMLOption * xmlopt)972 virNetworkLoadConfig(virNetworkObjList *nets,
973 const char *configDir,
974 const char *autostartDir,
975 const char *name,
976 virNetworkXMLOption *xmlopt)
977 {
978 char *configFile = NULL, *autostartLink = NULL;
979 virNetworkDef *def = NULL;
980 virNetworkObj *obj;
981 bool saveConfig = false;
982 int autostart;
983
984 if ((configFile = virNetworkConfigFile(configDir, name)) == NULL)
985 goto error;
986 if ((autostartLink = virNetworkConfigFile(autostartDir, name)) == NULL)
987 goto error;
988
989 if ((autostart = virFileLinkPointsTo(autostartLink, configFile)) < 0)
990 goto error;
991
992 if (!(def = virNetworkDefParseFile(configFile, xmlopt)))
993 goto error;
994
995 if (STRNEQ(name, def->name)) {
996 virReportError(VIR_ERR_INTERNAL_ERROR,
997 _("Network config filename '%s'"
998 " does not match network name '%s'"),
999 configFile, def->name);
1000 goto error;
1001 }
1002
1003 switch ((virNetworkForwardType) def->forward.type) {
1004 case VIR_NETWORK_FORWARD_NONE:
1005 case VIR_NETWORK_FORWARD_NAT:
1006 case VIR_NETWORK_FORWARD_ROUTE:
1007 case VIR_NETWORK_FORWARD_OPEN:
1008 if (!def->mac_specified) {
1009 virNetworkSetBridgeMacAddr(def);
1010 /* We just generated a new MAC address, and we need to persist
1011 * the configuration to disk to avoid the network getting a
1012 * different one the next time the daemon is started */
1013 saveConfig = true;
1014 }
1015 break;
1016
1017 case VIR_NETWORK_FORWARD_BRIDGE:
1018 case VIR_NETWORK_FORWARD_PRIVATE:
1019 case VIR_NETWORK_FORWARD_VEPA:
1020 case VIR_NETWORK_FORWARD_PASSTHROUGH:
1021 case VIR_NETWORK_FORWARD_HOSTDEV:
1022 /* Throw away MAC address for other forward types,
1023 * which could have been generated by older libvirt RPMs */
1024 def->mac_specified = false;
1025 break;
1026
1027 case VIR_NETWORK_FORWARD_LAST:
1028 default:
1029 virReportEnumRangeError(virNetworkForwardType, def->forward.type);
1030 goto error;
1031 }
1032
1033 /* The network didn't have a UUID so we generated a new one, and
1034 * we need to persist the configuration to disk to avoid the network
1035 * getting a different one the next time the daemon is started */
1036 if (!def->uuid_specified)
1037 saveConfig = true;
1038
1039 if (saveConfig &&
1040 virNetworkSaveConfig(configDir, def, xmlopt) < 0) {
1041 goto error;
1042 }
1043
1044 if (!(obj = virNetworkObjAssignDef(nets, def, 0)))
1045 goto error;
1046
1047 obj->autostart = (autostart == 1);
1048
1049 VIR_FREE(configFile);
1050 VIR_FREE(autostartLink);
1051
1052 return obj;
1053
1054 error:
1055 VIR_FREE(configFile);
1056 VIR_FREE(autostartLink);
1057 virNetworkDefFree(def);
1058 return NULL;
1059 }
1060
1061
1062 int
virNetworkObjLoadAllState(virNetworkObjList * nets,const char * stateDir,virNetworkXMLOption * xmlopt)1063 virNetworkObjLoadAllState(virNetworkObjList *nets,
1064 const char *stateDir,
1065 virNetworkXMLOption *xmlopt)
1066 {
1067 g_autoptr(DIR) dir = NULL;
1068 struct dirent *entry;
1069 int ret = -1;
1070 int rc;
1071
1072 if ((rc = virDirOpenIfExists(&dir, stateDir)) <= 0)
1073 return rc;
1074
1075 while ((ret = virDirRead(dir, &entry, stateDir)) > 0) {
1076 virNetworkObj *obj;
1077
1078 if (!virStringStripSuffix(entry->d_name, ".xml"))
1079 continue;
1080
1081 obj = virNetworkLoadState(nets, stateDir, entry->d_name, xmlopt);
1082
1083 if (obj &&
1084 virNetworkObjLoadAllPorts(obj, stateDir) < 0) {
1085 virNetworkObjEndAPI(&obj);
1086 return -1;
1087 }
1088 virNetworkObjEndAPI(&obj);
1089 }
1090
1091 return ret;
1092 }
1093
1094
1095 int
virNetworkObjLoadAllConfigs(virNetworkObjList * nets,const char * configDir,const char * autostartDir,virNetworkXMLOption * xmlopt)1096 virNetworkObjLoadAllConfigs(virNetworkObjList *nets,
1097 const char *configDir,
1098 const char *autostartDir,
1099 virNetworkXMLOption *xmlopt)
1100 {
1101 g_autoptr(DIR) dir = NULL;
1102 struct dirent *entry;
1103 int ret = -1;
1104 int rc;
1105
1106 if ((rc = virDirOpenIfExists(&dir, configDir)) <= 0)
1107 return rc;
1108
1109 while ((ret = virDirRead(dir, &entry, configDir)) > 0) {
1110 virNetworkObj *obj;
1111
1112 if (!virStringStripSuffix(entry->d_name, ".xml"))
1113 continue;
1114
1115 /* NB: ignoring errors, so one malformed config doesn't
1116 kill the whole process */
1117 obj = virNetworkLoadConfig(nets,
1118 configDir,
1119 autostartDir,
1120 entry->d_name,
1121 xmlopt);
1122 virNetworkObjEndAPI(&obj);
1123 }
1124
1125 return ret;
1126 }
1127
1128
1129 int
virNetworkObjDeleteConfig(const char * configDir,const char * autostartDir,virNetworkObj * obj)1130 virNetworkObjDeleteConfig(const char *configDir,
1131 const char *autostartDir,
1132 virNetworkObj *obj)
1133 {
1134 char *configFile = NULL;
1135 char *autostartLink = NULL;
1136 int ret = -1;
1137
1138 if (!(configFile = virNetworkConfigFile(configDir, obj->def->name)))
1139 goto error;
1140 if (!(autostartLink = virNetworkConfigFile(autostartDir, obj->def->name)))
1141 goto error;
1142
1143 /* Not fatal if this doesn't work */
1144 unlink(autostartLink);
1145 obj->autostart = false;
1146
1147 if (unlink(configFile) < 0) {
1148 virReportSystemError(errno,
1149 _("cannot remove config file '%s'"),
1150 configFile);
1151 goto error;
1152 }
1153
1154 ret = 0;
1155
1156 error:
1157 VIR_FREE(configFile);
1158 VIR_FREE(autostartLink);
1159 return ret;
1160 }
1161
1162
1163 struct virNetworkObjBridgeInUseHelperData {
1164 const char *bridge;
1165 const char *skipname;
1166 };
1167
1168 static int
virNetworkObjBridgeInUseHelper(const void * payload,const char * name G_GNUC_UNUSED,const void * opaque)1169 virNetworkObjBridgeInUseHelper(const void *payload,
1170 const char *name G_GNUC_UNUSED,
1171 const void *opaque)
1172 {
1173 int ret;
1174 virNetworkObj *obj = (virNetworkObj *) payload;
1175 const struct virNetworkObjBridgeInUseHelperData *data = opaque;
1176
1177 virObjectLock(obj);
1178 if (data->skipname &&
1179 ((obj->def && STREQ(obj->def->name, data->skipname)) ||
1180 (obj->newDef && STREQ(obj->newDef->name, data->skipname))))
1181 ret = 0;
1182 else if ((obj->def && obj->def->bridge &&
1183 STREQ(obj->def->bridge, data->bridge)) ||
1184 (obj->newDef && obj->newDef->bridge &&
1185 STREQ(obj->newDef->bridge, data->bridge)))
1186 ret = 1;
1187 else
1188 ret = 0;
1189 virObjectUnlock(obj);
1190 return ret;
1191 }
1192
1193
1194 bool
virNetworkObjBridgeInUse(virNetworkObjList * nets,const char * bridge,const char * skipname)1195 virNetworkObjBridgeInUse(virNetworkObjList *nets,
1196 const char *bridge,
1197 const char *skipname)
1198 {
1199 virNetworkObj *obj;
1200 struct virNetworkObjBridgeInUseHelperData data = {bridge, skipname};
1201
1202 virObjectRWLockRead(nets);
1203 obj = virHashSearch(nets->objs, virNetworkObjBridgeInUseHelper, &data, NULL);
1204 virObjectRWUnlock(nets);
1205
1206 return obj != NULL;
1207 }
1208
1209
1210 /*
1211 * virNetworkObjUpdate:
1212 *
1213 * Apply the supplied update to the given virNetworkObj. Except for
1214 * @network pointing to an actual network object rather than the
1215 * opaque virNetworkPtr, parameters are identical to the public API
1216 * virNetworkUpdate.
1217 *
1218 * The original virNetworkDefs are copied, and all modifications made
1219 * to these copies. The originals are replaced with the copies only
1220 * after success has been guaranteed.
1221 *
1222 * Returns: -1 on error, 0 on success.
1223 */
1224 int
virNetworkObjUpdate(virNetworkObj * obj,unsigned int command,unsigned int section,int parentIndex,const char * xml,virNetworkXMLOption * xmlopt,unsigned int flags)1225 virNetworkObjUpdate(virNetworkObj *obj,
1226 unsigned int command, /* virNetworkUpdateCommand */
1227 unsigned int section, /* virNetworkUpdateSection */
1228 int parentIndex,
1229 const char *xml,
1230 virNetworkXMLOption *xmlopt,
1231 unsigned int flags) /* virNetworkUpdateFlags */
1232 {
1233 int ret = -1;
1234 virNetworkDef *livedef = NULL;
1235 virNetworkDef *configdef = NULL;
1236
1237 /* normalize config data, and check for common invalid requests. */
1238 if (virNetworkObjConfigChangeSetup(obj, xmlopt, flags) < 0)
1239 goto cleanup;
1240
1241 if (flags & VIR_NETWORK_UPDATE_AFFECT_LIVE) {
1242 virNetworkDef *checkdef;
1243
1244 /* work on a copy of the def */
1245 if (!(livedef = virNetworkDefCopy(obj->def, xmlopt, 0)))
1246 goto cleanup;
1247 if (virNetworkDefUpdateSection(livedef, command, section,
1248 parentIndex, xml, flags) < 0) {
1249 goto cleanup;
1250 }
1251 /* run a final format/parse cycle to make sure we didn't
1252 * add anything illegal to the def
1253 */
1254 if (!(checkdef = virNetworkDefCopy(livedef, xmlopt, 0)))
1255 goto cleanup;
1256 virNetworkDefFree(checkdef);
1257 }
1258
1259 if (flags & VIR_NETWORK_UPDATE_AFFECT_CONFIG) {
1260 virNetworkDef *checkdef;
1261
1262 /* work on a copy of the def */
1263 if (!(configdef = virNetworkDefCopy(virNetworkObjGetPersistentDef(obj),
1264 xmlopt,
1265 VIR_NETWORK_XML_INACTIVE))) {
1266 goto cleanup;
1267 }
1268 if (virNetworkDefUpdateSection(configdef, command, section,
1269 parentIndex, xml, flags) < 0) {
1270 goto cleanup;
1271 }
1272 if (!(checkdef = virNetworkDefCopy(configdef,
1273 xmlopt,
1274 VIR_NETWORK_XML_INACTIVE))) {
1275 goto cleanup;
1276 }
1277 virNetworkDefFree(checkdef);
1278 }
1279
1280 if (configdef) {
1281 /* successfully modified copy, now replace original */
1282 if (virNetworkObjReplacePersistentDef(obj, configdef) < 0)
1283 goto cleanup;
1284 configdef = NULL;
1285 }
1286 if (livedef) {
1287 /* successfully modified copy, now replace original */
1288 virNetworkDefFree(obj->def);
1289 obj->def = g_steal_pointer(&livedef);
1290 }
1291
1292 ret = 0;
1293 cleanup:
1294 virNetworkDefFree(livedef);
1295 virNetworkDefFree(configdef);
1296 return ret;
1297 }
1298
1299
1300 #define MATCH(FLAG) (flags & (FLAG))
1301 static bool
virNetworkObjMatch(virNetworkObj * obj,unsigned int flags)1302 virNetworkObjMatch(virNetworkObj *obj,
1303 unsigned int flags)
1304 {
1305 /* filter by active state */
1306 if (MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_ACTIVE) &&
1307 !((MATCH(VIR_CONNECT_LIST_NETWORKS_ACTIVE) &&
1308 virNetworkObjIsActive(obj)) ||
1309 (MATCH(VIR_CONNECT_LIST_NETWORKS_INACTIVE) &&
1310 !virNetworkObjIsActive(obj))))
1311 return false;
1312
1313 /* filter by persistence */
1314 if (MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_PERSISTENT) &&
1315 !((MATCH(VIR_CONNECT_LIST_NETWORKS_PERSISTENT) &&
1316 obj->persistent) ||
1317 (MATCH(VIR_CONNECT_LIST_NETWORKS_TRANSIENT) &&
1318 !obj->persistent)))
1319 return false;
1320
1321 /* filter by autostart option */
1322 if (MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_AUTOSTART) &&
1323 !((MATCH(VIR_CONNECT_LIST_NETWORKS_AUTOSTART) &&
1324 obj->autostart) ||
1325 (MATCH(VIR_CONNECT_LIST_NETWORKS_NO_AUTOSTART) &&
1326 !obj->autostart)))
1327 return false;
1328
1329 return true;
1330 }
1331 #undef MATCH
1332
1333
1334 typedef struct _virNetworkObjListExportData virNetworkObjListExportData;
1335 struct _virNetworkObjListExportData {
1336 virConnectPtr conn;
1337 virNetworkPtr *nets;
1338 virNetworkObjListFilter filter;
1339 unsigned int flags;
1340 int nnets;
1341 bool error;
1342 };
1343
1344 static int
virNetworkObjListExportCallback(void * payload,const char * name G_GNUC_UNUSED,void * opaque)1345 virNetworkObjListExportCallback(void *payload,
1346 const char *name G_GNUC_UNUSED,
1347 void *opaque)
1348 {
1349 virNetworkObjListExportData *data = opaque;
1350 virNetworkObj *obj = payload;
1351 virNetworkPtr net = NULL;
1352
1353 if (data->error)
1354 return 0;
1355
1356 virObjectLock(obj);
1357
1358 if (data->filter &&
1359 !data->filter(data->conn, obj->def))
1360 goto cleanup;
1361
1362 if (!virNetworkObjMatch(obj, data->flags))
1363 goto cleanup;
1364
1365 if (!data->nets) {
1366 data->nnets++;
1367 goto cleanup;
1368 }
1369
1370 if (!(net = virGetNetwork(data->conn, obj->def->name, obj->def->uuid))) {
1371 data->error = true;
1372 goto cleanup;
1373 }
1374
1375 data->nets[data->nnets++] = net;
1376
1377 cleanup:
1378 virObjectUnlock(obj);
1379 return 0;
1380 }
1381
1382
1383 int
virNetworkObjListExport(virConnectPtr conn,virNetworkObjList * netobjs,virNetworkPtr ** nets,virNetworkObjListFilter filter,unsigned int flags)1384 virNetworkObjListExport(virConnectPtr conn,
1385 virNetworkObjList *netobjs,
1386 virNetworkPtr **nets,
1387 virNetworkObjListFilter filter,
1388 unsigned int flags)
1389 {
1390 int ret = -1;
1391 virNetworkObjListExportData data = {
1392 .conn = conn, .nets = NULL, .filter = filter, .flags = flags,
1393 .nnets = 0, .error = false };
1394
1395 virObjectRWLockRead(netobjs);
1396 if (nets)
1397 data.nets = g_new0(virNetworkPtr, virHashSize(netobjs->objs) + 1);
1398
1399 virHashForEach(netobjs->objs, virNetworkObjListExportCallback, &data);
1400
1401 if (data.error)
1402 goto cleanup;
1403
1404 if (data.nets) {
1405 /* trim the array to the final size */
1406 VIR_REALLOC_N(data.nets, data.nnets + 1);
1407 *nets = g_steal_pointer(&data.nets);
1408 }
1409
1410 ret = data.nnets;
1411 cleanup:
1412 virObjectRWUnlock(netobjs);
1413 while (data.nets && data.nnets)
1414 virObjectUnref(data.nets[--data.nnets]);
1415
1416 VIR_FREE(data.nets);
1417 return ret;
1418 }
1419
1420
1421 struct virNetworkObjListForEachHelperData {
1422 virNetworkObjListIterator callback;
1423 void *opaque;
1424 int ret;
1425 };
1426
1427 static int
virNetworkObjListForEachHelper(void * payload,const char * name G_GNUC_UNUSED,void * opaque)1428 virNetworkObjListForEachHelper(void *payload,
1429 const char *name G_GNUC_UNUSED,
1430 void *opaque)
1431 {
1432 struct virNetworkObjListForEachHelperData *data = opaque;
1433
1434 if (data->callback(payload, data->opaque) < 0)
1435 data->ret = -1;
1436 return 0;
1437 }
1438
1439
1440 /**
1441 * virNetworkObjListForEach:
1442 * @nets: a list of network objects
1443 * @callback: function to call over each of object in the list
1444 * @opaque: pointer to pass to the @callback
1445 *
1446 * Function iterates over the list of network objects and calls
1447 * passed callback over each one of them. You should avoid
1448 * calling those virNetworkObjList APIs, which lock the list
1449 * again in favor of their virNetworkObj*Locked variants.
1450 *
1451 * Returns: 0 on success, -1 otherwise.
1452 */
1453 int
virNetworkObjListForEach(virNetworkObjList * nets,virNetworkObjListIterator callback,void * opaque)1454 virNetworkObjListForEach(virNetworkObjList *nets,
1455 virNetworkObjListIterator callback,
1456 void *opaque)
1457 {
1458 struct virNetworkObjListForEachHelperData data = {
1459 .callback = callback, .opaque = opaque, .ret = 0};
1460 virObjectRWLockRead(nets);
1461 virHashForEachSafe(nets->objs, virNetworkObjListForEachHelper, &data);
1462 virObjectRWUnlock(nets);
1463 return data.ret;
1464 }
1465
1466
1467 struct virNetworkObjListGetHelperData {
1468 virConnectPtr conn;
1469 virNetworkObjListFilter filter;
1470 char **names;
1471 int nnames;
1472 int maxnames;
1473 bool active;
1474 bool error;
1475 };
1476
1477 static int
virNetworkObjListGetHelper(void * payload,const char * name G_GNUC_UNUSED,void * opaque)1478 virNetworkObjListGetHelper(void *payload,
1479 const char *name G_GNUC_UNUSED,
1480 void *opaque)
1481 {
1482 struct virNetworkObjListGetHelperData *data = opaque;
1483 virNetworkObj *obj = payload;
1484
1485 if (data->error)
1486 return 0;
1487
1488 if (data->maxnames >= 0 &&
1489 data->nnames == data->maxnames)
1490 return 0;
1491
1492 virObjectLock(obj);
1493
1494 if (data->filter &&
1495 !data->filter(data->conn, obj->def))
1496 goto cleanup;
1497
1498 if ((data->active && virNetworkObjIsActive(obj)) ||
1499 (!data->active && !virNetworkObjIsActive(obj))) {
1500 if (data->names)
1501 data->names[data->nnames] = g_strdup(obj->def->name);
1502 data->nnames++;
1503 }
1504
1505 cleanup:
1506 virObjectUnlock(obj);
1507 return 0;
1508 }
1509
1510
1511 int
virNetworkObjListGetNames(virNetworkObjList * nets,bool active,char ** names,int maxnames,virNetworkObjListFilter filter,virConnectPtr conn)1512 virNetworkObjListGetNames(virNetworkObjList *nets,
1513 bool active,
1514 char **names,
1515 int maxnames,
1516 virNetworkObjListFilter filter,
1517 virConnectPtr conn)
1518 {
1519 int ret = -1;
1520
1521 struct virNetworkObjListGetHelperData data = {
1522 .conn = conn, .filter = filter, .names = names, .nnames = 0,
1523 .maxnames = maxnames, .active = active, .error = false};
1524
1525 virObjectRWLockRead(nets);
1526 virHashForEach(nets->objs, virNetworkObjListGetHelper, &data);
1527 virObjectRWUnlock(nets);
1528
1529 if (data.error)
1530 goto cleanup;
1531
1532 ret = data.nnames;
1533 cleanup:
1534 if (ret < 0) {
1535 while (data.nnames)
1536 VIR_FREE(data.names[--data.nnames]);
1537 }
1538 return ret;
1539 }
1540
1541
1542 int
virNetworkObjListNumOfNetworks(virNetworkObjList * nets,bool active,virNetworkObjListFilter filter,virConnectPtr conn)1543 virNetworkObjListNumOfNetworks(virNetworkObjList *nets,
1544 bool active,
1545 virNetworkObjListFilter filter,
1546 virConnectPtr conn)
1547 {
1548 struct virNetworkObjListGetHelperData data = {
1549 .conn = conn, .filter = filter, .names = NULL, .nnames = 0,
1550 .maxnames = -1, .active = active, .error = false};
1551
1552 virObjectRWLockRead(nets);
1553 virHashForEach(nets->objs, virNetworkObjListGetHelper, &data);
1554 virObjectRWUnlock(nets);
1555
1556 return data.nnames;
1557 }
1558
1559
1560 struct virNetworkObjListPruneHelperData {
1561 unsigned int flags;
1562 };
1563
1564 static int
virNetworkObjListPruneHelper(const void * payload,const char * name G_GNUC_UNUSED,const void * opaque)1565 virNetworkObjListPruneHelper(const void *payload,
1566 const char *name G_GNUC_UNUSED,
1567 const void *opaque)
1568 {
1569 const struct virNetworkObjListPruneHelperData *data = opaque;
1570 virNetworkObj *obj = (virNetworkObj *) payload;
1571 int want = 0;
1572
1573 virObjectLock(obj);
1574 want = virNetworkObjMatch(obj, data->flags);
1575 virObjectUnlock(obj);
1576 return want;
1577 }
1578
1579
1580 /**
1581 * virNetworkObjListPrune:
1582 * @nets: a list of network objects
1583 * @flags: bitwise-OR of virConnectListAllNetworksFlags
1584 *
1585 * Iterate over list of network objects and remove the desired
1586 * ones from it.
1587 */
1588 void
virNetworkObjListPrune(virNetworkObjList * nets,unsigned int flags)1589 virNetworkObjListPrune(virNetworkObjList *nets,
1590 unsigned int flags)
1591 {
1592 struct virNetworkObjListPruneHelperData data = {flags};
1593
1594 virObjectRWLockWrite(nets);
1595 virHashRemoveSet(nets->objs, virNetworkObjListPruneHelper, &data);
1596 virObjectRWUnlock(nets);
1597 }
1598
1599
1600 char *
virNetworkObjGetPortStatusDir(virNetworkObj * net,const char * stateDir)1601 virNetworkObjGetPortStatusDir(virNetworkObj *net,
1602 const char *stateDir)
1603 {
1604 return g_strdup_printf("%s/%s/ports", stateDir, net->def->name);
1605 }
1606
1607 int
virNetworkObjAddPort(virNetworkObj * net,virNetworkPortDef * portdef,const char * stateDir)1608 virNetworkObjAddPort(virNetworkObj *net,
1609 virNetworkPortDef *portdef,
1610 const char *stateDir)
1611 {
1612 char uuidstr[VIR_UUID_STRING_BUFLEN];
1613 g_autofree char *dir = NULL;
1614
1615 virUUIDFormat(portdef->uuid, uuidstr);
1616
1617 if (virHashLookup(net->ports, uuidstr)) {
1618 virReportError(VIR_ERR_NETWORK_PORT_EXIST,
1619 _("Network port with UUID %s already exists"),
1620 uuidstr);
1621 return -1;
1622 }
1623
1624 if (!(dir = virNetworkObjGetPortStatusDir(net, stateDir)))
1625 return -1;
1626
1627 if (virHashAddEntry(net->ports, uuidstr, portdef) < 0)
1628 return -1;
1629
1630 if (virNetworkPortDefSaveStatus(portdef, dir) < 0) {
1631 virHashRemoveEntry(net->ports, uuidstr);
1632 return -1;
1633 }
1634
1635 return 0;
1636 }
1637
1638
1639 virNetworkPortDef *
virNetworkObjLookupPort(virNetworkObj * net,const unsigned char * uuid)1640 virNetworkObjLookupPort(virNetworkObj *net,
1641 const unsigned char *uuid)
1642 {
1643 virNetworkPortDef *ret = NULL;
1644 char uuidstr[VIR_UUID_STRING_BUFLEN];
1645
1646 virUUIDFormat(uuid, uuidstr);
1647
1648 if (!(ret = virHashLookup(net->ports, uuidstr))) {
1649 virReportError(VIR_ERR_NO_NETWORK_PORT,
1650 _("Network port with UUID %s does not exist"),
1651 uuidstr);
1652 return NULL;
1653 }
1654
1655 return ret;
1656 }
1657
1658
1659 int
virNetworkObjDeletePort(virNetworkObj * net,const unsigned char * uuid,const char * stateDir)1660 virNetworkObjDeletePort(virNetworkObj *net,
1661 const unsigned char *uuid,
1662 const char *stateDir)
1663 {
1664 char uuidstr[VIR_UUID_STRING_BUFLEN];
1665 g_autofree char *dir = NULL;
1666 virNetworkPortDef *portdef;
1667
1668 virUUIDFormat(uuid, uuidstr);
1669
1670 if (!(portdef = virHashLookup(net->ports, uuidstr))) {
1671 virReportError(VIR_ERR_NO_NETWORK_PORT,
1672 _("Network port with UUID %s does not exist"),
1673 uuidstr);
1674 return -1;
1675 }
1676
1677 if (!(dir = virNetworkObjGetPortStatusDir(net, stateDir)))
1678 return -1;
1679
1680 if (virNetworkPortDefDeleteStatus(portdef, dir) < 0)
1681 return -1;
1682
1683 if (virHashRemoveEntry(net->ports, uuidstr) < 0)
1684 return -1;
1685
1686 return 0;
1687 }
1688
1689
1690 int
virNetworkObjDeleteAllPorts(virNetworkObj * net,const char * stateDir)1691 virNetworkObjDeleteAllPorts(virNetworkObj *net,
1692 const char *stateDir)
1693 {
1694 g_autofree char *dir = NULL;
1695 g_autoptr(DIR) dh = NULL;
1696 struct dirent *de;
1697 int rc;
1698
1699 if (!(dir = virNetworkObjGetPortStatusDir(net, stateDir)))
1700 return -1;
1701
1702 if ((rc = virDirOpenIfExists(&dh, dir)) <= 0)
1703 return rc;
1704
1705 while ((rc = virDirRead(dh, &de, dir)) > 0) {
1706 char *file = NULL;
1707
1708 if (!virStringStripSuffix(de->d_name, ".xml"))
1709 continue;
1710
1711 file = g_strdup_printf("%s/%s.xml", dir, de->d_name);
1712
1713 if (unlink(file) < 0 && errno != ENOENT)
1714 VIR_WARN("Unable to delete %s", file);
1715
1716 VIR_FREE(file);
1717 }
1718
1719 virHashRemoveAll(net->ports);
1720 return 0;
1721 }
1722
1723
1724 typedef struct _virNetworkObjPortListExportData virNetworkObjPortListExportData;
1725 struct _virNetworkObjPortListExportData {
1726 virNetworkPtr net;
1727 virNetworkDef *def;
1728 virNetworkPortPtr *ports;
1729 virNetworkPortListFilter filter;
1730 int nports;
1731 bool error;
1732 };
1733
1734 static int
virNetworkObjPortListExportCallback(void * payload,const char * name G_GNUC_UNUSED,void * opaque)1735 virNetworkObjPortListExportCallback(void *payload,
1736 const char *name G_GNUC_UNUSED,
1737 void *opaque)
1738 {
1739 virNetworkObjPortListExportData *data = opaque;
1740 virNetworkPortDef *def = payload;
1741 virNetworkPortPtr port;
1742
1743 if (data->error)
1744 return 0;
1745
1746 if (data->filter &&
1747 !data->filter(data->net->conn, data->def, def))
1748 return 0;
1749
1750 if (!data->ports) {
1751 data->nports++;
1752 return 0;
1753 }
1754
1755 if (!(port = virGetNetworkPort(data->net, def->uuid))) {
1756 data->error = true;
1757 return 0;
1758 }
1759
1760 data->ports[data->nports++] = port;
1761
1762 return 0;
1763 }
1764
1765
1766 int
virNetworkObjPortListExport(virNetworkPtr net,virNetworkObj * obj,virNetworkPortPtr ** ports,virNetworkPortListFilter filter)1767 virNetworkObjPortListExport(virNetworkPtr net,
1768 virNetworkObj *obj,
1769 virNetworkPortPtr **ports,
1770 virNetworkPortListFilter filter)
1771 {
1772 virNetworkObjPortListExportData data = {
1773 net, obj->def, NULL, filter, 0, false,
1774 };
1775 int ret = -1;
1776
1777 if (ports) {
1778 *ports = NULL;
1779
1780 data.ports = g_new0(virNetworkPortPtr, virHashSize(obj->ports) + 1);
1781 }
1782
1783 virHashForEach(obj->ports, virNetworkObjPortListExportCallback, &data);
1784
1785 if (data.error)
1786 goto cleanup;
1787
1788 if (data.ports) {
1789 /* trim the array to the final size */
1790 VIR_REALLOC_N(data.ports, data.nports + 1);
1791 *ports = g_steal_pointer(&data.ports);
1792 }
1793
1794 ret = data.nports;
1795 cleanup:
1796 while (data.ports && data.nports)
1797 virObjectUnref(data.ports[--data.nports]);
1798
1799 VIR_FREE(data.ports);
1800 return ret;
1801 }
1802
1803
1804 typedef struct _virNetworkObjPortListForEachData virNetworkObjPortListForEachData;
1805 struct _virNetworkObjPortListForEachData {
1806 virNetworkPortListIter iter;
1807 void *opaque;
1808 bool err;
1809 };
1810
1811 static int
virNetworkObjPortForEachCallback(void * payload,const char * name G_GNUC_UNUSED,void * opaque)1812 virNetworkObjPortForEachCallback(void *payload,
1813 const char *name G_GNUC_UNUSED,
1814 void *opaque)
1815 {
1816 virNetworkObjPortListForEachData *data = opaque;
1817
1818 if (!data->iter(payload, data->opaque))
1819 data->err = true;
1820
1821 return 0;
1822 }
1823
1824 int
virNetworkObjPortForEach(virNetworkObj * obj,virNetworkPortListIter iter,void * opaque)1825 virNetworkObjPortForEach(virNetworkObj *obj,
1826 virNetworkPortListIter iter,
1827 void *opaque)
1828 {
1829 virNetworkObjPortListForEachData data = { iter, opaque, false };
1830 virHashForEachSafe(obj->ports, virNetworkObjPortForEachCallback, &data);
1831 if (data.err)
1832 return -1;
1833 return 0;
1834 }
1835
1836
1837 static int
virNetworkObjLoadAllPorts(virNetworkObj * net,const char * stateDir)1838 virNetworkObjLoadAllPorts(virNetworkObj *net,
1839 const char *stateDir)
1840 {
1841 g_autofree char *dir = NULL;
1842 g_autoptr(DIR) dh = NULL;
1843 struct dirent *de;
1844 int rc;
1845 char uuidstr[VIR_UUID_STRING_BUFLEN];
1846 g_autoptr(virNetworkPortDef) portdef = NULL;
1847
1848 if (!(dir = virNetworkObjGetPortStatusDir(net, stateDir)))
1849 return -1;
1850
1851 if ((rc = virDirOpenIfExists(&dh, dir)) <= 0)
1852 return rc;
1853
1854 while ((rc = virDirRead(dh, &de, dir)) > 0) {
1855 g_autofree char *file = NULL;
1856
1857 if (!virStringStripSuffix(de->d_name, ".xml"))
1858 continue;
1859
1860 file = g_strdup_printf("%s/%s.xml", dir, de->d_name);
1861
1862 portdef = virNetworkPortDefParseFile(file);
1863 if (!portdef) {
1864 VIR_WARN("Cannot parse port %s", file);
1865 continue;
1866 }
1867
1868 virUUIDFormat(portdef->uuid, uuidstr);
1869 if (virHashAddEntry(net->ports, uuidstr, portdef) < 0)
1870 return -1;
1871
1872 portdef = NULL;
1873 }
1874
1875 return 0;
1876 }
1877