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