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;
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkDef *def; /* The current definition */
|
|
|
|
virNetworkDef *newDef; /* New definition to activate at shutdown */
|
2017-05-12 12:40:04 +00:00
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
virBitmap *classIdMap; /* bitmap of class IDs for QoS */
|
2017-05-12 12:40:04 +00: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 07:16:13 +00:00
|
|
|
virMacMap *macmap;
|
2018-12-19 14:24:53 +00:00
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
GHashTable *ports; /* uuid -> virNetworkPortDef **/
|
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
|
|
|
};
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
static virClass *virNetworkObjClass;
|
|
|
|
static virClass *virNetworkObjListClass;
|
2017-03-08 15:25:24 +00:00
|
|
|
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
|
2021-03-11 07:16:13 +00: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 07:16:13 +00:00
|
|
|
virNetworkObj *
|
2017-03-08 15:25:24 +00:00
|
|
|
virNetworkObjNew(void)
|
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObj *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
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjEndAPI(virNetworkObj **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
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkDef *
|
|
|
|
virNetworkObjGetDef(virNetworkObj *obj)
|
2017-05-09 22:38:58 +00:00
|
|
|
{
|
|
|
|
return obj->def;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjSetDef(virNetworkObj *obj,
|
|
|
|
virNetworkDef *def)
|
2017-05-09 22:38:58 +00:00
|
|
|
{
|
|
|
|
obj->def = def;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkDef *
|
|
|
|
virNetworkObjGetNewDef(virNetworkObj *obj)
|
2017-05-09 22:38:58 +00:00
|
|
|
{
|
|
|
|
return obj->newDef;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-10 11:22:15 +00:00
|
|
|
bool
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjIsActive(virNetworkObj *obj)
|
2017-05-10 11:22:15 +00:00
|
|
|
{
|
|
|
|
return obj->active;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjSetActive(virNetworkObj *obj,
|
2017-05-10 11:22:15 +00:00
|
|
|
bool active)
|
|
|
|
{
|
|
|
|
obj->active = active;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-10 11:29:57 +00:00
|
|
|
bool
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjIsPersistent(virNetworkObj *obj)
|
2017-05-10 11:29:57 +00:00
|
|
|
{
|
|
|
|
return obj->persistent;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-10 11:12:27 +00:00
|
|
|
bool
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjIsAutostart(virNetworkObj *obj)
|
2017-05-10 11:12:27 +00:00
|
|
|
{
|
|
|
|
return obj->autostart;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjSetAutostart(virNetworkObj *obj,
|
2017-05-10 11:12:27 +00:00
|
|
|
bool autostart)
|
|
|
|
{
|
|
|
|
obj->autostart = autostart;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-09 21:22:43 +00:00
|
|
|
pid_t
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjGetDnsmasqPid(virNetworkObj *obj)
|
2017-05-09 21:22:43 +00:00
|
|
|
{
|
|
|
|
return obj->dnsmasqPid;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjSetDnsmasqPid(virNetworkObj *obj,
|
2017-05-09 21:22:43 +00:00
|
|
|
pid_t dnsmasqPid)
|
|
|
|
{
|
|
|
|
obj->dnsmasqPid = dnsmasqPid;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pid_t
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjGetRadvdPid(virNetworkObj *obj)
|
2017-05-09 21:22:43 +00:00
|
|
|
{
|
|
|
|
return obj->radvdPid;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjSetRadvdPid(virNetworkObj *obj,
|
2017-05-09 21:22:43 +00:00
|
|
|
pid_t radvdPid)
|
|
|
|
{
|
|
|
|
obj->radvdPid = radvdPid;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
virBitmap *
|
|
|
|
virNetworkObjGetClassIdMap(virNetworkObj *obj)
|
2017-05-09 21:41:23 +00:00
|
|
|
{
|
|
|
|
return obj->classIdMap;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
virMacMap *
|
|
|
|
virNetworkObjGetMacMap(virNetworkObj *obj)
|
2017-05-09 20:51:05 +00:00
|
|
|
{
|
|
|
|
return obj->macmap;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-09 21:57:41 +00:00
|
|
|
unsigned long long
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjGetFloorSum(virNetworkObj *obj)
|
2017-05-09 21:57:41 +00:00
|
|
|
{
|
|
|
|
return obj->floor_sum;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjSetFloorSum(virNetworkObj *obj,
|
2017-05-09 21:57:41 +00:00
|
|
|
unsigned long long floor_sum)
|
|
|
|
{
|
|
|
|
obj->floor_sum = floor_sum;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-09 20:51:05 +00:00
|
|
|
void
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjSetMacMap(virNetworkObj *obj,
|
|
|
|
virMacMap *macmap)
|
2017-05-09 20:51:05 +00:00
|
|
|
{
|
|
|
|
obj->macmap = macmap;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjUnrefMacMap(virNetworkObj *obj)
|
2017-05-09 20:51:05 +00:00
|
|
|
{
|
2017-07-26 11:42:51 +00:00
|
|
|
virObjectUnref(obj->macmap);
|
|
|
|
obj->macmap = NULL;
|
2017-05-09 20:51:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjMacMgrAdd(virNetworkObj *obj,
|
2017-05-09 20:51:05 +00:00
|
|
|
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
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjMacMgrDel(virNetworkObj *obj,
|
2017-05-09 20:51:05 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjList *
|
2017-03-08 15:41:57 +00:00
|
|
|
virNetworkObjListNew(void)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjList *nets;
|
2017-03-08 15:25:24 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
static virNetworkObj *
|
|
|
|
virNetworkObjFindByUUIDLocked(virNetworkObjList *nets,
|
2017-03-08 15:25:24 +00:00
|
|
|
const unsigned char *uuid)
|
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObj *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.
|
|
|
|
*/
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObj *
|
|
|
|
virNetworkObjFindByUUID(virNetworkObjList *nets,
|
2017-03-08 15:25:24 +00:00
|
|
|
const unsigned char *uuid)
|
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObj *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)
|
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObj *obj = (virNetworkObj *) 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
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
static virNetworkObj *
|
|
|
|
virNetworkObjFindByNameLocked(virNetworkObjList *nets,
|
2017-03-08 15:25:24 +00:00
|
|
|
const char *name)
|
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObj *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.
|
|
|
|
*/
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObj *
|
|
|
|
virNetworkObjFindByName(virNetworkObjList *nets,
|
2017-03-08 15:25:24 +00:00
|
|
|
const char *name)
|
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObj *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
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjTaint(virNetworkObj *obj,
|
2017-03-08 15:25:24 +00:00
|
|
|
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
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObj *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
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjList *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
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjUpdateAssignDef(virNetworkObj *obj,
|
|
|
|
virNetworkDef *def,
|
2017-03-08 16:19:20 +00:00
|
|
|
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.
|
|
|
|
*/
|
2021-03-11 07:16:13 +00:00
|
|
|
static virNetworkObj *
|
|
|
|
virNetworkObjAssignDefLocked(virNetworkObjList *nets,
|
|
|
|
virNetworkDef *def,
|
2017-03-08 16:41:18 +00:00
|
|
|
unsigned int flags)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObj *obj;
|
|
|
|
virNetworkObj *ret = NULL;
|
2017-03-08 15:25:24 +00:00
|
|
|
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
|
|
|
*
|
2021-03-11 07:16:13 +00:00
|
|
|
* Returns NULL on error, virNetworkObj *on success.
|
2017-03-08 15:25:24 +00:00
|
|
|
*/
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObj *
|
|
|
|
virNetworkObjAssignDef(virNetworkObjList *nets,
|
|
|
|
virNetworkDef *def,
|
2017-03-08 16:41:18 +00:00
|
|
|
unsigned int flags)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObj *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
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjSetDefTransient(virNetworkObj *obj,
|
2019-07-14 16:15:12 +00:00
|
|
|
bool live,
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkXMLOption *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
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjUnsetDefTransient(virNetworkObj *obj)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
2017-05-10 11:59:48 +00:00
|
|
|
if (obj->newDef) {
|
|
|
|
virNetworkDefFree(obj->def);
|
2021-03-24 09:32:58 +00:00
|
|
|
obj->def = g_steal_pointer(&obj->newDef);
|
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.
|
|
|
|
*
|
2021-03-11 07:16:13 +00:00
|
|
|
* Returns NULL on error, virNetworkDef *on success.
|
2017-03-08 15:25:24 +00:00
|
|
|
*/
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkDef *
|
|
|
|
virNetworkObjGetPersistentDef(virNetworkObj *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
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjReplacePersistentDef(virNetworkObj *obj,
|
|
|
|
virNetworkDef *def)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
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
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjConfigChangeSetup(virNetworkObj *obj,
|
|
|
|
virNetworkXMLOption *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
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjRemoveInactive(virNetworkObjList *nets,
|
|
|
|
virNetworkObj *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 *
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjFormat(virNetworkObj *obj,
|
|
|
|
virNetworkXMLOption *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,
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObj *obj,
|
|
|
|
virNetworkXMLOption *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
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
static virNetworkObj *
|
|
|
|
virNetworkLoadState(virNetworkObjList *nets,
|
2017-03-08 15:25:24 +00:00
|
|
|
const char *stateDir,
|
2019-07-14 16:15:12 +00:00
|
|
|
const char *name,
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkXMLOption *xmlopt)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
|
|
|
char *configFile = NULL;
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkDef *def = NULL;
|
|
|
|
virNetworkObj *obj = NULL;
|
2017-03-08 15:25:24 +00:00
|
|
|
xmlDocPtr xml = NULL;
|
|
|
|
xmlNodePtr node = NULL, *nodes = NULL;
|
|
|
|
xmlXPathContextPtr ctxt = NULL;
|
2021-03-11 07:16:13 +00:00
|
|
|
virBitmap *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
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
static virNetworkObj *
|
|
|
|
virNetworkLoadConfig(virNetworkObjList *nets,
|
2017-03-08 15:41:57 +00:00
|
|
|
const char *configDir,
|
|
|
|
const char *autostartDir,
|
2019-07-14 16:15:12 +00:00
|
|
|
const char *name,
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkXMLOption *xmlopt)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
|
|
|
char *configFile = NULL, *autostartLink = NULL;
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkDef *def = NULL;
|
|
|
|
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 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
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjLoadAllState(virNetworkObjList *nets,
|
2019-07-14 16:15:12 +00:00
|
|
|
const char *stateDir,
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkXMLOption *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) {
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObj *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
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjLoadAllConfigs(virNetworkObjList *nets,
|
2017-03-08 16:41:18 +00:00
|
|
|
const char *configDir,
|
2019-07-14 16:15:12 +00:00
|
|
|
const char *autostartDir,
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkXMLOption *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) {
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObj *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,
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObj *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;
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObj *obj = (virNetworkObj *) 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
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjBridgeInUse(virNetworkObjList *nets,
|
2017-03-08 16:41:18 +00:00
|
|
|
const char *bridge,
|
|
|
|
const char *skipname)
|
2017-03-08 15:25:24 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObj *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
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjUpdate(virNetworkObj *obj,
|
2017-03-08 15:25:24 +00:00
|
|
|
unsigned int command, /* virNetworkUpdateCommand */
|
|
|
|
unsigned int section, /* virNetworkUpdateSection */
|
|
|
|
int parentIndex,
|
|
|
|
const char *xml,
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkXMLOption *xmlopt,
|
2017-03-08 15:25:24 +00:00
|
|
|
unsigned int flags) /* virNetworkUpdateFlags */
|
|
|
|
{
|
|
|
|
int ret = -1;
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkDef *livedef = NULL;
|
|
|
|
virNetworkDef *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) {
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkDef *checkdef;
|
2017-03-08 15:25:24 +00:00
|
|
|
|
|
|
|
/* 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) {
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkDef *checkdef;
|
2017-03-08 15:25:24 +00:00
|
|
|
|
|
|
|
/* 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);
|
2021-03-24 09:32:58 +00:00
|
|
|
obj->def = g_steal_pointer(&livedef);
|
2017-03-08 15:25:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjMatch(virNetworkObj *obj,
|
2018-08-13 15:55:16 +00:00
|
|
|
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;
|
|
|
|
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
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjListExportData *data = opaque;
|
|
|
|
virNetworkObj *obj = payload;
|
2017-03-08 15:25:24 +00: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 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,
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjList *netobjs,
|
2017-03-08 15:25:24 +00:00
|
|
|
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 */
|
2021-03-19 23:37:05 +00:00
|
|
|
VIR_REALLOC_N(data.nets, data.nnets + 1);
|
2021-03-24 09:32:58 +00:00
|
|
|
*nets = g_steal_pointer(&data.nets);
|
2017-03-08 15:25:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjListForEach(virNetworkObjList *nets,
|
2017-03-08 15:25:24 +00:00
|
|
|
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;
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObj *obj = payload;
|
2017-03-08 15:25:24 +00:00
|
|
|
|
|
|
|
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
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjListGetNames(virNetworkObjList *nets,
|
2017-03-08 15:25:24 +00:00
|
|
|
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
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjListNumOfNetworks(virNetworkObjList *nets,
|
2017-03-08 15:25:24 +00:00
|
|
|
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;
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObj *obj = (virNetworkObj *) payload;
|
2017-03-08 15:25:24 +00:00
|
|
|
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
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjListPrune(virNetworkObjList *nets,
|
2017-03-08 15:25:24 +00:00
|
|
|
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 *
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjGetPortStatusDir(virNetworkObj *net,
|
2018-12-19 14:24:53 +00:00
|
|
|
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
|
2021-03-11 07:16:13 +00: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 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
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkPortDef *
|
|
|
|
virNetworkObjLookupPort(virNetworkObj *net,
|
2018-12-19 14:24:53 +00:00
|
|
|
const unsigned char *uuid)
|
|
|
|
{
|
2021-03-11 07:16:13 +00: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,
|
|
|
|
_("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
|
2021-03-11 07:16:13 +00: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 13:16:31 +00:00
|
|
|
g_autofree char *dir = NULL;
|
2021-03-11 07:16:13 +00: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,
|
|
|
|
_("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
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjDeleteAllPorts(virNetworkObj *net,
|
2018-12-19 14:24:53 +00:00
|
|
|
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;
|
|
|
|
struct _virNetworkObjPortListExportData {
|
|
|
|
virNetworkPtr net;
|
2021-03-11 07:16:13 +00: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 11:31:16 +00:00
|
|
|
const char *name G_GNUC_UNUSED,
|
2018-12-19 14:24:53 +00:00
|
|
|
void *opaque)
|
|
|
|
{
|
2021-03-11 07:16:13 +00: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 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,
|
2021-03-11 07:16:13 +00: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 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 */
|
2021-03-19 23:37:05 +00:00
|
|
|
VIR_REALLOC_N(data.ports, data.nports + 1);
|
2021-03-24 09:32:58 +00: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 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
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjPortForEach(virNetworkObj *obj,
|
2019-09-13 14:54:18 +00:00
|
|
|
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
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetworkObjLoadAllPorts(virNetworkObj *net,
|
2018-12-19 14:24:53 +00:00
|
|
|
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
|
|
|
}
|