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:
Stefan Berger 2010-03-25 13:46:09 -04:00 committed by Daniel P. Berrange
parent e4e20423ff
commit 065b6571bf
15 changed files with 2765 additions and 2 deletions

View File

@ -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])
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_DEFINE_UNQUOTED([IPTABLES_PATH], "$IPTABLES_PATH", [path to iptables binary])
@ -1268,6 +1271,15 @@ if test "$with_secrets" = "yes" ; then
fi
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_HELP_STRING([--with-storage-fs], [with FileSystem backend for the storage driver @<:@default=check@:>@]),[],[with_storage_fs=check])

View File

@ -116,6 +116,10 @@ endif
if WITH_SECRETS
libvirtd_LDADD += ../src/libvirt_driver_secret.la
endif
if WITH_NWFILTER
libvirtd_LDADD += ../src/libvirt_driver_nwfilter.la
endif
endif
libvirtd_LDADD += ../src/libvirt.la

View File

@ -96,6 +96,9 @@
# ifdef WITH_SECRETS
# include "secret/secret_driver.h"
# endif
# ifdef WITH_NWFILTER
# include "nwfilter/nwfilter_driver.h"
# endif
#endif
@ -876,6 +879,7 @@ static struct qemud_server *qemudInitialize(void) {
virDriverLoadModule("lxc");
virDriverLoadModule("uml");
virDriverLoadModule("one");
virDriverLoadModule("nwfilter");
#else
# ifdef WITH_NETWORK
networkRegister();
@ -892,6 +896,9 @@ static struct qemud_server *qemudInitialize(void) {
# ifdef WITH_SECRETS
secretRegister();
# endif
# ifdef WITH_NWFILTER
nwfilterRegister();
# endif
# ifdef WITH_QEMU
qemuRegister();
# endif

View File

@ -28,6 +28,9 @@ src/node_device/node_device_driver.c
src/node_device/node_device_linux_sysfs.c
src/node_device/node_device_udev.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_driver.c
src/openvz/openvz_conf.c

View File

@ -175,6 +175,7 @@ skipped_types = {
'virConnectDomainEventIOErrorCallback': "No function types in python",
'virConnectDomainEventGraphicsCallback': "No function types in python",
'virEventAddHandleFunc': "No function types in python",
'virNWFilterPtr': "No function types in python",
}
#######################################################################
@ -273,6 +274,7 @@ skip_impl = (
'virConnectListStorageVols',
'virConnectListDefinedStorageVols',
'virConnectListDefinedInterfaces',
'virConnectListNWFilters',
'virConnGetLastError',
'virGetLastError',
'virDomainGetInfo',

View File

@ -284,6 +284,11 @@ STORAGE_DRIVER_DISK_SOURCES = \
STORAGE_HELPER_DISK_SOURCES = \
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_DRIVER_SOURCES = \
@ -727,6 +732,22 @@ 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)
noinst_LTLIBRARIES += libvirt_driver_security.la
libvirt_la_LIBADD += libvirt_driver_security.la

View File

@ -39,6 +39,7 @@
#include "nwfilter_params.h"
#include "nwfilter_conf.h"
#include "domain_conf.h"
#include "nwfilter/nwfilter_gentech_driver.h"
#define VIR_FROM_THIS VIR_FROM_NWFILTER
@ -1605,10 +1606,42 @@ struct cbStruct {
};
static void
virNWFilterDomainFWUpdateCB(void *payload ATTRIBUTE_UNUSED,
virNWFilterDomainFWUpdateCB(void *payload,
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);
}

View File

@ -449,6 +449,42 @@ virNodeDeviceGetWWNs;
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
pciGetDevice;
pciFreeDevice;

View File

@ -380,4 +380,5 @@ LIBVIRT_0.7.8 {
virNWFilterUndefine;
} LIBVIRT_0.7.7;
# .... define new API here using predicted next version number ....

View 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;
}

View 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__ */

File diff suppressed because it is too large Load Diff

View 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

View 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;
}

View 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