mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-22 03:12:22 +00:00
Core driver implementation with ebtables support
This patch implements the core driver and provides - management functionality for managing the filter XMLs - compiling the internal filter representation into ebtables rules - applying ebtables rules on a network (tap,macvtap) interface - tearing down ebtables rules that were applied on behalf of an interface - updating of filters while VMs are running and causing the firewalls to be rebuilt - other bits and pieces Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
This commit is contained in:
parent
e4e20423ff
commit
065b6571bf
12
configure.ac
12
configure.ac
@ -294,6 +294,9 @@ if test x"$with_rhel5_api" = x"yes"; then
|
|||||||
AC_DEFINE([WITH_RHEL5_API], [1], [whether building for the RHEL-5 API])
|
AC_DEFINE([WITH_RHEL5_API], [1], [whether building for the RHEL-5 API])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
AC_PATH_PROG([BASH_PATH], [bash], /bin/bash, [/bin:$PATH])
|
||||||
|
AC_DEFINE_UNQUOTED([BASH_PATH], "$BASH_PATH", [path to bash binary])
|
||||||
|
|
||||||
AC_PATH_PROG([IPTABLES_PATH], [iptables], /sbin/iptables, [/usr/sbin:$PATH])
|
AC_PATH_PROG([IPTABLES_PATH], [iptables], /sbin/iptables, [/usr/sbin:$PATH])
|
||||||
AC_DEFINE_UNQUOTED([IPTABLES_PATH], "$IPTABLES_PATH", [path to iptables binary])
|
AC_DEFINE_UNQUOTED([IPTABLES_PATH], "$IPTABLES_PATH", [path to iptables binary])
|
||||||
|
|
||||||
@ -1268,6 +1271,15 @@ if test "$with_secrets" = "yes" ; then
|
|||||||
fi
|
fi
|
||||||
AM_CONDITIONAL([WITH_SECRETS], [test "$with_secrets" = "yes"])
|
AM_CONDITIONAL([WITH_SECRETS], [test "$with_secrets" = "yes"])
|
||||||
|
|
||||||
|
with_nwfilter=yes
|
||||||
|
if test "$with_libvirtd" = "no"; then
|
||||||
|
with_nwfilter=no
|
||||||
|
fi
|
||||||
|
if test "$with_nwfilter" = "yes" ; then
|
||||||
|
AC_DEFINE([WITH_NWFILTER], 1, [whether local network filter management driver is available])
|
||||||
|
fi
|
||||||
|
AM_CONDITIONAL([WITH_NWFILTER], [test "$with_nwfilter" = "yes"])
|
||||||
|
|
||||||
|
|
||||||
AC_ARG_WITH([storage-fs],
|
AC_ARG_WITH([storage-fs],
|
||||||
AC_HELP_STRING([--with-storage-fs], [with FileSystem backend for the storage driver @<:@default=check@:>@]),[],[with_storage_fs=check])
|
AC_HELP_STRING([--with-storage-fs], [with FileSystem backend for the storage driver @<:@default=check@:>@]),[],[with_storage_fs=check])
|
||||||
|
@ -116,6 +116,10 @@ endif
|
|||||||
if WITH_SECRETS
|
if WITH_SECRETS
|
||||||
libvirtd_LDADD += ../src/libvirt_driver_secret.la
|
libvirtd_LDADD += ../src/libvirt_driver_secret.la
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if WITH_NWFILTER
|
||||||
|
libvirtd_LDADD += ../src/libvirt_driver_nwfilter.la
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
libvirtd_LDADD += ../src/libvirt.la
|
libvirtd_LDADD += ../src/libvirt.la
|
||||||
|
@ -96,6 +96,9 @@
|
|||||||
# ifdef WITH_SECRETS
|
# ifdef WITH_SECRETS
|
||||||
# include "secret/secret_driver.h"
|
# include "secret/secret_driver.h"
|
||||||
# endif
|
# endif
|
||||||
|
# ifdef WITH_NWFILTER
|
||||||
|
# include "nwfilter/nwfilter_driver.h"
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@ -876,6 +879,7 @@ static struct qemud_server *qemudInitialize(void) {
|
|||||||
virDriverLoadModule("lxc");
|
virDriverLoadModule("lxc");
|
||||||
virDriverLoadModule("uml");
|
virDriverLoadModule("uml");
|
||||||
virDriverLoadModule("one");
|
virDriverLoadModule("one");
|
||||||
|
virDriverLoadModule("nwfilter");
|
||||||
#else
|
#else
|
||||||
# ifdef WITH_NETWORK
|
# ifdef WITH_NETWORK
|
||||||
networkRegister();
|
networkRegister();
|
||||||
@ -892,6 +896,9 @@ static struct qemud_server *qemudInitialize(void) {
|
|||||||
# ifdef WITH_SECRETS
|
# ifdef WITH_SECRETS
|
||||||
secretRegister();
|
secretRegister();
|
||||||
# endif
|
# endif
|
||||||
|
# ifdef WITH_NWFILTER
|
||||||
|
nwfilterRegister();
|
||||||
|
# endif
|
||||||
# ifdef WITH_QEMU
|
# ifdef WITH_QEMU
|
||||||
qemuRegister();
|
qemuRegister();
|
||||||
# endif
|
# endif
|
||||||
|
@ -28,6 +28,9 @@ src/node_device/node_device_driver.c
|
|||||||
src/node_device/node_device_linux_sysfs.c
|
src/node_device/node_device_linux_sysfs.c
|
||||||
src/node_device/node_device_udev.c
|
src/node_device/node_device_udev.c
|
||||||
src/nodeinfo.c
|
src/nodeinfo.c
|
||||||
|
src/nwfilter/nwfilter_driver.c
|
||||||
|
src/nwfilter/nwfilter_ebiptables_driver.c
|
||||||
|
src/nwfilter/nwfilter_gentech_driver.c
|
||||||
src/opennebula/one_conf.c
|
src/opennebula/one_conf.c
|
||||||
src/opennebula/one_driver.c
|
src/opennebula/one_driver.c
|
||||||
src/openvz/openvz_conf.c
|
src/openvz/openvz_conf.c
|
||||||
|
@ -175,6 +175,7 @@ skipped_types = {
|
|||||||
'virConnectDomainEventIOErrorCallback': "No function types in python",
|
'virConnectDomainEventIOErrorCallback': "No function types in python",
|
||||||
'virConnectDomainEventGraphicsCallback': "No function types in python",
|
'virConnectDomainEventGraphicsCallback': "No function types in python",
|
||||||
'virEventAddHandleFunc': "No function types in python",
|
'virEventAddHandleFunc': "No function types in python",
|
||||||
|
'virNWFilterPtr': "No function types in python",
|
||||||
}
|
}
|
||||||
|
|
||||||
#######################################################################
|
#######################################################################
|
||||||
@ -273,6 +274,7 @@ skip_impl = (
|
|||||||
'virConnectListStorageVols',
|
'virConnectListStorageVols',
|
||||||
'virConnectListDefinedStorageVols',
|
'virConnectListDefinedStorageVols',
|
||||||
'virConnectListDefinedInterfaces',
|
'virConnectListDefinedInterfaces',
|
||||||
|
'virConnectListNWFilters',
|
||||||
'virConnGetLastError',
|
'virConnGetLastError',
|
||||||
'virGetLastError',
|
'virGetLastError',
|
||||||
'virDomainGetInfo',
|
'virDomainGetInfo',
|
||||||
|
@ -284,6 +284,11 @@ STORAGE_DRIVER_DISK_SOURCES = \
|
|||||||
STORAGE_HELPER_DISK_SOURCES = \
|
STORAGE_HELPER_DISK_SOURCES = \
|
||||||
storage/parthelper.c
|
storage/parthelper.c
|
||||||
|
|
||||||
|
# Network filters
|
||||||
|
NWFILTER_DRIVER_SOURCES = \
|
||||||
|
nwfilter/nwfilter_driver.h nwfilter/nwfilter_driver.c \
|
||||||
|
nwfilter/nwfilter_gentech_driver.c \
|
||||||
|
nwfilter/nwfilter_ebiptables_driver.c
|
||||||
|
|
||||||
# Security framework and drivers for various models
|
# Security framework and drivers for various models
|
||||||
SECURITY_DRIVER_SOURCES = \
|
SECURITY_DRIVER_SOURCES = \
|
||||||
@ -727,6 +732,22 @@ endif
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
if WITH_NWFILTER
|
||||||
|
if WITH_DRIVER_MODULES
|
||||||
|
mod_LTLIBRARIES += libvirt_driver_nwfilter.la
|
||||||
|
else
|
||||||
|
libvirt_la_LIBADD += libvirt_driver_nwfilter.la
|
||||||
|
noinst_LTLIBRARIES += libvirt_driver_nwfilter.la
|
||||||
|
endif
|
||||||
|
libvirt_driver_nwfilter_la_CFLAGS = \
|
||||||
|
-I@top_srcdir@/src/conf
|
||||||
|
if WITH_DRIVER_MODULES
|
||||||
|
libvirt_driver_nwfilter_la_LDFLAGS = -module -avoid-version ../gnulib/lib/libgnu.la
|
||||||
|
endif
|
||||||
|
libvirt_driver_nwfilter_la_SOURCES = $(NWFILTER_DRIVER_SOURCES)
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
libvirt_driver_security_la_SOURCES = $(SECURITY_DRIVER_SOURCES)
|
libvirt_driver_security_la_SOURCES = $(SECURITY_DRIVER_SOURCES)
|
||||||
noinst_LTLIBRARIES += libvirt_driver_security.la
|
noinst_LTLIBRARIES += libvirt_driver_security.la
|
||||||
libvirt_la_LIBADD += libvirt_driver_security.la
|
libvirt_la_LIBADD += libvirt_driver_security.la
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include "nwfilter_params.h"
|
#include "nwfilter_params.h"
|
||||||
#include "nwfilter_conf.h"
|
#include "nwfilter_conf.h"
|
||||||
#include "domain_conf.h"
|
#include "domain_conf.h"
|
||||||
|
#include "nwfilter/nwfilter_gentech_driver.h"
|
||||||
|
|
||||||
|
|
||||||
#define VIR_FROM_THIS VIR_FROM_NWFILTER
|
#define VIR_FROM_THIS VIR_FROM_NWFILTER
|
||||||
@ -1605,10 +1606,42 @@ struct cbStruct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
virNWFilterDomainFWUpdateCB(void *payload ATTRIBUTE_UNUSED,
|
virNWFilterDomainFWUpdateCB(void *payload,
|
||||||
const char *name ATTRIBUTE_UNUSED,
|
const char *name ATTRIBUTE_UNUSED,
|
||||||
void *data ATTRIBUTE_UNUSED)
|
void *data)
|
||||||
{
|
{
|
||||||
|
virDomainObjPtr obj = payload;
|
||||||
|
virDomainDefPtr vm = obj->def;
|
||||||
|
struct cbStruct *cb = data;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
virDomainObjLock(obj);
|
||||||
|
|
||||||
|
if (virDomainObjIsActive(obj)) {
|
||||||
|
for (i = 0; i < vm->nnets; i++) {
|
||||||
|
virDomainNetDefPtr net = vm->nets[i];
|
||||||
|
if ((net->filter) && (net->ifname)) {
|
||||||
|
switch (cb->step) {
|
||||||
|
case STEP_APPLY_NEW:
|
||||||
|
cb->err = virNWFilterUpdateInstantiateFilter(cb->conn,
|
||||||
|
net);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STEP_TEAR_NEW:
|
||||||
|
cb->err = virNWFilterRollbackUpdateFilter(cb->conn, net);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STEP_TEAR_OLD:
|
||||||
|
cb->err = virNWFilterTearOldFilter(cb->conn, net);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (cb->err)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virDomainObjUnlock(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -449,6 +449,42 @@ virNodeDeviceGetWWNs;
|
|||||||
virNodeDeviceGetParentHost;
|
virNodeDeviceGetParentHost;
|
||||||
|
|
||||||
|
|
||||||
|
# nwfilter_conf.h
|
||||||
|
virNWFilterPoolLoadAllConfigs;
|
||||||
|
virNWFilterPoolObjAssignDef;
|
||||||
|
virNWFilterPoolObjSaveDef;
|
||||||
|
virNWFilterPoolObjFindByName;
|
||||||
|
virNWFilterPoolObjFindByUUID;
|
||||||
|
virNWFilterPoolObjLock;
|
||||||
|
virNWFilterPoolObjUnlock;
|
||||||
|
virNWFilterPoolObjRemove;
|
||||||
|
virNWFilterDefFree;
|
||||||
|
virNWFilterDefParseString;
|
||||||
|
virNWFilterPoolObjDeleteDef;
|
||||||
|
virNWFilterPoolObjListFree;
|
||||||
|
virNWFilterDefFormat;
|
||||||
|
virNWFilterChainSuffixTypeToString;
|
||||||
|
virNWFilterRuleActionTypeToString;
|
||||||
|
virNWFilterJumpTargetTypeToString;
|
||||||
|
virNWFilterRegisterCallbackDriver;
|
||||||
|
virNWFilterTestUnassignDef;
|
||||||
|
virNWFilterConfLayerInit;
|
||||||
|
virNWFilterConfLayerShutdown;
|
||||||
|
|
||||||
|
|
||||||
|
#nwfilter_params.h
|
||||||
|
virNWFilterHashTableCreate;
|
||||||
|
virNWFilterHashTableFree;
|
||||||
|
virNWFilterHashTablePut;
|
||||||
|
virNWFilterHashTablePutAll;
|
||||||
|
virNWFilterHashTableRemoveEntry;
|
||||||
|
|
||||||
|
|
||||||
|
# nwfilter_gentech_driver.h
|
||||||
|
virNWFilterInstantiateFilter;
|
||||||
|
virNWFilterTeardownFilter;
|
||||||
|
|
||||||
|
|
||||||
# pci.h
|
# pci.h
|
||||||
pciGetDevice;
|
pciGetDevice;
|
||||||
pciFreeDevice;
|
pciFreeDevice;
|
||||||
|
@ -380,4 +380,5 @@ LIBVIRT_0.7.8 {
|
|||||||
virNWFilterUndefine;
|
virNWFilterUndefine;
|
||||||
} LIBVIRT_0.7.7;
|
} LIBVIRT_0.7.7;
|
||||||
|
|
||||||
|
|
||||||
# .... define new API here using predicted next version number ....
|
# .... define new API here using predicted next version number ....
|
||||||
|
416
src/nwfilter/nwfilter_driver.c
Normal file
416
src/nwfilter/nwfilter_driver.c
Normal file
@ -0,0 +1,416 @@
|
|||||||
|
/*
|
||||||
|
* nwfilter_driver.c: core driver for network filter APIs
|
||||||
|
* (based on storage_driver.c)
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006-2009 Red Hat, Inc.
|
||||||
|
* Copyright (C) 2006-2008 Daniel P. Berrange
|
||||||
|
* Copyright (C) 2010 IBM Corporation
|
||||||
|
* Copyright (C) 2010 Stefan Berger
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* Author: Daniel P. Berrange <berrange@redhat.com>
|
||||||
|
* Stefan Berger <stefanb@us.ibm.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include "virterror_internal.h"
|
||||||
|
#include "datatypes.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "domain_conf.h"
|
||||||
|
#include "nwfilter_driver.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define VIR_FROM_THIS VIR_FROM_NWFILTER
|
||||||
|
|
||||||
|
#define nwfilterLog(msg...) fprintf(stderr, msg)
|
||||||
|
|
||||||
|
|
||||||
|
static virNWFilterDriverStatePtr driverState;
|
||||||
|
|
||||||
|
static int nwfilterDriverShutdown(void);
|
||||||
|
|
||||||
|
static void nwfilterDriverLock(virNWFilterDriverStatePtr driver)
|
||||||
|
{
|
||||||
|
virMutexLock(&driver->lock);
|
||||||
|
}
|
||||||
|
static void nwfilterDriverUnlock(virNWFilterDriverStatePtr driver)
|
||||||
|
{
|
||||||
|
virMutexUnlock(&driver->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virNWFilterStartup:
|
||||||
|
*
|
||||||
|
* Initialization function for the QEmu daemon
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
nwfilterDriverStartup(int privileged) {
|
||||||
|
char *base = NULL;
|
||||||
|
|
||||||
|
if (virNWFilterConfLayerInit() < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (VIR_ALLOC(driverState) < 0)
|
||||||
|
goto alloc_err_exit;
|
||||||
|
|
||||||
|
if (virMutexInit(&driverState->lock) < 0)
|
||||||
|
goto alloc_err_exit;
|
||||||
|
|
||||||
|
nwfilterDriverLock(driverState);
|
||||||
|
|
||||||
|
if (privileged) {
|
||||||
|
if ((base = strdup (SYSCONF_DIR "/libvirt")) == NULL)
|
||||||
|
goto out_of_memory;
|
||||||
|
} else {
|
||||||
|
uid_t uid = geteuid();
|
||||||
|
char *userdir = virGetUserDirectory(uid);
|
||||||
|
|
||||||
|
if (!userdir)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (virAsprintf(&base, "%s/.libvirt", userdir) == -1) {
|
||||||
|
nwfilterLog("out of memory in virAsprintf");
|
||||||
|
VIR_FREE(userdir);
|
||||||
|
goto out_of_memory;
|
||||||
|
}
|
||||||
|
VIR_FREE(userdir);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virAsprintf(&driverState->configDir,
|
||||||
|
"%s/nwfilter", base) == -1)
|
||||||
|
goto out_of_memory;
|
||||||
|
|
||||||
|
VIR_FREE(base);
|
||||||
|
|
||||||
|
if (virNWFilterPoolLoadAllConfigs(NULL,
|
||||||
|
&driverState->pools,
|
||||||
|
driverState->configDir) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
nwfilterDriverUnlock(driverState);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out_of_memory:
|
||||||
|
nwfilterLog("virNWFilterStartup: out of memory");
|
||||||
|
|
||||||
|
error:
|
||||||
|
VIR_FREE(base);
|
||||||
|
nwfilterDriverUnlock(driverState);
|
||||||
|
nwfilterDriverShutdown();
|
||||||
|
|
||||||
|
alloc_err_exit:
|
||||||
|
virNWFilterConfLayerShutdown();
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virNWFilterReload:
|
||||||
|
*
|
||||||
|
* Function to restart the nwfilter driver, it will recheck the configuration
|
||||||
|
* files and update its state
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
nwfilterDriverReload(void) {
|
||||||
|
if (!driverState) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
nwfilterDriverLock(driverState);
|
||||||
|
virNWFilterPoolLoadAllConfigs(NULL,
|
||||||
|
&driverState->pools,
|
||||||
|
driverState->configDir);
|
||||||
|
nwfilterDriverUnlock(driverState);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virNWFilterActive:
|
||||||
|
*
|
||||||
|
* Checks if the nwfilter driver is active, i.e. has an active pool
|
||||||
|
*
|
||||||
|
* Returns 1 if active, 0 otherwise
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
nwfilterDriverActive(void) {
|
||||||
|
if (!driverState->pools.count)
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virNWFilterShutdown:
|
||||||
|
*
|
||||||
|
* Shutdown the nwfilter driver, it will stop all active nwfilter pools
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
nwfilterDriverShutdown(void) {
|
||||||
|
if (!driverState)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
nwfilterDriverLock(driverState);
|
||||||
|
|
||||||
|
/* free inactive pools */
|
||||||
|
virNWFilterPoolObjListFree(&driverState->pools);
|
||||||
|
|
||||||
|
VIR_FREE(driverState->configDir);
|
||||||
|
nwfilterDriverUnlock(driverState);
|
||||||
|
virMutexDestroy(&driverState->lock);
|
||||||
|
VIR_FREE(driverState);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static virNWFilterPtr
|
||||||
|
nwfilterLookupByUUID(virConnectPtr conn,
|
||||||
|
const unsigned char *uuid) {
|
||||||
|
virNWFilterDriverStatePtr driver = conn->nwfilterPrivateData;
|
||||||
|
virNWFilterPoolObjPtr pool;
|
||||||
|
virNWFilterPtr ret = NULL;
|
||||||
|
|
||||||
|
nwfilterDriverLock(driver);
|
||||||
|
pool = virNWFilterPoolObjFindByUUID(&driver->pools, uuid);
|
||||||
|
nwfilterDriverUnlock(driver);
|
||||||
|
|
||||||
|
if (!pool) {
|
||||||
|
virNWFilterReportError(conn, VIR_ERR_NO_NWFILTER,
|
||||||
|
"%s", _("no pool with matching uuid"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = virGetNWFilter(conn, pool->def->name, pool->def->uuid);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (pool)
|
||||||
|
virNWFilterPoolObjUnlock(pool);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static virNWFilterPtr
|
||||||
|
nwfilterLookupByName(virConnectPtr conn,
|
||||||
|
const char *name) {
|
||||||
|
virNWFilterDriverStatePtr driver = conn->nwfilterPrivateData;
|
||||||
|
virNWFilterPoolObjPtr pool;
|
||||||
|
virNWFilterPtr ret = NULL;
|
||||||
|
|
||||||
|
nwfilterDriverLock(driver);
|
||||||
|
pool = virNWFilterPoolObjFindByName(&driver->pools, name);
|
||||||
|
nwfilterDriverUnlock(driver);
|
||||||
|
|
||||||
|
if (!pool) {
|
||||||
|
virNWFilterReportError(conn, VIR_ERR_NO_NWFILTER,
|
||||||
|
_("no pool with matching name '%s'"), name);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = virGetNWFilter(conn, pool->def->name, pool->def->uuid);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (pool)
|
||||||
|
virNWFilterPoolObjUnlock(pool);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static virDrvOpenStatus
|
||||||
|
nwfilterOpen(virConnectPtr conn,
|
||||||
|
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
|
||||||
|
int flags ATTRIBUTE_UNUSED) {
|
||||||
|
if (!driverState)
|
||||||
|
return VIR_DRV_OPEN_DECLINED;
|
||||||
|
|
||||||
|
conn->nwfilterPrivateData = driverState;
|
||||||
|
return VIR_DRV_OPEN_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
nwfilterClose(virConnectPtr conn) {
|
||||||
|
conn->nwfilterPrivateData = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
nwfilterNumNWFilters(virConnectPtr conn) {
|
||||||
|
virNWFilterDriverStatePtr driver = conn->nwfilterPrivateData;
|
||||||
|
return driver->pools.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
nwfilterListNWFilters(virConnectPtr conn,
|
||||||
|
char **const names,
|
||||||
|
int nnames) {
|
||||||
|
virNWFilterDriverStatePtr driver = conn->nwfilterPrivateData;
|
||||||
|
int got = 0, i;
|
||||||
|
|
||||||
|
nwfilterDriverLock(driver);
|
||||||
|
for (i = 0 ; i < driver->pools.count && got < nnames ; i++) {
|
||||||
|
virNWFilterPoolObjLock(driver->pools.objs[i]);
|
||||||
|
if (!(names[got] = strdup(driver->pools.objs[i]->def->name))) {
|
||||||
|
virNWFilterPoolObjUnlock(driver->pools.objs[i]);
|
||||||
|
virReportOOMError();
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
got++;
|
||||||
|
virNWFilterPoolObjUnlock(driver->pools.objs[i]);
|
||||||
|
}
|
||||||
|
nwfilterDriverUnlock(driver);
|
||||||
|
return got;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
nwfilterDriverUnlock(driver);
|
||||||
|
for (i = 0 ; i < got ; i++)
|
||||||
|
VIR_FREE(names[i]);
|
||||||
|
memset(names, 0, nnames * sizeof(*names));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static virNWFilterPtr
|
||||||
|
nwfilterDefine(virConnectPtr conn,
|
||||||
|
const char *xml,
|
||||||
|
unsigned int flags ATTRIBUTE_UNUSED) {
|
||||||
|
virNWFilterDriverStatePtr driver = conn->nwfilterPrivateData;
|
||||||
|
virNWFilterDefPtr def;
|
||||||
|
virNWFilterPoolObjPtr pool = NULL;
|
||||||
|
virNWFilterPtr ret = NULL;
|
||||||
|
|
||||||
|
nwfilterDriverLock(driver);
|
||||||
|
if (!(def = virNWFilterDefParseString(conn, xml)))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (!(pool = virNWFilterPoolObjAssignDef(conn, &driver->pools, def)))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (virNWFilterPoolObjSaveDef(conn, driver, pool, def) < 0) {
|
||||||
|
virNWFilterPoolObjRemove(&driver->pools, pool);
|
||||||
|
def = NULL;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
def = NULL;
|
||||||
|
|
||||||
|
ret = virGetNWFilter(conn, pool->def->name, pool->def->uuid);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
virNWFilterDefFree(def);
|
||||||
|
if (pool)
|
||||||
|
virNWFilterPoolObjUnlock(pool);
|
||||||
|
nwfilterDriverUnlock(driver);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
nwfilterUndefine(virNWFilterPtr obj) {
|
||||||
|
virNWFilterDriverStatePtr driver = obj->conn->nwfilterPrivateData;
|
||||||
|
virNWFilterPoolObjPtr pool;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
nwfilterDriverLock(driver);
|
||||||
|
pool = virNWFilterPoolObjFindByUUID(&driver->pools, obj->uuid);
|
||||||
|
if (!pool) {
|
||||||
|
virNWFilterReportError(obj->conn, VIR_ERR_INVALID_NWFILTER,
|
||||||
|
"%s", _("no nwfilter pool with matching uuid"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virNWFilterTestUnassignDef(obj->conn, pool)) {
|
||||||
|
virNWFilterReportError(obj->conn, VIR_ERR_INVALID_NWFILTER,
|
||||||
|
"%s",
|
||||||
|
_("nwfilter is in use"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virNWFilterPoolObjDeleteDef(obj->conn, pool) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
VIR_FREE(pool->configFile);
|
||||||
|
|
||||||
|
virNWFilterPoolObjRemove(&driver->pools, pool);
|
||||||
|
pool = NULL;
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (pool)
|
||||||
|
virNWFilterPoolObjUnlock(pool);
|
||||||
|
nwfilterDriverUnlock(driver);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static char *
|
||||||
|
nwfilterDumpXML(virNWFilterPtr obj,
|
||||||
|
unsigned int flags ATTRIBUTE_UNUSED) {
|
||||||
|
virNWFilterDriverStatePtr driver = obj->conn->nwfilterPrivateData;
|
||||||
|
virNWFilterPoolObjPtr pool;
|
||||||
|
char *ret = NULL;
|
||||||
|
|
||||||
|
nwfilterDriverLock(driver);
|
||||||
|
pool = virNWFilterPoolObjFindByUUID(&driver->pools, obj->uuid);
|
||||||
|
nwfilterDriverUnlock(driver);
|
||||||
|
|
||||||
|
if (!pool) {
|
||||||
|
virNWFilterReportError(obj->conn, VIR_ERR_INVALID_NWFILTER,
|
||||||
|
"%s", _("no nwfilter pool with matching uuid"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = virNWFilterDefFormat(obj->conn, pool->def);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (pool)
|
||||||
|
virNWFilterPoolObjUnlock(pool);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static virNWFilterDriver nwfilterDriver = {
|
||||||
|
.name = "nwfilter",
|
||||||
|
.open = nwfilterOpen,
|
||||||
|
.close = nwfilterClose,
|
||||||
|
.numOfNWFilters = nwfilterNumNWFilters,
|
||||||
|
.listNWFilters = nwfilterListNWFilters,
|
||||||
|
.nwfilterLookupByName = nwfilterLookupByName,
|
||||||
|
.nwfilterLookupByUUID = nwfilterLookupByUUID,
|
||||||
|
.defineXML = nwfilterDefine,
|
||||||
|
.undefine = nwfilterUndefine,
|
||||||
|
.getXMLDesc = nwfilterDumpXML,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static virStateDriver stateDriver = {
|
||||||
|
.name = "NWFilter",
|
||||||
|
.initialize = nwfilterDriverStartup,
|
||||||
|
.cleanup = nwfilterDriverShutdown,
|
||||||
|
.reload = nwfilterDriverReload,
|
||||||
|
.active = nwfilterDriverActive,
|
||||||
|
};
|
||||||
|
|
||||||
|
int nwfilterRegister(void) {
|
||||||
|
virRegisterNWFilterDriver(&nwfilterDriver);
|
||||||
|
virRegisterStateDriver(&stateDriver);
|
||||||
|
return 0;
|
||||||
|
}
|
36
src/nwfilter/nwfilter_driver.h
Normal file
36
src/nwfilter/nwfilter_driver.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* nwfilter_driver.h: core driver for nwfilter APIs
|
||||||
|
* (based on storage driver)
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006-2008 Red Hat, Inc.
|
||||||
|
* Copyright (C) 2006-2008 Daniel P. Berrange
|
||||||
|
* Copyright (C) 2010 IBM Corporation
|
||||||
|
* Copyright (C) 2010 Stefan Berger
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* Author: Daniel P. Berrange <berrange@redhat.com>
|
||||||
|
* Stefan Berger <stefanb@us.ibm.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __VIR_NWFILTER_DRIVER_H__
|
||||||
|
#define __VIR_NWFILTER_DRIVER_H__
|
||||||
|
|
||||||
|
#include "nwfilter_params.h"
|
||||||
|
#include "nwfilter_conf.h"
|
||||||
|
|
||||||
|
int nwfilterRegister(void);
|
||||||
|
|
||||||
|
#endif /* __VIR_NWFILTER_DRIVER_H__ */
|
1414
src/nwfilter/nwfilter_ebiptables_driver.c
Normal file
1414
src/nwfilter/nwfilter_ebiptables_driver.c
Normal file
File diff suppressed because it is too large
Load Diff
41
src/nwfilter/nwfilter_ebiptables_driver.h
Normal file
41
src/nwfilter/nwfilter_ebiptables_driver.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* nwfilter_ebiptables_driver.h: ebtables/iptables driver support
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 IBM Corporation
|
||||||
|
* Copyright (C) 2010 Stefan Berger
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* Author: Stefan Berger <stefanb@us.ibm.com>
|
||||||
|
*/
|
||||||
|
#ifndef VIR_NWFILTER_EBTABLES_DRIVER_H__
|
||||||
|
#define VIR_NWFILTER_EBTABLES_DRIVER_H__
|
||||||
|
|
||||||
|
#define MAX_CHAINNAME_LENGTH 32 /* see linux/netfilter_bridge/ebtables.h */
|
||||||
|
|
||||||
|
typedef struct _ebiptablesRuleInst ebiptablesRuleInst;
|
||||||
|
typedef ebiptablesRuleInst *ebiptablesRuleInstPtr;
|
||||||
|
struct _ebiptablesRuleInst {
|
||||||
|
char *commandTemplate;
|
||||||
|
enum virNWFilterChainSuffixType neededProtocolChain;
|
||||||
|
char chainprefix; // I for incoming, O for outgoing
|
||||||
|
unsigned int priority;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern virNWFilterTechDriver ebiptables_driver;
|
||||||
|
|
||||||
|
#define EBIPTABLES_DRIVER_ID "ebiptables"
|
||||||
|
|
||||||
|
#endif
|
683
src/nwfilter/nwfilter_gentech_driver.c
Normal file
683
src/nwfilter/nwfilter_gentech_driver.c
Normal file
@ -0,0 +1,683 @@
|
|||||||
|
/*
|
||||||
|
* nwfilter_gentech_driver.c: generic technology driver
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 IBM Corp.
|
||||||
|
* Copyright (C) 2010 Stefan Berger
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* Author: Stefan Berger <stefanb@us.ibm.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include "memory.h"
|
||||||
|
#include "logging.h"
|
||||||
|
#include "datatypes.h"
|
||||||
|
#include "domain_conf.h"
|
||||||
|
#include "virterror_internal.h"
|
||||||
|
#include "nwfilter_gentech_driver.h"
|
||||||
|
#include "nwfilter_ebiptables_driver.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define VIR_FROM_THIS VIR_FROM_NWFILTER
|
||||||
|
|
||||||
|
|
||||||
|
#define NWFILTER_STD_VAR_MAC "MAC"
|
||||||
|
|
||||||
|
|
||||||
|
static virNWFilterTechDriverPtr filter_tech_drivers[] = {
|
||||||
|
&ebiptables_driver,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
virNWFilterTechDriverPtr
|
||||||
|
virNWFilterTechDriverForName(const char *name) {
|
||||||
|
int i = 0;
|
||||||
|
while (filter_tech_drivers[i]) {
|
||||||
|
if (STREQ(filter_tech_drivers[i]->name, name))
|
||||||
|
return filter_tech_drivers[i];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virNWFilterRuleInstAddData:
|
||||||
|
* @conn : pointer to virConnect object
|
||||||
|
* @res : pointer to virNWFilterRuleInst object collecting the instantiation
|
||||||
|
* data of a single firewall rule.
|
||||||
|
* @data : the opaque data that the driver wants to add
|
||||||
|
*
|
||||||
|
* Add instantiation data to a firewall rule. An instantiated firewall
|
||||||
|
* rule may hold multiple data structure representing its instantiation
|
||||||
|
* data. This may for example be the case if a rule has been defined
|
||||||
|
* for bidirectional traffic and data needs to be added to the incoming
|
||||||
|
* and outgoing chains.
|
||||||
|
*
|
||||||
|
* Returns 0 in case of success, 1 in case of an error with the error
|
||||||
|
* message attached to the virConnect object.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
virNWFilterRuleInstAddData(virConnectPtr conn ATTRIBUTE_UNUSED,
|
||||||
|
virNWFilterRuleInstPtr res,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
if (VIR_REALLOC_N(res->data, res->ndata+1) < 0) {
|
||||||
|
virReportOOMError();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
res->data[res->ndata++] = data;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
virNWFilterRuleInstFree(virNWFilterRuleInstPtr inst)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if (!inst)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < inst->ndata; i++)
|
||||||
|
inst->techdriver->freeRuleInstance(inst->data[i]);
|
||||||
|
|
||||||
|
VIR_FREE(inst->data);
|
||||||
|
VIR_FREE(inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virNWFilterVarHashmapAddStdValues:
|
||||||
|
* @conn: Poijter to virConnect object
|
||||||
|
* @tables: pointer to hash tabel to add values to
|
||||||
|
* @macaddr: The string of the MAC address to add to the hash table,
|
||||||
|
* may be NULL
|
||||||
|
*
|
||||||
|
* Returns 0 in case of success, 1 in case an error happened with
|
||||||
|
* error having been reported.
|
||||||
|
*
|
||||||
|
* Adds a couple of standard keys (MAC, IP) to the hash table.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
virNWFilterVarHashmapAddStdValues(virConnectPtr conn,
|
||||||
|
virNWFilterHashTablePtr table,
|
||||||
|
char *macaddr)
|
||||||
|
{
|
||||||
|
if (macaddr) {
|
||||||
|
if (virHashAddEntry(table->hashTable,
|
||||||
|
NWFILTER_STD_VAR_MAC,
|
||||||
|
macaddr) < 0) {
|
||||||
|
virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"%s", _("Could not add variable 'MAC' to hashmap"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virNWFilterCreateVarHashmap:
|
||||||
|
* @conn: pointer to virConnect object
|
||||||
|
* @macaddr: pointer to string containing formatted MAC address of interface
|
||||||
|
*
|
||||||
|
* Create a hashmap used for evaluating the firewall rules. Initializes
|
||||||
|
* it with the standard variable 'MAC'.
|
||||||
|
*
|
||||||
|
* Returns pointer to hashmap, NULL if an error occcurred and error message
|
||||||
|
* is attached to the virConnect object.
|
||||||
|
*/
|
||||||
|
virNWFilterHashTablePtr
|
||||||
|
virNWFilterCreateVarHashmap(virConnectPtr conn,
|
||||||
|
char *macaddr) {
|
||||||
|
virNWFilterHashTablePtr table = virNWFilterHashTableCreate(0);
|
||||||
|
if (!table) {
|
||||||
|
virReportOOMError();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virNWFilterVarHashmapAddStdValues(conn, table, macaddr)) {
|
||||||
|
virNWFilterHashTableFree(table);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virNWFilterRuleInstantiate:
|
||||||
|
* @conn: pointer to virConnect object
|
||||||
|
* @techdriver: the driver to use for instantiation
|
||||||
|
* @filter: The filter the rule is part of
|
||||||
|
* @rule : The rule that is to be instantiated
|
||||||
|
* @ifname: The name of the interface
|
||||||
|
* @vars: map containing variable names and value used for instantiation
|
||||||
|
*
|
||||||
|
* Returns virNWFilterRuleInst object on success, NULL on error with
|
||||||
|
* error reported.
|
||||||
|
*
|
||||||
|
* Instantiate a single rule. Return a pointer to virNWFilterRuleInst
|
||||||
|
* object that will hold an array of driver-specific data resulting
|
||||||
|
* from the instantiation. Returns NULL on error with error reported.
|
||||||
|
*/
|
||||||
|
static virNWFilterRuleInstPtr
|
||||||
|
virNWFilterRuleInstantiate(virConnectPtr conn,
|
||||||
|
virNWFilterTechDriverPtr techdriver,
|
||||||
|
enum virDomainNetType nettype,
|
||||||
|
virNWFilterDefPtr filter,
|
||||||
|
virNWFilterRuleDefPtr rule,
|
||||||
|
const char *ifname,
|
||||||
|
virNWFilterHashTablePtr vars)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
int i;
|
||||||
|
virNWFilterRuleInstPtr ret;
|
||||||
|
|
||||||
|
if (VIR_ALLOC(ret) < 0) {
|
||||||
|
virReportOOMError();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret->techdriver = techdriver;
|
||||||
|
|
||||||
|
rc = techdriver->createRuleInstance(conn, nettype, filter,
|
||||||
|
rule, ifname, vars, ret);
|
||||||
|
|
||||||
|
if (rc) {
|
||||||
|
for (i = 0; i < ret->ndata; i++)
|
||||||
|
techdriver->freeRuleInstance(ret->data[i]);
|
||||||
|
VIR_FREE(ret);
|
||||||
|
ret = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virNWFilterCreateVarsFrom:
|
||||||
|
* @conn: pointer to virConnect object
|
||||||
|
* @vars1: pointer to hash table
|
||||||
|
* @vars2: pointer to hash table
|
||||||
|
*
|
||||||
|
* Returns pointer to new hashtable or NULL in case of error with
|
||||||
|
* error already reported.
|
||||||
|
*
|
||||||
|
* Creates a new hash table with contents of var1 and var2 added where
|
||||||
|
* contents of var2 will overwrite those of var1.
|
||||||
|
*/
|
||||||
|
static virNWFilterHashTablePtr
|
||||||
|
virNWFilterCreateVarsFrom(virConnectPtr conn,
|
||||||
|
virNWFilterHashTablePtr vars1,
|
||||||
|
virNWFilterHashTablePtr vars2)
|
||||||
|
{
|
||||||
|
virNWFilterHashTablePtr res = virNWFilterHashTableCreate(0);
|
||||||
|
if (!res) {
|
||||||
|
virReportOOMError();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virNWFilterHashTablePutAll(conn, vars1, res))
|
||||||
|
goto err_exit;
|
||||||
|
|
||||||
|
if (virNWFilterHashTablePutAll(conn, vars2, res))
|
||||||
|
goto err_exit;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
|
||||||
|
err_exit:
|
||||||
|
virNWFilterHashTableFree(res);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _virNWFilterPoolInstantiateRec:
|
||||||
|
* @conn: pointer to virConnect object
|
||||||
|
* @techdriver: The driver to use for instantiation
|
||||||
|
* @filter: The filter to instantiate
|
||||||
|
* @ifname: The name of the interface to apply the rules to
|
||||||
|
* @vars: A map holding variable names and values used for instantiating
|
||||||
|
* the filter and its subfilters.
|
||||||
|
* @nEntries: number of virNWFilterInst objects collected
|
||||||
|
* @insts: pointer to array for virNWFilterIns object pointers
|
||||||
|
* @useNewFilter: instruct whether to use a newDef pointer rather than a
|
||||||
|
* def ptr which is useful during a filter update
|
||||||
|
* @foundNewFilter: pointer to int indivating whether a newDef pointer was
|
||||||
|
* ever used; variable expected to be initialized to 0 by caller
|
||||||
|
*
|
||||||
|
* Returns 0 on success, a value otherwise.
|
||||||
|
*
|
||||||
|
* Recursively instantiate a filter by instantiating the given filter along
|
||||||
|
* with all its subfilters in a depth-first traversal of the tree of
|
||||||
|
* referenced filters. The name of the interface to which the rules belong
|
||||||
|
* must be provided. Apply the values of variables as needed. Terminate with
|
||||||
|
* error when a referenced filter is missing or a variable could not be
|
||||||
|
* resolved -- among other reasons.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
_virNWFilterInstantiateRec(virConnectPtr conn,
|
||||||
|
virNWFilterTechDriverPtr techdriver,
|
||||||
|
enum virDomainNetType nettype,
|
||||||
|
virNWFilterDefPtr filter,
|
||||||
|
const char *ifname,
|
||||||
|
virNWFilterHashTablePtr vars,
|
||||||
|
int *nEntries,
|
||||||
|
virNWFilterRuleInstPtr **insts,
|
||||||
|
enum instCase useNewFilter, int *foundNewFilter)
|
||||||
|
{
|
||||||
|
virNWFilterDriverStatePtr driver = conn->nwfilterPrivateData;
|
||||||
|
virNWFilterPoolObjPtr obj;
|
||||||
|
int rc = 0;
|
||||||
|
int i;
|
||||||
|
virNWFilterRuleInstPtr inst;
|
||||||
|
virNWFilterDefPtr next_filter;
|
||||||
|
|
||||||
|
for (i = 0; i < filter->nentries; i++) {
|
||||||
|
virNWFilterRuleDefPtr rule = filter->filterEntries[i]->rule;
|
||||||
|
virNWFilterIncludeDefPtr inc = filter->filterEntries[i]->include;
|
||||||
|
if (rule) {
|
||||||
|
inst = virNWFilterRuleInstantiate(conn,
|
||||||
|
techdriver,
|
||||||
|
nettype,
|
||||||
|
filter,
|
||||||
|
rule,
|
||||||
|
ifname,
|
||||||
|
vars);
|
||||||
|
if (!inst) {
|
||||||
|
rc = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VIR_REALLOC_N(*insts, (*nEntries)+1) < 0) {
|
||||||
|
virReportOOMError();
|
||||||
|
rc = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*insts)[(*nEntries)++] = inst;
|
||||||
|
|
||||||
|
} else if (inc) {
|
||||||
|
VIR_DEBUG("Instantiating filter %s\n", inc->filterref);
|
||||||
|
obj = virNWFilterPoolObjFindByName(&driver->pools,
|
||||||
|
inc->filterref);
|
||||||
|
if (obj) {
|
||||||
|
|
||||||
|
if (obj->wantRemoved) {
|
||||||
|
virNWFilterReportError(conn, VIR_ERR_NO_NWFILTER,
|
||||||
|
_("Filter '%s' is in use."),
|
||||||
|
inc->filterref);
|
||||||
|
rc = 1;
|
||||||
|
virNWFilterPoolObjUnlock(obj);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a temporary hashmap for depth-first tree traversal
|
||||||
|
virNWFilterHashTablePtr tmpvars =
|
||||||
|
virNWFilterCreateVarsFrom(conn,
|
||||||
|
inc->params,
|
||||||
|
vars);
|
||||||
|
if (!tmpvars) {
|
||||||
|
virReportOOMError();
|
||||||
|
rc = 1;
|
||||||
|
virNWFilterPoolObjUnlock(obj);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
next_filter = obj->def;
|
||||||
|
|
||||||
|
switch (useNewFilter) {
|
||||||
|
case INSTANTIATE_FOLLOW_NEWFILTER:
|
||||||
|
if (obj->newDef) {
|
||||||
|
next_filter = obj->newDef;
|
||||||
|
*foundNewFilter = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case INSTANTIATE_ALWAYS:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = _virNWFilterInstantiateRec(conn,
|
||||||
|
techdriver,
|
||||||
|
nettype,
|
||||||
|
next_filter,
|
||||||
|
ifname,
|
||||||
|
tmpvars,
|
||||||
|
nEntries, insts,
|
||||||
|
useNewFilter,
|
||||||
|
foundNewFilter);
|
||||||
|
|
||||||
|
virNWFilterHashTableFree(tmpvars);
|
||||||
|
|
||||||
|
virNWFilterPoolObjUnlock(obj);
|
||||||
|
if (rc)
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("referenced filter '%s' is missing"),
|
||||||
|
inc->filterref);
|
||||||
|
rc = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
virNWFilterRuleInstancesToArray(int nEntries,
|
||||||
|
virNWFilterRuleInstPtr *insts,
|
||||||
|
void ***ptrs,
|
||||||
|
int *nptrs)
|
||||||
|
{
|
||||||
|
int i,j;
|
||||||
|
|
||||||
|
*nptrs = 0;
|
||||||
|
|
||||||
|
for (j = 0; j < nEntries; j++)
|
||||||
|
(*nptrs) += insts[j]->ndata;
|
||||||
|
|
||||||
|
if ((*nptrs) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (VIR_ALLOC_N((*ptrs), (*nptrs)) < 0) {
|
||||||
|
virReportOOMError();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*nptrs) = 0;
|
||||||
|
|
||||||
|
for (j = 0; j < nEntries; j++)
|
||||||
|
for (i = 0; i < insts[j]->ndata; i++)
|
||||||
|
(*ptrs)[(*nptrs)++] = insts[j]->data[i];
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virNWFilterInstantiate:
|
||||||
|
* @conn: pointer to virConnect object
|
||||||
|
* @techdriver: The driver to use for instantiation
|
||||||
|
* @filter: The filter to instantiate
|
||||||
|
* @ifname: The name of the interface to apply the rules to
|
||||||
|
* @vars: A map holding variable names and values used for instantiating
|
||||||
|
* the filter and its subfilters.
|
||||||
|
*
|
||||||
|
* Returns 0 on success, a value otherwise.
|
||||||
|
*
|
||||||
|
* Instantiate a filter by instantiating the filter itself along with
|
||||||
|
* all its subfilters in a depth-first traversal of the tree of referenced
|
||||||
|
* filters. The name of the interface to which the rules belong must be
|
||||||
|
* provided. Apply the values of variables as needed.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
virNWFilterInstantiate(virConnectPtr conn,
|
||||||
|
virNWFilterTechDriverPtr techdriver,
|
||||||
|
enum virDomainNetType nettype,
|
||||||
|
virNWFilterDefPtr filter,
|
||||||
|
const char *ifname,
|
||||||
|
virNWFilterHashTablePtr vars,
|
||||||
|
enum instCase useNewFilter, int *foundNewFilter,
|
||||||
|
bool teardownOld)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
int j, nptrs;
|
||||||
|
int nEntries = 0;
|
||||||
|
virNWFilterRuleInstPtr *insts = NULL;
|
||||||
|
void **ptrs = NULL;
|
||||||
|
int instantiate = 1;
|
||||||
|
|
||||||
|
rc = _virNWFilterInstantiateRec(conn,
|
||||||
|
techdriver,
|
||||||
|
nettype,
|
||||||
|
filter,
|
||||||
|
ifname,
|
||||||
|
vars,
|
||||||
|
&nEntries, &insts,
|
||||||
|
useNewFilter, foundNewFilter);
|
||||||
|
|
||||||
|
if (rc)
|
||||||
|
goto err_exit;
|
||||||
|
|
||||||
|
switch (useNewFilter) {
|
||||||
|
case INSTANTIATE_FOLLOW_NEWFILTER:
|
||||||
|
instantiate = *foundNewFilter;
|
||||||
|
break;
|
||||||
|
case INSTANTIATE_ALWAYS:
|
||||||
|
instantiate = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instantiate) {
|
||||||
|
|
||||||
|
rc = virNWFilterRuleInstancesToArray(nEntries, insts,
|
||||||
|
&ptrs, &nptrs);
|
||||||
|
if (rc)
|
||||||
|
goto err_exit;
|
||||||
|
|
||||||
|
rc = techdriver->applyNewRules(conn, ifname, nptrs, ptrs);
|
||||||
|
|
||||||
|
if (teardownOld && rc == 0)
|
||||||
|
techdriver->tearOldRules(conn, ifname);
|
||||||
|
|
||||||
|
VIR_FREE(ptrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
err_exit:
|
||||||
|
|
||||||
|
for (j = 0; j < nEntries; j++)
|
||||||
|
virNWFilterRuleInstFree(insts[j]);
|
||||||
|
|
||||||
|
VIR_FREE(insts);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
_virNWFilterInstantiateFilter(virConnectPtr conn,
|
||||||
|
const virDomainNetDefPtr net,
|
||||||
|
bool teardownOld,
|
||||||
|
enum instCase useNewFilter)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
const char *drvname = EBIPTABLES_DRIVER_ID;
|
||||||
|
virNWFilterDriverStatePtr driver = conn->nwfilterPrivateData;
|
||||||
|
virNWFilterTechDriverPtr techdriver;
|
||||||
|
virNWFilterPoolObjPtr obj;
|
||||||
|
virNWFilterHashTablePtr vars, vars1;
|
||||||
|
virNWFilterDefPtr filter;
|
||||||
|
char vmmacaddr[VIR_MAC_STRING_BUFLEN] = {0};
|
||||||
|
int foundNewFilter = 0;
|
||||||
|
char *str_macaddr = NULL;
|
||||||
|
|
||||||
|
techdriver = virNWFilterTechDriverForName(drvname);
|
||||||
|
|
||||||
|
if (!techdriver) {
|
||||||
|
virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("Could not get access to ACL tech "
|
||||||
|
"driver '%s'"),
|
||||||
|
drvname);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
VIR_DEBUG("filter name: %s\n", net->filter);
|
||||||
|
|
||||||
|
obj = virNWFilterPoolObjFindByName(&driver->pools, net->filter);
|
||||||
|
if (!obj) {
|
||||||
|
virNWFilterReportError(conn, VIR_ERR_NO_NWFILTER,
|
||||||
|
_("Could not find filter '%s'"),
|
||||||
|
net->filter);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj->wantRemoved) {
|
||||||
|
virNWFilterReportError(conn, VIR_ERR_NO_NWFILTER,
|
||||||
|
_("Filter '%s' is in use."),
|
||||||
|
net->filter);
|
||||||
|
rc = 1;
|
||||||
|
goto err_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
virFormatMacAddr(net->mac, vmmacaddr);
|
||||||
|
str_macaddr = strdup(vmmacaddr);
|
||||||
|
if (!str_macaddr) {
|
||||||
|
virReportOOMError();
|
||||||
|
rc = 1;
|
||||||
|
goto err_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
vars1 = virNWFilterCreateVarHashmap(conn,
|
||||||
|
str_macaddr);
|
||||||
|
if (!vars1) {
|
||||||
|
rc = 1;
|
||||||
|
goto err_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
str_macaddr = NULL;
|
||||||
|
|
||||||
|
vars = virNWFilterCreateVarsFrom(conn,
|
||||||
|
vars1,
|
||||||
|
net->filterparams);
|
||||||
|
if (!vars) {
|
||||||
|
rc = 1;
|
||||||
|
goto err_exit_vars1;
|
||||||
|
}
|
||||||
|
|
||||||
|
filter = obj->def;
|
||||||
|
|
||||||
|
switch (useNewFilter) {
|
||||||
|
case INSTANTIATE_FOLLOW_NEWFILTER:
|
||||||
|
if (obj->newDef) {
|
||||||
|
filter = obj->newDef;
|
||||||
|
foundNewFilter = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INSTANTIATE_ALWAYS:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = virNWFilterInstantiate(conn,
|
||||||
|
techdriver,
|
||||||
|
net->type,
|
||||||
|
filter,
|
||||||
|
net->ifname,
|
||||||
|
vars,
|
||||||
|
useNewFilter, &foundNewFilter,
|
||||||
|
teardownOld);
|
||||||
|
|
||||||
|
virNWFilterHashTableFree(vars);
|
||||||
|
|
||||||
|
err_exit_vars1:
|
||||||
|
virNWFilterHashTableFree(vars1);
|
||||||
|
|
||||||
|
err_exit:
|
||||||
|
|
||||||
|
virNWFilterPoolObjUnlock(obj);
|
||||||
|
|
||||||
|
VIR_FREE(str_macaddr);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
virNWFilterInstantiateFilter(virConnectPtr conn,
|
||||||
|
const virDomainNetDefPtr net)
|
||||||
|
{
|
||||||
|
return _virNWFilterInstantiateFilter(conn, net,
|
||||||
|
1,
|
||||||
|
INSTANTIATE_ALWAYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
virNWFilterUpdateInstantiateFilter(virConnectPtr conn,
|
||||||
|
const virDomainNetDefPtr net)
|
||||||
|
{
|
||||||
|
return _virNWFilterInstantiateFilter(conn, net,
|
||||||
|
0,
|
||||||
|
INSTANTIATE_FOLLOW_NEWFILTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
int virNWFilterRollbackUpdateFilter(virConnectPtr conn,
|
||||||
|
const virDomainNetDefPtr net)
|
||||||
|
{
|
||||||
|
const char *drvname = EBIPTABLES_DRIVER_ID;
|
||||||
|
virNWFilterTechDriverPtr techdriver;
|
||||||
|
techdriver = virNWFilterTechDriverForName(drvname);
|
||||||
|
if (!techdriver) {
|
||||||
|
virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("Could not get access to ACL tech "
|
||||||
|
"driver '%s'"),
|
||||||
|
drvname);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return techdriver->tearNewRules(conn, net->ifname);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
virNWFilterTearOldFilter(virConnectPtr conn,
|
||||||
|
virDomainNetDefPtr net)
|
||||||
|
{
|
||||||
|
const char *drvname = EBIPTABLES_DRIVER_ID;
|
||||||
|
virNWFilterTechDriverPtr techdriver;
|
||||||
|
techdriver = virNWFilterTechDriverForName(drvname);
|
||||||
|
if (!techdriver) {
|
||||||
|
virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("Could not get access to ACL tech "
|
||||||
|
"driver '%s'"),
|
||||||
|
drvname);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return techdriver->tearOldRules(conn, net->ifname);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
virNWFilterTeardownFilter(const virDomainNetDefPtr net)
|
||||||
|
{
|
||||||
|
const char *drvname = EBIPTABLES_DRIVER_ID;
|
||||||
|
virNWFilterTechDriverPtr techdriver;
|
||||||
|
techdriver = virNWFilterTechDriverForName(drvname);
|
||||||
|
|
||||||
|
if (!techdriver) {
|
||||||
|
#if 0
|
||||||
|
virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("Could not get access to ACL tech "
|
||||||
|
"driver '%s'"),
|
||||||
|
drvname);
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
techdriver->allTeardown(net->ifname);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
54
src/nwfilter/nwfilter_gentech_driver.h
Normal file
54
src/nwfilter/nwfilter_gentech_driver.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* nwfilter_gentech_driver.h: generic technology driver include file
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 IBM Corp.
|
||||||
|
* Copyright (C) 2010 Stefan Berger
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* Author: Stefan Berger <stefanb@us.ibm.com>
|
||||||
|
*/
|
||||||
|
#ifndef __NWFILTER_GENTECH_DRIVER_H
|
||||||
|
#define __NWFILTER_GENTECH_DRIVER_H
|
||||||
|
|
||||||
|
virNWFilterTechDriverPtr virNWFilterTechDriverForName(const char *name);
|
||||||
|
|
||||||
|
int virNWFilterRuleInstAddData(virConnectPtr conn,
|
||||||
|
virNWFilterRuleInstPtr res,
|
||||||
|
void *data);
|
||||||
|
|
||||||
|
|
||||||
|
enum instCase {
|
||||||
|
INSTANTIATE_ALWAYS,
|
||||||
|
INSTANTIATE_FOLLOW_NEWFILTER,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int virNWFilterInstantiateFilter(virConnectPtr conn,
|
||||||
|
const virDomainNetDefPtr net);
|
||||||
|
int virNWFilterUpdateInstantiateFilter(virConnectPtr conn,
|
||||||
|
const virDomainNetDefPtr net);
|
||||||
|
int virNWFilterRollbackUpdateFilter(virConnectPtr conn,
|
||||||
|
const virDomainNetDefPtr net);
|
||||||
|
|
||||||
|
int virNWFilterTearOldFilter(virConnectPtr conn,
|
||||||
|
const virDomainNetDefPtr net);
|
||||||
|
|
||||||
|
int virNWFilterTeardownFilter(const virDomainNetDefPtr net);
|
||||||
|
|
||||||
|
virNWFilterHashTablePtr virNWFilterCreateVarHashmap(virConnectPtr conn,
|
||||||
|
char *macaddr);
|
||||||
|
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user