2017-03-08 10:25:24 -05:00
|
|
|
/*
|
|
|
|
* virnetworkobj.c: handle network objects
|
|
|
|
* (derived from network_conf.c)
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library. If not, see
|
|
|
|
* <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
|
|
|
|
#include "datatypes.h"
|
|
|
|
#include "virnetworkobj.h"
|
|
|
|
|
|
|
|
#include "viralloc.h"
|
|
|
|
#include "virerror.h"
|
|
|
|
#include "virfile.h"
|
|
|
|
#include "virhash.h"
|
|
|
|
#include "virlog.h"
|
|
|
|
#include "virstring.h"
|
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_NETWORK
|
|
|
|
|
|
|
|
VIR_LOG_INIT("conf.virnetworkobj");
|
|
|
|
|
2017-08-16 12:55:03 +02:00
|
|
|
/* Currently, /sbin/tc implementation allows up to 16 bits for
|
|
|
|
* minor class size. But the initial bitmap doesn't have to be
|
|
|
|
* that big. */
|
|
|
|
#define INIT_CLASS_ID_BITMAP_SIZE (1<<4)
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2017-05-12 08:40:04 -04:00
|
|
|
struct _virNetworkObj {
|
|
|
|
virObjectLockable parent;
|
|
|
|
|
|
|
|
pid_t dnsmasqPid;
|
|
|
|
bool active;
|
|
|
|
bool autostart;
|
|
|
|
bool persistent;
|
|
|
|
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkDef *def; /* The current definition */
|
|
|
|
virNetworkDef *newDef; /* New definition to activate at shutdown */
|
2017-05-12 08:40:04 -04:00
|
|
|
|
2021-03-11 08:16:13 +01:00
|
|
|
virBitmap *classIdMap; /* bitmap of class IDs for QoS */
|
2017-05-12 08:40:04 -04:00
|
|
|
unsigned long long floor_sum; /* sum of all 'floor'-s of attached NICs */
|
|
|
|
|
|
|
|
unsigned int taint;
|
|
|
|
|
|
|
|
/* Immutable pointer, self locking APIs */
|
2021-03-11 08:16:13 +01:00
|
|
|
virMacMap *macmap;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
2021-03-11 08:16:13 +01:00
|
|
|
GHashTable *ports; /* uuid -> virNetworkPortDef **/
|
2017-05-12 08:40:04 -04:00
|
|
|
};
|
|
|
|
|
2017-03-08 10:25:24 -05:00
|
|
|
struct _virNetworkObjList {
|
2017-10-10 10:02:32 -04:00
|
|
|
virObjectRWLockable parent;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2020-10-22 19:04:18 +02:00
|
|
|
GHashTable *objs;
|
2017-03-08 10:25:24 -05:00
|
|
|
};
|
|
|
|
|
2021-03-11 08:16:13 +01:00
|
|
|
static virClass *virNetworkObjClass;
|
|
|
|
static virClass *virNetworkObjListClass;
|
2017-03-08 10:25:24 -05:00
|
|
|
static void virNetworkObjDispose(void *obj);
|
|
|
|
static void virNetworkObjListDispose(void *obj);
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
static int
|
|
|
|
virNetworkObjOnceInit(void)
|
2017-03-08 10:25:24 -05:00
|
|
|
{
|
2018-04-17 17:42:33 +02:00
|
|
|
if (!VIR_CLASS_NEW(virNetworkObj, virClassForObjectLockable()))
|
2017-03-08 10:25:24 -05:00
|
|
|
return -1;
|
|
|
|
|
2018-04-17 17:42:33 +02:00
|
|
|
if (!VIR_CLASS_NEW(virNetworkObjList, virClassForObjectRWLockable()))
|
2017-03-08 10:25:24 -05:00
|
|
|
return -1;
|
2018-04-17 17:42:33 +02:00
|
|
|
|
2017-03-08 10:25:24 -05:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-01-20 12:23:29 -05:00
|
|
|
VIR_ONCE_GLOBAL_INIT(virNetworkObj);
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2018-12-19 14:24:53 +00:00
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjLoadAllPorts(virNetworkObj *net,
|
2018-12-19 14:24:53 +00:00
|
|
|
const char *stateDir);
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2019-11-21 19:27:58 +00:00
|
|
|
virNetworkObjPortFree(void *val)
|
2018-12-19 14:24:53 +00:00
|
|
|
{
|
|
|
|
virNetworkPortDefFree(val);
|
|
|
|
}
|
|
|
|
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObj *
|
2017-03-08 10:25:24 -05:00
|
|
|
virNetworkObjNew(void)
|
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObj *obj;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
|
|
|
if (virNetworkObjInitialize() < 0)
|
|
|
|
return NULL;
|
|
|
|
|
2017-05-10 07:59:48 -04:00
|
|
|
if (!(obj = virObjectLockableNew(virNetworkObjClass)))
|
2017-03-08 10:25:24 -05:00
|
|
|
return NULL;
|
|
|
|
|
2020-10-01 17:42:11 +02:00
|
|
|
obj->classIdMap = virBitmapNew(INIT_CLASS_ID_BITMAP_SIZE);
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2021-07-23 10:46:40 +02:00
|
|
|
/* The first three class IDs are already taken. */
|
|
|
|
ignore_value(virBitmapSetBit(obj->classIdMap, 0));
|
|
|
|
ignore_value(virBitmapSetBit(obj->classIdMap, 1));
|
|
|
|
ignore_value(virBitmapSetBit(obj->classIdMap, 2));
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2021-07-06 09:16:06 +02:00
|
|
|
obj->ports = virHashNew(virNetworkObjPortFree);
|
2023-04-17 10:10:04 +02:00
|
|
|
obj->dnsmasqPid = (pid_t)-1;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
2017-05-10 08:40:40 -04:00
|
|
|
virObjectLock(obj);
|
|
|
|
|
2017-05-10 07:59:48 -04:00
|
|
|
return obj;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2017-03-08 10:25:24 -05:00
|
|
|
void
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjEndAPI(virNetworkObj **obj)
|
2017-03-08 10:25:24 -05:00
|
|
|
{
|
2017-05-10 07:59:48 -04:00
|
|
|
if (!*obj)
|
2017-03-08 10:25:24 -05:00
|
|
|
return;
|
|
|
|
|
2017-05-10 07:59:48 -04:00
|
|
|
virObjectUnlock(*obj);
|
2022-01-28 18:42:45 +01:00
|
|
|
g_clear_pointer(obj, virObjectUnref);
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkDef *
|
|
|
|
virNetworkObjGetDef(virNetworkObj *obj)
|
2017-05-09 18:38:58 -04:00
|
|
|
{
|
|
|
|
return obj->def;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjSetDef(virNetworkObj *obj,
|
|
|
|
virNetworkDef *def)
|
2017-05-09 18:38:58 -04:00
|
|
|
{
|
|
|
|
obj->def = def;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkDef *
|
|
|
|
virNetworkObjGetNewDef(virNetworkObj *obj)
|
2017-05-09 18:38:58 -04:00
|
|
|
{
|
|
|
|
return obj->newDef;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-10 07:22:15 -04:00
|
|
|
bool
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjIsActive(virNetworkObj *obj)
|
2017-05-10 07:22:15 -04:00
|
|
|
{
|
|
|
|
return obj->active;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjSetActive(virNetworkObj *obj,
|
2017-05-10 07:22:15 -04:00
|
|
|
bool active)
|
|
|
|
{
|
|
|
|
obj->active = active;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-10 07:29:57 -04:00
|
|
|
bool
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjIsPersistent(virNetworkObj *obj)
|
2017-05-10 07:29:57 -04:00
|
|
|
{
|
|
|
|
return obj->persistent;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-10 07:12:27 -04:00
|
|
|
bool
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjIsAutostart(virNetworkObj *obj)
|
2017-05-10 07:12:27 -04:00
|
|
|
{
|
|
|
|
return obj->autostart;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjSetAutostart(virNetworkObj *obj,
|
2017-05-10 07:12:27 -04:00
|
|
|
bool autostart)
|
|
|
|
{
|
|
|
|
obj->autostart = autostart;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-09 17:22:43 -04:00
|
|
|
pid_t
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjGetDnsmasqPid(virNetworkObj *obj)
|
2017-05-09 17:22:43 -04:00
|
|
|
{
|
|
|
|
return obj->dnsmasqPid;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjSetDnsmasqPid(virNetworkObj *obj,
|
2017-05-09 17:22:43 -04:00
|
|
|
pid_t dnsmasqPid)
|
|
|
|
{
|
|
|
|
obj->dnsmasqPid = dnsmasqPid;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 08:16:13 +01:00
|
|
|
virBitmap *
|
|
|
|
virNetworkObjGetClassIdMap(virNetworkObj *obj)
|
2017-05-09 17:41:23 -04:00
|
|
|
{
|
|
|
|
return obj->classIdMap;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 08:16:13 +01:00
|
|
|
virMacMap *
|
|
|
|
virNetworkObjGetMacMap(virNetworkObj *obj)
|
2017-05-09 16:51:05 -04:00
|
|
|
{
|
|
|
|
return obj->macmap;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-09 17:57:41 -04:00
|
|
|
unsigned long long
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjGetFloorSum(virNetworkObj *obj)
|
2017-05-09 17:57:41 -04:00
|
|
|
{
|
|
|
|
return obj->floor_sum;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjSetFloorSum(virNetworkObj *obj,
|
2017-05-09 17:57:41 -04:00
|
|
|
unsigned long long floor_sum)
|
|
|
|
{
|
|
|
|
obj->floor_sum = floor_sum;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-09 16:51:05 -04:00
|
|
|
void
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjSetMacMap(virNetworkObj *obj,
|
2022-08-09 11:38:43 +02:00
|
|
|
virMacMap **macmap)
|
2017-05-09 16:51:05 -04:00
|
|
|
{
|
2022-08-09 11:38:43 +02:00
|
|
|
obj->macmap = g_steal_pointer(macmap);
|
2017-05-09 16:51:05 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjUnrefMacMap(virNetworkObj *obj)
|
2017-05-09 16:51:05 -04:00
|
|
|
{
|
2022-01-28 18:42:45 +01:00
|
|
|
g_clear_pointer(&obj->macmap, virObjectUnref);
|
2017-05-09 16:51:05 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjMacMgrAdd(virNetworkObj *obj,
|
2017-05-09 16:51:05 -04:00
|
|
|
const char *dnsmasqStateDir,
|
|
|
|
const char *domain,
|
|
|
|
const virMacAddr *mac)
|
|
|
|
{
|
|
|
|
char macStr[VIR_MAC_STRING_BUFLEN];
|
2023-01-06 17:18:31 +08:00
|
|
|
g_autofree char *file = NULL;
|
2017-05-09 16:51:05 -04:00
|
|
|
|
|
|
|
if (!obj->macmap)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
virMacAddrFormat(mac, macStr);
|
|
|
|
|
|
|
|
if (!(file = virMacMapFileName(dnsmasqStateDir, obj->def->bridge)))
|
2023-01-06 17:18:31 +08:00
|
|
|
return -1;
|
2017-05-09 16:51:05 -04:00
|
|
|
|
|
|
|
if (virMacMapAdd(obj->macmap, domain, macStr) < 0)
|
2023-01-06 17:18:31 +08:00
|
|
|
return -1;
|
2017-05-09 16:51:05 -04:00
|
|
|
|
|
|
|
if (virMacMapWriteFile(obj->macmap, file) < 0)
|
2023-01-06 17:18:31 +08:00
|
|
|
return -1;
|
2017-05-09 16:51:05 -04:00
|
|
|
|
2023-01-06 17:18:31 +08:00
|
|
|
return 0;
|
2017-05-09 16:51:05 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjMacMgrDel(virNetworkObj *obj,
|
2017-05-09 16:51:05 -04:00
|
|
|
const char *dnsmasqStateDir,
|
|
|
|
const char *domain,
|
|
|
|
const virMacAddr *mac)
|
|
|
|
{
|
|
|
|
char macStr[VIR_MAC_STRING_BUFLEN];
|
2023-01-06 17:18:31 +08:00
|
|
|
g_autofree char *file = NULL;
|
2017-05-09 16:51:05 -04:00
|
|
|
|
|
|
|
if (!obj->macmap)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
virMacAddrFormat(mac, macStr);
|
|
|
|
|
|
|
|
if (!(file = virMacMapFileName(dnsmasqStateDir, obj->def->bridge)))
|
2023-01-06 17:18:31 +08:00
|
|
|
return -1;
|
2017-05-09 16:51:05 -04:00
|
|
|
|
|
|
|
if (virMacMapRemove(obj->macmap, domain, macStr) < 0)
|
2023-01-06 17:18:31 +08:00
|
|
|
return -1;
|
2017-05-09 16:51:05 -04:00
|
|
|
|
|
|
|
if (virMacMapWriteFile(obj->macmap, file) < 0)
|
2023-01-06 17:18:31 +08:00
|
|
|
return -1;
|
2017-05-09 16:51:05 -04:00
|
|
|
|
2023-01-06 17:18:31 +08:00
|
|
|
return 0;
|
2017-05-09 16:51:05 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjList *
|
2017-03-08 10:41:57 -05:00
|
|
|
virNetworkObjListNew(void)
|
2017-03-08 10:25:24 -05:00
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjList *nets;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
|
|
|
if (virNetworkObjInitialize() < 0)
|
|
|
|
return NULL;
|
|
|
|
|
2017-10-10 10:02:32 -04:00
|
|
|
if (!(nets = virObjectRWLockableNew(virNetworkObjListClass)))
|
2017-03-08 10:25:24 -05:00
|
|
|
return NULL;
|
|
|
|
|
2022-07-13 15:26:51 -05:00
|
|
|
nets->objs = virHashNew(virObjectUnref);
|
2017-03-08 10:25:24 -05:00
|
|
|
|
|
|
|
return nets;
|
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2021-03-11 08:16:13 +01:00
|
|
|
static virNetworkObj *
|
|
|
|
virNetworkObjFindByUUIDLocked(virNetworkObjList *nets,
|
2017-03-08 10:25:24 -05:00
|
|
|
const unsigned char *uuid)
|
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObj *obj = NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
|
|
|
|
virUUIDFormat(uuid, uuidstr);
|
|
|
|
|
2017-05-10 07:59:48 -04:00
|
|
|
obj = virHashLookup(nets->objs, uuidstr);
|
|
|
|
if (obj)
|
|
|
|
virObjectRef(obj);
|
|
|
|
return obj;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2017-03-08 10:25:24 -05:00
|
|
|
/**
|
|
|
|
* virNetworkObjFindByUUID:
|
|
|
|
* @nets: list of network objects
|
|
|
|
* @uuid: network uuid to find
|
|
|
|
*
|
|
|
|
* This functions locks @nets and find network object which
|
|
|
|
* corresponds to @uuid.
|
|
|
|
*
|
|
|
|
* Returns: locked and ref'd network object.
|
|
|
|
*/
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObj *
|
|
|
|
virNetworkObjFindByUUID(virNetworkObjList *nets,
|
2017-03-08 10:25:24 -05:00
|
|
|
const unsigned char *uuid)
|
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObj *obj;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2017-10-10 10:02:32 -04:00
|
|
|
virObjectRWLockRead(nets);
|
2017-05-10 07:59:48 -04:00
|
|
|
obj = virNetworkObjFindByUUIDLocked(nets, uuid);
|
2017-10-10 10:02:32 -04:00
|
|
|
virObjectRWUnlock(nets);
|
2017-05-10 07:59:48 -04:00
|
|
|
if (obj)
|
|
|
|
virObjectLock(obj);
|
|
|
|
return obj;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2017-03-08 10:25:24 -05:00
|
|
|
static int
|
|
|
|
virNetworkObjSearchName(const void *payload,
|
2020-10-21 13:31:16 +02:00
|
|
|
const char *name G_GNUC_UNUSED,
|
2017-03-08 10:25:24 -05:00
|
|
|
const void *data)
|
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObj *obj = (virNetworkObj *) payload;
|
2017-03-08 10:25:24 -05:00
|
|
|
int want = 0;
|
|
|
|
|
2017-05-10 07:59:48 -04:00
|
|
|
virObjectLock(obj);
|
|
|
|
if (STREQ(obj->def->name, (const char *)data))
|
2017-03-08 10:25:24 -05:00
|
|
|
want = 1;
|
2017-05-10 07:59:48 -04:00
|
|
|
virObjectUnlock(obj);
|
2017-03-08 10:25:24 -05:00
|
|
|
return want;
|
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2021-03-11 08:16:13 +01:00
|
|
|
static virNetworkObj *
|
|
|
|
virNetworkObjFindByNameLocked(virNetworkObjList *nets,
|
2017-03-08 10:25:24 -05:00
|
|
|
const char *name)
|
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObj *obj = NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2017-05-10 07:59:48 -04:00
|
|
|
obj = virHashSearch(nets->objs, virNetworkObjSearchName, name, NULL);
|
|
|
|
if (obj)
|
|
|
|
virObjectRef(obj);
|
|
|
|
return obj;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2017-03-08 10:25:24 -05:00
|
|
|
/**
|
|
|
|
* virNetworkObjFindByName:
|
|
|
|
* @nets: list of network objects
|
|
|
|
* @name: network name to find
|
|
|
|
*
|
|
|
|
* This functions locks @nets and find network object which
|
|
|
|
* corresponds to @name.
|
|
|
|
*
|
|
|
|
* Returns: locked and ref'd network object.
|
|
|
|
*/
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObj *
|
|
|
|
virNetworkObjFindByName(virNetworkObjList *nets,
|
2017-03-08 10:25:24 -05:00
|
|
|
const char *name)
|
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObj *obj;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2017-10-10 10:02:32 -04:00
|
|
|
virObjectRWLockRead(nets);
|
2017-05-10 07:59:48 -04:00
|
|
|
obj = virNetworkObjFindByNameLocked(nets, name);
|
2017-10-10 10:02:32 -04:00
|
|
|
virObjectRWUnlock(nets);
|
2017-05-10 07:59:48 -04:00
|
|
|
if (obj)
|
|
|
|
virObjectLock(obj);
|
|
|
|
return obj;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2017-03-08 10:25:24 -05:00
|
|
|
bool
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjTaint(virNetworkObj *obj,
|
2017-03-08 10:25:24 -05:00
|
|
|
virNetworkTaintFlags taint)
|
|
|
|
{
|
|
|
|
unsigned int flag = (1 << taint);
|
|
|
|
|
|
|
|
if (obj->taint & flag)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
obj->taint |= flag;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2017-05-10 07:59:48 -04:00
|
|
|
virNetworkObjDispose(void *opaque)
|
2017-03-08 10:25:24 -05:00
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObj *obj = opaque;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2021-11-30 14:13:28 +01:00
|
|
|
g_clear_pointer(&obj->ports, g_hash_table_unref);
|
2017-05-10 07:59:48 -04:00
|
|
|
virNetworkDefFree(obj->def);
|
|
|
|
virNetworkDefFree(obj->newDef);
|
|
|
|
virBitmapFree(obj->classIdMap);
|
|
|
|
virObjectUnref(obj->macmap);
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2017-03-08 10:25:24 -05:00
|
|
|
static void
|
2017-05-10 07:59:48 -04:00
|
|
|
virNetworkObjListDispose(void *opaque)
|
2017-03-08 10:25:24 -05:00
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjList *nets = opaque;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2021-11-30 14:13:28 +01:00
|
|
|
g_clear_pointer(&nets->objs, g_hash_table_unref);
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2017-03-08 10:25:24 -05:00
|
|
|
/*
|
2017-03-08 11:19:20 -05:00
|
|
|
* virNetworkObjUpdateAssignDef:
|
2017-03-08 10:25:24 -05:00
|
|
|
* @network: the network object to update
|
|
|
|
* @def: the new NetworkDef (will be consumed by this function)
|
|
|
|
* @live: is this new def the "live" version, or the "persistent" version
|
|
|
|
*
|
|
|
|
* Replace the appropriate copy of the given network's def or newDef
|
|
|
|
* with def. Use "live" and current state of the network to determine
|
|
|
|
* which to replace and what to do with the old defs. When a non-live
|
|
|
|
* def is set, indicate that the network is now persistent.
|
|
|
|
*
|
|
|
|
* NB: a persistent network can be made transient by calling with:
|
|
|
|
* virNetworkObjAssignDef(network, NULL, false) (i.e. set the
|
|
|
|
* persistent def to NULL)
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjUpdateAssignDef(virNetworkObj *obj,
|
|
|
|
virNetworkDef *def,
|
2017-03-08 11:19:20 -05:00
|
|
|
bool live)
|
2017-03-08 10:25:24 -05:00
|
|
|
{
|
|
|
|
if (live) {
|
|
|
|
/* before setting new live def, save (into newDef) any
|
|
|
|
* existing persistent (!live) def to be restored when the
|
|
|
|
* network is destroyed, unless there is one already saved.
|
|
|
|
*/
|
2017-05-10 07:59:48 -04:00
|
|
|
if (obj->persistent && !obj->newDef)
|
|
|
|
obj->newDef = obj->def;
|
2017-03-08 10:25:24 -05:00
|
|
|
else
|
2017-05-10 07:59:48 -04:00
|
|
|
virNetworkDefFree(obj->def);
|
|
|
|
obj->def = def;
|
2017-03-08 10:25:24 -05:00
|
|
|
} else { /* !live */
|
2017-05-10 07:59:48 -04:00
|
|
|
virNetworkDefFree(obj->newDef);
|
|
|
|
if (virNetworkObjIsActive(obj)) {
|
2017-03-08 10:25:24 -05:00
|
|
|
/* save new configuration to be restored on network
|
|
|
|
* shutdown, leaving current live def alone
|
|
|
|
*/
|
2017-05-10 07:59:48 -04:00
|
|
|
obj->newDef = def;
|
2017-03-08 10:25:24 -05:00
|
|
|
} else { /* !live and !active */
|
2017-05-10 07:59:48 -04:00
|
|
|
if (obj->def && !obj->persistent) {
|
2017-03-08 10:25:24 -05:00
|
|
|
/* network isn't (yet) marked active or persistent,
|
|
|
|
* but already has a "live" def set. This means we are
|
|
|
|
* currently setting the persistent def as a part of
|
|
|
|
* the process of starting the network, so we need to
|
|
|
|
* preserve the "not yet live" def in network->def.
|
|
|
|
*/
|
2017-05-10 07:59:48 -04:00
|
|
|
obj->newDef = def;
|
2017-03-08 10:25:24 -05:00
|
|
|
} else {
|
|
|
|
/* either there is no live def set, or this network
|
|
|
|
* was already set as persistent, so the proper thing
|
|
|
|
* is to overwrite network->def.
|
|
|
|
*/
|
2017-05-10 07:59:48 -04:00
|
|
|
obj->newDef = NULL;
|
|
|
|
virNetworkDefFree(obj->def);
|
|
|
|
obj->def = def;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
}
|
2017-05-10 07:59:48 -04:00
|
|
|
obj->persistent = !!def;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2017-03-08 10:25:24 -05:00
|
|
|
/*
|
|
|
|
* If flags & VIR_NETWORK_OBJ_LIST_ADD_CHECK_LIVE then this will
|
|
|
|
* refuse updating an existing def if the current def is live
|
|
|
|
*
|
|
|
|
* If flags & VIR_NETWORK_OBJ_LIST_ADD_LIVE then the @def being
|
|
|
|
* added is assumed to represent a live config, not a future
|
|
|
|
* inactive config
|
|
|
|
*
|
|
|
|
* If flags is zero, network is considered as inactive and persistent.
|
|
|
|
*/
|
2021-03-11 08:16:13 +01:00
|
|
|
static virNetworkObj *
|
|
|
|
virNetworkObjAssignDefLocked(virNetworkObjList *nets,
|
|
|
|
virNetworkDef *def,
|
2017-03-08 11:41:18 -05:00
|
|
|
unsigned int flags)
|
2017-03-08 10:25:24 -05:00
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObj *obj;
|
|
|
|
virNetworkObj *ret = NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
|
|
|
|
/* See if a network with matching UUID already exists */
|
2017-05-10 07:59:48 -04:00
|
|
|
if ((obj = virNetworkObjFindByUUIDLocked(nets, def->uuid))) {
|
|
|
|
virObjectLock(obj);
|
2017-03-08 10:25:24 -05:00
|
|
|
/* UUID matches, but if names don't match, refuse it */
|
2017-05-10 07:59:48 -04:00
|
|
|
if (STRNEQ(obj->def->name, def->name)) {
|
|
|
|
virUUIDFormat(obj->def->uuid, uuidstr);
|
2017-03-08 10:25:24 -05:00
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED,
|
2023-03-09 11:20:54 +01:00
|
|
|
_("network '%1$s' is already defined with uuid %2$s"),
|
2017-05-10 07:59:48 -04:00
|
|
|
obj->def->name, uuidstr);
|
2017-03-08 10:25:24 -05:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & VIR_NETWORK_OBJ_LIST_ADD_CHECK_LIVE) {
|
|
|
|
/* UUID & name match, but if network is already active, refuse it */
|
2017-05-10 07:59:48 -04:00
|
|
|
if (virNetworkObjIsActive(obj)) {
|
2017-03-08 10:25:24 -05:00
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
2023-03-09 11:20:54 +01:00
|
|
|
_("network is already active as '%1$s'"),
|
2017-05-10 07:59:48 -04:00
|
|
|
obj->def->name);
|
2017-03-08 10:25:24 -05:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-10 07:59:48 -04:00
|
|
|
virNetworkObjUpdateAssignDef(obj, def,
|
2017-03-08 11:19:20 -05:00
|
|
|
!!(flags & VIR_NETWORK_OBJ_LIST_ADD_LIVE));
|
2017-03-08 10:25:24 -05:00
|
|
|
} else {
|
|
|
|
/* UUID does not match, but if a name matches, refuse it */
|
2017-05-10 07:59:48 -04:00
|
|
|
if ((obj = virNetworkObjFindByNameLocked(nets, def->name))) {
|
|
|
|
virObjectLock(obj);
|
|
|
|
virUUIDFormat(obj->def->uuid, uuidstr);
|
2017-03-08 10:25:24 -05:00
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED,
|
2023-03-09 11:20:54 +01:00
|
|
|
_("network '%1$s' already exists with uuid %2$s"),
|
2017-03-08 10:25:24 -05:00
|
|
|
def->name, uuidstr);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2017-05-10 07:59:48 -04:00
|
|
|
if (!(obj = virNetworkObjNew()))
|
2017-03-08 10:25:24 -05:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
virUUIDFormat(def->uuid, uuidstr);
|
2017-05-10 07:59:48 -04:00
|
|
|
if (virHashAddEntry(nets->objs, uuidstr, obj) < 0)
|
2017-03-08 10:25:24 -05:00
|
|
|
goto cleanup;
|
2017-07-26 09:43:12 -04:00
|
|
|
virObjectRef(obj);
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2017-05-10 07:59:48 -04:00
|
|
|
obj->def = def;
|
|
|
|
obj->persistent = !(flags & VIR_NETWORK_OBJ_LIST_ADD_LIVE);
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
2019-10-16 13:43:01 +02:00
|
|
|
ret = g_steal_pointer(&obj);
|
2017-03-08 10:25:24 -05:00
|
|
|
|
|
|
|
cleanup:
|
2017-05-10 07:59:48 -04:00
|
|
|
virNetworkObjEndAPI(&obj);
|
2017-03-08 10:25:24 -05:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2017-03-08 10:25:24 -05:00
|
|
|
/*
|
2017-03-08 11:41:18 -05:00
|
|
|
* virNetworkObjAssignDef:
|
2017-03-08 10:25:24 -05:00
|
|
|
* @nets: list of all networks
|
|
|
|
* @def: the new NetworkDef (will be consumed by this function iff successful)
|
|
|
|
* @flags: bitwise-OR of VIR_NETWORK_OBJ_LIST_ADD_* flags
|
|
|
|
*
|
|
|
|
* Either replace the appropriate copy of the NetworkDef with name
|
|
|
|
* matching def->name or, if not found, create a new NetworkObj with
|
|
|
|
* def. For an existing network, use "live" and current state of the
|
|
|
|
* network to determine which to replace.
|
|
|
|
*
|
2017-03-08 11:41:18 -05:00
|
|
|
* Look at virNetworkObjAssignDefLocked() for @flags description.
|
2017-03-08 10:25:24 -05:00
|
|
|
*
|
2021-03-11 08:16:13 +01:00
|
|
|
* Returns NULL on error, virNetworkObj *on success.
|
2017-03-08 10:25:24 -05:00
|
|
|
*/
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObj *
|
|
|
|
virNetworkObjAssignDef(virNetworkObjList *nets,
|
|
|
|
virNetworkDef *def,
|
2017-03-08 11:41:18 -05:00
|
|
|
unsigned int flags)
|
2017-03-08 10:25:24 -05:00
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObj *obj;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2017-10-10 10:02:32 -04:00
|
|
|
virObjectRWLockWrite(nets);
|
2017-05-10 07:59:48 -04:00
|
|
|
obj = virNetworkObjAssignDefLocked(nets, def, flags);
|
2017-10-10 10:02:32 -04:00
|
|
|
virObjectRWUnlock(nets);
|
2017-05-10 07:59:48 -04:00
|
|
|
return obj;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2017-03-08 10:25:24 -05:00
|
|
|
/*
|
|
|
|
* virNetworkObjSetDefTransient:
|
|
|
|
* @network: network object pointer
|
|
|
|
* @live: if true, run this operation even for an inactive network.
|
|
|
|
* this allows freely updated network->def with runtime defaults
|
|
|
|
* before starting the network, which will be discarded on network
|
|
|
|
* shutdown. Any cleanup paths need to be sure to handle newDef if
|
|
|
|
* the network is never started.
|
|
|
|
*
|
|
|
|
* Mark the active network config as transient. Ensures live-only update
|
|
|
|
* operations do not persist past network destroy.
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 on failure
|
|
|
|
*/
|
|
|
|
int
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjSetDefTransient(virNetworkObj *obj,
|
2019-07-14 12:15:12 -04:00
|
|
|
bool live,
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkXMLOption *xmlopt)
|
2017-03-08 10:25:24 -05:00
|
|
|
{
|
2017-05-10 07:59:48 -04:00
|
|
|
if (!virNetworkObjIsActive(obj) && !live)
|
2017-03-08 10:25:24 -05:00
|
|
|
return 0;
|
|
|
|
|
2017-05-10 07:59:48 -04:00
|
|
|
if (!obj->persistent || obj->newDef)
|
2017-03-08 10:25:24 -05:00
|
|
|
return 0;
|
|
|
|
|
2019-07-14 12:15:12 -04:00
|
|
|
obj->newDef = virNetworkDefCopy(obj->def,
|
|
|
|
xmlopt,
|
|
|
|
VIR_NETWORK_XML_INACTIVE);
|
2017-05-10 07:59:48 -04:00
|
|
|
return obj->newDef ? 0 : -1;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2017-03-08 10:25:24 -05:00
|
|
|
/* virNetworkObjUnsetDefTransient:
|
|
|
|
*
|
|
|
|
* This *undoes* what virNetworkObjSetDefTransient did.
|
|
|
|
*/
|
|
|
|
void
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjUnsetDefTransient(virNetworkObj *obj)
|
2017-03-08 10:25:24 -05:00
|
|
|
{
|
2017-05-10 07:59:48 -04:00
|
|
|
if (obj->newDef) {
|
|
|
|
virNetworkDefFree(obj->def);
|
2021-03-24 10:32:58 +01:00
|
|
|
obj->def = g_steal_pointer(&obj->newDef);
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2017-03-08 10:25:24 -05:00
|
|
|
/*
|
|
|
|
* virNetworkObjGetPersistentDef:
|
|
|
|
* @network: network object pointer
|
|
|
|
*
|
|
|
|
* Return the persistent network configuration. If network is transient,
|
|
|
|
* return the running config.
|
|
|
|
*
|
2021-03-11 08:16:13 +01:00
|
|
|
* Returns NULL on error, virNetworkDef *on success.
|
2017-03-08 10:25:24 -05:00
|
|
|
*/
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkDef *
|
|
|
|
virNetworkObjGetPersistentDef(virNetworkObj *obj)
|
2017-03-08 10:25:24 -05:00
|
|
|
{
|
2017-05-10 07:59:48 -04:00
|
|
|
if (obj->newDef)
|
|
|
|
return obj->newDef;
|
2017-03-08 10:25:24 -05:00
|
|
|
else
|
2017-05-10 07:59:48 -04:00
|
|
|
return obj->def;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2017-03-08 10:25:24 -05:00
|
|
|
/*
|
|
|
|
* virNetworkObjReplacePersistentDef:
|
|
|
|
* @network: network object pointer
|
|
|
|
* @def: new virNetworkDef to replace current persistent config
|
|
|
|
*
|
|
|
|
* Replace the "persistent" network configuration with the given new
|
|
|
|
* virNetworkDef. This pays attention to whether or not the network
|
|
|
|
* is active.
|
|
|
|
*
|
|
|
|
* Returns -1 on error, 0 on success
|
|
|
|
*/
|
|
|
|
int
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjReplacePersistentDef(virNetworkObj *obj,
|
|
|
|
virNetworkDef *def)
|
2017-03-08 10:25:24 -05:00
|
|
|
{
|
2017-05-10 07:59:48 -04:00
|
|
|
if (virNetworkObjIsActive(obj)) {
|
|
|
|
virNetworkDefFree(obj->newDef);
|
|
|
|
obj->newDef = def;
|
2017-03-08 10:25:24 -05:00
|
|
|
} else {
|
2017-05-10 07:59:48 -04:00
|
|
|
virNetworkDefFree(obj->def);
|
|
|
|
obj->def = def;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2017-03-08 10:25:24 -05:00
|
|
|
/*
|
2017-03-08 11:41:18 -05:00
|
|
|
* virNetworkObjConfigChangeSetup:
|
2017-03-08 10:25:24 -05:00
|
|
|
*
|
|
|
|
* 1) checks whether network state is consistent with the requested
|
|
|
|
* type of modification.
|
|
|
|
*
|
|
|
|
* 3) make sure there are separate "def" and "newDef" copies of
|
|
|
|
* networkDef if appropriate.
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 on error.
|
|
|
|
*/
|
2017-03-08 11:41:18 -05:00
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjConfigChangeSetup(virNetworkObj *obj,
|
2017-03-08 11:41:18 -05:00
|
|
|
unsigned int flags)
|
2017-03-08 10:25:24 -05:00
|
|
|
{
|
|
|
|
bool isActive;
|
|
|
|
|
2017-05-10 07:59:48 -04:00
|
|
|
isActive = virNetworkObjIsActive(obj);
|
2017-03-08 10:25:24 -05:00
|
|
|
|
|
|
|
if (!isActive && (flags & VIR_NETWORK_UPDATE_AFFECT_LIVE)) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("network is not running"));
|
2019-10-21 15:18:51 -03:00
|
|
|
return -1;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
2023-08-17 00:17:13 +05:30
|
|
|
if ((flags & VIR_NETWORK_UPDATE_AFFECT_CONFIG) &&
|
|
|
|
!obj->persistent) {
|
2017-03-08 10:25:24 -05:00
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
2023-08-17 00:17:13 +05:30
|
|
|
_("cannot change persistent config of a transient network"));
|
2019-10-21 15:18:51 -03:00
|
|
|
return -1;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
2019-10-21 15:18:51 -03:00
|
|
|
return 0;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
|
|
|
void
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjRemoveInactive(virNetworkObjList *nets,
|
|
|
|
virNetworkObj *obj)
|
2017-03-08 10:25:24 -05:00
|
|
|
{
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
|
2017-05-10 07:59:48 -04:00
|
|
|
virUUIDFormat(obj->def->uuid, uuidstr);
|
|
|
|
virObjectRef(obj);
|
|
|
|
virObjectUnlock(obj);
|
2017-10-10 10:02:32 -04:00
|
|
|
virObjectRWLockWrite(nets);
|
2017-05-10 07:59:48 -04:00
|
|
|
virObjectLock(obj);
|
2017-03-08 10:25:24 -05:00
|
|
|
virHashRemoveEntry(nets->objs, uuidstr);
|
2017-10-10 10:02:32 -04:00
|
|
|
virObjectRWUnlock(nets);
|
2017-05-10 07:59:48 -04:00
|
|
|
virObjectUnref(obj);
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2017-03-08 10:25:24 -05:00
|
|
|
static char *
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjFormat(virNetworkObj *obj,
|
|
|
|
virNetworkXMLOption *xmlopt,
|
2017-03-08 10:25:24 -05:00
|
|
|
unsigned int flags)
|
|
|
|
{
|
2020-07-02 22:19:01 -04:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2017-05-10 07:59:48 -04:00
|
|
|
char *classIdStr = virBitmapFormat(obj->classIdMap);
|
2017-03-08 10:25:24 -05:00
|
|
|
size_t i;
|
|
|
|
|
2017-07-26 08:01:55 -04:00
|
|
|
if (!classIdStr)
|
2020-07-02 23:19:26 -04:00
|
|
|
return NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
|
|
|
virBufferAddLit(&buf, "<networkstatus>\n");
|
|
|
|
virBufferAdjustIndent(&buf, 2);
|
2017-07-26 08:01:55 -04:00
|
|
|
virBufferAsprintf(&buf, "<class_id bitmap='%s'/>\n", classIdStr);
|
2017-05-10 07:59:48 -04:00
|
|
|
virBufferAsprintf(&buf, "<floor sum='%llu'/>\n", obj->floor_sum);
|
2017-07-26 08:01:55 -04:00
|
|
|
VIR_FREE(classIdStr);
|
2017-03-08 10:25:24 -05:00
|
|
|
|
|
|
|
for (i = 0; i < VIR_NETWORK_TAINT_LAST; i++) {
|
2017-05-10 07:59:48 -04:00
|
|
|
if (obj->taint & (1 << i))
|
2017-03-08 10:25:24 -05:00
|
|
|
virBufferAsprintf(&buf, "<taint flag='%s'/>\n",
|
|
|
|
virNetworkTaintTypeToString(i));
|
|
|
|
}
|
|
|
|
|
2019-07-14 12:15:12 -04:00
|
|
|
if (virNetworkDefFormatBuf(&buf, obj->def, xmlopt, flags) < 0)
|
2020-07-02 23:19:26 -04:00
|
|
|
return NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
|
|
|
virBufferAdjustIndent(&buf, -2);
|
|
|
|
virBufferAddLit(&buf, "</networkstatus>");
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
|
|
|
int
|
2017-03-08 11:41:18 -05:00
|
|
|
virNetworkObjSaveStatus(const char *statusDir,
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObj *obj,
|
|
|
|
virNetworkXMLOption *xmlopt)
|
2017-03-08 10:25:24 -05:00
|
|
|
{
|
|
|
|
int flags = 0;
|
2023-01-06 17:18:31 +08:00
|
|
|
g_autofree char *xml = NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2019-07-14 12:15:12 -04:00
|
|
|
if (!(xml = virNetworkObjFormat(obj, xmlopt, flags)))
|
2023-01-06 17:18:31 +08:00
|
|
|
return -1;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2017-05-10 07:59:48 -04:00
|
|
|
if (virNetworkSaveXML(statusDir, obj->def, xml))
|
2023-01-06 17:18:31 +08:00
|
|
|
return -1;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2023-01-06 17:18:31 +08:00
|
|
|
return 0;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2021-03-11 08:16:13 +01:00
|
|
|
static virNetworkObj *
|
|
|
|
virNetworkLoadState(virNetworkObjList *nets,
|
2017-03-08 10:25:24 -05:00
|
|
|
const char *stateDir,
|
2019-07-14 12:15:12 -04:00
|
|
|
const char *name,
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkXMLOption *xmlopt)
|
2017-03-08 10:25:24 -05:00
|
|
|
{
|
2021-08-17 12:45:13 +02:00
|
|
|
g_autofree char *configFile = NULL;
|
2022-08-18 13:24:41 -04:00
|
|
|
g_autoptr(virNetworkDef) def = NULL;
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObj *obj = NULL;
|
2021-08-17 12:45:13 +02:00
|
|
|
g_autoptr(xmlDoc) xml = NULL;
|
|
|
|
xmlNodePtr node = NULL;
|
|
|
|
g_autoptr(xmlXPathContext) ctxt = NULL;
|
|
|
|
g_autoptr(virBitmap) classIdMap = NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
unsigned long long floor_sum_val = 0;
|
|
|
|
unsigned int taint = 0;
|
|
|
|
int n;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
|
|
|
|
if ((configFile = virNetworkConfigFile(stateDir, name)) == NULL)
|
2022-08-18 13:28:39 -04:00
|
|
|
return NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2022-09-23 14:53:21 +02:00
|
|
|
if (!(xml = virXMLParseFileCtxt(configFile, &ctxt)))
|
2022-08-18 13:28:39 -04:00
|
|
|
return NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
|
|
|
if (!(node = virXPathNode("//network", ctxt))) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Could not find any 'network' element in status file"));
|
2022-08-18 13:28:39 -04:00
|
|
|
return NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* parse the definition first */
|
|
|
|
ctxt->node = node;
|
2019-07-14 12:15:12 -04:00
|
|
|
if (!(def = virNetworkDefParseXML(ctxt, xmlopt)))
|
2022-08-18 13:28:39 -04:00
|
|
|
return NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
|
|
|
if (STRNEQ(name, def->name)) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2023-03-09 11:20:54 +01:00
|
|
|
_("Network config filename '%1$s' does not match network name '%2$s'"),
|
2017-03-08 10:25:24 -05:00
|
|
|
configFile, def->name);
|
2022-08-18 13:28:39 -04:00
|
|
|
return NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* now parse possible status data */
|
|
|
|
node = xmlDocGetRootElement(xml);
|
2017-08-14 14:31:52 +02:00
|
|
|
if (virXMLNodeNameEqual(node, "networkstatus")) {
|
2017-03-08 10:25:24 -05:00
|
|
|
/* Newer network status file. Contains useful
|
|
|
|
* info which are not to be found in bare config XML */
|
2021-08-17 12:45:13 +02:00
|
|
|
g_autofree char *classIdStr = NULL;
|
|
|
|
g_autofree char *floor_sum = NULL;
|
|
|
|
g_autofree xmlNodePtr *nodes = NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
|
|
|
ctxt->node = node;
|
2017-07-26 08:01:55 -04:00
|
|
|
if ((classIdStr = virXPathString("string(./class_id[1]/@bitmap)",
|
|
|
|
ctxt))) {
|
2021-08-17 12:45:13 +02:00
|
|
|
if (!(classIdMap = virBitmapParseUnlimited(classIdStr)))
|
2022-08-18 13:28:39 -04:00
|
|
|
return NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
floor_sum = virXPathString("string(./floor[1]/@sum)", ctxt);
|
|
|
|
if (floor_sum &&
|
|
|
|
virStrToLong_ull(floor_sum, NULL, 10, &floor_sum_val) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2023-03-09 11:20:54 +01:00
|
|
|
_("Malformed 'floor_sum' attribute: %1$s"),
|
2017-03-08 10:25:24 -05:00
|
|
|
floor_sum);
|
2022-08-18 13:28:39 -04:00
|
|
|
return NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((n = virXPathNodeSet("./taint", ctxt, &nodes)) < 0)
|
2022-08-18 13:28:39 -04:00
|
|
|
return NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
2021-08-17 12:45:13 +02:00
|
|
|
g_autofree char *str = virXMLPropString(nodes[i], "flag");
|
2017-03-08 10:25:24 -05:00
|
|
|
if (str) {
|
|
|
|
int flag = virNetworkTaintTypeFromString(str);
|
|
|
|
if (flag < 0) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
2023-03-09 11:20:54 +01:00
|
|
|
_("Unknown taint flag %1$s"), str);
|
2022-08-18 13:28:39 -04:00
|
|
|
return NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
/* Compute taint mask here. The network object does not
|
|
|
|
* exist yet, so we can't use virNetworkObjtTaint. */
|
|
|
|
taint |= (1 << flag);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* create the object */
|
2022-08-18 13:28:39 -04:00
|
|
|
if (!(obj = virNetworkObjAssignDef(nets, def, VIR_NETWORK_OBJ_LIST_ADD_LIVE)))
|
|
|
|
return NULL;
|
|
|
|
|
2022-08-18 13:24:41 -04:00
|
|
|
def = NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
|
|
|
/* assign status data stored in the network object */
|
2017-07-26 08:01:55 -04:00
|
|
|
if (classIdMap) {
|
2017-05-10 07:59:48 -04:00
|
|
|
virBitmapFree(obj->classIdMap);
|
2021-08-17 12:45:13 +02:00
|
|
|
obj->classIdMap = g_steal_pointer(&classIdMap);
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if (floor_sum_val > 0)
|
2017-05-10 07:59:48 -04:00
|
|
|
obj->floor_sum = floor_sum_val;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2017-05-10 07:59:48 -04:00
|
|
|
obj->taint = taint;
|
|
|
|
obj->active = true; /* network with a state file is by definition active */
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2017-05-10 07:59:48 -04:00
|
|
|
return obj;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2021-03-11 08:16:13 +01:00
|
|
|
static virNetworkObj *
|
|
|
|
virNetworkLoadConfig(virNetworkObjList *nets,
|
2017-03-08 10:41:57 -05:00
|
|
|
const char *configDir,
|
|
|
|
const char *autostartDir,
|
2019-07-14 12:15:12 -04:00
|
|
|
const char *name,
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkXMLOption *xmlopt)
|
2017-03-08 10:25:24 -05:00
|
|
|
{
|
2023-01-06 17:18:31 +08:00
|
|
|
g_autofree char *configFile = NULL;
|
|
|
|
g_autofree char *autostartLink = NULL;
|
2022-08-18 13:24:41 -04:00
|
|
|
g_autoptr(virNetworkDef) def = NULL;
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObj *obj;
|
conf: Write network config to disk after generating UUID
While we generally expect libvirt objects to be defined using the
appropriate APIs, there are cases where it's reasonable for an
external entity, usually a package manager, to drop a valid
configuration file under /etc/libvirt and have libvirt take over
from there: notably, this is exactly how the default network is
handled.
For the most part, whether the configuration is saved back to disk
after being parsed by libvirt doesn't matter, because we'll end up
with the same values anyway, but an obvious exception to this is
data that gets randomly generated when not present, namely MAC
address and UUID.
Historically, both were handled by our build system, but commit
a47ae7c004e9 moved handling of the former inside libvirt proper;
this commit extends such behavior to the latter as well.
Proper error handling for the virNetworkSaveConfig() call, which
was missing until now, is introduced in the process.
Signed-off-by: Andrea Bolognani <abologna@redhat.com>
Reviewed-by: Laine Stump <laine@redhat.com>
2020-11-19 16:08:13 +01:00
|
|
|
bool saveConfig = false;
|
2017-03-08 10:25:24 -05:00
|
|
|
int autostart;
|
|
|
|
|
|
|
|
if ((configFile = virNetworkConfigFile(configDir, name)) == NULL)
|
2023-01-06 17:18:31 +08:00
|
|
|
return NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
if ((autostartLink = virNetworkConfigFile(autostartDir, name)) == NULL)
|
2023-01-06 17:18:31 +08:00
|
|
|
return NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
|
|
|
if ((autostart = virFileLinkPointsTo(autostartLink, configFile)) < 0)
|
2023-01-06 17:18:31 +08:00
|
|
|
return NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2022-09-23 13:28:44 +02:00
|
|
|
if (!(def = virNetworkDefParse(NULL, configFile, xmlopt, false)))
|
2023-01-06 17:18:31 +08:00
|
|
|
return NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
|
|
|
if (STRNEQ(name, def->name)) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2023-03-09 11:20:54 +01:00
|
|
|
_("Network config filename '%1$s' does not match network name '%2$s'"),
|
2017-03-08 10:25:24 -05:00
|
|
|
configFile, def->name);
|
2023-01-06 17:18:31 +08:00
|
|
|
return NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
2018-07-24 11:49:48 +08:00
|
|
|
switch ((virNetworkForwardType) def->forward.type) {
|
|
|
|
case VIR_NETWORK_FORWARD_NONE:
|
|
|
|
case VIR_NETWORK_FORWARD_NAT:
|
|
|
|
case VIR_NETWORK_FORWARD_ROUTE:
|
|
|
|
case VIR_NETWORK_FORWARD_OPEN:
|
2017-03-08 10:25:24 -05:00
|
|
|
if (!def->mac_specified) {
|
|
|
|
virNetworkSetBridgeMacAddr(def);
|
conf: Write network config to disk after generating UUID
While we generally expect libvirt objects to be defined using the
appropriate APIs, there are cases where it's reasonable for an
external entity, usually a package manager, to drop a valid
configuration file under /etc/libvirt and have libvirt take over
from there: notably, this is exactly how the default network is
handled.
For the most part, whether the configuration is saved back to disk
after being parsed by libvirt doesn't matter, because we'll end up
with the same values anyway, but an obvious exception to this is
data that gets randomly generated when not present, namely MAC
address and UUID.
Historically, both were handled by our build system, but commit
a47ae7c004e9 moved handling of the former inside libvirt proper;
this commit extends such behavior to the latter as well.
Proper error handling for the virNetworkSaveConfig() call, which
was missing until now, is introduced in the process.
Signed-off-by: Andrea Bolognani <abologna@redhat.com>
Reviewed-by: Laine Stump <laine@redhat.com>
2020-11-19 16:08:13 +01:00
|
|
|
/* We just generated a new MAC address, and we need to persist
|
|
|
|
* the configuration to disk to avoid the network getting a
|
|
|
|
* different one the next time the daemon is started */
|
|
|
|
saveConfig = true;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
2018-07-24 11:49:48 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_NETWORK_FORWARD_BRIDGE:
|
|
|
|
case VIR_NETWORK_FORWARD_PRIVATE:
|
|
|
|
case VIR_NETWORK_FORWARD_VEPA:
|
|
|
|
case VIR_NETWORK_FORWARD_PASSTHROUGH:
|
|
|
|
case VIR_NETWORK_FORWARD_HOSTDEV:
|
2017-03-08 10:25:24 -05:00
|
|
|
/* Throw away MAC address for other forward types,
|
|
|
|
* which could have been generated by older libvirt RPMs */
|
|
|
|
def->mac_specified = false;
|
2018-07-24 11:49:48 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_NETWORK_FORWARD_LAST:
|
|
|
|
default:
|
|
|
|
virReportEnumRangeError(virNetworkForwardType, def->forward.type);
|
2023-01-06 17:18:31 +08:00
|
|
|
return NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
conf: Write network config to disk after generating UUID
While we generally expect libvirt objects to be defined using the
appropriate APIs, there are cases where it's reasonable for an
external entity, usually a package manager, to drop a valid
configuration file under /etc/libvirt and have libvirt take over
from there: notably, this is exactly how the default network is
handled.
For the most part, whether the configuration is saved back to disk
after being parsed by libvirt doesn't matter, because we'll end up
with the same values anyway, but an obvious exception to this is
data that gets randomly generated when not present, namely MAC
address and UUID.
Historically, both were handled by our build system, but commit
a47ae7c004e9 moved handling of the former inside libvirt proper;
this commit extends such behavior to the latter as well.
Proper error handling for the virNetworkSaveConfig() call, which
was missing until now, is introduced in the process.
Signed-off-by: Andrea Bolognani <abologna@redhat.com>
Reviewed-by: Laine Stump <laine@redhat.com>
2020-11-19 16:08:13 +01:00
|
|
|
/* The network didn't have a UUID so we generated a new one, and
|
|
|
|
* we need to persist the configuration to disk to avoid the network
|
|
|
|
* getting a different one the next time the daemon is started */
|
|
|
|
if (!def->uuid_specified)
|
|
|
|
saveConfig = true;
|
|
|
|
|
|
|
|
if (saveConfig &&
|
|
|
|
virNetworkSaveConfig(configDir, def, xmlopt) < 0) {
|
2023-01-06 17:18:31 +08:00
|
|
|
return NULL;
|
conf: Write network config to disk after generating UUID
While we generally expect libvirt objects to be defined using the
appropriate APIs, there are cases where it's reasonable for an
external entity, usually a package manager, to drop a valid
configuration file under /etc/libvirt and have libvirt take over
from there: notably, this is exactly how the default network is
handled.
For the most part, whether the configuration is saved back to disk
after being parsed by libvirt doesn't matter, because we'll end up
with the same values anyway, but an obvious exception to this is
data that gets randomly generated when not present, namely MAC
address and UUID.
Historically, both were handled by our build system, but commit
a47ae7c004e9 moved handling of the former inside libvirt proper;
this commit extends such behavior to the latter as well.
Proper error handling for the virNetworkSaveConfig() call, which
was missing until now, is introduced in the process.
Signed-off-by: Andrea Bolognani <abologna@redhat.com>
Reviewed-by: Laine Stump <laine@redhat.com>
2020-11-19 16:08:13 +01:00
|
|
|
}
|
|
|
|
|
2017-05-10 07:59:48 -04:00
|
|
|
if (!(obj = virNetworkObjAssignDef(nets, def, 0)))
|
2023-01-06 17:18:31 +08:00
|
|
|
return NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2022-08-18 13:24:41 -04:00
|
|
|
def = NULL;
|
|
|
|
|
2017-05-10 07:59:48 -04:00
|
|
|
obj->autostart = (autostart == 1);
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2017-05-10 07:59:48 -04:00
|
|
|
return obj;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjLoadAllState(virNetworkObjList *nets,
|
2019-07-14 12:15:12 -04:00
|
|
|
const char *stateDir,
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkXMLOption *xmlopt)
|
2017-03-08 10:25:24 -05:00
|
|
|
{
|
2020-10-25 17:50:51 -04:00
|
|
|
g_autoptr(DIR) dir = NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
struct dirent *entry;
|
|
|
|
int ret = -1;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if ((rc = virDirOpenIfExists(&dir, stateDir)) <= 0)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
while ((ret = virDirRead(dir, &entry, stateDir)) > 0) {
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObj *obj;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2019-03-06 15:30:04 +01:00
|
|
|
if (!virStringStripSuffix(entry->d_name, ".xml"))
|
2017-03-08 10:25:24 -05:00
|
|
|
continue;
|
|
|
|
|
2019-07-14 12:15:12 -04:00
|
|
|
obj = virNetworkLoadState(nets, stateDir, entry->d_name, xmlopt);
|
2018-12-19 14:24:53 +00:00
|
|
|
|
|
|
|
if (obj &&
|
|
|
|
virNetworkObjLoadAllPorts(obj, stateDir) < 0) {
|
|
|
|
virNetworkObjEndAPI(&obj);
|
2020-10-27 17:49:11 -04:00
|
|
|
return -1;
|
2018-12-19 14:24:53 +00:00
|
|
|
}
|
2017-05-10 07:59:48 -04:00
|
|
|
virNetworkObjEndAPI(&obj);
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
int
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjLoadAllConfigs(virNetworkObjList *nets,
|
2017-03-08 11:41:18 -05:00
|
|
|
const char *configDir,
|
2019-07-14 12:15:12 -04:00
|
|
|
const char *autostartDir,
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkXMLOption *xmlopt)
|
2017-03-08 10:25:24 -05:00
|
|
|
{
|
2020-10-25 17:50:51 -04:00
|
|
|
g_autoptr(DIR) dir = NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
struct dirent *entry;
|
|
|
|
int ret = -1;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if ((rc = virDirOpenIfExists(&dir, configDir)) <= 0)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
while ((ret = virDirRead(dir, &entry, configDir)) > 0) {
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObj *obj;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2019-03-06 15:30:04 +01:00
|
|
|
if (!virStringStripSuffix(entry->d_name, ".xml"))
|
2017-03-08 10:25:24 -05:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/* NB: ignoring errors, so one malformed config doesn't
|
|
|
|
kill the whole process */
|
2017-05-10 07:59:48 -04:00
|
|
|
obj = virNetworkLoadConfig(nets,
|
2017-03-08 10:25:24 -05:00
|
|
|
configDir,
|
|
|
|
autostartDir,
|
2019-07-14 12:15:12 -04:00
|
|
|
entry->d_name,
|
|
|
|
xmlopt);
|
2017-05-10 07:59:48 -04:00
|
|
|
virNetworkObjEndAPI(&obj);
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
|
|
|
int
|
2017-03-08 11:41:18 -05:00
|
|
|
virNetworkObjDeleteConfig(const char *configDir,
|
|
|
|
const char *autostartDir,
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObj *obj)
|
2017-03-08 10:25:24 -05:00
|
|
|
{
|
2023-01-06 17:18:31 +08:00
|
|
|
g_autofree char *configFile = NULL;
|
|
|
|
g_autofree char *autostartLink = NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2017-05-10 07:59:48 -04:00
|
|
|
if (!(configFile = virNetworkConfigFile(configDir, obj->def->name)))
|
2023-01-06 17:18:31 +08:00
|
|
|
return -1;
|
2017-05-10 07:59:48 -04:00
|
|
|
if (!(autostartLink = virNetworkConfigFile(autostartDir, obj->def->name)))
|
2023-01-06 17:18:31 +08:00
|
|
|
return -1;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
|
|
|
/* Not fatal if this doesn't work */
|
|
|
|
unlink(autostartLink);
|
2017-05-10 07:59:48 -04:00
|
|
|
obj->autostart = false;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
|
|
|
if (unlink(configFile) < 0) {
|
|
|
|
virReportSystemError(errno,
|
2023-03-09 11:20:54 +01:00
|
|
|
_("cannot remove config file '%1$s'"),
|
2017-03-08 10:25:24 -05:00
|
|
|
configFile);
|
2023-01-06 17:18:31 +08:00
|
|
|
return -1;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
2023-01-06 17:18:31 +08:00
|
|
|
return 0;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2017-03-08 11:41:18 -05:00
|
|
|
struct virNetworkObjBridgeInUseHelperData {
|
2017-03-08 10:25:24 -05:00
|
|
|
const char *bridge;
|
|
|
|
const char *skipname;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
2017-03-08 11:41:18 -05:00
|
|
|
virNetworkObjBridgeInUseHelper(const void *payload,
|
2020-10-21 13:31:16 +02:00
|
|
|
const char *name G_GNUC_UNUSED,
|
2017-03-08 11:41:18 -05:00
|
|
|
const void *opaque)
|
2017-03-08 10:25:24 -05:00
|
|
|
{
|
|
|
|
int ret;
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObj *obj = (virNetworkObj *) payload;
|
2017-03-08 11:41:18 -05:00
|
|
|
const struct virNetworkObjBridgeInUseHelperData *data = opaque;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2017-05-10 07:59:48 -04:00
|
|
|
virObjectLock(obj);
|
2017-03-08 10:25:24 -05:00
|
|
|
if (data->skipname &&
|
2017-05-10 07:59:48 -04:00
|
|
|
((obj->def && STREQ(obj->def->name, data->skipname)) ||
|
|
|
|
(obj->newDef && STREQ(obj->newDef->name, data->skipname))))
|
2017-03-08 10:25:24 -05:00
|
|
|
ret = 0;
|
2017-05-10 07:59:48 -04:00
|
|
|
else if ((obj->def && obj->def->bridge &&
|
|
|
|
STREQ(obj->def->bridge, data->bridge)) ||
|
|
|
|
(obj->newDef && obj->newDef->bridge &&
|
|
|
|
STREQ(obj->newDef->bridge, data->bridge)))
|
2017-03-08 10:25:24 -05:00
|
|
|
ret = 1;
|
|
|
|
else
|
|
|
|
ret = 0;
|
2017-05-10 07:59:48 -04:00
|
|
|
virObjectUnlock(obj);
|
2017-03-08 10:25:24 -05:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2017-08-17 15:41:37 -04:00
|
|
|
bool
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjBridgeInUse(virNetworkObjList *nets,
|
2017-03-08 11:41:18 -05:00
|
|
|
const char *bridge,
|
|
|
|
const char *skipname)
|
2017-03-08 10:25:24 -05:00
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObj *obj;
|
2017-03-08 11:41:18 -05:00
|
|
|
struct virNetworkObjBridgeInUseHelperData data = {bridge, skipname};
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2017-10-10 10:02:32 -04:00
|
|
|
virObjectRWLockRead(nets);
|
2017-06-13 15:56:14 +02:00
|
|
|
obj = virHashSearch(nets->objs, virNetworkObjBridgeInUseHelper, &data, NULL);
|
2017-10-10 10:02:32 -04:00
|
|
|
virObjectRWUnlock(nets);
|
2017-03-08 10:25:24 -05:00
|
|
|
|
|
|
|
return obj != NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* virNetworkObjUpdate:
|
|
|
|
*
|
|
|
|
* Apply the supplied update to the given virNetworkObj. Except for
|
|
|
|
* @network pointing to an actual network object rather than the
|
|
|
|
* opaque virNetworkPtr, parameters are identical to the public API
|
|
|
|
* virNetworkUpdate.
|
|
|
|
*
|
|
|
|
* The original virNetworkDefs are copied, and all modifications made
|
|
|
|
* to these copies. The originals are replaced with the copies only
|
|
|
|
* after success has been guaranteed.
|
|
|
|
*
|
|
|
|
* Returns: -1 on error, 0 on success.
|
|
|
|
*/
|
|
|
|
int
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjUpdate(virNetworkObj *obj,
|
2017-03-08 10:25:24 -05:00
|
|
|
unsigned int command, /* virNetworkUpdateCommand */
|
|
|
|
unsigned int section, /* virNetworkUpdateSection */
|
|
|
|
int parentIndex,
|
|
|
|
const char *xml,
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkXMLOption *xmlopt,
|
2017-03-08 10:25:24 -05:00
|
|
|
unsigned int flags) /* virNetworkUpdateFlags */
|
|
|
|
{
|
2022-08-18 13:24:41 -04:00
|
|
|
g_autoptr(virNetworkDef) livedef = NULL;
|
|
|
|
g_autoptr(virNetworkDef) configdef = NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
|
|
|
/* normalize config data, and check for common invalid requests. */
|
2023-08-17 00:17:13 +05:30
|
|
|
if (virNetworkObjConfigChangeSetup(obj, flags) < 0)
|
2022-08-18 13:28:39 -04:00
|
|
|
return -1;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
|
|
|
if (flags & VIR_NETWORK_UPDATE_AFFECT_LIVE) {
|
2022-08-18 13:24:41 -04:00
|
|
|
g_autoptr(virNetworkDef) checkdef = NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
|
|
|
/* work on a copy of the def */
|
2019-07-14 12:15:12 -04:00
|
|
|
if (!(livedef = virNetworkDefCopy(obj->def, xmlopt, 0)))
|
2022-08-18 13:28:39 -04:00
|
|
|
return -1;
|
|
|
|
|
2017-03-08 10:25:24 -05:00
|
|
|
if (virNetworkDefUpdateSection(livedef, command, section,
|
|
|
|
parentIndex, xml, flags) < 0) {
|
2022-08-18 13:28:39 -04:00
|
|
|
return -1;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
/* run a final format/parse cycle to make sure we didn't
|
|
|
|
* add anything illegal to the def
|
|
|
|
*/
|
2019-07-14 12:15:12 -04:00
|
|
|
if (!(checkdef = virNetworkDefCopy(livedef, xmlopt, 0)))
|
2022-08-18 13:28:39 -04:00
|
|
|
return -1;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & VIR_NETWORK_UPDATE_AFFECT_CONFIG) {
|
2022-08-18 13:24:41 -04:00
|
|
|
g_autoptr(virNetworkDef) checkdef = NULL;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
|
|
|
/* work on a copy of the def */
|
2017-05-10 07:59:48 -04:00
|
|
|
if (!(configdef = virNetworkDefCopy(virNetworkObjGetPersistentDef(obj),
|
2019-07-14 12:15:12 -04:00
|
|
|
xmlopt,
|
2017-03-08 10:25:24 -05:00
|
|
|
VIR_NETWORK_XML_INACTIVE))) {
|
2022-08-18 13:28:39 -04:00
|
|
|
return -1;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
if (virNetworkDefUpdateSection(configdef, command, section,
|
|
|
|
parentIndex, xml, flags) < 0) {
|
2022-08-18 13:28:39 -04:00
|
|
|
return -1;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
if (!(checkdef = virNetworkDefCopy(configdef,
|
2019-07-14 12:15:12 -04:00
|
|
|
xmlopt,
|
2017-03-08 10:25:24 -05:00
|
|
|
VIR_NETWORK_XML_INACTIVE))) {
|
2022-08-18 13:28:39 -04:00
|
|
|
return -1;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (configdef) {
|
|
|
|
/* successfully modified copy, now replace original */
|
2017-05-10 07:59:48 -04:00
|
|
|
if (virNetworkObjReplacePersistentDef(obj, configdef) < 0)
|
2022-08-18 13:28:39 -04:00
|
|
|
return -1;
|
|
|
|
|
2017-03-08 10:25:24 -05:00
|
|
|
configdef = NULL;
|
|
|
|
}
|
|
|
|
if (livedef) {
|
|
|
|
/* successfully modified copy, now replace original */
|
2017-05-10 07:59:48 -04:00
|
|
|
virNetworkDefFree(obj->def);
|
2021-03-24 10:32:58 +01:00
|
|
|
obj->def = g_steal_pointer(&livedef);
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
2022-08-18 13:28:39 -04:00
|
|
|
return 0;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2017-03-08 10:25:24 -05:00
|
|
|
#define MATCH(FLAG) (flags & (FLAG))
|
|
|
|
static bool
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjMatch(virNetworkObj *obj,
|
2018-08-13 11:55:16 -04:00
|
|
|
unsigned int flags)
|
2017-03-08 10:25:24 -05:00
|
|
|
{
|
|
|
|
/* filter by active state */
|
|
|
|
if (MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_ACTIVE) &&
|
|
|
|
!((MATCH(VIR_CONNECT_LIST_NETWORKS_ACTIVE) &&
|
2017-05-10 07:59:48 -04:00
|
|
|
virNetworkObjIsActive(obj)) ||
|
2017-03-08 10:25:24 -05:00
|
|
|
(MATCH(VIR_CONNECT_LIST_NETWORKS_INACTIVE) &&
|
2017-05-10 07:59:48 -04:00
|
|
|
!virNetworkObjIsActive(obj))))
|
2017-03-08 10:25:24 -05:00
|
|
|
return false;
|
|
|
|
|
|
|
|
/* filter by persistence */
|
|
|
|
if (MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_PERSISTENT) &&
|
|
|
|
!((MATCH(VIR_CONNECT_LIST_NETWORKS_PERSISTENT) &&
|
2017-05-10 07:59:48 -04:00
|
|
|
obj->persistent) ||
|
2017-03-08 10:25:24 -05:00
|
|
|
(MATCH(VIR_CONNECT_LIST_NETWORKS_TRANSIENT) &&
|
2017-05-10 07:59:48 -04:00
|
|
|
!obj->persistent)))
|
2017-03-08 10:25:24 -05:00
|
|
|
return false;
|
|
|
|
|
|
|
|
/* filter by autostart option */
|
|
|
|
if (MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_AUTOSTART) &&
|
|
|
|
!((MATCH(VIR_CONNECT_LIST_NETWORKS_AUTOSTART) &&
|
2017-05-10 07:59:48 -04:00
|
|
|
obj->autostart) ||
|
2017-03-08 10:25:24 -05:00
|
|
|
(MATCH(VIR_CONNECT_LIST_NETWORKS_NO_AUTOSTART) &&
|
2017-05-10 07:59:48 -04:00
|
|
|
!obj->autostart)))
|
2017-03-08 10:25:24 -05:00
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
#undef MATCH
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2018-08-13 11:55:14 -04:00
|
|
|
typedef struct _virNetworkObjListExportData virNetworkObjListExportData;
|
|
|
|
struct _virNetworkObjListExportData {
|
2017-03-08 10:25:24 -05:00
|
|
|
virConnectPtr conn;
|
|
|
|
virNetworkPtr *nets;
|
|
|
|
virNetworkObjListFilter filter;
|
|
|
|
unsigned int flags;
|
|
|
|
int nnets;
|
|
|
|
bool error;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
2018-08-13 11:55:15 -04:00
|
|
|
virNetworkObjListExportCallback(void *payload,
|
2020-10-21 13:31:16 +02:00
|
|
|
const char *name G_GNUC_UNUSED,
|
2018-08-13 11:55:15 -04:00
|
|
|
void *opaque)
|
2017-03-08 10:25:24 -05:00
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjListExportData *data = opaque;
|
|
|
|
virNetworkObj *obj = payload;
|
2017-03-08 10:25:24 -05:00
|
|
|
virNetworkPtr net = NULL;
|
|
|
|
|
|
|
|
if (data->error)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
virObjectLock(obj);
|
|
|
|
|
|
|
|
if (data->filter &&
|
|
|
|
!data->filter(data->conn, obj->def))
|
|
|
|
goto cleanup;
|
|
|
|
|
2018-08-13 11:55:16 -04:00
|
|
|
if (!virNetworkObjMatch(obj, data->flags))
|
2017-03-08 10:25:24 -05:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!data->nets) {
|
|
|
|
data->nnets++;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(net = virGetNetwork(data->conn, obj->def->name, obj->def->uuid))) {
|
|
|
|
data->error = true;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
data->nets[data->nnets++] = net;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virObjectUnlock(obj);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2017-03-08 10:25:24 -05:00
|
|
|
int
|
|
|
|
virNetworkObjListExport(virConnectPtr conn,
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjList *netobjs,
|
2017-03-08 10:25:24 -05:00
|
|
|
virNetworkPtr **nets,
|
|
|
|
virNetworkObjListFilter filter,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
2018-08-13 11:55:14 -04:00
|
|
|
virNetworkObjListExportData data = {
|
2017-05-10 08:58:38 -04:00
|
|
|
.conn = conn, .nets = NULL, .filter = filter, .flags = flags,
|
|
|
|
.nnets = 0, .error = false };
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2017-10-10 10:02:32 -04:00
|
|
|
virObjectRWLockRead(netobjs);
|
2020-10-07 21:15:50 +02:00
|
|
|
if (nets)
|
2020-10-12 19:45:37 +02:00
|
|
|
data.nets = g_new0(virNetworkPtr, virHashSize(netobjs->objs) + 1);
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2018-08-13 11:55:15 -04:00
|
|
|
virHashForEach(netobjs->objs, virNetworkObjListExportCallback, &data);
|
2017-03-08 10:25:24 -05:00
|
|
|
|
|
|
|
if (data.error)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (data.nets) {
|
|
|
|
/* trim the array to the final size */
|
2021-03-20 00:37:05 +01:00
|
|
|
VIR_REALLOC_N(data.nets, data.nnets + 1);
|
2021-03-24 10:32:58 +01:00
|
|
|
*nets = g_steal_pointer(&data.nets);
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = data.nnets;
|
|
|
|
cleanup:
|
2017-10-10 10:02:32 -04:00
|
|
|
virObjectRWUnlock(netobjs);
|
2017-03-08 10:25:24 -05:00
|
|
|
while (data.nets && data.nnets)
|
|
|
|
virObjectUnref(data.nets[--data.nnets]);
|
|
|
|
|
|
|
|
VIR_FREE(data.nets);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2017-03-08 10:25:24 -05:00
|
|
|
struct virNetworkObjListForEachHelperData {
|
|
|
|
virNetworkObjListIterator callback;
|
|
|
|
void *opaque;
|
|
|
|
int ret;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
|
|
virNetworkObjListForEachHelper(void *payload,
|
2020-10-21 13:31:16 +02:00
|
|
|
const char *name G_GNUC_UNUSED,
|
2017-03-08 10:25:24 -05:00
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
struct virNetworkObjListForEachHelperData *data = opaque;
|
|
|
|
|
|
|
|
if (data->callback(payload, data->opaque) < 0)
|
|
|
|
data->ret = -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2017-03-08 10:25:24 -05:00
|
|
|
/**
|
|
|
|
* virNetworkObjListForEach:
|
|
|
|
* @nets: a list of network objects
|
|
|
|
* @callback: function to call over each of object in the list
|
|
|
|
* @opaque: pointer to pass to the @callback
|
|
|
|
*
|
|
|
|
* Function iterates over the list of network objects and calls
|
|
|
|
* passed callback over each one of them. You should avoid
|
|
|
|
* calling those virNetworkObjList APIs, which lock the list
|
|
|
|
* again in favor of their virNetworkObj*Locked variants.
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, -1 otherwise.
|
|
|
|
*/
|
|
|
|
int
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjListForEach(virNetworkObjList *nets,
|
2017-03-08 10:25:24 -05:00
|
|
|
virNetworkObjListIterator callback,
|
|
|
|
void *opaque)
|
|
|
|
{
|
2017-05-10 08:58:38 -04:00
|
|
|
struct virNetworkObjListForEachHelperData data = {
|
|
|
|
.callback = callback, .opaque = opaque, .ret = 0};
|
2017-10-10 10:02:32 -04:00
|
|
|
virObjectRWLockRead(nets);
|
2020-10-23 09:49:36 +02:00
|
|
|
virHashForEachSafe(nets->objs, virNetworkObjListForEachHelper, &data);
|
2017-10-10 10:02:32 -04:00
|
|
|
virObjectRWUnlock(nets);
|
2017-03-08 10:25:24 -05:00
|
|
|
return data.ret;
|
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2017-03-08 10:25:24 -05:00
|
|
|
struct virNetworkObjListGetHelperData {
|
|
|
|
virConnectPtr conn;
|
|
|
|
virNetworkObjListFilter filter;
|
|
|
|
char **names;
|
2017-08-15 16:48:37 -04:00
|
|
|
int nnames;
|
2017-07-26 10:18:39 -04:00
|
|
|
int maxnames;
|
2017-03-08 10:25:24 -05:00
|
|
|
bool active;
|
|
|
|
bool error;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
|
|
virNetworkObjListGetHelper(void *payload,
|
2020-10-21 13:31:16 +02:00
|
|
|
const char *name G_GNUC_UNUSED,
|
2017-03-08 10:25:24 -05:00
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
struct virNetworkObjListGetHelperData *data = opaque;
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObj *obj = payload;
|
2017-03-08 10:25:24 -05:00
|
|
|
|
|
|
|
if (data->error)
|
|
|
|
return 0;
|
|
|
|
|
2017-07-26 10:18:39 -04:00
|
|
|
if (data->maxnames >= 0 &&
|
2017-08-15 16:48:37 -04:00
|
|
|
data->nnames == data->maxnames)
|
2017-03-08 10:25:24 -05:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
virObjectLock(obj);
|
|
|
|
|
|
|
|
if (data->filter &&
|
|
|
|
!data->filter(data->conn, obj->def))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if ((data->active && virNetworkObjIsActive(obj)) ||
|
|
|
|
(!data->active && !virNetworkObjIsActive(obj))) {
|
2019-10-20 13:49:46 +02:00
|
|
|
if (data->names)
|
|
|
|
data->names[data->nnames] = g_strdup(obj->def->name);
|
2017-08-15 16:48:37 -04:00
|
|
|
data->nnames++;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virObjectUnlock(obj);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2017-03-08 10:25:24 -05:00
|
|
|
int
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjListGetNames(virNetworkObjList *nets,
|
2017-03-08 10:25:24 -05:00
|
|
|
bool active,
|
|
|
|
char **names,
|
2017-07-26 10:18:39 -04:00
|
|
|
int maxnames,
|
2017-03-08 10:25:24 -05:00
|
|
|
virNetworkObjListFilter filter,
|
|
|
|
virConnectPtr conn)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
struct virNetworkObjListGetHelperData data = {
|
2017-08-15 16:48:37 -04:00
|
|
|
.conn = conn, .filter = filter, .names = names, .nnames = 0,
|
|
|
|
.maxnames = maxnames, .active = active, .error = false};
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2017-10-10 10:02:32 -04:00
|
|
|
virObjectRWLockRead(nets);
|
2017-03-08 10:25:24 -05:00
|
|
|
virHashForEach(nets->objs, virNetworkObjListGetHelper, &data);
|
2017-10-10 10:02:32 -04:00
|
|
|
virObjectRWUnlock(nets);
|
2017-03-08 10:25:24 -05:00
|
|
|
|
|
|
|
if (data.error)
|
|
|
|
goto cleanup;
|
|
|
|
|
2017-08-15 16:48:37 -04:00
|
|
|
ret = data.nnames;
|
2017-03-08 10:25:24 -05:00
|
|
|
cleanup:
|
|
|
|
if (ret < 0) {
|
2017-08-15 16:48:37 -04:00
|
|
|
while (data.nnames)
|
|
|
|
VIR_FREE(data.names[--data.nnames]);
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2017-03-08 10:25:24 -05:00
|
|
|
int
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjListNumOfNetworks(virNetworkObjList *nets,
|
2017-03-08 10:25:24 -05:00
|
|
|
bool active,
|
|
|
|
virNetworkObjListFilter filter,
|
|
|
|
virConnectPtr conn)
|
|
|
|
{
|
|
|
|
struct virNetworkObjListGetHelperData data = {
|
2017-08-15 16:48:37 -04:00
|
|
|
.conn = conn, .filter = filter, .names = NULL, .nnames = 0,
|
|
|
|
.maxnames = -1, .active = active, .error = false};
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2017-10-10 10:02:32 -04:00
|
|
|
virObjectRWLockRead(nets);
|
2017-03-08 10:25:24 -05:00
|
|
|
virHashForEach(nets->objs, virNetworkObjListGetHelper, &data);
|
2017-10-10 10:02:32 -04:00
|
|
|
virObjectRWUnlock(nets);
|
2017-03-08 10:25:24 -05:00
|
|
|
|
2017-08-15 16:48:37 -04:00
|
|
|
return data.nnames;
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2017-03-08 10:25:24 -05:00
|
|
|
struct virNetworkObjListPruneHelperData {
|
|
|
|
unsigned int flags;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
|
|
virNetworkObjListPruneHelper(const void *payload,
|
2020-10-21 13:31:16 +02:00
|
|
|
const char *name G_GNUC_UNUSED,
|
2017-03-08 10:25:24 -05:00
|
|
|
const void *opaque)
|
|
|
|
{
|
|
|
|
const struct virNetworkObjListPruneHelperData *data = opaque;
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObj *obj = (virNetworkObj *) payload;
|
2017-03-08 10:25:24 -05:00
|
|
|
int want = 0;
|
|
|
|
|
|
|
|
virObjectLock(obj);
|
2018-08-13 11:55:16 -04:00
|
|
|
want = virNetworkObjMatch(obj, data->flags);
|
2017-03-08 10:25:24 -05:00
|
|
|
virObjectUnlock(obj);
|
|
|
|
return want;
|
|
|
|
}
|
|
|
|
|
2017-03-08 10:41:57 -05:00
|
|
|
|
2017-03-08 10:25:24 -05:00
|
|
|
/**
|
|
|
|
* virNetworkObjListPrune:
|
|
|
|
* @nets: a list of network objects
|
|
|
|
* @flags: bitwise-OR of virConnectListAllNetworksFlags
|
|
|
|
*
|
|
|
|
* Iterate over list of network objects and remove the desired
|
|
|
|
* ones from it.
|
|
|
|
*/
|
|
|
|
void
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjListPrune(virNetworkObjList *nets,
|
2017-03-08 10:25:24 -05:00
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
struct virNetworkObjListPruneHelperData data = {flags};
|
|
|
|
|
2017-10-10 10:02:32 -04:00
|
|
|
virObjectRWLockWrite(nets);
|
2017-03-08 10:25:24 -05:00
|
|
|
virHashRemoveSet(nets->objs, virNetworkObjListPruneHelper, &data);
|
2017-10-10 10:02:32 -04:00
|
|
|
virObjectRWUnlock(nets);
|
2017-03-08 10:25:24 -05:00
|
|
|
}
|
2018-12-19 14:24:53 +00:00
|
|
|
|
|
|
|
|
|
|
|
char *
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjGetPortStatusDir(virNetworkObj *net,
|
2018-12-19 14:24:53 +00:00
|
|
|
const char *stateDir)
|
|
|
|
{
|
2021-10-22 10:56:01 +02:00
|
|
|
return g_strdup_printf("%s/%s/ports", stateDir, net->def->name);
|
2018-12-19 14:24:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjAddPort(virNetworkObj *net,
|
|
|
|
virNetworkPortDef *portdef,
|
2018-12-19 14:24:53 +00:00
|
|
|
const char *stateDir)
|
|
|
|
{
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
2019-10-15 15:16:31 +02:00
|
|
|
g_autofree char *dir = NULL;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
|
|
|
virUUIDFormat(portdef->uuid, uuidstr);
|
|
|
|
|
|
|
|
if (virHashLookup(net->ports, uuidstr)) {
|
|
|
|
virReportError(VIR_ERR_NETWORK_PORT_EXIST,
|
2023-03-09 11:20:54 +01:00
|
|
|
_("Network port with UUID %1$s already exists"),
|
2018-12-19 14:24:53 +00:00
|
|
|
uuidstr);
|
2019-07-09 16:51:43 +02:00
|
|
|
return -1;
|
2018-12-19 14:24:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!(dir = virNetworkObjGetPortStatusDir(net, stateDir)))
|
2019-07-09 16:51:43 +02:00
|
|
|
return -1;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
|
|
|
if (virHashAddEntry(net->ports, uuidstr, portdef) < 0)
|
2019-07-09 16:51:43 +02:00
|
|
|
return -1;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
|
|
|
if (virNetworkPortDefSaveStatus(portdef, dir) < 0) {
|
|
|
|
virHashRemoveEntry(net->ports, uuidstr);
|
2019-07-09 16:51:43 +02:00
|
|
|
return -1;
|
2018-12-19 14:24:53 +00:00
|
|
|
}
|
|
|
|
|
2019-07-09 16:51:43 +02:00
|
|
|
return 0;
|
2018-12-19 14:24:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkPortDef *
|
|
|
|
virNetworkObjLookupPort(virNetworkObj *net,
|
2018-12-19 14:24:53 +00:00
|
|
|
const unsigned char *uuid)
|
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkPortDef *ret = NULL;
|
2018-12-19 14:24:53 +00:00
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
|
|
|
|
virUUIDFormat(uuid, uuidstr);
|
|
|
|
|
|
|
|
if (!(ret = virHashLookup(net->ports, uuidstr))) {
|
|
|
|
virReportError(VIR_ERR_NO_NETWORK_PORT,
|
2023-03-09 11:20:54 +01:00
|
|
|
_("Network port with UUID %1$s does not exist"),
|
2018-12-19 14:24:53 +00:00
|
|
|
uuidstr);
|
2019-10-21 15:18:51 -03:00
|
|
|
return NULL;
|
2018-12-19 14:24:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjDeletePort(virNetworkObj *net,
|
2018-12-19 14:24:53 +00:00
|
|
|
const unsigned char *uuid,
|
|
|
|
const char *stateDir)
|
|
|
|
{
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
2019-10-15 15:16:31 +02:00
|
|
|
g_autofree char *dir = NULL;
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkPortDef *portdef;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
|
|
|
virUUIDFormat(uuid, uuidstr);
|
|
|
|
|
|
|
|
if (!(portdef = virHashLookup(net->ports, uuidstr))) {
|
|
|
|
virReportError(VIR_ERR_NO_NETWORK_PORT,
|
2023-03-09 11:20:54 +01:00
|
|
|
_("Network port with UUID %1$s does not exist"),
|
2018-12-19 14:24:53 +00:00
|
|
|
uuidstr);
|
2019-07-09 16:57:44 +02:00
|
|
|
return -1;
|
2018-12-19 14:24:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!(dir = virNetworkObjGetPortStatusDir(net, stateDir)))
|
2019-07-09 16:57:44 +02:00
|
|
|
return -1;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
|
|
|
if (virNetworkPortDefDeleteStatus(portdef, dir) < 0)
|
2019-07-09 16:57:44 +02:00
|
|
|
return -1;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
|
|
|
if (virHashRemoveEntry(net->ports, uuidstr) < 0)
|
2019-07-09 16:57:44 +02:00
|
|
|
return -1;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
2019-07-09 16:57:44 +02:00
|
|
|
return 0;
|
2018-12-19 14:24:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjDeleteAllPorts(virNetworkObj *net,
|
2018-12-19 14:24:53 +00:00
|
|
|
const char *stateDir)
|
|
|
|
{
|
2019-10-15 15:16:31 +02:00
|
|
|
g_autofree char *dir = NULL;
|
2020-10-25 17:50:51 -04:00
|
|
|
g_autoptr(DIR) dh = NULL;
|
2018-12-19 14:24:53 +00:00
|
|
|
struct dirent *de;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (!(dir = virNetworkObjGetPortStatusDir(net, stateDir)))
|
2020-10-27 17:49:11 -04:00
|
|
|
return -1;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
2020-10-27 17:49:11 -04:00
|
|
|
if ((rc = virDirOpenIfExists(&dh, dir)) <= 0)
|
|
|
|
return rc;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
|
|
|
while ((rc = virDirRead(dh, &de, dir)) > 0) {
|
|
|
|
char *file = NULL;
|
|
|
|
|
|
|
|
if (!virStringStripSuffix(de->d_name, ".xml"))
|
|
|
|
continue;
|
|
|
|
|
2019-10-22 15:26:14 +02:00
|
|
|
file = g_strdup_printf("%s/%s.xml", dir, de->d_name);
|
2018-12-19 14:24:53 +00:00
|
|
|
|
|
|
|
if (unlink(file) < 0 && errno != ENOENT)
|
|
|
|
VIR_WARN("Unable to delete %s", file);
|
|
|
|
|
|
|
|
VIR_FREE(file);
|
|
|
|
}
|
|
|
|
|
|
|
|
virHashRemoveAll(net->ports);
|
2020-10-27 17:49:11 -04:00
|
|
|
return 0;
|
2018-12-19 14:24:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct _virNetworkObjPortListExportData virNetworkObjPortListExportData;
|
|
|
|
struct _virNetworkObjPortListExportData {
|
|
|
|
virNetworkPtr net;
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkDef *def;
|
2018-12-19 14:24:53 +00:00
|
|
|
virNetworkPortPtr *ports;
|
|
|
|
virNetworkPortListFilter filter;
|
|
|
|
int nports;
|
|
|
|
bool error;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
|
|
virNetworkObjPortListExportCallback(void *payload,
|
2020-10-21 13:31:16 +02:00
|
|
|
const char *name G_GNUC_UNUSED,
|
2018-12-19 14:24:53 +00:00
|
|
|
void *opaque)
|
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjPortListExportData *data = opaque;
|
|
|
|
virNetworkPortDef *def = payload;
|
2018-12-19 14:24:53 +00:00
|
|
|
virNetworkPortPtr port;
|
|
|
|
|
|
|
|
if (data->error)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (data->filter &&
|
|
|
|
!data->filter(data->net->conn, data->def, def))
|
2020-01-06 18:57:26 -03:00
|
|
|
return 0;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
|
|
|
if (!data->ports) {
|
|
|
|
data->nports++;
|
2020-01-06 18:57:26 -03:00
|
|
|
return 0;
|
2018-12-19 14:24:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!(port = virGetNetworkPort(data->net, def->uuid))) {
|
|
|
|
data->error = true;
|
2020-01-06 18:57:26 -03:00
|
|
|
return 0;
|
2018-12-19 14:24:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
data->ports[data->nports++] = port;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
virNetworkObjPortListExport(virNetworkPtr net,
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObj *obj,
|
2018-12-19 14:24:53 +00:00
|
|
|
virNetworkPortPtr **ports,
|
|
|
|
virNetworkPortListFilter filter)
|
|
|
|
{
|
|
|
|
virNetworkObjPortListExportData data = {
|
|
|
|
net, obj->def, NULL, filter, 0, false,
|
|
|
|
};
|
|
|
|
int ret = -1;
|
|
|
|
|
2019-06-18 18:33:04 +01:00
|
|
|
if (ports) {
|
|
|
|
*ports = NULL;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
2020-10-12 19:45:37 +02:00
|
|
|
data.ports = g_new0(virNetworkPortPtr, virHashSize(obj->ports) + 1);
|
2019-06-18 18:33:04 +01:00
|
|
|
}
|
2018-12-19 14:24:53 +00:00
|
|
|
|
|
|
|
virHashForEach(obj->ports, virNetworkObjPortListExportCallback, &data);
|
|
|
|
|
|
|
|
if (data.error)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (data.ports) {
|
|
|
|
/* trim the array to the final size */
|
2021-03-20 00:37:05 +01:00
|
|
|
VIR_REALLOC_N(data.ports, data.nports + 1);
|
2021-03-24 10:32:58 +01:00
|
|
|
*ports = g_steal_pointer(&data.ports);
|
2018-12-19 14:24:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = data.nports;
|
|
|
|
cleanup:
|
|
|
|
while (data.ports && data.nports)
|
|
|
|
virObjectUnref(data.ports[--data.nports]);
|
|
|
|
|
|
|
|
VIR_FREE(data.ports);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-09-13 15:54:18 +01:00
|
|
|
typedef struct _virNetworkObjPortListForEachData virNetworkObjPortListForEachData;
|
|
|
|
struct _virNetworkObjPortListForEachData {
|
|
|
|
virNetworkPortListIter iter;
|
|
|
|
void *opaque;
|
|
|
|
bool err;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
|
|
virNetworkObjPortForEachCallback(void *payload,
|
2020-10-21 13:31:16 +02:00
|
|
|
const char *name G_GNUC_UNUSED,
|
2019-09-13 15:54:18 +01:00
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
virNetworkObjPortListForEachData *data = opaque;
|
|
|
|
|
|
|
|
if (!data->iter(payload, data->opaque))
|
|
|
|
data->err = true;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjPortForEach(virNetworkObj *obj,
|
2019-09-13 15:54:18 +01:00
|
|
|
virNetworkPortListIter iter,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
virNetworkObjPortListForEachData data = { iter, opaque, false };
|
2020-10-23 09:49:36 +02:00
|
|
|
virHashForEachSafe(obj->ports, virNetworkObjPortForEachCallback, &data);
|
2019-09-13 15:54:18 +01:00
|
|
|
if (data.err)
|
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-12-19 14:24:53 +00:00
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
virNetworkObjLoadAllPorts(virNetworkObj *net,
|
2018-12-19 14:24:53 +00:00
|
|
|
const char *stateDir)
|
|
|
|
{
|
2019-10-15 15:16:31 +02:00
|
|
|
g_autofree char *dir = NULL;
|
2020-10-25 17:50:51 -04:00
|
|
|
g_autoptr(DIR) dh = NULL;
|
2018-12-19 14:24:53 +00:00
|
|
|
struct dirent *de;
|
|
|
|
int rc;
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
2019-10-15 14:47:50 +02:00
|
|
|
g_autoptr(virNetworkPortDef) portdef = NULL;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
|
|
|
if (!(dir = virNetworkObjGetPortStatusDir(net, stateDir)))
|
2020-10-27 17:49:11 -04:00
|
|
|
return -1;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
2020-10-27 17:49:11 -04:00
|
|
|
if ((rc = virDirOpenIfExists(&dh, dir)) <= 0)
|
|
|
|
return rc;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
|
|
|
while ((rc = virDirRead(dh, &de, dir)) > 0) {
|
2020-02-24 01:46:14 -05:00
|
|
|
g_autofree char *file = NULL;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
|
|
|
if (!virStringStripSuffix(de->d_name, ".xml"))
|
|
|
|
continue;
|
|
|
|
|
2019-10-22 15:26:14 +02:00
|
|
|
file = g_strdup_printf("%s/%s.xml", dir, de->d_name);
|
2018-12-19 14:24:53 +00:00
|
|
|
|
2022-09-22 16:09:27 +02:00
|
|
|
portdef = virNetworkPortDefParse(NULL, file, 0);
|
2018-12-19 14:24:53 +00:00
|
|
|
if (!portdef) {
|
|
|
|
VIR_WARN("Cannot parse port %s", file);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
virUUIDFormat(portdef->uuid, uuidstr);
|
|
|
|
if (virHashAddEntry(net->ports, uuidstr, portdef) < 0)
|
2020-10-27 17:49:11 -04:00
|
|
|
return -1;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
|
|
|
portdef = NULL;
|
|
|
|
}
|
|
|
|
|
2020-10-27 17:49:11 -04:00
|
|
|
return 0;
|
2018-12-19 14:24:53 +00:00
|
|
|
}
|
2023-08-17 00:17:13 +05:30
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetworkObjUpdateModificationImpact:
|
|
|
|
*
|
|
|
|
* @obj: network object
|
|
|
|
* @flags: flags to update the modification impact on
|
|
|
|
*
|
|
|
|
* Resolves virNetworkUpdateFlags in @flags so that they correctly
|
|
|
|
* apply to the actual state of @obj. @flags may be modified after call to this
|
|
|
|
* function.
|
|
|
|
*
|
|
|
|
* Returns 0 on success if @flags point to a valid combination for @obj or -1 on
|
|
|
|
* error.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virNetworkObjUpdateModificationImpact(virNetworkObj *obj,
|
|
|
|
unsigned int *flags)
|
|
|
|
{
|
|
|
|
bool isActive = virNetworkObjIsActive(obj);
|
|
|
|
|
|
|
|
if ((*flags & (VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG)) ==
|
|
|
|
VIR_NETWORK_UPDATE_AFFECT_CURRENT) {
|
|
|
|
if (isActive)
|
|
|
|
*flags |= VIR_NETWORK_UPDATE_AFFECT_LIVE;
|
|
|
|
else
|
|
|
|
*flags |= VIR_NETWORK_UPDATE_AFFECT_CONFIG;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virNetworkObjConfigChangeSetup(obj, *flags) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetworkObjGetDefs:
|
|
|
|
*
|
|
|
|
* @net: network object
|
|
|
|
* @flags: for virNetworkUpdateFlags
|
|
|
|
* @liveDef: Set the pointer to the live definition of @net.
|
|
|
|
* @persDef: Set the pointer to the config definition of @net.
|
|
|
|
*
|
|
|
|
* Helper function to resolve @flags and retrieve correct network pointer
|
|
|
|
* objects. This function should be used only when the network driver
|
|
|
|
* creates net->newDef once the network has started.
|
|
|
|
*
|
|
|
|
* If @liveDef or @persDef are set it implies that @flags request modification
|
|
|
|
* thereof.
|
|
|
|
*
|
|
|
|
* Returns 0 on success and sets @liveDef and @persDef; -1 if @flags are
|
|
|
|
* inappropriate.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
virNetworkObjGetDefs(virNetworkObj *net,
|
|
|
|
unsigned int flags,
|
|
|
|
virNetworkDef **liveDef,
|
|
|
|
virNetworkDef **persDef)
|
|
|
|
{
|
|
|
|
if (liveDef)
|
|
|
|
*liveDef = NULL;
|
|
|
|
|
|
|
|
if (persDef)
|
|
|
|
*persDef = NULL;
|
|
|
|
|
|
|
|
if (virNetworkObjUpdateModificationImpact(net, &flags) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virNetworkObjIsActive(net)) {
|
|
|
|
if (liveDef && (flags & VIR_NETWORK_UPDATE_AFFECT_LIVE))
|
|
|
|
*liveDef = net->def;
|
|
|
|
|
|
|
|
if (persDef && (flags & VIR_NETWORK_UPDATE_AFFECT_CONFIG))
|
|
|
|
*persDef = net->newDef;
|
|
|
|
} else {
|
|
|
|
if (persDef)
|
|
|
|
*persDef = net->def;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetworkObjGetOneDefState:
|
|
|
|
*
|
|
|
|
* @net: Network object
|
|
|
|
* @flags: for virNetworkUpdateFlags
|
|
|
|
* @live: set to true if live config was returned (may be omitted)
|
|
|
|
*
|
|
|
|
* Helper function to resolve @flags and return the correct network pointer
|
|
|
|
* object. This function returns one of @net->def or @net->persistentDef
|
|
|
|
* according to @flags. @live is set to true if the live net config will be
|
|
|
|
* returned. This helper should be used only in APIs that guarantee
|
|
|
|
* that @flags contains exactly one of VIR_NETWORK_UPDATE_AFFECT_LIVE or
|
|
|
|
* VIR_NETWORK_UPDATE_AFFECT_CONFIG and not both.
|
|
|
|
*
|
|
|
|
* Returns the correct definition pointer or NULL on error.
|
|
|
|
*/
|
|
|
|
static virNetworkDef *
|
|
|
|
virNetworkObjGetOneDefState(virNetworkObj *net,
|
|
|
|
unsigned int flags,
|
|
|
|
bool *live)
|
|
|
|
{
|
|
|
|
if (flags & VIR_NETWORK_UPDATE_AFFECT_LIVE &&
|
|
|
|
flags & VIR_NETWORK_UPDATE_AFFECT_CONFIG) {
|
|
|
|
virReportInvalidArg(flags, "%s",
|
|
|
|
_("Flags 'VIR_NETWORK_UPDATE_AFFECT_LIVE' and 'VIR_NETWORK_UPDATE_AFFECT_CONFIG' are mutually exclusive"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virNetworkObjUpdateModificationImpact(net, &flags) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (live)
|
|
|
|
*live = flags & VIR_NETWORK_UPDATE_AFFECT_LIVE;
|
|
|
|
|
|
|
|
if (virNetworkObjIsActive(net) && flags & VIR_NETWORK_UPDATE_AFFECT_CONFIG)
|
|
|
|
return net->newDef;
|
|
|
|
|
|
|
|
return net->def;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virNetworkObjGetOneDef:
|
|
|
|
*
|
|
|
|
* @net: Network object
|
|
|
|
* @flags: for virNetworkUpdateFlags
|
|
|
|
*
|
|
|
|
* Helper function to resolve @flags and return the correct network pointer
|
|
|
|
* object. This function returns one of @net->def or @net->persistentDef
|
|
|
|
* according to @flags. This helper should be used only in APIs that guarantee
|
|
|
|
* that @flags contains exactly one of VIR_NETWORK_UPDATE_AFFECT_LIVE or
|
|
|
|
* VIR_NETWORK_UPDATE_AFFECT_CONFIG and not both.
|
|
|
|
*
|
|
|
|
* Returns the correct definition pointer or NULL on error.
|
|
|
|
*/
|
|
|
|
static virNetworkDef *
|
|
|
|
virNetworkObjGetOneDef(virNetworkObj *net,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
return virNetworkObjGetOneDefState(net, flags, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
virNetworkObjGetMetadata(virNetworkObj *net,
|
|
|
|
int type,
|
|
|
|
const char *uri,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
virNetworkDef *def;
|
|
|
|
char *ret = NULL;
|
|
|
|
|
|
|
|
virCheckFlags(VIR_NETWORK_UPDATE_AFFECT_LIVE |
|
|
|
|
VIR_NETWORK_UPDATE_AFFECT_CONFIG, NULL);
|
|
|
|
|
|
|
|
if (type >= VIR_NETWORK_METADATA_LAST) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("unknown metadata type '%1$d'"), type);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(def = virNetworkObjGetOneDef(net, flags)))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
switch ((virNetworkMetadataType) type) {
|
|
|
|
case VIR_NETWORK_METADATA_DESCRIPTION:
|
|
|
|
ret = g_strdup(def->description);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_NETWORK_METADATA_TITLE:
|
|
|
|
ret = g_strdup(def->title);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_NETWORK_METADATA_ELEMENT:
|
|
|
|
if (!def->metadata)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (virXMLExtractNamespaceXML(def->metadata, uri, &ret) < 0)
|
|
|
|
return NULL;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_NETWORK_METADATA_LAST:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ret)
|
|
|
|
virReportError(VIR_ERR_NO_NETWORK_METADATA, "%s",
|
|
|
|
_("Requested metadata element is not present"));
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
virNetworkDefSetMetadata(virNetworkDef *def,
|
|
|
|
int type,
|
|
|
|
const char *metadata,
|
|
|
|
const char *key,
|
|
|
|
const char *uri)
|
|
|
|
{
|
|
|
|
g_autoptr(xmlDoc) doc = NULL;
|
|
|
|
xmlNodePtr old;
|
|
|
|
g_autoptr(xmlNode) new = NULL;
|
|
|
|
|
|
|
|
if (type >= VIR_NETWORK_METADATA_LAST) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("unknown metadata type '%1$d'"), type);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch ((virNetworkMetadataType) type) {
|
|
|
|
case VIR_NETWORK_METADATA_DESCRIPTION:
|
|
|
|
g_clear_pointer(&def->description, g_free);
|
|
|
|
|
|
|
|
if (STRNEQ_NULLABLE(metadata, ""))
|
|
|
|
def->description = g_strdup(metadata);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_NETWORK_METADATA_TITLE:
|
|
|
|
g_clear_pointer(&def->title, g_free);
|
|
|
|
|
|
|
|
if (STRNEQ_NULLABLE(metadata, ""))
|
|
|
|
def->title = g_strdup(metadata);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_NETWORK_METADATA_ELEMENT:
|
|
|
|
if (metadata) {
|
|
|
|
|
|
|
|
/* parse and modify the xml from the user */
|
|
|
|
if (!(doc = virXMLParseStringCtxt(metadata, _("(metadata_xml)"), NULL)))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virXMLInjectNamespace(doc->children, uri, key) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* create the root node if needed */
|
|
|
|
if (!def->metadata)
|
|
|
|
def->metadata = virXMLNewNode(NULL, "metadata");
|
|
|
|
|
|
|
|
if (!(new = xmlCopyNode(doc->children, 1))) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Failed to copy XML node"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* remove possible other nodes sharing the namespace */
|
|
|
|
while ((old = virXMLFindChildNodeByNs(def->metadata, uri))) {
|
|
|
|
xmlUnlinkNode(old);
|
|
|
|
xmlFreeNode(old);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (new) {
|
|
|
|
if (!(xmlAddChild(def->metadata, new))) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("failed to add metadata to XML document"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
new = NULL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_NETWORK_METADATA_LAST:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
virNetworkObjSetMetadata(virNetworkObj *net,
|
|
|
|
int type,
|
|
|
|
const char *metadata,
|
|
|
|
const char *key,
|
|
|
|
const char *uri,
|
|
|
|
virNetworkXMLOption *xmlopt,
|
|
|
|
const char *stateDir,
|
|
|
|
const char *configDir,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
virNetworkDef *def;
|
|
|
|
virNetworkDef *persistentDef;
|
|
|
|
|
|
|
|
virCheckFlags(VIR_NETWORK_UPDATE_AFFECT_LIVE |
|
|
|
|
VIR_NETWORK_UPDATE_AFFECT_CONFIG, -1);
|
|
|
|
|
|
|
|
if (virNetworkObjGetDefs(net, flags, &def, &persistentDef) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (def) {
|
|
|
|
if (virNetworkDefSetMetadata(def, type, metadata, key, uri) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virNetworkObjSaveStatus(stateDir, net, xmlopt) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (persistentDef) {
|
|
|
|
if (virNetworkDefSetMetadata(persistentDef, type, metadata, key,
|
|
|
|
uri) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virNetworkSaveConfig(configDir, persistentDef, xmlopt) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|