2017-03-08 15:25:24 +00: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 10:55:03 +00: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 15:25:24 +00:00
|
|
|
|
2017-05-12 12:40:04 +00:00
|
|
|
struct _virNetworkObj {
|
|
|
|
virObjectLockable parent;
|
|
|
|
|
|
|
|
pid_t dnsmasqPid;
|
|
|
|
pid_t radvdPid;
|
|
|
|
bool active;
|
|
|
|
bool autostart;
|
|
|
|
bool persistent;
|
|
|
|
|
|
|
|
virNetworkDefPtr def; /* The current definition */
|
|
|
|
virNetworkDefPtr newDef; /* New definition to activate at shutdown */
|
|
|
|
|
|
|
|
virBitmapPtr classIdMap; /* bitmap of class IDs for QoS */
|
|
|
|
unsigned long long floor_sum; /* sum of all 'floor'-s of attached NICs */
|
|
|
|
|
|
|
|
unsigned int taint;
|
|
|
|
|
|
|
|
/* Immutable pointer, self locking APIs */
|
|
|
|
virMacMapPtr macmap;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
2020-10-22 17:04:18 +00:00
|
|
|
GHashTable *ports; /* uuid -> virNetworkPortDefPtr */
|
2017-05-12 12:40:04 +00:00
|
|
|
};
|
|
|
|
|
2017-03-08 15:25:24 +00:00
|
|
|
struct _virNetworkObjList {
|
2017-10-10 14:02:32 +00:00
|
|
|
virObjectRWLockable parent;
|
2017-03-08 15:25:24 +00:00
|
|
|
|
2020-10-22 17:04:18 +00:00
|
|
|
GHashTable *objs;
|
2017-03-08 15:25:24 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static virClassPtr virNetworkObjClass;
|
|
|
|
static virClassPtr virNetworkObjListClass;
|
|
|
|
static void virNetworkObjDispose(void *obj);
|
|
|
|
static void virNetworkObjListDispose(void *obj);
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
static int
|
|
|
|
virNetworkObjOnceInit(void)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
2018-04-17 15:42:33 +00:00
|
|
|
if (!VIR_CLASS_NEW(virNetworkObj, virClassForObjectLockable()))
|
2017-03-08 15:25:24 +00:00
|
|
|
return -1;
|
|
|
|
|
2018-04-17 15:42:33 +00:00
|
|
|
if (!VIR_CLASS_NEW(virNetworkObjList, virClassForObjectRWLockable()))
|
2017-03-08 15:25:24 +00:00
|
|
|
return -1;
|
2018-04-17 15:42:33 +00:00
|
|
|
|
2017-03-08 15:25:24 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-01-20 17:23:29 +00:00
|
|
|
VIR_ONCE_GLOBAL_INIT(virNetworkObj);
|
2017-03-08 15:25:24 +00:00
|
|
|
|
2018-12-19 14:24:53 +00:00
|
|
|
static int
|
|
|
|
virNetworkObjLoadAllPorts(virNetworkObjPtr net,
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2017-03-08 15:25:24 +00:00
|
|
|
virNetworkObjPtr
|
|
|
|
virNetworkObjNew(void)
|
|
|
|
{
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjPtr obj;
|
2017-03-08 15:25:24 +00:00
|
|
|
|
|
|
|
if (virNetworkObjInitialize() < 0)
|
|
|
|
return NULL;
|
|
|
|
|
2017-05-10 11:59:48 +00:00
|
|
|
if (!(obj = virObjectLockableNew(virNetworkObjClass)))
|
2017-03-08 15:25:24 +00:00
|
|
|
return NULL;
|
|
|
|
|
2020-10-01 15:42:11 +00:00
|
|
|
obj->classIdMap = virBitmapNew(INIT_CLASS_ID_BITMAP_SIZE);
|
2017-03-08 15:25:24 +00:00
|
|
|
|
|
|
|
/* The first three class IDs are already taken */
|
2017-08-16 10:55:03 +00:00
|
|
|
if (virBitmapSetBitExpand(obj->classIdMap, 0) < 0 ||
|
|
|
|
virBitmapSetBitExpand(obj->classIdMap, 1) < 0 ||
|
|
|
|
virBitmapSetBitExpand(obj->classIdMap, 2) < 0)
|
|
|
|
goto error;
|
2017-03-08 15:25:24 +00:00
|
|
|
|
2020-10-20 16:43:20 +00:00
|
|
|
if (!(obj->ports = virHashNew(virNetworkObjPortFree)))
|
2018-12-19 14:24:53 +00:00
|
|
|
goto error;
|
|
|
|
|
2017-05-10 12:40:40 +00:00
|
|
|
virObjectLock(obj);
|
|
|
|
|
2017-05-10 11:59:48 +00:00
|
|
|
return obj;
|
2017-03-08 15:25:24 +00:00
|
|
|
|
|
|
|
error:
|
2017-05-10 11:59:48 +00:00
|
|
|
virObjectUnref(obj);
|
2017-03-08 15:25:24 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-03-08 15:25:24 +00:00
|
|
|
void
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjEndAPI(virNetworkObjPtr *obj)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
2017-05-10 11:59:48 +00:00
|
|
|
if (!*obj)
|
2017-03-08 15:25:24 +00:00
|
|
|
return;
|
|
|
|
|
2017-05-10 11:59:48 +00:00
|
|
|
virObjectUnlock(*obj);
|
|
|
|
virObjectUnref(*obj);
|
|
|
|
*obj = NULL;
|
2017-03-08 15:25:24 +00:00
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-05-09 22:38:58 +00:00
|
|
|
virNetworkDefPtr
|
|
|
|
virNetworkObjGetDef(virNetworkObjPtr obj)
|
|
|
|
{
|
|
|
|
return obj->def;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
virNetworkObjSetDef(virNetworkObjPtr obj,
|
|
|
|
virNetworkDefPtr def)
|
|
|
|
{
|
|
|
|
obj->def = def;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virNetworkDefPtr
|
|
|
|
virNetworkObjGetNewDef(virNetworkObjPtr obj)
|
|
|
|
{
|
|
|
|
return obj->newDef;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-10 11:22:15 +00:00
|
|
|
bool
|
|
|
|
virNetworkObjIsActive(virNetworkObjPtr obj)
|
|
|
|
{
|
|
|
|
return obj->active;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
virNetworkObjSetActive(virNetworkObjPtr obj,
|
|
|
|
bool active)
|
|
|
|
{
|
|
|
|
obj->active = active;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-10 11:29:57 +00:00
|
|
|
bool
|
|
|
|
virNetworkObjIsPersistent(virNetworkObjPtr obj)
|
|
|
|
{
|
|
|
|
return obj->persistent;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-10 11:12:27 +00:00
|
|
|
bool
|
|
|
|
virNetworkObjIsAutostart(virNetworkObjPtr obj)
|
|
|
|
{
|
|
|
|
return obj->autostart;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
virNetworkObjSetAutostart(virNetworkObjPtr obj,
|
|
|
|
bool autostart)
|
|
|
|
{
|
|
|
|
obj->autostart = autostart;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-09 21:22:43 +00:00
|
|
|
pid_t
|
|
|
|
virNetworkObjGetDnsmasqPid(virNetworkObjPtr obj)
|
|
|
|
{
|
|
|
|
return obj->dnsmasqPid;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
virNetworkObjSetDnsmasqPid(virNetworkObjPtr obj,
|
|
|
|
pid_t dnsmasqPid)
|
|
|
|
{
|
|
|
|
obj->dnsmasqPid = dnsmasqPid;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pid_t
|
|
|
|
virNetworkObjGetRadvdPid(virNetworkObjPtr obj)
|
|
|
|
{
|
|
|
|
return obj->radvdPid;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
virNetworkObjSetRadvdPid(virNetworkObjPtr obj,
|
|
|
|
pid_t radvdPid)
|
|
|
|
{
|
|
|
|
obj->radvdPid = radvdPid;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-09 21:41:23 +00:00
|
|
|
virBitmapPtr
|
|
|
|
virNetworkObjGetClassIdMap(virNetworkObjPtr obj)
|
|
|
|
{
|
|
|
|
return obj->classIdMap;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-09 20:51:05 +00:00
|
|
|
virMacMapPtr
|
|
|
|
virNetworkObjGetMacMap(virNetworkObjPtr obj)
|
|
|
|
{
|
|
|
|
return obj->macmap;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-09 21:57:41 +00:00
|
|
|
unsigned long long
|
|
|
|
virNetworkObjGetFloorSum(virNetworkObjPtr obj)
|
|
|
|
{
|
|
|
|
return obj->floor_sum;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
virNetworkObjSetFloorSum(virNetworkObjPtr obj,
|
|
|
|
unsigned long long floor_sum)
|
|
|
|
{
|
|
|
|
obj->floor_sum = floor_sum;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-09 20:51:05 +00:00
|
|
|
void
|
|
|
|
virNetworkObjSetMacMap(virNetworkObjPtr obj,
|
|
|
|
virMacMapPtr macmap)
|
|
|
|
{
|
|
|
|
obj->macmap = macmap;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
virNetworkObjUnrefMacMap(virNetworkObjPtr obj)
|
|
|
|
{
|
2017-07-26 11:42:51 +00:00
|
|
|
virObjectUnref(obj->macmap);
|
|
|
|
obj->macmap = NULL;
|
2017-05-09 20:51:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
virNetworkObjMacMgrAdd(virNetworkObjPtr obj,
|
|
|
|
const char *dnsmasqStateDir,
|
|
|
|
const char *domain,
|
|
|
|
const virMacAddr *mac)
|
|
|
|
{
|
|
|
|
char macStr[VIR_MAC_STRING_BUFLEN];
|
|
|
|
char *file = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (!obj->macmap)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
virMacAddrFormat(mac, macStr);
|
|
|
|
|
|
|
|
if (!(file = virMacMapFileName(dnsmasqStateDir, obj->def->bridge)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virMacMapAdd(obj->macmap, domain, macStr) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virMacMapWriteFile(obj->macmap, file) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(file);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
virNetworkObjMacMgrDel(virNetworkObjPtr obj,
|
|
|
|
const char *dnsmasqStateDir,
|
|
|
|
const char *domain,
|
|
|
|
const virMacAddr *mac)
|
|
|
|
{
|
|
|
|
char macStr[VIR_MAC_STRING_BUFLEN];
|
|
|
|
char *file = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (!obj->macmap)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
virMacAddrFormat(mac, macStr);
|
|
|
|
|
|
|
|
if (!(file = virMacMapFileName(dnsmasqStateDir, obj->def->bridge)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virMacMapRemove(obj->macmap, domain, macStr) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virMacMapWriteFile(obj->macmap, file) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(file);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
virNetworkObjListPtr
|
|
|
|
virNetworkObjListNew(void)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
|
|
|
virNetworkObjListPtr nets;
|
|
|
|
|
|
|
|
if (virNetworkObjInitialize() < 0)
|
|
|
|
return NULL;
|
|
|
|
|
2017-10-10 14:02:32 +00:00
|
|
|
if (!(nets = virObjectRWLockableNew(virNetworkObjListClass)))
|
2017-03-08 15:25:24 +00:00
|
|
|
return NULL;
|
|
|
|
|
2020-10-20 16:43:20 +00:00
|
|
|
if (!(nets->objs = virHashNew(virObjectFreeHashData))) {
|
2017-03-08 15:25:24 +00:00
|
|
|
virObjectUnref(nets);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nets;
|
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-07-25 15:04:11 +00:00
|
|
|
static virNetworkObjPtr
|
2017-03-08 15:25:24 +00:00
|
|
|
virNetworkObjFindByUUIDLocked(virNetworkObjListPtr nets,
|
|
|
|
const unsigned char *uuid)
|
|
|
|
{
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjPtr obj = NULL;
|
2017-03-08 15:25:24 +00:00
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
|
|
|
|
virUUIDFormat(uuid, uuidstr);
|
|
|
|
|
2017-05-10 11:59:48 +00:00
|
|
|
obj = virHashLookup(nets->objs, uuidstr);
|
|
|
|
if (obj)
|
|
|
|
virObjectRef(obj);
|
|
|
|
return obj;
|
2017-03-08 15:25:24 +00:00
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-03-08 15:25:24 +00: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.
|
|
|
|
*/
|
|
|
|
virNetworkObjPtr
|
|
|
|
virNetworkObjFindByUUID(virNetworkObjListPtr nets,
|
|
|
|
const unsigned char *uuid)
|
|
|
|
{
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjPtr obj;
|
2017-03-08 15:25:24 +00:00
|
|
|
|
2017-10-10 14:02:32 +00:00
|
|
|
virObjectRWLockRead(nets);
|
2017-05-10 11:59:48 +00:00
|
|
|
obj = virNetworkObjFindByUUIDLocked(nets, uuid);
|
2017-10-10 14:02:32 +00:00
|
|
|
virObjectRWUnlock(nets);
|
2017-05-10 11:59:48 +00:00
|
|
|
if (obj)
|
|
|
|
virObjectLock(obj);
|
|
|
|
return obj;
|
2017-03-08 15:25:24 +00:00
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-03-08 15:25:24 +00:00
|
|
|
static int
|
|
|
|
virNetworkObjSearchName(const void *payload,
|
2020-10-21 11:31:16 +00:00
|
|
|
const char *name G_GNUC_UNUSED,
|
2017-03-08 15:25:24 +00:00
|
|
|
const void *data)
|
|
|
|
{
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjPtr obj = (virNetworkObjPtr) payload;
|
2017-03-08 15:25:24 +00:00
|
|
|
int want = 0;
|
|
|
|
|
2017-05-10 11:59:48 +00:00
|
|
|
virObjectLock(obj);
|
|
|
|
if (STREQ(obj->def->name, (const char *)data))
|
2017-03-08 15:25:24 +00:00
|
|
|
want = 1;
|
2017-05-10 11:59:48 +00:00
|
|
|
virObjectUnlock(obj);
|
2017-03-08 15:25:24 +00:00
|
|
|
return want;
|
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-07-25 15:04:11 +00:00
|
|
|
static virNetworkObjPtr
|
2017-03-08 15:25:24 +00:00
|
|
|
virNetworkObjFindByNameLocked(virNetworkObjListPtr nets,
|
|
|
|
const char *name)
|
|
|
|
{
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjPtr obj = NULL;
|
2017-03-08 15:25:24 +00:00
|
|
|
|
2017-05-10 11:59:48 +00:00
|
|
|
obj = virHashSearch(nets->objs, virNetworkObjSearchName, name, NULL);
|
|
|
|
if (obj)
|
|
|
|
virObjectRef(obj);
|
|
|
|
return obj;
|
2017-03-08 15:25:24 +00:00
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-03-08 15:25:24 +00: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.
|
|
|
|
*/
|
|
|
|
virNetworkObjPtr
|
|
|
|
virNetworkObjFindByName(virNetworkObjListPtr nets,
|
|
|
|
const char *name)
|
|
|
|
{
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjPtr obj;
|
2017-03-08 15:25:24 +00:00
|
|
|
|
2017-10-10 14:02:32 +00:00
|
|
|
virObjectRWLockRead(nets);
|
2017-05-10 11:59:48 +00:00
|
|
|
obj = virNetworkObjFindByNameLocked(nets, name);
|
2017-10-10 14:02:32 +00:00
|
|
|
virObjectRWUnlock(nets);
|
2017-05-10 11:59:48 +00:00
|
|
|
if (obj)
|
|
|
|
virObjectLock(obj);
|
|
|
|
return obj;
|
2017-03-08 15:25:24 +00:00
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-03-08 15:25:24 +00:00
|
|
|
bool
|
|
|
|
virNetworkObjTaint(virNetworkObjPtr obj,
|
|
|
|
virNetworkTaintFlags taint)
|
|
|
|
{
|
|
|
|
unsigned int flag = (1 << taint);
|
|
|
|
|
|
|
|
if (obj->taint & flag)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
obj->taint |= flag;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjDispose(void *opaque)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjPtr obj = opaque;
|
2017-03-08 15:25:24 +00:00
|
|
|
|
2018-12-19 14:24:53 +00:00
|
|
|
virHashFree(obj->ports);
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkDefFree(obj->def);
|
|
|
|
virNetworkDefFree(obj->newDef);
|
|
|
|
virBitmapFree(obj->classIdMap);
|
|
|
|
virObjectUnref(obj->macmap);
|
2017-03-08 15:25:24 +00:00
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-03-08 15:25:24 +00:00
|
|
|
static void
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjListDispose(void *opaque)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjListPtr nets = opaque;
|
2017-03-08 15:25:24 +00:00
|
|
|
|
|
|
|
virHashFree(nets->objs);
|
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-03-08 15:25:24 +00:00
|
|
|
/*
|
2017-03-08 16:19:20 +00:00
|
|
|
* virNetworkObjUpdateAssignDef:
|
2017-03-08 15:25:24 +00: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
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjUpdateAssignDef(virNetworkObjPtr obj,
|
2017-03-08 16:19:20 +00:00
|
|
|
virNetworkDefPtr def,
|
|
|
|
bool live)
|
2017-03-08 15:25:24 +00: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 11:59:48 +00:00
|
|
|
if (obj->persistent && !obj->newDef)
|
|
|
|
obj->newDef = obj->def;
|
2017-03-08 15:25:24 +00:00
|
|
|
else
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkDefFree(obj->def);
|
|
|
|
obj->def = def;
|
2017-03-08 15:25:24 +00:00
|
|
|
} else { /* !live */
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkDefFree(obj->newDef);
|
|
|
|
if (virNetworkObjIsActive(obj)) {
|
2017-03-08 15:25:24 +00:00
|
|
|
/* save new configuration to be restored on network
|
|
|
|
* shutdown, leaving current live def alone
|
|
|
|
*/
|
2017-05-10 11:59:48 +00:00
|
|
|
obj->newDef = def;
|
2017-03-08 15:25:24 +00:00
|
|
|
} else { /* !live and !active */
|
2017-05-10 11:59:48 +00:00
|
|
|
if (obj->def && !obj->persistent) {
|
2017-03-08 15:25:24 +00: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 11:59:48 +00:00
|
|
|
obj->newDef = def;
|
2017-03-08 15:25:24 +00: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 11:59:48 +00:00
|
|
|
obj->newDef = NULL;
|
|
|
|
virNetworkDefFree(obj->def);
|
|
|
|
obj->def = def;
|
2017-03-08 15:25:24 +00:00
|
|
|
}
|
|
|
|
}
|
2017-05-10 11:59:48 +00:00
|
|
|
obj->persistent = !!def;
|
2017-03-08 15:25:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-03-08 15:25:24 +00: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.
|
|
|
|
*/
|
|
|
|
static virNetworkObjPtr
|
2017-03-08 16:41:18 +00:00
|
|
|
virNetworkObjAssignDefLocked(virNetworkObjListPtr nets,
|
|
|
|
virNetworkDefPtr def,
|
|
|
|
unsigned int flags)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjPtr obj;
|
2017-03-08 15:25:24 +00:00
|
|
|
virNetworkObjPtr ret = NULL;
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
|
|
|
|
/* See if a network with matching UUID already exists */
|
2017-05-10 11:59:48 +00:00
|
|
|
if ((obj = virNetworkObjFindByUUIDLocked(nets, def->uuid))) {
|
|
|
|
virObjectLock(obj);
|
2017-03-08 15:25:24 +00:00
|
|
|
/* UUID matches, but if names don't match, refuse it */
|
2017-05-10 11:59:48 +00:00
|
|
|
if (STRNEQ(obj->def->name, def->name)) {
|
|
|
|
virUUIDFormat(obj->def->uuid, uuidstr);
|
2017-03-08 15:25:24 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("network '%s' is already defined with uuid %s"),
|
2017-05-10 11:59:48 +00:00
|
|
|
obj->def->name, uuidstr);
|
2017-03-08 15:25:24 +00: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 11:59:48 +00:00
|
|
|
if (virNetworkObjIsActive(obj)) {
|
2017-03-08 15:25:24 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
_("network is already active as '%s'"),
|
2017-05-10 11:59:48 +00:00
|
|
|
obj->def->name);
|
2017-03-08 15:25:24 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjUpdateAssignDef(obj, def,
|
2017-03-08 16:19:20 +00:00
|
|
|
!!(flags & VIR_NETWORK_OBJ_LIST_ADD_LIVE));
|
2017-03-08 15:25:24 +00:00
|
|
|
} else {
|
|
|
|
/* UUID does not match, but if a name matches, refuse it */
|
2017-05-10 11:59:48 +00:00
|
|
|
if ((obj = virNetworkObjFindByNameLocked(nets, def->name))) {
|
|
|
|
virObjectLock(obj);
|
|
|
|
virUUIDFormat(obj->def->uuid, uuidstr);
|
2017-03-08 15:25:24 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("network '%s' already exists with uuid %s"),
|
|
|
|
def->name, uuidstr);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2017-05-10 11:59:48 +00:00
|
|
|
if (!(obj = virNetworkObjNew()))
|
2017-03-08 15:25:24 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
virUUIDFormat(def->uuid, uuidstr);
|
2017-05-10 11:59:48 +00:00
|
|
|
if (virHashAddEntry(nets->objs, uuidstr, obj) < 0)
|
2017-03-08 15:25:24 +00:00
|
|
|
goto cleanup;
|
2017-07-26 13:43:12 +00:00
|
|
|
virObjectRef(obj);
|
2017-03-08 15:25:24 +00:00
|
|
|
|
2017-05-10 11:59:48 +00:00
|
|
|
obj->def = def;
|
|
|
|
obj->persistent = !(flags & VIR_NETWORK_OBJ_LIST_ADD_LIVE);
|
2017-03-08 15:25:24 +00:00
|
|
|
}
|
|
|
|
|
2019-10-16 11:43:01 +00:00
|
|
|
ret = g_steal_pointer(&obj);
|
2017-03-08 15:25:24 +00:00
|
|
|
|
|
|
|
cleanup:
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjEndAPI(&obj);
|
2017-03-08 15:25:24 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-03-08 15:25:24 +00:00
|
|
|
/*
|
2017-03-08 16:41:18 +00:00
|
|
|
* virNetworkObjAssignDef:
|
2017-03-08 15:25:24 +00: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 16:41:18 +00:00
|
|
|
* Look at virNetworkObjAssignDefLocked() for @flags description.
|
2017-03-08 15:25:24 +00:00
|
|
|
*
|
|
|
|
* Returns NULL on error, virNetworkObjPtr on success.
|
|
|
|
*/
|
|
|
|
virNetworkObjPtr
|
2017-03-08 16:41:18 +00:00
|
|
|
virNetworkObjAssignDef(virNetworkObjListPtr nets,
|
|
|
|
virNetworkDefPtr def,
|
|
|
|
unsigned int flags)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjPtr obj;
|
2017-03-08 15:25:24 +00:00
|
|
|
|
2017-10-10 14:02:32 +00:00
|
|
|
virObjectRWLockWrite(nets);
|
2017-05-10 11:59:48 +00:00
|
|
|
obj = virNetworkObjAssignDefLocked(nets, def, flags);
|
2017-10-10 14:02:32 +00:00
|
|
|
virObjectRWUnlock(nets);
|
2017-05-10 11:59:48 +00:00
|
|
|
return obj;
|
2017-03-08 15:25:24 +00:00
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-03-08 15:25:24 +00: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
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjSetDefTransient(virNetworkObjPtr obj,
|
2019-07-14 16:15:12 +00:00
|
|
|
bool live,
|
|
|
|
virNetworkXMLOptionPtr xmlopt)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
2017-05-10 11:59:48 +00:00
|
|
|
if (!virNetworkObjIsActive(obj) && !live)
|
2017-03-08 15:25:24 +00:00
|
|
|
return 0;
|
|
|
|
|
2017-05-10 11:59:48 +00:00
|
|
|
if (!obj->persistent || obj->newDef)
|
2017-03-08 15:25:24 +00:00
|
|
|
return 0;
|
|
|
|
|
2019-07-14 16:15:12 +00:00
|
|
|
obj->newDef = virNetworkDefCopy(obj->def,
|
|
|
|
xmlopt,
|
|
|
|
VIR_NETWORK_XML_INACTIVE);
|
2017-05-10 11:59:48 +00:00
|
|
|
return obj->newDef ? 0 : -1;
|
2017-03-08 15:25:24 +00:00
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-03-08 15:25:24 +00:00
|
|
|
/* virNetworkObjUnsetDefTransient:
|
|
|
|
*
|
|
|
|
* This *undoes* what virNetworkObjSetDefTransient did.
|
|
|
|
*/
|
|
|
|
void
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjUnsetDefTransient(virNetworkObjPtr obj)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
2017-05-10 11:59:48 +00:00
|
|
|
if (obj->newDef) {
|
|
|
|
virNetworkDefFree(obj->def);
|
|
|
|
obj->def = obj->newDef;
|
|
|
|
obj->newDef = NULL;
|
2017-03-08 15:25:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-03-08 15:25:24 +00:00
|
|
|
/*
|
|
|
|
* virNetworkObjGetPersistentDef:
|
|
|
|
* @network: network object pointer
|
|
|
|
*
|
|
|
|
* Return the persistent network configuration. If network is transient,
|
|
|
|
* return the running config.
|
|
|
|
*
|
|
|
|
* Returns NULL on error, virNetworkDefPtr on success.
|
|
|
|
*/
|
|
|
|
virNetworkDefPtr
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjGetPersistentDef(virNetworkObjPtr obj)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
2017-05-10 11:59:48 +00:00
|
|
|
if (obj->newDef)
|
|
|
|
return obj->newDef;
|
2017-03-08 15:25:24 +00:00
|
|
|
else
|
2017-05-10 11:59:48 +00:00
|
|
|
return obj->def;
|
2017-03-08 15:25:24 +00:00
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-03-08 15:25:24 +00: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
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjReplacePersistentDef(virNetworkObjPtr obj,
|
2017-03-08 15:25:24 +00:00
|
|
|
virNetworkDefPtr def)
|
|
|
|
{
|
2017-05-10 11:59:48 +00:00
|
|
|
if (virNetworkObjIsActive(obj)) {
|
|
|
|
virNetworkDefFree(obj->newDef);
|
|
|
|
obj->newDef = def;
|
2017-03-08 15:25:24 +00:00
|
|
|
} else {
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkDefFree(obj->def);
|
|
|
|
obj->def = def;
|
2017-03-08 15:25:24 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-03-08 15:25:24 +00:00
|
|
|
/*
|
2017-03-08 16:41:18 +00:00
|
|
|
* virNetworkObjConfigChangeSetup:
|
2017-03-08 15:25:24 +00: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 16:41:18 +00:00
|
|
|
static int
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjConfigChangeSetup(virNetworkObjPtr obj,
|
2019-07-14 16:15:12 +00:00
|
|
|
virNetworkXMLOptionPtr xmlopt,
|
2017-03-08 16:41:18 +00:00
|
|
|
unsigned int flags)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
|
|
|
bool isActive;
|
|
|
|
|
2017-05-10 11:59:48 +00:00
|
|
|
isActive = virNetworkObjIsActive(obj);
|
2017-03-08 15:25:24 +00:00
|
|
|
|
|
|
|
if (!isActive && (flags & VIR_NETWORK_UPDATE_AFFECT_LIVE)) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("network is not running"));
|
2019-10-21 18:18:51 +00:00
|
|
|
return -1;
|
2017-03-08 15:25:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & VIR_NETWORK_UPDATE_AFFECT_CONFIG) {
|
2017-05-10 11:59:48 +00:00
|
|
|
if (!obj->persistent) {
|
2017-03-08 15:25:24 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
|
_("cannot change persistent config of a "
|
|
|
|
"transient network"));
|
2019-10-21 18:18:51 +00:00
|
|
|
return -1;
|
2017-03-08 15:25:24 +00:00
|
|
|
}
|
|
|
|
/* this should already have been done by the driver, but do it
|
|
|
|
* anyway just in case.
|
|
|
|
*/
|
2019-07-14 16:15:12 +00:00
|
|
|
if (isActive && (virNetworkObjSetDefTransient(obj, false, xmlopt) < 0))
|
2019-10-21 18:18:51 +00:00
|
|
|
return -1;
|
2017-03-08 15:25:24 +00:00
|
|
|
}
|
|
|
|
|
2019-10-21 18:18:51 +00:00
|
|
|
return 0;
|
2017-03-08 15:25:24 +00:00
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
|
|
|
void
|
2017-03-08 16:41:18 +00:00
|
|
|
virNetworkObjRemoveInactive(virNetworkObjListPtr nets,
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjPtr obj)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
|
2017-05-10 11:59:48 +00:00
|
|
|
virUUIDFormat(obj->def->uuid, uuidstr);
|
|
|
|
virObjectRef(obj);
|
|
|
|
virObjectUnlock(obj);
|
2017-10-10 14:02:32 +00:00
|
|
|
virObjectRWLockWrite(nets);
|
2017-05-10 11:59:48 +00:00
|
|
|
virObjectLock(obj);
|
2017-03-08 15:25:24 +00:00
|
|
|
virHashRemoveEntry(nets->objs, uuidstr);
|
2017-10-10 14:02:32 +00:00
|
|
|
virObjectRWUnlock(nets);
|
2017-05-10 11:59:48 +00:00
|
|
|
virObjectUnref(obj);
|
2017-03-08 15:25:24 +00:00
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-03-08 15:25:24 +00:00
|
|
|
static char *
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjFormat(virNetworkObjPtr obj,
|
2019-07-14 16:15:12 +00:00
|
|
|
virNetworkXMLOptionPtr xmlopt,
|
2017-03-08 15:25:24 +00:00
|
|
|
unsigned int flags)
|
|
|
|
{
|
2020-07-03 02:19:01 +00:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2017-05-10 11:59:48 +00:00
|
|
|
char *classIdStr = virBitmapFormat(obj->classIdMap);
|
2017-03-08 15:25:24 +00:00
|
|
|
size_t i;
|
|
|
|
|
2017-07-26 12:01:55 +00:00
|
|
|
if (!classIdStr)
|
2020-07-03 03:19:26 +00:00
|
|
|
return NULL;
|
2017-03-08 15:25:24 +00:00
|
|
|
|
|
|
|
virBufferAddLit(&buf, "<networkstatus>\n");
|
|
|
|
virBufferAdjustIndent(&buf, 2);
|
2017-07-26 12:01:55 +00:00
|
|
|
virBufferAsprintf(&buf, "<class_id bitmap='%s'/>\n", classIdStr);
|
2017-05-10 11:59:48 +00:00
|
|
|
virBufferAsprintf(&buf, "<floor sum='%llu'/>\n", obj->floor_sum);
|
2017-07-26 12:01:55 +00:00
|
|
|
VIR_FREE(classIdStr);
|
2017-03-08 15:25:24 +00:00
|
|
|
|
|
|
|
for (i = 0; i < VIR_NETWORK_TAINT_LAST; i++) {
|
2017-05-10 11:59:48 +00:00
|
|
|
if (obj->taint & (1 << i))
|
2017-03-08 15:25:24 +00:00
|
|
|
virBufferAsprintf(&buf, "<taint flag='%s'/>\n",
|
|
|
|
virNetworkTaintTypeToString(i));
|
|
|
|
}
|
|
|
|
|
2019-07-14 16:15:12 +00:00
|
|
|
if (virNetworkDefFormatBuf(&buf, obj->def, xmlopt, flags) < 0)
|
2020-07-03 03:19:26 +00:00
|
|
|
return NULL;
|
2017-03-08 15:25:24 +00:00
|
|
|
|
|
|
|
virBufferAdjustIndent(&buf, -2);
|
|
|
|
virBufferAddLit(&buf, "</networkstatus>");
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
|
|
|
int
|
2017-03-08 16:41:18 +00:00
|
|
|
virNetworkObjSaveStatus(const char *statusDir,
|
2019-07-14 16:15:12 +00:00
|
|
|
virNetworkObjPtr obj,
|
|
|
|
virNetworkXMLOptionPtr xmlopt)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
int flags = 0;
|
|
|
|
char *xml;
|
|
|
|
|
2019-07-14 16:15:12 +00:00
|
|
|
if (!(xml = virNetworkObjFormat(obj, xmlopt, flags)))
|
2017-03-08 15:25:24 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2017-05-10 11:59:48 +00:00
|
|
|
if (virNetworkSaveXML(statusDir, obj->def, xml))
|
2017-03-08 15:25:24 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(xml);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-03-08 16:41:18 +00:00
|
|
|
static virNetworkObjPtr
|
2017-03-08 15:25:24 +00:00
|
|
|
virNetworkLoadState(virNetworkObjListPtr nets,
|
|
|
|
const char *stateDir,
|
2019-07-14 16:15:12 +00:00
|
|
|
const char *name,
|
|
|
|
virNetworkXMLOptionPtr xmlopt)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
|
|
|
char *configFile = NULL;
|
|
|
|
virNetworkDefPtr def = NULL;
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjPtr obj = NULL;
|
2017-03-08 15:25:24 +00:00
|
|
|
xmlDocPtr xml = NULL;
|
|
|
|
xmlNodePtr node = NULL, *nodes = NULL;
|
|
|
|
xmlXPathContextPtr ctxt = NULL;
|
2017-07-26 12:01:55 +00:00
|
|
|
virBitmapPtr classIdMap = NULL;
|
2017-03-08 15:25:24 +00:00
|
|
|
unsigned long long floor_sum_val = 0;
|
|
|
|
unsigned int taint = 0;
|
|
|
|
int n;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
|
|
|
|
if ((configFile = virNetworkConfigFile(stateDir, name)) == NULL)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!(xml = virXMLParseCtxt(configFile, NULL, _("(network status)"), &ctxt)))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!(node = virXPathNode("//network", ctxt))) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Could not find any 'network' element in status file"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* parse the definition first */
|
|
|
|
ctxt->node = node;
|
2019-07-14 16:15:12 +00:00
|
|
|
if (!(def = virNetworkDefParseXML(ctxt, xmlopt)))
|
2017-03-08 15:25:24 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (STRNEQ(name, def->name)) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Network config filename '%s'"
|
|
|
|
" does not match network name '%s'"),
|
|
|
|
configFile, def->name);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* now parse possible status data */
|
|
|
|
node = xmlDocGetRootElement(xml);
|
2017-08-14 12:31:52 +00:00
|
|
|
if (virXMLNodeNameEqual(node, "networkstatus")) {
|
2017-03-08 15:25:24 +00:00
|
|
|
/* Newer network status file. Contains useful
|
|
|
|
* info which are not to be found in bare config XML */
|
2017-07-26 12:01:55 +00:00
|
|
|
char *classIdStr = NULL;
|
2017-03-08 15:25:24 +00:00
|
|
|
char *floor_sum = NULL;
|
|
|
|
|
|
|
|
ctxt->node = node;
|
2017-07-26 12:01:55 +00:00
|
|
|
if ((classIdStr = virXPathString("string(./class_id[1]/@bitmap)",
|
|
|
|
ctxt))) {
|
2017-08-16 10:55:03 +00:00
|
|
|
if (!(classIdMap = virBitmapParseUnlimited(classIdStr))) {
|
2017-07-26 12:01:55 +00:00
|
|
|
VIR_FREE(classIdStr);
|
2017-03-08 15:25:24 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
2017-07-26 12:01:55 +00:00
|
|
|
VIR_FREE(classIdStr);
|
2017-03-08 15:25:24 +00: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,
|
|
|
|
_("Malformed 'floor_sum' attribute: %s"),
|
|
|
|
floor_sum);
|
|
|
|
VIR_FREE(floor_sum);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
VIR_FREE(floor_sum);
|
|
|
|
|
|
|
|
if ((n = virXPathNodeSet("./taint", ctxt, &nodes)) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
char *str = virXMLPropString(nodes[i], "flag");
|
|
|
|
if (str) {
|
|
|
|
int flag = virNetworkTaintTypeFromString(str);
|
|
|
|
if (flag < 0) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("Unknown taint flag %s"), str);
|
|
|
|
VIR_FREE(str);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
VIR_FREE(str);
|
|
|
|
/* Compute taint mask here. The network object does not
|
|
|
|
* exist yet, so we can't use virNetworkObjtTaint. */
|
|
|
|
taint |= (1 << flag);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
VIR_FREE(nodes);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* create the object */
|
2017-05-10 11:59:48 +00:00
|
|
|
if (!(obj = virNetworkObjAssignDef(nets, def,
|
2017-03-08 16:41:18 +00:00
|
|
|
VIR_NETWORK_OBJ_LIST_ADD_LIVE)))
|
2017-03-08 15:25:24 +00:00
|
|
|
goto error;
|
|
|
|
/* do not put any "goto error" below this comment */
|
|
|
|
|
|
|
|
/* assign status data stored in the network object */
|
2017-07-26 12:01:55 +00:00
|
|
|
if (classIdMap) {
|
2017-05-10 11:59:48 +00:00
|
|
|
virBitmapFree(obj->classIdMap);
|
|
|
|
obj->classIdMap = classIdMap;
|
2017-03-08 15:25:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (floor_sum_val > 0)
|
2017-05-10 11:59:48 +00:00
|
|
|
obj->floor_sum = floor_sum_val;
|
2017-03-08 15:25:24 +00:00
|
|
|
|
2017-05-10 11:59:48 +00:00
|
|
|
obj->taint = taint;
|
|
|
|
obj->active = true; /* network with a state file is by definition active */
|
2017-03-08 15:25:24 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(configFile);
|
|
|
|
xmlFreeDoc(xml);
|
|
|
|
xmlXPathFreeContext(ctxt);
|
2017-05-10 11:59:48 +00:00
|
|
|
return obj;
|
2017-03-08 15:25:24 +00:00
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(nodes);
|
2017-07-26 12:01:55 +00:00
|
|
|
virBitmapFree(classIdMap);
|
2017-03-08 15:25:24 +00:00
|
|
|
virNetworkDefFree(def);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-03-08 16:41:18 +00:00
|
|
|
static virNetworkObjPtr
|
2017-03-08 15:41:57 +00:00
|
|
|
virNetworkLoadConfig(virNetworkObjListPtr nets,
|
|
|
|
const char *configDir,
|
|
|
|
const char *autostartDir,
|
2019-07-14 16:15:12 +00:00
|
|
|
const char *name,
|
|
|
|
virNetworkXMLOptionPtr xmlopt)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
|
|
|
char *configFile = NULL, *autostartLink = NULL;
|
|
|
|
virNetworkDefPtr def = NULL;
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjPtr 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 15:08:13 +00:00
|
|
|
bool saveConfig = false;
|
2017-03-08 15:25:24 +00:00
|
|
|
int autostart;
|
|
|
|
|
|
|
|
if ((configFile = virNetworkConfigFile(configDir, name)) == NULL)
|
|
|
|
goto error;
|
|
|
|
if ((autostartLink = virNetworkConfigFile(autostartDir, name)) == NULL)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if ((autostart = virFileLinkPointsTo(autostartLink, configFile)) < 0)
|
|
|
|
goto error;
|
|
|
|
|
2019-07-14 16:15:12 +00:00
|
|
|
if (!(def = virNetworkDefParseFile(configFile, xmlopt)))
|
2017-03-08 15:25:24 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (STRNEQ(name, def->name)) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Network config filename '%s'"
|
|
|
|
" does not match network name '%s'"),
|
|
|
|
configFile, def->name);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2018-07-24 03:49:48 +00: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 15:25:24 +00: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 15:08:13 +00: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 15:25:24 +00:00
|
|
|
}
|
2018-07-24 03:49:48 +00: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 15:25:24 +00: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 03:49:48 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_NETWORK_FORWARD_LAST:
|
|
|
|
default:
|
|
|
|
virReportEnumRangeError(virNetworkForwardType, def->forward.type);
|
|
|
|
goto error;
|
2017-03-08 15:25:24 +00: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 15:08:13 +00: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) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2017-05-10 11:59:48 +00:00
|
|
|
if (!(obj = virNetworkObjAssignDef(nets, def, 0)))
|
2017-03-08 15:25:24 +00:00
|
|
|
goto error;
|
|
|
|
|
2017-05-10 11:59:48 +00:00
|
|
|
obj->autostart = (autostart == 1);
|
2017-03-08 15:25:24 +00:00
|
|
|
|
|
|
|
VIR_FREE(configFile);
|
|
|
|
VIR_FREE(autostartLink);
|
|
|
|
|
2017-05-10 11:59:48 +00:00
|
|
|
return obj;
|
2017-03-08 15:25:24 +00:00
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(configFile);
|
|
|
|
VIR_FREE(autostartLink);
|
|
|
|
virNetworkDefFree(def);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2017-03-08 16:41:18 +00:00
|
|
|
virNetworkObjLoadAllState(virNetworkObjListPtr nets,
|
2019-07-14 16:15:12 +00:00
|
|
|
const char *stateDir,
|
|
|
|
virNetworkXMLOptionPtr xmlopt)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
2020-10-25 21:50:51 +00:00
|
|
|
g_autoptr(DIR) dir = NULL;
|
2017-03-08 15:25:24 +00:00
|
|
|
struct dirent *entry;
|
|
|
|
int ret = -1;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if ((rc = virDirOpenIfExists(&dir, stateDir)) <= 0)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
while ((ret = virDirRead(dir, &entry, stateDir)) > 0) {
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjPtr obj;
|
2017-03-08 15:25:24 +00:00
|
|
|
|
2019-03-06 14:30:04 +00:00
|
|
|
if (!virStringStripSuffix(entry->d_name, ".xml"))
|
2017-03-08 15:25:24 +00:00
|
|
|
continue;
|
|
|
|
|
2019-07-14 16:15:12 +00: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 21:49:11 +00:00
|
|
|
return -1;
|
2018-12-19 14:24:53 +00:00
|
|
|
}
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjEndAPI(&obj);
|
2017-03-08 15:25:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
int
|
2017-03-08 16:41:18 +00:00
|
|
|
virNetworkObjLoadAllConfigs(virNetworkObjListPtr nets,
|
|
|
|
const char *configDir,
|
2019-07-14 16:15:12 +00:00
|
|
|
const char *autostartDir,
|
|
|
|
virNetworkXMLOptionPtr xmlopt)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
2020-10-25 21:50:51 +00:00
|
|
|
g_autoptr(DIR) dir = NULL;
|
2017-03-08 15:25:24 +00:00
|
|
|
struct dirent *entry;
|
|
|
|
int ret = -1;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if ((rc = virDirOpenIfExists(&dir, configDir)) <= 0)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
while ((ret = virDirRead(dir, &entry, configDir)) > 0) {
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjPtr obj;
|
2017-03-08 15:25:24 +00:00
|
|
|
|
2019-03-06 14:30:04 +00:00
|
|
|
if (!virStringStripSuffix(entry->d_name, ".xml"))
|
2017-03-08 15:25:24 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/* NB: ignoring errors, so one malformed config doesn't
|
|
|
|
kill the whole process */
|
2017-05-10 11:59:48 +00:00
|
|
|
obj = virNetworkLoadConfig(nets,
|
2017-03-08 15:25:24 +00:00
|
|
|
configDir,
|
|
|
|
autostartDir,
|
2019-07-14 16:15:12 +00:00
|
|
|
entry->d_name,
|
|
|
|
xmlopt);
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjEndAPI(&obj);
|
2017-03-08 15:25:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
|
|
|
int
|
2017-03-08 16:41:18 +00:00
|
|
|
virNetworkObjDeleteConfig(const char *configDir,
|
|
|
|
const char *autostartDir,
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjPtr obj)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
|
|
|
char *configFile = NULL;
|
|
|
|
char *autostartLink = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
2017-05-10 11:59:48 +00:00
|
|
|
if (!(configFile = virNetworkConfigFile(configDir, obj->def->name)))
|
2017-03-08 15:25:24 +00:00
|
|
|
goto error;
|
2017-05-10 11:59:48 +00:00
|
|
|
if (!(autostartLink = virNetworkConfigFile(autostartDir, obj->def->name)))
|
2017-03-08 15:25:24 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
/* Not fatal if this doesn't work */
|
|
|
|
unlink(autostartLink);
|
2017-05-10 11:59:48 +00:00
|
|
|
obj->autostart = false;
|
2017-03-08 15:25:24 +00:00
|
|
|
|
|
|
|
if (unlink(configFile) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("cannot remove config file '%s'"),
|
|
|
|
configFile);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(configFile);
|
|
|
|
VIR_FREE(autostartLink);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-03-08 16:41:18 +00:00
|
|
|
struct virNetworkObjBridgeInUseHelperData {
|
2017-03-08 15:25:24 +00:00
|
|
|
const char *bridge;
|
|
|
|
const char *skipname;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
2017-03-08 16:41:18 +00:00
|
|
|
virNetworkObjBridgeInUseHelper(const void *payload,
|
2020-10-21 11:31:16 +00:00
|
|
|
const char *name G_GNUC_UNUSED,
|
2017-03-08 16:41:18 +00:00
|
|
|
const void *opaque)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
|
|
|
int ret;
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjPtr obj = (virNetworkObjPtr) payload;
|
2017-03-08 16:41:18 +00:00
|
|
|
const struct virNetworkObjBridgeInUseHelperData *data = opaque;
|
2017-03-08 15:25:24 +00:00
|
|
|
|
2017-05-10 11:59:48 +00:00
|
|
|
virObjectLock(obj);
|
2017-03-08 15:25:24 +00:00
|
|
|
if (data->skipname &&
|
2017-05-10 11:59:48 +00:00
|
|
|
((obj->def && STREQ(obj->def->name, data->skipname)) ||
|
|
|
|
(obj->newDef && STREQ(obj->newDef->name, data->skipname))))
|
2017-03-08 15:25:24 +00:00
|
|
|
ret = 0;
|
2017-05-10 11:59:48 +00: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 15:25:24 +00:00
|
|
|
ret = 1;
|
|
|
|
else
|
|
|
|
ret = 0;
|
2017-05-10 11:59:48 +00:00
|
|
|
virObjectUnlock(obj);
|
2017-03-08 15:25:24 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-08-17 19:41:37 +00:00
|
|
|
bool
|
2017-03-08 16:41:18 +00:00
|
|
|
virNetworkObjBridgeInUse(virNetworkObjListPtr nets,
|
|
|
|
const char *bridge,
|
|
|
|
const char *skipname)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
|
|
|
virNetworkObjPtr obj;
|
2017-03-08 16:41:18 +00:00
|
|
|
struct virNetworkObjBridgeInUseHelperData data = {bridge, skipname};
|
2017-03-08 15:25:24 +00:00
|
|
|
|
2017-10-10 14:02:32 +00:00
|
|
|
virObjectRWLockRead(nets);
|
2017-06-13 13:56:14 +00:00
|
|
|
obj = virHashSearch(nets->objs, virNetworkObjBridgeInUseHelper, &data, NULL);
|
2017-10-10 14:02:32 +00:00
|
|
|
virObjectRWUnlock(nets);
|
2017-03-08 15:25:24 +00: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
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjUpdate(virNetworkObjPtr obj,
|
2017-03-08 15:25:24 +00:00
|
|
|
unsigned int command, /* virNetworkUpdateCommand */
|
|
|
|
unsigned int section, /* virNetworkUpdateSection */
|
|
|
|
int parentIndex,
|
|
|
|
const char *xml,
|
2019-07-14 16:15:12 +00:00
|
|
|
virNetworkXMLOptionPtr xmlopt,
|
2017-03-08 15:25:24 +00:00
|
|
|
unsigned int flags) /* virNetworkUpdateFlags */
|
|
|
|
{
|
|
|
|
int ret = -1;
|
2021-03-11 14:37:07 +00:00
|
|
|
virNetworkDefPtr livedef = NULL;
|
|
|
|
virNetworkDefPtr configdef = NULL;
|
2017-03-08 15:25:24 +00:00
|
|
|
|
|
|
|
/* normalize config data, and check for common invalid requests. */
|
2019-07-14 16:15:12 +00:00
|
|
|
if (virNetworkObjConfigChangeSetup(obj, xmlopt, flags) < 0)
|
2017-03-08 15:25:24 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (flags & VIR_NETWORK_UPDATE_AFFECT_LIVE) {
|
|
|
|
virNetworkDefPtr checkdef;
|
|
|
|
|
|
|
|
/* work on a copy of the def */
|
2019-07-14 16:15:12 +00:00
|
|
|
if (!(livedef = virNetworkDefCopy(obj->def, xmlopt, 0)))
|
2017-03-08 15:25:24 +00:00
|
|
|
goto cleanup;
|
|
|
|
if (virNetworkDefUpdateSection(livedef, command, section,
|
|
|
|
parentIndex, xml, flags) < 0) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
/* run a final format/parse cycle to make sure we didn't
|
|
|
|
* add anything illegal to the def
|
|
|
|
*/
|
2019-07-14 16:15:12 +00:00
|
|
|
if (!(checkdef = virNetworkDefCopy(livedef, xmlopt, 0)))
|
2017-03-08 15:25:24 +00:00
|
|
|
goto cleanup;
|
|
|
|
virNetworkDefFree(checkdef);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & VIR_NETWORK_UPDATE_AFFECT_CONFIG) {
|
|
|
|
virNetworkDefPtr checkdef;
|
|
|
|
|
|
|
|
/* work on a copy of the def */
|
2017-05-10 11:59:48 +00:00
|
|
|
if (!(configdef = virNetworkDefCopy(virNetworkObjGetPersistentDef(obj),
|
2019-07-14 16:15:12 +00:00
|
|
|
xmlopt,
|
2017-03-08 15:25:24 +00:00
|
|
|
VIR_NETWORK_XML_INACTIVE))) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (virNetworkDefUpdateSection(configdef, command, section,
|
|
|
|
parentIndex, xml, flags) < 0) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (!(checkdef = virNetworkDefCopy(configdef,
|
2019-07-14 16:15:12 +00:00
|
|
|
xmlopt,
|
2017-03-08 15:25:24 +00:00
|
|
|
VIR_NETWORK_XML_INACTIVE))) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
virNetworkDefFree(checkdef);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (configdef) {
|
|
|
|
/* successfully modified copy, now replace original */
|
2017-05-10 11:59:48 +00:00
|
|
|
if (virNetworkObjReplacePersistentDef(obj, configdef) < 0)
|
2017-03-08 15:25:24 +00:00
|
|
|
goto cleanup;
|
|
|
|
configdef = NULL;
|
|
|
|
}
|
|
|
|
if (livedef) {
|
|
|
|
/* successfully modified copy, now replace original */
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkDefFree(obj->def);
|
|
|
|
obj->def = livedef;
|
2017-03-08 15:25:24 +00:00
|
|
|
livedef = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
virNetworkDefFree(livedef);
|
|
|
|
virNetworkDefFree(configdef);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-03-08 15:25:24 +00:00
|
|
|
#define MATCH(FLAG) (flags & (FLAG))
|
|
|
|
static bool
|
2018-08-13 15:55:16 +00:00
|
|
|
virNetworkObjMatch(virNetworkObjPtr obj,
|
|
|
|
unsigned int flags)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
|
|
|
/* filter by active state */
|
|
|
|
if (MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_ACTIVE) &&
|
|
|
|
!((MATCH(VIR_CONNECT_LIST_NETWORKS_ACTIVE) &&
|
2017-05-10 11:59:48 +00:00
|
|
|
virNetworkObjIsActive(obj)) ||
|
2017-03-08 15:25:24 +00:00
|
|
|
(MATCH(VIR_CONNECT_LIST_NETWORKS_INACTIVE) &&
|
2017-05-10 11:59:48 +00:00
|
|
|
!virNetworkObjIsActive(obj))))
|
2017-03-08 15:25:24 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
/* filter by persistence */
|
|
|
|
if (MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_PERSISTENT) &&
|
|
|
|
!((MATCH(VIR_CONNECT_LIST_NETWORKS_PERSISTENT) &&
|
2017-05-10 11:59:48 +00:00
|
|
|
obj->persistent) ||
|
2017-03-08 15:25:24 +00:00
|
|
|
(MATCH(VIR_CONNECT_LIST_NETWORKS_TRANSIENT) &&
|
2017-05-10 11:59:48 +00:00
|
|
|
!obj->persistent)))
|
2017-03-08 15:25:24 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
/* filter by autostart option */
|
|
|
|
if (MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_AUTOSTART) &&
|
|
|
|
!((MATCH(VIR_CONNECT_LIST_NETWORKS_AUTOSTART) &&
|
2017-05-10 11:59:48 +00:00
|
|
|
obj->autostart) ||
|
2017-03-08 15:25:24 +00:00
|
|
|
(MATCH(VIR_CONNECT_LIST_NETWORKS_NO_AUTOSTART) &&
|
2017-05-10 11:59:48 +00:00
|
|
|
!obj->autostart)))
|
2017-03-08 15:25:24 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
#undef MATCH
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2018-08-13 15:55:14 +00:00
|
|
|
typedef struct _virNetworkObjListExportData virNetworkObjListExportData;
|
|
|
|
typedef virNetworkObjListExportData *virNetworkObjListExportDataPtr;
|
|
|
|
struct _virNetworkObjListExportData {
|
2017-03-08 15:25:24 +00:00
|
|
|
virConnectPtr conn;
|
|
|
|
virNetworkPtr *nets;
|
|
|
|
virNetworkObjListFilter filter;
|
|
|
|
unsigned int flags;
|
|
|
|
int nnets;
|
|
|
|
bool error;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
2018-08-13 15:55:15 +00:00
|
|
|
virNetworkObjListExportCallback(void *payload,
|
2020-10-21 11:31:16 +00:00
|
|
|
const char *name G_GNUC_UNUSED,
|
2018-08-13 15:55:15 +00:00
|
|
|
void *opaque)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
2018-08-13 15:55:14 +00:00
|
|
|
virNetworkObjListExportDataPtr data = opaque;
|
2017-03-08 15:25:24 +00:00
|
|
|
virNetworkObjPtr obj = payload;
|
|
|
|
virNetworkPtr net = NULL;
|
|
|
|
|
|
|
|
if (data->error)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
virObjectLock(obj);
|
|
|
|
|
|
|
|
if (data->filter &&
|
|
|
|
!data->filter(data->conn, obj->def))
|
|
|
|
goto cleanup;
|
|
|
|
|
2018-08-13 15:55:16 +00:00
|
|
|
if (!virNetworkObjMatch(obj, data->flags))
|
2017-03-08 15:25:24 +00: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 15:41:57 +00:00
|
|
|
|
2017-03-08 15:25:24 +00:00
|
|
|
int
|
|
|
|
virNetworkObjListExport(virConnectPtr conn,
|
|
|
|
virNetworkObjListPtr netobjs,
|
|
|
|
virNetworkPtr **nets,
|
|
|
|
virNetworkObjListFilter filter,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
2018-08-13 15:55:14 +00:00
|
|
|
virNetworkObjListExportData data = {
|
2017-05-10 12:58:38 +00:00
|
|
|
.conn = conn, .nets = NULL, .filter = filter, .flags = flags,
|
|
|
|
.nnets = 0, .error = false };
|
2017-03-08 15:25:24 +00:00
|
|
|
|
2017-10-10 14:02:32 +00:00
|
|
|
virObjectRWLockRead(netobjs);
|
2020-10-07 19:15:50 +00:00
|
|
|
if (nets)
|
2020-10-12 17:45:37 +00:00
|
|
|
data.nets = g_new0(virNetworkPtr, virHashSize(netobjs->objs) + 1);
|
2017-03-08 15:25:24 +00:00
|
|
|
|
2018-08-13 15:55:15 +00:00
|
|
|
virHashForEach(netobjs->objs, virNetworkObjListExportCallback, &data);
|
2017-03-08 15:25:24 +00:00
|
|
|
|
|
|
|
if (data.error)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (data.nets) {
|
|
|
|
/* trim the array to the final size */
|
|
|
|
ignore_value(VIR_REALLOC_N(data.nets, data.nnets + 1));
|
|
|
|
*nets = data.nets;
|
|
|
|
data.nets = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = data.nnets;
|
|
|
|
cleanup:
|
2017-10-10 14:02:32 +00:00
|
|
|
virObjectRWUnlock(netobjs);
|
2017-03-08 15:25:24 +00:00
|
|
|
while (data.nets && data.nnets)
|
|
|
|
virObjectUnref(data.nets[--data.nnets]);
|
|
|
|
|
|
|
|
VIR_FREE(data.nets);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-03-08 15:25:24 +00:00
|
|
|
struct virNetworkObjListForEachHelperData {
|
|
|
|
virNetworkObjListIterator callback;
|
|
|
|
void *opaque;
|
|
|
|
int ret;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
|
|
virNetworkObjListForEachHelper(void *payload,
|
2020-10-21 11:31:16 +00:00
|
|
|
const char *name G_GNUC_UNUSED,
|
2017-03-08 15:25:24 +00:00
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
struct virNetworkObjListForEachHelperData *data = opaque;
|
|
|
|
|
|
|
|
if (data->callback(payload, data->opaque) < 0)
|
|
|
|
data->ret = -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-03-08 15:25:24 +00: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
|
|
|
|
virNetworkObjListForEach(virNetworkObjListPtr nets,
|
|
|
|
virNetworkObjListIterator callback,
|
|
|
|
void *opaque)
|
|
|
|
{
|
2017-05-10 12:58:38 +00:00
|
|
|
struct virNetworkObjListForEachHelperData data = {
|
|
|
|
.callback = callback, .opaque = opaque, .ret = 0};
|
2017-10-10 14:02:32 +00:00
|
|
|
virObjectRWLockRead(nets);
|
2020-10-23 07:49:36 +00:00
|
|
|
virHashForEachSafe(nets->objs, virNetworkObjListForEachHelper, &data);
|
2017-10-10 14:02:32 +00:00
|
|
|
virObjectRWUnlock(nets);
|
2017-03-08 15:25:24 +00:00
|
|
|
return data.ret;
|
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-03-08 15:25:24 +00:00
|
|
|
struct virNetworkObjListGetHelperData {
|
|
|
|
virConnectPtr conn;
|
|
|
|
virNetworkObjListFilter filter;
|
|
|
|
char **names;
|
2017-08-15 20:48:37 +00:00
|
|
|
int nnames;
|
2017-07-26 14:18:39 +00:00
|
|
|
int maxnames;
|
2017-03-08 15:25:24 +00:00
|
|
|
bool active;
|
|
|
|
bool error;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
|
|
virNetworkObjListGetHelper(void *payload,
|
2020-10-21 11:31:16 +00:00
|
|
|
const char *name G_GNUC_UNUSED,
|
2017-03-08 15:25:24 +00:00
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
struct virNetworkObjListGetHelperData *data = opaque;
|
|
|
|
virNetworkObjPtr obj = payload;
|
|
|
|
|
|
|
|
if (data->error)
|
|
|
|
return 0;
|
|
|
|
|
2017-07-26 14:18:39 +00:00
|
|
|
if (data->maxnames >= 0 &&
|
2017-08-15 20:48:37 +00:00
|
|
|
data->nnames == data->maxnames)
|
2017-03-08 15:25:24 +00: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 11:49:46 +00:00
|
|
|
if (data->names)
|
|
|
|
data->names[data->nnames] = g_strdup(obj->def->name);
|
2017-08-15 20:48:37 +00:00
|
|
|
data->nnames++;
|
2017-03-08 15:25:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virObjectUnlock(obj);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-03-08 15:25:24 +00:00
|
|
|
int
|
|
|
|
virNetworkObjListGetNames(virNetworkObjListPtr nets,
|
|
|
|
bool active,
|
|
|
|
char **names,
|
2017-07-26 14:18:39 +00:00
|
|
|
int maxnames,
|
2017-03-08 15:25:24 +00:00
|
|
|
virNetworkObjListFilter filter,
|
|
|
|
virConnectPtr conn)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
struct virNetworkObjListGetHelperData data = {
|
2017-08-15 20:48:37 +00:00
|
|
|
.conn = conn, .filter = filter, .names = names, .nnames = 0,
|
|
|
|
.maxnames = maxnames, .active = active, .error = false};
|
2017-03-08 15:25:24 +00:00
|
|
|
|
2017-10-10 14:02:32 +00:00
|
|
|
virObjectRWLockRead(nets);
|
2017-03-08 15:25:24 +00:00
|
|
|
virHashForEach(nets->objs, virNetworkObjListGetHelper, &data);
|
2017-10-10 14:02:32 +00:00
|
|
|
virObjectRWUnlock(nets);
|
2017-03-08 15:25:24 +00:00
|
|
|
|
|
|
|
if (data.error)
|
|
|
|
goto cleanup;
|
|
|
|
|
2017-08-15 20:48:37 +00:00
|
|
|
ret = data.nnames;
|
2017-03-08 15:25:24 +00:00
|
|
|
cleanup:
|
|
|
|
if (ret < 0) {
|
2017-08-15 20:48:37 +00:00
|
|
|
while (data.nnames)
|
|
|
|
VIR_FREE(data.names[--data.nnames]);
|
2017-03-08 15:25:24 +00:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-03-08 15:25:24 +00:00
|
|
|
int
|
|
|
|
virNetworkObjListNumOfNetworks(virNetworkObjListPtr nets,
|
|
|
|
bool active,
|
|
|
|
virNetworkObjListFilter filter,
|
|
|
|
virConnectPtr conn)
|
|
|
|
{
|
|
|
|
struct virNetworkObjListGetHelperData data = {
|
2017-08-15 20:48:37 +00:00
|
|
|
.conn = conn, .filter = filter, .names = NULL, .nnames = 0,
|
|
|
|
.maxnames = -1, .active = active, .error = false};
|
2017-03-08 15:25:24 +00:00
|
|
|
|
2017-10-10 14:02:32 +00:00
|
|
|
virObjectRWLockRead(nets);
|
2017-03-08 15:25:24 +00:00
|
|
|
virHashForEach(nets->objs, virNetworkObjListGetHelper, &data);
|
2017-10-10 14:02:32 +00:00
|
|
|
virObjectRWUnlock(nets);
|
2017-03-08 15:25:24 +00:00
|
|
|
|
2017-08-15 20:48:37 +00:00
|
|
|
return data.nnames;
|
2017-03-08 15:25:24 +00:00
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-03-08 15:25:24 +00:00
|
|
|
struct virNetworkObjListPruneHelperData {
|
|
|
|
unsigned int flags;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
|
|
virNetworkObjListPruneHelper(const void *payload,
|
2020-10-21 11:31:16 +00:00
|
|
|
const char *name G_GNUC_UNUSED,
|
2017-03-08 15:25:24 +00:00
|
|
|
const void *opaque)
|
|
|
|
{
|
|
|
|
const struct virNetworkObjListPruneHelperData *data = opaque;
|
|
|
|
virNetworkObjPtr obj = (virNetworkObjPtr) payload;
|
|
|
|
int want = 0;
|
|
|
|
|
|
|
|
virObjectLock(obj);
|
2018-08-13 15:55:16 +00:00
|
|
|
want = virNetworkObjMatch(obj, data->flags);
|
2017-03-08 15:25:24 +00:00
|
|
|
virObjectUnlock(obj);
|
|
|
|
return want;
|
|
|
|
}
|
|
|
|
|
2017-03-08 15:41:57 +00:00
|
|
|
|
2017-03-08 15:25:24 +00: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
|
|
|
|
virNetworkObjListPrune(virNetworkObjListPtr nets,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
struct virNetworkObjListPruneHelperData data = {flags};
|
|
|
|
|
2017-10-10 14:02:32 +00:00
|
|
|
virObjectRWLockWrite(nets);
|
2017-03-08 15:25:24 +00:00
|
|
|
virHashRemoveSet(nets->objs, virNetworkObjListPruneHelper, &data);
|
2017-10-10 14:02:32 +00:00
|
|
|
virObjectRWUnlock(nets);
|
2017-03-08 15:25:24 +00:00
|
|
|
}
|
2018-12-19 14:24:53 +00:00
|
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
virNetworkObjGetPortStatusDir(virNetworkObjPtr net,
|
|
|
|
const char *stateDir)
|
|
|
|
{
|
|
|
|
char *ret;
|
2019-10-22 13:26:14 +00:00
|
|
|
ret = g_strdup_printf("%s/%s/ports", stateDir, net->def->name);
|
2018-12-19 14:24:53 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
virNetworkObjAddPort(virNetworkObjPtr net,
|
|
|
|
virNetworkPortDefPtr portdef,
|
|
|
|
const char *stateDir)
|
|
|
|
{
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
2019-10-15 13:16:31 +00: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,
|
|
|
|
_("Network port with UUID %s already exists"),
|
|
|
|
uuidstr);
|
2019-07-09 14:51:43 +00:00
|
|
|
return -1;
|
2018-12-19 14:24:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!(dir = virNetworkObjGetPortStatusDir(net, stateDir)))
|
2019-07-09 14:51:43 +00:00
|
|
|
return -1;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
|
|
|
if (virHashAddEntry(net->ports, uuidstr, portdef) < 0)
|
2019-07-09 14:51:43 +00:00
|
|
|
return -1;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
|
|
|
if (virNetworkPortDefSaveStatus(portdef, dir) < 0) {
|
|
|
|
virHashRemoveEntry(net->ports, uuidstr);
|
2019-07-09 14:51:43 +00:00
|
|
|
return -1;
|
2018-12-19 14:24:53 +00:00
|
|
|
}
|
|
|
|
|
2019-07-09 14:51:43 +00:00
|
|
|
return 0;
|
2018-12-19 14:24:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virNetworkPortDefPtr
|
|
|
|
virNetworkObjLookupPort(virNetworkObjPtr net,
|
|
|
|
const unsigned char *uuid)
|
|
|
|
{
|
|
|
|
virNetworkPortDefPtr ret = NULL;
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
|
|
|
|
virUUIDFormat(uuid, uuidstr);
|
|
|
|
|
|
|
|
if (!(ret = virHashLookup(net->ports, uuidstr))) {
|
|
|
|
virReportError(VIR_ERR_NO_NETWORK_PORT,
|
|
|
|
_("Network port with UUID %s does not exist"),
|
|
|
|
uuidstr);
|
2019-10-21 18:18:51 +00:00
|
|
|
return NULL;
|
2018-12-19 14:24:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
virNetworkObjDeletePort(virNetworkObjPtr net,
|
|
|
|
const unsigned char *uuid,
|
|
|
|
const char *stateDir)
|
|
|
|
{
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *dir = NULL;
|
2018-12-19 14:24:53 +00:00
|
|
|
virNetworkPortDefPtr portdef;
|
|
|
|
|
|
|
|
virUUIDFormat(uuid, uuidstr);
|
|
|
|
|
|
|
|
if (!(portdef = virHashLookup(net->ports, uuidstr))) {
|
|
|
|
virReportError(VIR_ERR_NO_NETWORK_PORT,
|
|
|
|
_("Network port with UUID %s does not exist"),
|
|
|
|
uuidstr);
|
2019-07-09 14:57:44 +00:00
|
|
|
return -1;
|
2018-12-19 14:24:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!(dir = virNetworkObjGetPortStatusDir(net, stateDir)))
|
2019-07-09 14:57:44 +00:00
|
|
|
return -1;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
|
|
|
if (virNetworkPortDefDeleteStatus(portdef, dir) < 0)
|
2019-07-09 14:57:44 +00:00
|
|
|
return -1;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
|
|
|
if (virHashRemoveEntry(net->ports, uuidstr) < 0)
|
2019-07-09 14:57:44 +00:00
|
|
|
return -1;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
2019-07-09 14:57:44 +00:00
|
|
|
return 0;
|
2018-12-19 14:24:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
virNetworkObjDeleteAllPorts(virNetworkObjPtr net,
|
|
|
|
const char *stateDir)
|
|
|
|
{
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *dir = NULL;
|
2020-10-25 21:50:51 +00: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 21:49:11 +00:00
|
|
|
return -1;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
2020-10-27 21:49:11 +00: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 13:26:14 +00: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 21:49:11 +00:00
|
|
|
return 0;
|
2018-12-19 14:24:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct _virNetworkObjPortListExportData virNetworkObjPortListExportData;
|
|
|
|
typedef virNetworkObjPortListExportData *virNetworkObjPortListExportDataPtr;
|
|
|
|
struct _virNetworkObjPortListExportData {
|
|
|
|
virNetworkPtr net;
|
|
|
|
virNetworkDefPtr def;
|
|
|
|
virNetworkPortPtr *ports;
|
|
|
|
virNetworkPortListFilter filter;
|
|
|
|
int nports;
|
|
|
|
bool error;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
|
|
virNetworkObjPortListExportCallback(void *payload,
|
2020-10-21 11:31:16 +00:00
|
|
|
const char *name G_GNUC_UNUSED,
|
2018-12-19 14:24:53 +00:00
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
virNetworkObjPortListExportDataPtr data = opaque;
|
|
|
|
virNetworkPortDefPtr def = payload;
|
|
|
|
virNetworkPortPtr port;
|
|
|
|
|
|
|
|
if (data->error)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (data->filter &&
|
|
|
|
!data->filter(data->net->conn, data->def, def))
|
2020-01-06 21:57:26 +00:00
|
|
|
return 0;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
|
|
|
if (!data->ports) {
|
|
|
|
data->nports++;
|
2020-01-06 21:57:26 +00:00
|
|
|
return 0;
|
2018-12-19 14:24:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!(port = virGetNetworkPort(data->net, def->uuid))) {
|
|
|
|
data->error = true;
|
2020-01-06 21:57:26 +00:00
|
|
|
return 0;
|
2018-12-19 14:24:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
data->ports[data->nports++] = port;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
virNetworkObjPortListExport(virNetworkPtr net,
|
|
|
|
virNetworkObjPtr obj,
|
|
|
|
virNetworkPortPtr **ports,
|
|
|
|
virNetworkPortListFilter filter)
|
|
|
|
{
|
|
|
|
virNetworkObjPortListExportData data = {
|
|
|
|
net, obj->def, NULL, filter, 0, false,
|
|
|
|
};
|
|
|
|
int ret = -1;
|
|
|
|
|
2019-06-18 17:33:04 +00:00
|
|
|
if (ports) {
|
|
|
|
*ports = NULL;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
2020-10-12 17:45:37 +00:00
|
|
|
data.ports = g_new0(virNetworkPortPtr, virHashSize(obj->ports) + 1);
|
2019-06-18 17:33:04 +00: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 */
|
|
|
|
ignore_value(VIR_REALLOC_N(data.ports, data.nports + 1));
|
|
|
|
*ports = data.ports;
|
|
|
|
data.ports = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = data.nports;
|
|
|
|
cleanup:
|
|
|
|
while (data.ports && data.nports)
|
|
|
|
virObjectUnref(data.ports[--data.nports]);
|
|
|
|
|
|
|
|
VIR_FREE(data.ports);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-09-13 14:54:18 +00:00
|
|
|
typedef struct _virNetworkObjPortListForEachData virNetworkObjPortListForEachData;
|
|
|
|
struct _virNetworkObjPortListForEachData {
|
|
|
|
virNetworkPortListIter iter;
|
|
|
|
void *opaque;
|
|
|
|
bool err;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
|
|
virNetworkObjPortForEachCallback(void *payload,
|
2020-10-21 11:31:16 +00:00
|
|
|
const char *name G_GNUC_UNUSED,
|
2019-09-13 14:54:18 +00:00
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
virNetworkObjPortListForEachData *data = opaque;
|
|
|
|
|
|
|
|
if (!data->iter(payload, data->opaque))
|
|
|
|
data->err = true;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
virNetworkObjPortForEach(virNetworkObjPtr obj,
|
|
|
|
virNetworkPortListIter iter,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
virNetworkObjPortListForEachData data = { iter, opaque, false };
|
2020-10-23 07:49:36 +00:00
|
|
|
virHashForEachSafe(obj->ports, virNetworkObjPortForEachCallback, &data);
|
2019-09-13 14:54:18 +00:00
|
|
|
if (data.err)
|
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-12-19 14:24:53 +00:00
|
|
|
static int
|
|
|
|
virNetworkObjLoadAllPorts(virNetworkObjPtr net,
|
|
|
|
const char *stateDir)
|
|
|
|
{
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *dir = NULL;
|
2020-10-25 21:50:51 +00: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 12:47:50 +00:00
|
|
|
g_autoptr(virNetworkPortDef) portdef = NULL;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
|
|
|
if (!(dir = virNetworkObjGetPortStatusDir(net, stateDir)))
|
2020-10-27 21:49:11 +00:00
|
|
|
return -1;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
2020-10-27 21:49:11 +00: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 06:46:14 +00:00
|
|
|
g_autofree char *file = NULL;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
|
|
|
if (!virStringStripSuffix(de->d_name, ".xml"))
|
|
|
|
continue;
|
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
file = g_strdup_printf("%s/%s.xml", dir, de->d_name);
|
2018-12-19 14:24:53 +00:00
|
|
|
|
|
|
|
portdef = virNetworkPortDefParseFile(file);
|
|
|
|
if (!portdef) {
|
|
|
|
VIR_WARN("Cannot parse port %s", file);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
virUUIDFormat(portdef->uuid, uuidstr);
|
|
|
|
if (virHashAddEntry(net->ports, uuidstr, portdef) < 0)
|
2020-10-27 21:49:11 +00:00
|
|
|
return -1;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
|
|
|
portdef = NULL;
|
|
|
|
}
|
|
|
|
|
2020-10-27 21:49:11 +00:00
|
|
|
return 0;
|
2018-12-19 14:24:53 +00:00
|
|
|
}
|