[libvirt] [PATCH] Remove qemudDomainSetMaxMemory.
by Chris Lalancette
As previously discussed[1], this patch removes the
qemudDomainSetMaxMemory() function, since it doesn't
work. This means that instead of getting somewhat
cryptic errors, you will now get:
error: Unable to change MaxMemorySize
error: this function is not supported by the hypervisor: virDomainSetMaxMemory
Which describes the situation perfectly.
[1] https://www.redhat.com/archives/libvir-list/2010-February/msg00928.html
Signed-off-by: Chris Lalancette <clalance(a)redhat.com>
---
src/qemu/qemu_driver.c | 42 +-----------------------------------------
1 files changed, 1 insertions(+), 41 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index c5490b2..6bfae93 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -3816,46 +3816,6 @@ cleanup:
return ret;
}
-static int qemudDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax) {
- struct qemud_driver *driver = dom->conn->privateData;
- virDomainObjPtr vm;
- int ret = -1;
-
- qemuDriverLock(driver);
- vm = virDomainFindByUUID(&driver->domains, dom->uuid);
- qemuDriverUnlock(driver);
-
- if (!vm) {
- char uuidstr[VIR_UUID_STRING_BUFLEN];
- virUUIDFormat(dom->uuid, uuidstr);
- qemuReportError(VIR_ERR_NO_DOMAIN,
- _("no domain with matching uuid '%s'"), uuidstr);
- goto cleanup;
- }
-
- if (!virDomainObjIsActive(vm)) {
- qemuReportError(VIR_ERR_OPERATION_INVALID,
- "%s", _("domain is not running"));
- goto cleanup;
- }
-
- if (newmax < vm->def->memory) {
- qemuReportError(VIR_ERR_INVALID_ARG, "%s",
- _("cannot set max memory lower than current memory"));
- goto cleanup;
- }
-
- /* There isn't any way to change this value for a running qemu guest */
- qemuReportError(VIR_ERR_NO_SUPPORT,
- "%s", _("cannot set max memory of an active domain"));
-
-cleanup:
- if (vm)
- virDomainObjUnlock(vm);
- return ret;
-}
-
-
static int qemudDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
struct qemud_driver *driver = dom->conn->privateData;
qemuDomainObjPrivatePtr priv;
@@ -9506,7 +9466,7 @@ static virDriver qemuDriver = {
qemudDomainDestroy, /* domainDestroy */
qemudDomainGetOSType, /* domainGetOSType */
qemudDomainGetMaxMemory, /* domainGetMaxMemory */
- qemudDomainSetMaxMemory, /* domainSetMaxMemory */
+ NULL, /* domainSetMaxMemory */
qemudDomainSetMemory, /* domainSetMemory */
qemudDomainGetInfo, /* domainGetInfo */
qemudDomainSave, /* domainSave */
--
1.6.6.1
14 years, 7 months
[libvirt] [PATCH] Fix a JSON CPU information bug.
by Chris Lalancette
When using the JSON monitor, qemuMonitorJSONExtractCPUInfo
was returning 0 on success. Unfortunately, higher levels of
the cpuinfo code expect that it returns the number of CPUs
it found on success. This one-line patch fixes it so that
it returns the correct number. This makes "virsh vcpuinfo <domain>"
work when using the JSON monitor.
Signed-off-by: Chris Lalancette <clalance(a)redhat.com>
---
src/qemu/qemu_monitor_json.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index f04fd2e..7a263cb 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -648,7 +648,7 @@ qemuMonitorJSONExtractCPUInfo(virJSONValuePtr reply,
*pids = threads;
threads = NULL;
- ret = 0;
+ ret = ncpus;
cleanup:
VIR_FREE(threads);
--
1.6.6.1
14 years, 7 months
[libvirt] [PATCH 12/13] Core driver implementation with ebtables support
by Stefan Berger
Attachment may have been too big for mailserver -- sending patch inline.
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(a)us.ibm.com>
---
configure.ac | 3
daemon/libvirtd.c | 7
include/libvirt/virterror.h | 5
python/generator.py | 2
src/conf/nwfilter_conf.c | 2503
++++++++++++++++++++++++++++++
src/conf/nwfilter_conf.h | 472 +++++
src/datatypes.c | 142 +
src/datatypes.h | 32
src/nwfilter/nwfilter_driver.c | 429 +++++
src/nwfilter/nwfilter_driver.h | 35
src/nwfilter/nwfilter_ebiptables_driver.c | 1313 +++++++++++++++
src/nwfilter/nwfilter_ebiptables_driver.h | 41
src/nwfilter/nwfilter_gentech_driver.c | 656 +++++++
src/nwfilter/nwfilter_gentech_driver.h | 52
src/util/virterror.c | 27
15 files changed, 5719 insertions(+)
Index: libvirt-acl/src/conf/nwfilter_conf.c
===================================================================
--- /dev/null
+++ libvirt-acl/src/conf/nwfilter_conf.c
@@ -0,0 +1,2503 @@
+/*
+ * nwfilter_conf.c: network filter XML processing
+ * (derived from storage_conf.c)
+ *
+ * Copyright (C) 2006-2010 Red Hat, Inc.
+ * Copyright (C) 2006-2008 Daniel P. Berrange
+ *
+ * Copyright (C) 2010 IBM Corporation
+ *
+ * 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(a)us.ibm.com>
+ */
+#include <stdio.h>
+#include <config.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <regex.h>
+#include <dirent.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/ethernet.h>
+
+#include "config.h"
+
+#include "virterror_internal.h"
+#include "datatypes.h"
+#include "nwfilter_conf.h"
+#include "domain_conf.h"
+
+#include "xml.h"
+#include "uuid.h"
+#include "buf.h"
+#include "util.h"
+#include "memory.h"
+
+#include "nwfilter/nwfilter_gentech_driver.h"
+
+
+#define VIR_FROM_THIS VIR_FROM_NWFILTER
+
+#define virNWFilterError(conn, code, fmt...)
\
+ virReportErrorHelper(conn, VIR_FROM_NWFILTER, code,
__FILE__,\
+ __FUNCTION__, __LINE__, fmt)
+
+VIR_ENUM_IMPL(virNWFilterRuleAction, VIR_NWFILTER_RULE_ACTION_LAST,
+ "drop",
+ "accept");
+
+VIR_ENUM_IMPL(virNWFilterJumpTarget, VIR_NWFILTER_RULE_ACTION_LAST,
+ "DROP",
+ "ACCEPT");
+
+VIR_ENUM_IMPL(virNWFilterRuleDirection,
VIR_NWFILTER_RULE_DIRECTION_LAST,
+ "in",
+ "out",
+ "inout");
+
+VIR_ENUM_IMPL(virNWFilterChainPolicy, VIR_NWFILTER_CHAIN_POLICY_LAST,
+ "ACCEPT",
+ "DROP");
+
+VIR_ENUM_IMPL(virNWFilterEbtablesTable,
VIR_NWFILTER_EBTABLES_TABLE_LAST,
+ "filter",
+ "nat",
+ "broute");
+
+VIR_ENUM_IMPL(virNWFilterChainSuffix, VIR_NWFILTER_CHAINSUFFIX_LAST,
+ "root",
+ "arp",
+ "ipv4");
+
+
+/*
+ * a map entry for a simple static int-to-string map
+ */
+struct int_map {
+ int32_t attr;
+ const char *val;
+};
+
+
+/*
+ * only one filter update allowed
+ */
+static virMutex updateMutex;
+
+static void
+virNWFilterLockFilterUpdates(void) {
+ virMutexLock(&updateMutex);
+}
+
+static void
+virNWFilterUnlockFilterUpdates(void) {
+ virMutexUnlock(&updateMutex);
+}
+
+
+/*
+ * regular expressions for parameter names and values
+ */
+static regex_t regex_nam;
+static regex_t regex_val;
+
+
+/*
+ * attribute names for the rules XML
+ */
+static const char srcmacaddr_str[] = "srcmacaddr";
+static const char srcmacmask_str[] = "srcmacmask";
+static const char dstmacaddr_str[] = "dstmacaddr";
+static const char dstmacmask_str[] = "dstmacmask";
+static const char srcipaddr_str[] = "srcipaddr";
+static const char srcipmask_str[] = "srcipmask";
+static const char dstipaddr_str[] = "dstipaddr";
+static const char dstipmask_str[] = "dstipmask";
+static const char srcportstart_str[] = "srcportstart";
+static const char srcportend_str[] = "srcportend";
+static const char dstportstart_str[] = "dstportstart";
+static const char dstportend_str[] = "dstportend";
+
+#define SRCMACADDR srcmacaddr_str
+#define SRCMACMASK srcmacmask_str
+#define DSTMACADDR dstmacaddr_str
+#define DSTMACMASK dstmacmask_str
+#define SRCIPADDR srcipaddr_str
+#define SRCIPMASK srcipmask_str
+#define DSTIPADDR dstipaddr_str
+#define DSTIPMASK dstipmask_str
+#define SRCPORTSTART srcportstart_str
+#define SRCPORTEND srcportend_str
+#define DSTPORTSTART dstportstart_str
+#define DSTPORTEND dstportend_str
+
+
+/**
+ * intMapGetByInt:
+ * @intmap: Pointer to int-to-string map
+ * @attr: The attribute to look up
+ * @res: Pointer to string pointer for result
+ *
+ * Returns 1 if value was found with result returned, 0 otherwise.
+ *
+ * lookup a map entry given the integer.
+ */
+static bool
+intMapGetByInt(const struct int_map *intmap, int32_t attr, const char
**res)
+{
+ int i = 0;
+ bool found = 0;
+ while (intmap[i].val && !found) {
+ if (intmap[i].attr == attr) {
+ *res = intmap[i].val;
+ found = 1;
+ }
+ i++;
+ }
+ return found;
+}
+
+
+/**
+ * intMapGetByString:
+ * @intmap: Pointer to int-to-string map
+ * @str: Pointer to string for which to find the entry
+ * @casecmp : Whether to ignore case when doing string matching
+ * @result: Pointer to int for result
+ *
+ * Returns 0 if no entry was found, 1 otherwise.
+ *
+ * Do a lookup in the map trying to find an integer key using the
string
+ * value. Returns 1 if entry was found with result returned, 0
otherwise.
+ */
+static bool
+intMapGetByString(const struct int_map *intmap, const char *str, int
casecmp,
+ int32_t *result)
+{
+ int i = 0;
+ bool found = 0;
+ while (intmap[i].val && !found) {
+ if ( (casecmp && STRCASEEQ(intmap[i].val, str)) ||
+ STREQ (intmap[i].val, str) ) {
+ *result = intmap[i].attr;
+ found = 1;
+ }
+ i++;
+ }
+ return found;
+}
+
+
+void
+virNWFilterRuleDefFree(virNWFilterRuleDefPtr def) {
+ int i;
+ if (!def)
+ return;
+
+ for (i = 0; i < def->nvars; i++)
+ VIR_FREE(def->vars[i]);
+
+ VIR_FREE(def->vars);
+
+ VIR_FREE(def);
+}
+
+
+static void
+hashDealloc(void *payload, const char *name ATTRIBUTE_UNUSED)
+{
+ VIR_FREE(payload);
+}
+
+
+static void
+virNWFilterIncludeDefFree(virNWFilterIncludeDefPtr inc) {
+ if (!inc)
+ return;
+ virNWFilterHashTableFree(inc->params);
+ VIR_FREE(inc->filterref);
+ VIR_FREE(inc);
+}
+
+
+static void
+virNWFilterEntryFree(virNWFilterEntryPtr entry) {
+ if (!entry)
+ return;
+
+ virNWFilterRuleDefFree(entry->rule);
+ virNWFilterIncludeDefFree(entry->include);
+ VIR_FREE(entry);
+}
+
+
+void
+virNWFilterDefFree(virNWFilterDefPtr def) {
+ int i;
+ if (!def)
+ return;
+
+ VIR_FREE(def->name);
+
+ for (i = 0; i < def->nentries; i++)
+ virNWFilterEntryFree(def->filterEntries[i]);
+
+ VIR_FREE(def->filterEntries);
+
+ VIR_FREE(def);
+}
+
+
+void
+virNWFilterPoolObjFree(virNWFilterPoolObjPtr obj) {
+ if (!obj)
+ return;
+
+ virNWFilterDefFree(obj->def);
+ virNWFilterDefFree(obj->newDef);
+
+ VIR_FREE(obj->configFile);
+
+ virMutexDestroy(&obj->lock);
+
+ VIR_FREE(obj);
+}
+
+
+void
+virNWFilterPoolObjListFree(virNWFilterPoolObjListPtr pools)
+{
+ unsigned int i;
+ for (i = 0 ; i < pools->count ; i++)
+ virNWFilterPoolObjFree(pools->objs[i]);
+ VIR_FREE(pools->objs);
+ pools->count = 0;
+}
+
+
+static int
+virNWFilterRuleDefAddVar(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virNWFilterRuleDefPtr nwf,
+ nwItemDesc *item,
+ const char *var)
+{
+ int i = 0;
+
+ if (nwf->vars) {
+ for (i = 0; i < nwf->nvars; i++)
+ if (STREQ(nwf->vars[i], var)) {
+ item->var = nwf->vars[i];
+ return 0;
+ }
+ }
+
+ if (VIR_REALLOC_N(nwf->vars, nwf->nvars+1) < 0) {
+ virReportOOMError();
+ return 1;
+ }
+
+ nwf->vars[nwf->nvars] = strdup(var);
+
+ if (!nwf->vars[nwf->nvars]) {
+ virReportOOMError();
+ return 1;
+ }
+
+ item->var = nwf->vars[nwf->nvars++];
+
+ return 0;
+}
+
+
+void
+virNWFilterPoolObjRemove(virNWFilterPoolObjListPtr pools,
+ virNWFilterPoolObjPtr pool)
+{
+ unsigned int i;
+
+ virNWFilterPoolObjUnlock(pool);
+
+ for (i = 0 ; i < pools->count ; i++) {
+ virNWFilterPoolObjLock(pools->objs[i]);
+ if (pools->objs[i] == pool) {
+ virNWFilterPoolObjUnlock(pools->objs[i]);
+ virNWFilterPoolObjFree(pools->objs[i]);
+
+ if (i < (pools->count - 1))
+ memmove(pools->objs + i, pools->objs + i + 1,
+ sizeof(*(pools->objs)) * (pools->count - (i +
1)));
+
+ if (VIR_REALLOC_N(pools->objs, pools->count - 1) < 0) {
+ ; /* Failure to reduce memory allocation isn't fatal */
+ }
+ pools->count--;
+
+ break;
+ }
+ virNWFilterPoolObjUnlock(pools->objs[i]);
+ }
+}
+
+
+
+typedef bool (*valueValidator)(enum attrDatatype datatype, void
*valptr,
+ virNWFilterRuleDefPtr nwf);
+typedef bool (*valueFormatter)(virBufferPtr buf,
+ virNWFilterRuleDefPtr nwf);
+
+typedef struct _virXMLAttr2Struct virXMLAttr2Struct;
+struct _virXMLAttr2Struct
+{
+ const char *name; // attribute name
+ enum attrDatatype datatype;
+ int dataIdx; // offset of the hasXYZ boolean
+ valueValidator validator; // beyond-standard checkers
+ valueFormatter formatter; // beyond-standard formatter
+};
+
+
+
+static bool
+checkPriority(enum attrDatatype datatype ATTRIBUTE_UNUSED, void *val,
+ virNWFilterRuleDefPtr nwf ATTRIBUTE_UNUSED)
+{
+ unsigned char prio = *(unsigned char *)val;
+ if (prio > 7)
+ return 0;
+ return 1;
+}
+
+
+static bool
+checkVLAN(enum attrDatatype datatype ATTRIBUTE_UNUSED, void *val,
+ virNWFilterRuleDefPtr nwf ATTRIBUTE_UNUSED)
+{
+ uint16_t vid = *(uint16_t *)val;
+ if (vid >= 0x1000)
+ return 0;
+ return 1;
+}
+
+
+
+
+static const struct int_map macProtoMap[] = {
+ {
+ .attr = ETHERTYPE_ARP,
+ .val = "arp",
+ }, {
+ .attr = ETHERTYPE_IP,
+ .val = "ipv4",
+ }, {
+ .val = NULL,
+ }
+};
+
+
+static bool
+checkMacProtocolID(enum attrDatatype datatype, void *value,
+ virNWFilterRuleDefPtr nwf ATTRIBUTE_UNUSED)
+{
+ int32_t res = -1;
+ const char *str;
+
+ if (datatype == DATATYPE_STRING) {
+ if (intMapGetByString(macProtoMap, (char *)value, 1, &res) ==
0)
+ res = -1;
+ } else if (datatype == DATATYPE_UINT16) {
+ if (intMapGetByInt(macProtoMap,
+ (int32_t)*(uint16_t *)value, &str) == 0)
+ res = -1;
+ }
+
+ if (res != -1) {
+ nwf->p.ethHdrFilter.dataProtocolID.u.u16 = res;
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static bool
+macProtocolIDFormatter(virBufferPtr buf,
+ virNWFilterRuleDefPtr nwf)
+{
+ const char *str = NULL;
+
+ if (intMapGetByInt(macProtoMap,
+ nwf->p.ethHdrFilter.dataProtocolID.u.u16,
+ &str)) {
+ virBufferVSprintf(buf, "%s", str);
+ return 1;
+ }
+ return 0;
+}
+
+
+/* generic function to check for a valid (ipv4,ipv6, mac) mask
+ * A mask is valid of there is a sequence of 1's followed by a sequence
+ * of 0s or only 1s or only 0s
+ */
+static bool
+checkValidMask(unsigned char *data, int len)
+{
+ uint32_t idx = 0;
+ uint8_t mask = 0x80;
+ int checkones = 1;
+
+ while ((idx >> 3) < len) {
+ if (checkones) {
+ if (!(data[idx>>3] & mask))
+ checkones = 0;
+ } else {
+ if ((data[idx>>3] & mask))
+ return 0;
+ }
+
+ idx++;
+ mask >>= 1;
+ if (!mask)
+ mask = 0x80;
+ }
+ return 1;
+}
+
+
+/* check for a valid IPv4 mask */
+static bool
+checkIPv4Mask(enum attrDatatype datatype ATTRIBUTE_UNUSED, void
*maskptr,
+ virNWFilterRuleDefPtr nwf ATTRIBUTE_UNUSED)
+{
+ return checkValidMask(maskptr, 4);
+}
+
+
+static bool
+checkMACMask(enum attrDatatype datatype ATTRIBUTE_UNUSED,
+ void *macMask,
+ virNWFilterRuleDefPtr nwf ATTRIBUTE_UNUSED)
+{
+ return checkValidMask((unsigned char *)macMask, 6);
+}
+
+
+static int getMaskNumBits(const unsigned char *mask, int len) {
+ int i = 0;
+ while (i < (len << 3)) {
+ if (!(mask[i>>3] & (0x80 >> (i & 3))))
+ break;
+ i++;
+ }
+ return i;
+}
+
+/*
+ * supported arp opcode -- see 'ebtables -h arp' for the naming
+ */
+static const struct int_map arpOpcodeMap[] = {
+ {
+ .attr = 1,
+ .val = "Request",
+ } , {
+ .attr = 2,
+ .val = "Reply",
+ } , {
+ .attr = 3,
+ .val = "Request_Reverse",
+ } , {
+ .attr = 4,
+ .val = "Reply_Reverse",
+ } , {
+ .attr = 5,
+ .val = "DRARP_Request",
+ } , {
+ .attr = 6,
+ .val = "DRARP_Reply",
+ } , {
+ .attr = 7,
+ .val = "DRARP_Error",
+ } , {
+ .attr = 8,
+ .val = "InARP_Request",
+ } , {
+ .attr = 9,
+ .val = "ARP_NAK",
+ } , {
+ .val = NULL,
+ }
+};
+
+
+static bool
+arpOpcodeValidator(enum attrDatatype datatype,
+ void *value,
+ virNWFilterRuleDefPtr nwf)
+{
+ int32_t res = -1;
+ const char *str;
+
+ if (datatype == DATATYPE_STRING) {
+ if (intMapGetByString(arpOpcodeMap, (char *)value, 1, &res) ==
0)
+ res = -1;
+ } else if (datatype == DATATYPE_UINT8) {
+ if (intMapGetByInt(arpOpcodeMap,
+ (uint32_t)*(uint16_t *)value, &str) == 0)
+ res = -1;
+ }
+
+ if (res != -1) {
+ nwf->p.arpHdrFilter.dataOpcode.u.u16 = res;
+ return 1;
+ }
+ return 0;
+}
+
+
+static bool
+arpOpcodeFormatter(virBufferPtr buf,
+ virNWFilterRuleDefPtr nwf)
+{
+ const char *str = NULL;
+
+ if (intMapGetByInt(arpOpcodeMap,
+ nwf->p.arpHdrFilter.dataOpcode.u.u16,
+ &str)) {
+ virBufferVSprintf(buf, "%s", str);
+ return 1;
+ }
+ return 0;
+}
+
+
+static const struct int_map ipProtoMap[] = {
+ {
+ .attr = IPPROTO_TCP,
+ .val = "tcp",
+ } , {
+ .attr = IPPROTO_UDP,
+ .val = "udp",
+ } , {
+ .attr = IPPROTO_ICMP,
+ .val = "icmp",
+ } , {
+ .attr = IPPROTO_IGMP,
+ .val = "igmp",
+#ifdef IPPROTO_SCTP
+ } , {
+ .attr = IPPROTO_SCTP,
+ .val = "sctp",
+#endif
+ } , {
+ .val = NULL,
+ }
+};
+
+
+static bool checkIPProtocolID(enum attrDatatype datatype,
+ void *value,
+ virNWFilterRuleDefPtr nwf)
+{
+ int32_t res = -1;
+ const char *str;
+
+ if (datatype == DATATYPE_STRING) {
+ if (intMapGetByString(ipProtoMap, (char *)value, 1, &res) == 0)
+ res = -1;
+ } else if (datatype == DATATYPE_UINT8) {
+ // may just accept what user provides and not test...
+ if (intMapGetByInt(ipProtoMap,
+ (uint32_t)*(uint16_t *)value, &str) == 0)
+ res = -1;
+ }
+
+ if (res != -1) {
+ nwf->p.ipHdrFilter.ipHdr.dataProtocolID.u.u16 = res;
+ return 1;
+ }
+ return 0;
+}
+
+
+static bool
+formatIPProtocolID(virBufferPtr buf,
+ virNWFilterRuleDefPtr nwf)
+{
+ const char *str = NULL;
+
+ if (intMapGetByInt(ipProtoMap,
+ nwf->p.ipHdrFilter.ipHdr.dataProtocolID.u.u16,
+ &str)) {
+ virBufferVSprintf(buf, "%s", str);
+ return 1;
+ }
+ return 0;
+}
+
+
+static const virXMLAttr2Struct macAttributes[] = {
+ {
+ .name = SRCMACADDR,
+ .datatype = DATATYPE_MACADDR,
+ .dataIdx = offsetof(virNWFilterRuleDef,
p.ethHdrFilter.dataSrcMACAddr),
+ },
+ {
+ .name = SRCMACMASK,
+ .datatype = DATATYPE_MACMASK,
+ .dataIdx = offsetof(virNWFilterRuleDef,
p.ethHdrFilter.dataSrcMACMask),
+ },
+ {
+ .name = DSTMACADDR,
+ .datatype = DATATYPE_MACADDR,
+ .dataIdx = offsetof(virNWFilterRuleDef,
p.ethHdrFilter.dataDstMACAddr),
+ },
+ {
+ .name = DSTMACMASK,
+ .datatype = DATATYPE_MACMASK,
+ .dataIdx = offsetof(virNWFilterRuleDef,
p.ethHdrFilter.dataDstMACMask),
+ },
+ {
+ .name = "protocolid",
+ .datatype = DATATYPE_UINT16 | DATATYPE_STRING,
+ .dataIdx = offsetof(virNWFilterRuleDef,
p.ethHdrFilter.dataProtocolID),
+ .validator= checkMacProtocolID,
+ .formatter= macProtocolIDFormatter,
+ },
+ {
+ .name = "priority",
+ .datatype = DATATYPE_UINT8,
+ .dataIdx = offsetof(virNWFilterRuleDef,
p.ethHdrFilter.dataPriority),
+ .validator= checkPriority, // enforce only 3 valid bits
+ },
+ {
+ .name = "vlanid",
+ .datatype = DATATYPE_UINT16,
+ .dataIdx = offsetof(virNWFilterRuleDef,
p.ethHdrFilter.dataVLANID),
+ .validator= checkVLAN, // enforce only 12 valid bits
+ },
+ {
+ .name = NULL,
+ }
+};
+
+static const virXMLAttr2Struct arpAttributes[] = {
+ {
+ .name = "hwtype",
+ .datatype = DATATYPE_UINT16,
+ .dataIdx = offsetof(virNWFilterRuleDef,
p.arpHdrFilter.dataHWType),
+ }, {
+ .name = "protocoltype",
+ .datatype = DATATYPE_UINT16,
+ .dataIdx = offsetof(virNWFilterRuleDef,
p.arpHdrFilter.dataProtocolType),
+ }, {
+ .name = "opcode",
+ .datatype = DATATYPE_UINT8 | DATATYPE_STRING,
+ .dataIdx = offsetof(virNWFilterRuleDef,
p.arpHdrFilter.dataOpcode),
+ .validator= arpOpcodeValidator,
+ .formatter= arpOpcodeFormatter,
+ }, {
+ .name = SRCMACADDR,
+ .datatype = DATATYPE_MACADDR,
+ .dataIdx = offsetof(virNWFilterRuleDef,
p.arpHdrFilter.dataSrcMACAddr),
+ }, {
+ .name = DSTMACADDR,
+ .datatype = DATATYPE_MACADDR,
+ .dataIdx = offsetof(virNWFilterRuleDef,
p.arpHdrFilter.dataDstMACAddr),
+ }, {
+ .name = SRCIPADDR,
+ .datatype = DATATYPE_IPADDR,
+ .dataIdx = offsetof(virNWFilterRuleDef,
p.arpHdrFilter.dataSrcIPAddr),
+ }, {
+ .name = DSTIPADDR,
+ .datatype = DATATYPE_IPADDR,
+ .dataIdx = offsetof(virNWFilterRuleDef,
p.arpHdrFilter.dataDstIPAddr),
+ },
+ {
+ .name = NULL,
+ }
+};
+
+static const virXMLAttr2Struct ipAttributes[] = {
+ {
+ .name = "version",
+ .datatype = DATATYPE_UINT8,
+ .dataIdx = offsetof(virNWFilterRuleDef,
p.ipHdrFilter.ipHdr.dataIPVersion),
+ },
+ {
+ .name = SRCIPADDR,
+ .datatype = DATATYPE_IPADDR,
+ .dataIdx = offsetof(virNWFilterRuleDef,
p.ipHdrFilter.ipHdr.dataSrcAddr),
+ },
+ {
+ .name = DSTIPADDR,
+ .datatype = DATATYPE_IPADDR,
+ .dataIdx = offsetof(virNWFilterRuleDef,
p.ipHdrFilter.ipHdr.dataDstAddr),
+ },
+ {
+ .name = SRCIPMASK,
+ .datatype = DATATYPE_IPMASK,
+ .dataIdx = offsetof(virNWFilterRuleDef,
p.ipHdrFilter.ipHdr.dataSrcMask),
+ },
+ {
+ .name = DSTIPMASK,
+ .datatype = DATATYPE_IPMASK,
+ .dataIdx = offsetof(virNWFilterRuleDef,
p.ipHdrFilter.ipHdr.dataDstMask),
+ },
+ {
+ .name = "protocol",
+ .datatype = DATATYPE_STRING,
+ .dataIdx = offsetof(virNWFilterRuleDef,
p.ipHdrFilter.ipHdr.dataProtocolID),
+ .validator= checkIPProtocolID,
+ .formatter= formatIPProtocolID,
+ },
+ {
+ .name = SRCPORTSTART,
+ .datatype = DATATYPE_UINT16,
+ .dataIdx = offsetof(virNWFilterRuleDef,
p.ipHdrFilter.portData.dataSrcPortStart),
+ },
+ {
+ .name = SRCPORTEND,
+ .datatype = DATATYPE_UINT16,
+ .dataIdx = offsetof(virNWFilterRuleDef,
p.ipHdrFilter.portData.dataSrcPortEnd),
+ },
+ {
+ .name = DSTPORTSTART,
+ .datatype = DATATYPE_UINT16,
+ .dataIdx = offsetof(virNWFilterRuleDef,
p.ipHdrFilter.portData.dataDstPortStart),
+ },
+ {
+ .name = DSTPORTEND,
+ .datatype = DATATYPE_UINT16,
+ .dataIdx = offsetof(virNWFilterRuleDef,
p.ipHdrFilter.portData.dataDstPortEnd),
+ },
+ {
+ .name = NULL,
+ }
+};
+
+
+typedef struct _virAttributes virAttributes;
+struct _virAttributes {
+ const char *id;
+ const virXMLAttr2Struct *att;
+ enum virNWFilterRuleProtocolType prtclType;
+};
+
+
+static const virAttributes virAttr[] = {
+ {
+ .id = "arp",
+ .att = arpAttributes,
+ .prtclType = VIR_NWFILTER_RULE_PROTOCOL_ARP,
+ }, {
+ .id = "mac",
+ .att = macAttributes,
+ .prtclType = VIR_NWFILTER_RULE_PROTOCOL_MAC,
+ }, {
+ .id = "ip",
+ .att = ipAttributes,
+ .prtclType = VIR_NWFILTER_RULE_PROTOCOL_IP,
+ }, {
+ .id = NULL,
+ }
+};
+
+
+static bool
+virNWMACAddressParser(const char *input,
+ nwMACAddressPtr output)
+{
+ if (virParseMacAddr(input, &output->addr[0]) == 0)
+ return 1;
+ return 0;
+}
+
+
+static bool
+virNWIPv4AddressParser(const char *input,
+ nwIPAddressPtr output)
+{
+ int i;
+ char *endptr;
+ const char *n = input;
+ long int d;
+
+ for (i = 0; i < 4; i++) {
+ d = strtol(n, &endptr, 10);
+ if (d < 0 || d > 255 ||
+ (endptr - n > 3 ) ||
+ (i <= 2 && *endptr != '.' ) ||
+ (i == 3 && *endptr != '\0'))
+ return 0;
+ output->addr.ipv4Addr[i] = (unsigned char)d;
+ n = endptr + 1;
+ }
+ return 1;
+}
+
+
+static int
+virNWFilterRuleDetailsParse(virConnectPtr conn ATTRIBUTE_UNUSED,
+ xmlNodePtr node,
+ virNWFilterRuleDefPtr nwf,
+ const virXMLAttr2Struct *att)
+{
+ int rc = 0;
+ int idx = 0;
+ char *prop;
+ int found = 0;
+ enum attrDatatype datatype, att_datatypes;
+ enum virNWFilterEntryItemFlags *flags ,match_flag = 0, flags_set =
0;
+ nwItemDesc *item;
+ int int_val;
+ void *data_ptr, *storage_ptr;
+ valueValidator validator;
+ char *match = virXMLPropString(node, "match");
+ nwIPAddress ipaddr;
+
+ if (match && STREQ(match, "no"))
+ match_flag = NWFILTER_ENTRY_ITEM_FLAG_IS_NEG;
+ VIR_FREE(match);
+ match = NULL;
+
+ while (att[idx].name != NULL && rc == 0) {
+ prop = virXMLPropString(node, att[idx].name);
+
+ item = (nwItemDesc *)((char *)nwf + att[idx].dataIdx);
+ flags = &item->flags;
+ flags_set = match_flag;
+
+ if (prop) {
+ found = 0;
+
+ validator = NULL;
+
+ if (STRPREFIX(prop, "$")) {
+ flags_set |= NWFILTER_ENTRY_ITEM_FLAG_HAS_VAR;
+ storage_ptr = NULL;
+
+ if (virNWFilterRuleDefAddVar(conn,
+ nwf,
+ item,
+ &prop[1]))
+ rc = -1;
+ found = 1;
+ }
+
+ datatype = 1;
+
+ att_datatypes = att[idx].datatype;
+
+ while (datatype <= DATATYPE_LAST && found == 0 && rc == 0)
{
+ if ((att_datatypes & datatype)) {
+
+ att_datatypes ^= datatype;
+
+ validator = att[idx].validator;
+
+ switch (datatype) {
+
+ case DATATYPE_UINT8:
+ storage_ptr = &item->u.u8;
+ if (sscanf(prop, "%d", &int_val) == 1) {
+ if (int_val >= 0 && int_val <= 0xff) {
+ if (!validator)
+ *(uint8_t *)storage_ptr =
int_val;
+ found = 1;
+ data_ptr = &int_val;
+ } else
+ rc = -1;
+ } else
+ rc = -1;
+ break;
+
+ case DATATYPE_UINT16:
+ storage_ptr = &item->u.u16;
+ if (sscanf(prop, "%d", &int_val) == 1) {
+ if (int_val >= 0 && int_val <= 0xffff)
{
+ if (!validator)
+ *(uint16_t *)storage_ptr =
int_val;
+ found = 1;
+ data_ptr = &int_val;
+ } else
+ rc = -1;
+ } else
+ rc = -1;
+ break;
+
+ case DATATYPE_IPADDR:
+ // parse as dotted IPv4
+ // search for existing parser in libvirt
+ // later: also parse as IPv6
+ storage_ptr = &item->u.ipaddr;
+ if (!virNWIPv4AddressParser(prop,
+ (nwIPAddressPtr)storage_ptr)) {
+ rc = -1;
+ }
+ found = 1;
+ break;
+
+ case DATATYPE_IPMASK:
+ // parse as dotted IPv4
+ // parse as CIDR mask
+ // later: also parse as IPv6
+ storage_ptr = &item->u.u8;
+ if (!virNWIPv4AddressParser(prop, &ipaddr))
{
+ if (sscanf(prop, "%d", &int_val) == 1)
{
+ if (int_val >= 0 && int_val <= 32)
{
+ if (!validator)
+ *(uint8_t *)storage_ptr =
+ (uint8_t)int_val;
+ found = 1;
+ data_ptr = &int_val;
+ } else
+ rc = -1;
+ } else
+ rc = -1;
+ } else {
+ if (checkIPv4Mask(datatype,
+ ipaddr.addr.ipv4Addr,
nwf))
+ *(uint8_t *)storage_ptr =
+
getMaskNumBits(ipaddr.addr.ipv4Addr,
+
sizeof(ipaddr.addr.ipv4Addr));
+ else
+ rc = -1;
+ found = 1;
+ }
+ break;
+
+ case DATATYPE_MACADDR:
+ storage_ptr = &item->u.macaddr;
+ if (!virNWMACAddressParser(prop,
+ (nwMACAddressPtr)storage_ptr))
{
+ rc = -1;
+ }
+ found = 1;
+ break;
+
+ case DATATYPE_MACMASK:
+ validator = checkMACMask;
+ storage_ptr = &item->u.macaddr;
+ if (!virNWMACAddressParser(prop,
+ (nwMACAddressPtr)storage_ptr))
{
+ rc = -1;
+ }
+ data_ptr = storage_ptr;
+ found = 1;
+ break;
+
+ case DATATYPE_STRING:
+ if (!validator) {
+ // not supported
+ rc = -1;
+ break;
+ }
+ data_ptr = prop;
+ found = 1;
+ break;
+
+ case DATATYPE_LAST:
+ default:
+ break;
+ }
+ }
+
+ if (rc != 0 && att_datatypes != 0) {
+ rc = 0;
+ found = 0;
+ }
+
+ datatype <<= 1;
+ } /* while */
+
+ if (found == 1 && rc == 0) {
+ *flags = NWFILTER_ENTRY_ITEM_FLAG_EXISTS | flags_set;
+ item->datatype = datatype >> 1;
+ if (validator) {
+ if (!validator(datatype >> 1, data_ptr, nwf)) {
+ rc = -1;
+ *flags = 0;
+ }
+ }
+ }
+
+ if (!found || rc) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("%s has illegal value %s"),
+ att[idx].name, prop);
+ rc = -1;
+ }
+ VIR_FREE(prop);
+ }
+ idx++;
+ }
+
+ return rc;
+}
+
+
+/**
+ * virNWFilterHashTablePut:
+ * @table: Pointer to a virNWFilterHashTable
+ * @name: name of the key to enter
+ * @val: The value associated with the key
+ * @freeName: Whether the name must be freed on table destruction
+ *
+ * Returns 0 on success, 1 on failure.
+ *
+ * Put an entry into the hashmap replacing and freeing an existing
entry
+ * if one existed.
+ */
+int
+virNWFilterHashTablePut(virNWFilterHashTablePtr table,
+ const char *name,
+ char *val,
+ int copyName)
+{
+ if (!virHashLookup(table->hashTable, name)) {
+ if (copyName) {
+ name = strdup(name);
+ if (!name)
+ return 1;
+
+ if (VIR_REALLOC_N(table->names, table->nNames + 1) < 0) {
+ VIR_FREE(name);
+ return 1;
+ }
+ table->names[table->nNames++] = (char *)name;
+ }
+
+ if (virHashAddEntry(table->hashTable, name, val) != 0) {
+ if (copyName) {
+ VIR_FREE(name);
+ table->nNames--;
+ }
+ return 1;
+ }
+ } else {
+ if (virHashUpdateEntry(table->hashTable, name, val,
hashDealloc) != 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+/**
+ * virNWFilterHashTableFree:
+ * @table: Pointer to virNWFilterHashTable
+ *
+ * Free a hashtable de-allocating memory for all its entries.
+ *
+ * All hash tables within the NWFilter driver must use this
+ * function to deallocate and free their content.
+ */
+void
+virNWFilterHashTableFree(virNWFilterHashTablePtr table)
+{
+ int i;
+ if (!table)
+ return;
+ virHashFree(table->hashTable, hashDealloc);
+
+ for (i = 0; i < table->nNames; i++)
+ VIR_FREE(table->names[i]);
+ VIR_FREE(table->names);
+ VIR_FREE(table);
+}
+
+
+virNWFilterHashTablePtr
+virNWFilterHashTableCreate(int n) {
+ virNWFilterHashTablePtr ret;
+
+ if (VIR_ALLOC(ret) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+ ret->hashTable = virHashCreate(n);
+ if (!ret->hashTable) {
+ virReportOOMError();
+ VIR_FREE(ret);
+ return NULL;
+ }
+ return ret;
+}
+
+
+int
+virNWFilterHashTableRemoveEntry(virNWFilterHashTablePtr ht,
+ const char *entry)
+{
+ int i;
+ int rc = virHashRemoveEntry(ht->hashTable, entry, hashDealloc);
+
+ if (rc == 0) {
+ for (i = 0; i < ht->nNames; i++) {
+ if (STREQ(ht->names[i], entry)) {
+ VIR_FREE(ht->names[i]);
+ ht->names[i] = ht->names[--ht->nNames];
+ ht->names[ht->nNames] = NULL;
+ break;
+ }
+ }
+ }
+ return rc;
+}
+
+
+struct addToTableStruct {
+ virNWFilterHashTablePtr target;
+ int errOccurred;
+ virConnectPtr conn;
+};
+
+
+static void
+addToTable(void *payload, const char *name, void *data)
+{
+ struct addToTableStruct *atts = (struct addToTableStruct *)data;
+ char *val;
+
+ if (atts->errOccurred)
+ return;
+
+ val = strdup((char *)payload);
+ if (!val) {
+ virReportOOMError();
+ atts->errOccurred = 1;
+ return;
+ }
+
+ if (virNWFilterHashTablePut(atts->target, name, val, 1) != 0) {
+ virNWFilterReportError(atts->conn, VIR_ERR_INTERNAL_ERROR,
+ _("Could not put variable '%s' into
hashmap"),
+ name);
+ atts->errOccurred = 1;
+ VIR_FREE(val);
+ }
+}
+
+
+int
+virNWFilterHashTablePutAll(virConnectPtr conn,
+ virNWFilterHashTablePtr src,
+ virNWFilterHashTablePtr dest)
+{
+ struct addToTableStruct atts = {
+ .target = dest,
+ .errOccurred = 0,
+ .conn = conn,
+ };
+
+ virHashForEach(src->hashTable, addToTable, &atts);
+ if (atts.errOccurred)
+ goto err_exit;
+
+ return 0;
+
+err_exit:
+ return 1;
+}
+
+
+virNWFilterHashTablePtr
+virNWFilterParseParamAttributes(xmlNodePtr cur)
+{
+ char *nam, *val;
+
+ virNWFilterHashTablePtr table = virNWFilterHashTableCreate(0);
+ if (!table) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ cur = cur->children;
+
+ while (cur != NULL) {
+ if (cur->type == XML_ELEMENT_NODE) {
+ if (xmlStrEqual(cur->name, BAD_CAST "parameter")) {
+ nam = virXMLPropString(cur, "name");
+ val = virXMLPropString(cur, "value");
+ if (nam != NULL && val != NULL) {
+ if (regexec(®ex_nam, nam, 0, NULL, 0) != 0)
+ goto skip_entry;
+ if (regexec(®ex_val, val, 0, NULL, 0) != 0)
+ goto skip_entry;
+ if (virNWFilterHashTablePut(table, nam, val, 1)) {
+ VIR_FREE(nam);
+ VIR_FREE(val);
+ virNWFilterHashTableFree(table);
+ return NULL;
+ }
+ val = NULL;
+ }
+skip_entry:
+ VIR_FREE(nam);
+ VIR_FREE(val);
+ }
+ }
+ cur = cur->next;
+ }
+ return table;
+}
+
+
+struct formatterParam {
+ virBufferPtr buf;
+ const char *indent;
+};
+
+
+static void
+_formatParameterAttrs(void *payload, const char *name, void *data)
+{
+ struct formatterParam *fp = (struct formatterParam *)data;
+
+ virBufferVSprintf(fp->buf, "%s<parameter name='%s' value='%s'/>\n",
+ fp->indent,
+ name,
+ (char *)payload);
+}
+
+
+char *
+virNWFilterFormatParamAttributes(virNWFilterHashTablePtr table,
+ const char *indent)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ struct formatterParam fp = {
+ .buf = &buf,
+ .indent = indent,
+ };
+
+ virHashForEach(table->hashTable, _formatParameterAttrs, &fp);
+
+ if (virBufferError(&buf)) {
+ virReportOOMError();
+ virBufferFreeAndReset(&buf);
+ return NULL;
+ }
+
+ return virBufferContentAndReset(&buf);
+}
+
+
+static virNWFilterIncludeDefPtr
+virNWFilterIncludeParse(virConnectPtr conn,
+ xmlNodePtr cur)
+{
+ virNWFilterIncludeDefPtr ret;
+
+ if (VIR_ALLOC(ret) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ ret->filterref = virXMLPropString(cur, "filter");
+ if (!ret->filterref) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s",
+ _("rule node requires action
attribute"));
+ goto err_exit;
+ }
+
+ ret->params = virNWFilterParseParamAttributes(cur);
+ if (!ret->params)
+ goto err_exit;
+
+cleanup:
+ return ret;
+
+err_exit:
+ virNWFilterIncludeDefFree(ret);
+ ret = NULL;
+ goto cleanup;
+}
+
+
+static void
+virNWFilterRuleDefFixup(virNWFilterRuleDefPtr rule)
+{
+#define COPY_NEG_SIGN(A, B) \
+ (A).flags = ((A).flags & ~NWFILTER_ENTRY_ITEM_FLAG_IS_NEG) | \
+ ((B).flags & NWFILTER_ENTRY_ITEM_FLAG_IS_NEG);
+
+ switch (rule->prtclType) {
+ case VIR_NWFILTER_RULE_PROTOCOL_MAC:
+ COPY_NEG_SIGN(rule->p.ethHdrFilter.dataSrcMACMask,
+ rule->p.ethHdrFilter.dataSrcMACAddr);
+ COPY_NEG_SIGN(rule->p.ethHdrFilter.dataDstMACMask,
+ rule->p.ethHdrFilter.dataDstMACAddr);
+ break;
+
+ case VIR_NWFILTER_RULE_PROTOCOL_IP:
+ COPY_NEG_SIGN(rule->p.ipHdrFilter.ipHdr.dataSrcMask,
+ rule->p.ipHdrFilter.ipHdr.dataSrcAddr);
+ COPY_NEG_SIGN(rule->p.ipHdrFilter.ipHdr.dataDstMask,
+ rule->p.ipHdrFilter.ipHdr.dataDstAddr);
+ break;
+
+ case VIR_NWFILTER_RULE_PROTOCOL_ARP:
+ case VIR_NWFILTER_RULE_PROTOCOL_NONE:
+ break;
+ }
+
+#undef COPY_NEG_SIGN
+}
+
+
+static virNWFilterRuleDefPtr
+virNWFilterRuleParse(virConnectPtr conn,
+ xmlNodePtr node)
+{
+ char *action;
+ char *direction;
+ char *prio;
+ int found;
+ int found_i;
+ unsigned int priority;
+
+ xmlNodePtr cur;
+ virNWFilterRuleDefPtr ret;
+
+ if (VIR_ALLOC(ret) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ action = virXMLPropString(node, "action");
+ direction = virXMLPropString(node, "direction");
+ prio = virXMLPropString(node, "priority");
+
+ if (!action) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s",
+ _("rule node requires action
attribute"));
+ goto err_exit;
+ }
+
+ if ((ret->action = virNWFilterRuleActionTypeFromString(action)) <
0) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s",
+ _("unknown rule action attribute
value"));
+ goto err_exit;
+ }
+
+ if (!direction) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s",
+ _("rule node requires direction
attribute"));
+ goto err_exit;
+ }
+
+ if ((ret->tt = virNWFilterRuleDirectionTypeFromString(direction)) <
0) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s",
+ _("unknown rule direction attribute
value"));
+ goto err_exit;
+ }
+
+ ret->priority = MAX_RULE_PRIORITY / 2;
+
+ if (prio) {
+ if (sscanf(prio, "%d", (int *)&priority) == 1) {
+ if ((int)priority >= 0 && priority <= MAX_RULE_PRIORITY)
+ ret->priority = priority;
+ }
+ }
+
+ cur = node->children;
+
+ found = 0;
+
+ while (cur != NULL) {
+ if (cur->type == XML_ELEMENT_NODE) {
+ int i = 0;
+ while (1) {
+ if (found)
+ i = found_i;
+
+ if (xmlStrEqual(cur->name, BAD_CAST virAttr[i].id)) {
+
+ found_i = i;
+ found = 1;
+ ret->prtclType = virAttr[i].prtclType;
+
+ if (virNWFilterRuleDetailsParse(conn,
+ cur,
+ ret,
+ virAttr[i].att) <
0) {
+ /* we ignore malformed rules
+ goto err_exit;
+ */
+ }
+ break;
+ }
+ if (!found) {
+ i++;
+ if (!virAttr[i].id)
+ break;
+ } else
+ break;
+ }
+ }
+
+ cur = cur->next;
+ }
+
+ virNWFilterRuleDefFixup(ret);
+
+cleanup:
+ VIR_FREE(prio);
+ VIR_FREE(action);
+ VIR_FREE(direction);
+
+ return ret;
+
+err_exit:
+ virNWFilterRuleDefFree(ret);
+ ret = NULL;
+ goto cleanup;
+}
+
+
+static virNWFilterDefPtr
+virNWFilterDefParseXML(virConnectPtr conn,
+ xmlXPathContextPtr ctxt) {
+ virNWFilterDefPtr ret;
+ xmlNodePtr curr = ctxt->node;
+ char *uuid = NULL;
+ char *chain = NULL;
+ virNWFilterEntryPtr entry;
+
+ if (VIR_ALLOC(ret) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ ret->name = virXPathString("string(./@name)", ctxt);
+ if (!ret->name) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("filter has no name"));
+ goto cleanup;
+ }
+
+ ret->chainsuffix = VIR_NWFILTER_CHAINSUFFIX_ROOT;
+ chain = virXPathString("string(./@chain)", ctxt);
+ if (chain) {
+ if ((ret->chainsuffix =
+ virNWFilterChainSuffixTypeFromString(chain)) < 0) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown chain suffix '%s'"),
chain);
+ goto cleanup;
+ }
+ }
+
+ uuid = virXPathString("string(./uuid)", ctxt);
+ if (uuid == NULL) {
+ if (virUUIDGenerate(ret->uuid) < 0) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("unable to generate uuid"));
+ goto cleanup;
+ }
+ } else {
+ if (virUUIDParse(uuid, ret->uuid) < 0) {
+ virNWFilterReportError(conn, VIR_ERR_XML_ERROR,
+ "%s", _("malformed uuid element"));
+ goto cleanup;
+ }
+ VIR_FREE(uuid);
+ }
+
+ curr = curr->children;
+
+ while (curr != NULL) {
+ if (curr->type == XML_ELEMENT_NODE) {
+ if (VIR_ALLOC(entry) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ /* ignore malformed rule and include elements */
+ if (xmlStrEqual(curr->name, BAD_CAST "rule"))
+ entry->rule = virNWFilterRuleParse(conn, curr);
+ else if (xmlStrEqual(curr->name, BAD_CAST "filterref"))
+ entry->include = virNWFilterIncludeParse(conn, curr);
+
+ if (entry->rule || entry->include) {
+ if (VIR_REALLOC_N(ret->filterEntries, ret->nentries+1)
< 0) {
+ VIR_FREE(entry);
+ virReportOOMError();
+ goto cleanup;
+ }
+ ret->filterEntries[ret->nentries++] = entry;
+ } else
+ VIR_FREE(entry);
+ }
+ curr = curr->next;
+ }
+
+ VIR_FREE(chain);
+
+ return ret;
+
+ cleanup:
+ VIR_FREE(chain);
+ VIR_FREE(uuid);
+ return NULL;
+}
+
+
+/* Called from SAX on parsing errors in the XML. */
+static void
+catchXMLError (void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
+{
+ xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+
+ if (ctxt) {
+ virConnectPtr conn = ctxt->_private;
+
+ if (conn &&
+ conn->err.code == VIR_ERR_NONE &&
+ ctxt->lastError.level == XML_ERR_FATAL &&
+ ctxt->lastError.message != NULL) {
+ virNWFilterReportError(conn, VIR_ERR_XML_DETAIL,
+ _("at line %d: %s"),
+ ctxt->lastError.line,
+ ctxt->lastError.message);
+ }
+ }
+}
+
+
+virNWFilterDefPtr
+virNWFilterDefParseNode(virConnectPtr conn,
+ xmlDocPtr xml,
+ xmlNodePtr root) {
+ xmlXPathContextPtr ctxt = NULL;
+ virNWFilterDefPtr def = NULL;
+
+ if (STRNEQ((const char *)root->name, "filter")) {
+ virNWFilterReportError(conn, VIR_ERR_XML_ERROR,
+ "%s",
+ _("unknown root element for nw filter
pool"));
+ goto cleanup;
+ }
+
+ ctxt = xmlXPathNewContext(xml);
+ if (ctxt == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ ctxt->node = root;
+ def = virNWFilterDefParseXML(conn, ctxt);
+
+cleanup:
+ xmlXPathFreeContext(ctxt);
+ return def;
+}
+
+
+static virNWFilterDefPtr
+virNWFilterDefParse(virConnectPtr conn,
+ const char *xmlStr,
+ const char *filename) {
+ virNWFilterDefPtr ret = NULL;
+ xmlParserCtxtPtr pctxt;
+ xmlDocPtr xml = NULL;
+ xmlNodePtr node = NULL;
+
+ /* Set up a parser context so we can catch the details of XML
errors. */
+ pctxt = xmlNewParserCtxt ();
+ if (!pctxt || !pctxt->sax)
+ goto cleanup;
+ pctxt->sax->error = catchXMLError;
+ pctxt->_private = conn;
+
+ if (conn) virResetError (&conn->err);
+ if (filename) {
+ xml = xmlCtxtReadFile (pctxt, filename, NULL,
+ XML_PARSE_NOENT | XML_PARSE_NONET |
+ XML_PARSE_NOWARNING);
+ } else {
+ xml = xmlCtxtReadDoc (pctxt, BAD_CAST xmlStr,
+ "nwfilter.xml", NULL,
+ XML_PARSE_NOENT | XML_PARSE_NONET |
+ XML_PARSE_NOWARNING);
+ }
+
+ if (!xml) {
+ if (conn && conn->err.code == VIR_ERR_NONE)
+ virNWFilterReportError(conn, VIR_ERR_XML_ERROR,
+ "%s",_("failed to parse xml
document"));
+ goto cleanup;
+ }
+
+ node = xmlDocGetRootElement(xml);
+ if (node == NULL) {
+ virNWFilterReportError(conn, VIR_ERR_XML_ERROR,
+ "%s", _("missing root element"));
+ goto cleanup;
+ }
+
+ ret = virNWFilterDefParseNode(conn, xml, node);
+
+ xmlFreeParserCtxt (pctxt);
+ xmlFreeDoc(xml);
+
+ return ret;
+
+ cleanup:
+ xmlFreeParserCtxt (pctxt);
+ xmlFreeDoc(xml);
+ return NULL;
+}
+
+
+virNWFilterDefPtr
+virNWFilterDefParseString(virConnectPtr conn,
+ const char *xmlStr)
+{
+ return virNWFilterDefParse(conn, xmlStr, NULL);
+}
+
+
+virNWFilterDefPtr
+virNWFilterDefParseFile(virConnectPtr conn,
+ const char *filename)
+{
+ return virNWFilterDefParse(conn, NULL, filename);
+}
+
+
+virNWFilterPoolObjPtr
+virNWFilterPoolObjFindByUUID(virNWFilterPoolObjListPtr pools,
+ const unsigned char *uuid)
+{
+ unsigned int i;
+
+ for (i = 0 ; i < pools->count ; i++) {
+ virNWFilterPoolObjLock(pools->objs[i]);
+ if (!memcmp(pools->objs[i]->def->uuid, uuid, VIR_UUID_BUFLEN))
+ return pools->objs[i];
+ virNWFilterPoolObjUnlock(pools->objs[i]);
+ }
+
+ return NULL;
+}
+
+
+virNWFilterPoolObjPtr
+virNWFilterPoolObjFindByName(virNWFilterPoolObjListPtr pools,
+ const char *name)
+{
+ unsigned int i;
+
+ for (i = 0 ; i < pools->count ; i++) {
+ virNWFilterPoolObjLock(pools->objs[i]);
+ if (STREQ(pools->objs[i]->def->name, name))
+ return pools->objs[i];
+ virNWFilterPoolObjUnlock(pools->objs[i]);
+ }
+
+ return NULL;
+}
+
+
+int virNWFilterSaveXML(virConnectPtr conn,
+ const char *configDir,
+ virNWFilterDefPtr def,
+ const char *xml)
+{
+ char *configFile = NULL;
+ int fd = -1, ret = -1;
+ size_t towrite;
+ int err;
+
+ if ((configFile = virNWFilterConfigFile(conn, configDir,
def->name)) == NULL)
+ goto cleanup;
+
+ if ((err = virFileMakePath(configDir))) {
+ virReportSystemError(err,
+ _("cannot create config directory '%s'"),
+ configDir);
+ goto cleanup;
+ }
+
+ if ((fd = open(configFile,
+ O_WRONLY | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR )) < 0) {
+ virReportSystemError(errno,
+ _("cannot create config file '%s'"),
+ configFile);
+ goto cleanup;
+ }
+
+ towrite = strlen(xml);
+ if (safewrite(fd, xml, towrite) < 0) {
+ virReportSystemError(errno,
+ _("cannot write config file '%s'"),
+ configFile);
+ goto cleanup;
+ }
+
+ if (close(fd) < 0) {
+ virReportSystemError(errno,
+ _("cannot save config file '%s'"),
+ configFile);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ if (fd != -1)
+ close(fd);
+
+ VIR_FREE(configFile);
+
+ return ret;
+}
+
+
+int virNWFilterSaveConfig(virConnectPtr conn,
+ const char *configDir,
+ virNWFilterDefPtr def)
+{
+ int ret = -1;
+ char *xml;
+
+ if (!(xml = virNWFilterDefFormat(conn, def)))
+ goto cleanup;
+
+ if (virNWFilterSaveXML(conn, configDir, def, xml))
+ goto cleanup;
+
+ ret = 0;
+cleanup:
+ VIR_FREE(xml);
+ return ret;
+}
+
+
+static int
+_virNWFilterDefLoopDetect(virConnectPtr conn,
+ virNWFilterPoolObjListPtr pools,
+ virNWFilterDefPtr def,
+ const char *filtername)
+{
+ int rc = 0;
+ int i;
+ virNWFilterEntryPtr entry;
+ virNWFilterPoolObjPtr obj;
+
+ if (!def)
+ return 0;
+
+ for (i = 0; i < def->nentries; i++) {
+ entry = def->filterEntries[i];
+ if (entry->include) {
+
+ if (STREQ(filtername, entry->include->filterref)) {
+ rc = 1;
+ break;
+ }
+
+ obj = virNWFilterPoolObjFindByName(pools,
+
entry->include->filterref);
+ if (obj) {
+ rc = _virNWFilterDefLoopDetect(conn,
+ pools,
+ obj->def, filtername);
+
+ virNWFilterPoolObjUnlock(obj);
+ if (rc)
+ break;
+ }
+ }
+ }
+
+ return rc;
+}
+
+
+/*
+ * virNWFilterDefLoopDetect:
+ * @conn: pointer to virConnect object
+ * @pools : the pools to search
+ * @def : the filter definiton that may add a loop and is to be tested
+ *
+ * Detect a loop introduced through the filters being able to
+ * reference each other.
+ *
+ * Returns 0 in case no loop was detected, 1 otherwise.
+ */
+static int
+virNWFilterDefLoopDetect(virConnectPtr conn,
+ virNWFilterPoolObjListPtr pools,
+ virNWFilterDefPtr def)
+{
+ return _virNWFilterDefLoopDetect(conn, pools, def, def->name);
+}
+
+int nCallbackDriver;
+#define MAX_CALLBACK_DRIVER 10
+static virNWFilterCallbackDriverPtr
callbackDrvArray[MAX_CALLBACK_DRIVER];
+
+void
+virNWFilterRegisterCallbackDriver(virNWFilterCallbackDriverPtr cbd)
+{
+ if (nCallbackDriver < MAX_CALLBACK_DRIVER) {
+ callbackDrvArray[nCallbackDriver++] = cbd;
+ }
+}
+
+
+struct cbStruct {
+ virConnectPtr conn;
+ int doUpdate;
+ int err;
+};
+
+static void
+virNWFilterDomainFWUpdateCB(void *payload,
+ const char *name 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)) {
+ if (cb->doUpdate)
+ cb->err =
virNWFilterUpdateInstantiateFilter(cb->conn,
+ net);
+ else
+ cb->err = virNWFilterRollbackUpdateFilter(cb->conn,
net);
+ if (cb->err)
+ break;
+ }
+ }
+ }
+
+ virDomainObjUnlock(obj);
+}
+
+
+static int
+virNWFilterTriggerVMFilterRebuild(virConnectPtr conn)
+{
+ int i;
+ int err;
+ struct cbStruct cb = {
+ .conn = conn,
+ .err = 0,
+ .doUpdate = 1,
+ };
+
+ for (i = 0; i < nCallbackDriver; i++) {
+ callbackDrvArray[i]->vmFilterRebuild(conn,
+
virNWFilterDomainFWUpdateCB,
+ &cb);
+ }
+
+ err = cb.err;
+
+ if (err) {
+ cb.doUpdate = 0; // rollback
+ cb.err = 0;
+
+ for (i = 0; i < nCallbackDriver; i++)
+ callbackDrvArray[i]->vmFilterRebuild(conn,
+
virNWFilterDomainFWUpdateCB,
+ &cb);
+ }
+
+ return err;
+}
+
+
+int
+virNWFilterTestUnassignDef(virConnectPtr conn,
+ virNWFilterPoolObjPtr pool)
+{
+ int rc = 0;
+
+ virNWFilterLockFilterUpdates();
+
+ pool->wantRemoved = 1;
+ // trigger the update on VMs referencing the filter
+ if (virNWFilterTriggerVMFilterRebuild(conn))
+ rc = 1;
+
+ pool->wantRemoved = 0;
+ virNWFilterUnlockFilterUpdates();
+ return rc;
+}
+
+
+virNWFilterPoolObjPtr
+virNWFilterPoolObjAssignDef(virConnectPtr conn,
+ virNWFilterPoolObjListPtr pools,
+ virNWFilterDefPtr def)
+{
+ virNWFilterPoolObjPtr pool;
+
+ if (virNWFilterDefLoopDetect(conn, pools, def)) {
+ virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
+ "%s", _("filter would introduce loop"));
+ return NULL;
+ }
+
+ if ((pool = virNWFilterPoolObjFindByName(pools, def->name))) {
+ virNWFilterLockFilterUpdates();
+ pool->newDef = def;
+ // trigger the update on VMs referencing the filter
+ if (virNWFilterTriggerVMFilterRebuild(conn)) {
+ pool->newDef = NULL;
+ virNWFilterUnlockFilterUpdates();
+ virNWFilterPoolObjUnlock(pool);
+ return NULL;
+ }
+
+ virNWFilterDefFree(pool->def);
+ pool->def = def;
+ pool->newDef = NULL;
+ virNWFilterUnlockFilterUpdates();
+ return pool;
+ }
+
+ if (VIR_ALLOC(pool) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ if (virRecursiveMutexInit(&pool->lock) < 0) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot initialize mutex"));
+ VIR_FREE(pool);
+ return NULL;
+ }
+ virNWFilterPoolObjLock(pool);
+ pool->active = 0;
+ pool->def = def;
+
+ if (VIR_REALLOC_N(pools->objs, pools->count+1) < 0) {
+ pool->def = NULL;
+ virNWFilterPoolObjUnlock(pool);
+ virNWFilterPoolObjFree(pool);
+ virReportOOMError();
+ return NULL;
+ }
+ pools->objs[pools->count++] = pool;
+
+ return pool;
+}
+
+
+static virNWFilterPoolObjPtr
+virNWFilterPoolObjLoad(virConnectPtr conn,
+ virNWFilterPoolObjListPtr pools,
+ const char *file,
+ const char *path)
+{
+ virNWFilterDefPtr def;
+ virNWFilterPoolObjPtr pool;
+
+ if (!(def = virNWFilterDefParseFile(conn, path))) {
+ return NULL;
+ }
+
+ if (!virFileMatchesNameSuffix(file, def->name, ".xml")) {
+ virNWFilterError(conn, VIR_ERR_INVALID_NWFILTER,
+ "NWFilter pool config filename '%s' does not match pool
name '%s'",
+ path, def->name);
+ virNWFilterDefFree(def);
+ return NULL;
+ }
+
+ if (!(pool = virNWFilterPoolObjAssignDef(conn, pools, def))) {
+ virNWFilterDefFree(def);
+ return NULL;
+ }
+
+ pool->configFile = strdup(path);
+ if (pool->configFile == NULL) {
+ virReportOOMError();
+ virNWFilterDefFree(def);
+ return NULL;
+ }
+
+ return pool;
+}
+
+
+int
+virNWFilterPoolLoadAllConfigs(virConnectPtr conn,
+ virNWFilterPoolObjListPtr pools,
+ const char *configDir)
+{
+ DIR *dir;
+ struct dirent *entry;
+
+ if (!(dir = opendir(configDir))) {
+ if (errno == ENOENT) {
+ return 0;
+ }
+ virReportSystemError(errno, _("Failed to open dir '%s'"),
+ configDir);
+ return -1;
+ }
+
+ while ((entry = readdir(dir))) {
+ char path[PATH_MAX];
+ virNWFilterPoolObjPtr pool;
+
+ if (entry->d_name[0] == '.')
+ continue;
+
+ if (!virFileHasSuffix(entry->d_name, ".xml"))
+ continue;
+
+ if (virFileBuildPath(configDir, entry->d_name,
+ NULL, path, PATH_MAX) < 0) {
+ virNWFilterError(conn, VIR_ERR_INTERNAL_ERROR,
+ "Config filename '%s/%s' is too long",
+ configDir, entry->d_name);
+ continue;
+ }
+
+ pool = virNWFilterPoolObjLoad(conn, pools, entry->d_name,
path);
+ if (pool)
+ virNWFilterPoolObjUnlock(pool);
+ }
+
+ closedir(dir);
+
+ return 0;
+}
+
+
+int
+virNWFilterPoolObjSaveDef(virConnectPtr conn,
+ virNWFilterDriverStatePtr driver,
+ virNWFilterPoolObjPtr pool,
+ virNWFilterDefPtr def)
+{
+ char *xml;
+ int fd = -1, ret = -1;
+ ssize_t towrite;
+
+ if (!pool->configFile) {
+ int err;
+ char path[PATH_MAX];
+
+ if ((err = virFileMakePath(driver->configDir))) {
+ virReportSystemError(err,
+ _("cannot create config directory %
s"),
+ driver->configDir);
+ return -1;
+ }
+
+ if (virFileBuildPath(driver->configDir, def->name, ".xml",
+ path, sizeof(path)) < 0) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot construct config file
path"));
+ return -1;
+ }
+ if (!(pool->configFile = strdup(path))) {
+ virReportOOMError();
+ return -1;
+ }
+ }
+
+ if (!(xml = virNWFilterDefFormat(conn, def))) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("failed to generate XML"));
+ return -1;
+ }
+
+ if ((fd = open(pool->configFile,
+ O_WRONLY | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR )) < 0) {
+ virReportSystemError(errno,
+ _("cannot create config file %s"),
+ pool->configFile);
+ goto cleanup;
+ }
+
+ towrite = strlen(xml);
+ if (safewrite(fd, xml, towrite) != towrite) {
+ virReportSystemError(errno,
+ _("cannot write config file %s"),
+ pool->configFile);
+ goto cleanup;
+ }
+
+ if (close(fd) < 0) {
+ virReportSystemError(errno,
+ _("cannot save config file %s"),
+ pool->configFile);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ if (fd != -1)
+ close(fd);
+
+ VIR_FREE(xml);
+
+ return ret;
+}
+
+
+int
+virNWFilterPoolObjDeleteDef(virConnectPtr conn,
+ virNWFilterPoolObjPtr pool)
+{
+ if (!pool->configFile) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("no config file for %s"),
pool->def->name);
+ return -1;
+ }
+
+ if (unlink(pool->configFile) < 0) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot remove config for %s"),
+ pool->def->name);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static void
+virNWIPAddressFormat(virBufferPtr buf, nwIPAddressPtr ipaddr)
+{
+ if (!ipaddr->isIPv6) {
+ virBufferVSprintf(buf, "%d.%d.%d.%d",
+ ipaddr->addr.ipv4Addr[0],
+ ipaddr->addr.ipv4Addr[1],
+ ipaddr->addr.ipv4Addr[2],
+ ipaddr->addr.ipv4Addr[3]);
+ } else {
+ virBufferAddLit(buf, "MISSING IPv6 ADDRESS FORMATTER");
+ }
+}
+
+
+static void
+virNWFilterRuleDefDetailsFormat(virConnectPtr conn,
+ virBufferPtr buf,
+ const char *type,
+ const virXMLAttr2Struct *att,
+ virNWFilterRuleDefPtr def)
+{
+ int i, j;
+ bool typeShown = 0;
+ bool neverShown = 1;
+ enum match {
+ MATCH_NONE = 0,
+ MATCH_YES,
+ MATCH_NO
+ } matchShown = MATCH_NONE;
+ nwItemDesc *item;
+
+ while (att[i].name) {
+ item = (nwItemDesc *)((char *)def + att[i].dataIdx);
+ enum virNWFilterEntryItemFlags flags = item->flags;
+ void *storage_ptr;
+ if ((flags & NWFILTER_ENTRY_ITEM_FLAG_EXISTS)) {
+ if (!typeShown) {
+ virBufferVSprintf(buf, " <%s", type);
+ typeShown = 1;
+ neverShown = 0;
+ }
+
+ if ((flags & NWFILTER_ENTRY_ITEM_FLAG_IS_NEG)) {
+ if (matchShown == MATCH_NONE) {
+ virBufferAddLit(buf, " match='no'");
+ matchShown = MATCH_NO;
+ } else if (matchShown == MATCH_YES) {
+ virBufferAddLit(buf, "/>\n");
+ typeShown = 0;
+ matchShown = MATCH_NONE;
+ continue;
+ }
+ } else {
+ if (matchShown == MATCH_NO) {
+ virBufferAddLit(buf, "/>\n");
+ typeShown = 0;
+ matchShown = MATCH_NONE;
+ continue;
+ }
+ matchShown = MATCH_YES;
+ }
+
+ virBufferVSprintf(buf, " %s='",
+ att[i].name);
+ if (att[i].formatter) {
+ if (!att[i].formatter(buf, def)) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("formatter for %s %s
reported error"),
+ type,
+ att[i].name);
+ goto err_exit;
+ }
+ } else if ((flags & NWFILTER_ENTRY_ITEM_FLAG_HAS_VAR)) {
+ virBufferVSprintf(buf, "$%s", item->var);
+ } else {
+ switch (att[i].datatype) {
+
+ case DATATYPE_IPMASK:
+ // display all masks in CIDR format
+ case DATATYPE_UINT8:
+ storage_ptr = &item->u.u8;
+ virBufferVSprintf(buf, "%d", *(uint8_t
*)storage_ptr);
+ break;
+
+ case DATATYPE_UINT16:
+ storage_ptr = &item->u.u16;
+ virBufferVSprintf(buf, "%d", *(uint16_t
*)storage_ptr);
+ break;
+
+ case DATATYPE_IPADDR:
+ storage_ptr = &item->u.ipaddr;
+ virNWIPAddressFormat(buf,
+ (nwIPAddressPtr)storage_ptr);
+ break;
+
+ case DATATYPE_MACMASK:
+ case DATATYPE_MACADDR:
+ storage_ptr = &item->u.macaddr;
+ for (j = 0; j < 6; j++)
+ virBufferVSprintf(buf, "%02x%s",
+
((nwMACAddressPtr)storage_ptr)->addr[j],
+ (j < 5) ? ":" : "");
+ break;
+
+ case DATATYPE_STRING:
+ default:
+ virBufferVSprintf(buf,
+ "UNSUPPORTED DATATYPE 0x%02x\n",
+ att[i].datatype);
+ }
+ }
+ virBufferAddLit(buf, "'");
+ }
+ i++;
+ }
+ if (typeShown)
+ virBufferAddLit(buf, "/>\n");
+
+ if (neverShown)
+ virBufferVSprintf(buf,
+ " <%s/>\n", type);
+
+err_exit:
+ return;
+}
+
+
+static char *
+virNWFilterRuleDefFormat(virConnectPtr conn,
+ virNWFilterRuleDefPtr def)
+{
+ int i;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ virBuffer buf2 = VIR_BUFFER_INITIALIZER;
+ char *data;
+
+ virBufferVSprintf(&buf, " <rule action='%s' direction='%s'
priority='%d'",
+ virNWFilterRuleActionTypeToString(def->action),
+ virNWFilterRuleDirectionTypeToString(def->tt),
+ def->priority);
+
+ i = 0;
+ while (virAttr[i].id) {
+ if (virAttr[i].prtclType == def->prtclType) {
+ virNWFilterRuleDefDetailsFormat(conn,
+ &buf2,
+ virAttr[i].id,
+ virAttr[i].att,
+ def);
+ break;
+ }
+ i++;
+ }
+
+ if (virBufferError(&buf2))
+ goto no_memory;
+
+ data = virBufferContentAndReset(&buf2);
+
+ if (data) {
+ virBufferAddLit(&buf, ">\n");
+ virBufferVSprintf(&buf, "%s </rule>\n", data);
+ VIR_FREE(data);
+ } else
+ virBufferAddLit(&buf, "/>\n");
+
+ if (virBufferError(&buf))
+ goto no_memory;
+
+ return virBufferContentAndReset(&buf);
+
+no_memory:
+ virReportOOMError();
+ virBufferFreeAndReset(&buf);
+ virBufferFreeAndReset(&buf2);
+
+ return NULL;
+}
+
+
+static char *
+virNWFilterIncludeDefFormat(virNWFilterIncludeDefPtr inc)
+{
+ char *attrs;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ virBufferVSprintf(&buf," <filterref filter='%s'",
+ inc->filterref);
+
+ attrs = virNWFilterFormatParamAttributes(inc->params, " ");
+
+ if (!attrs || strlen(attrs) <= 1)
+ virBufferAddLit(&buf, "/>\n");
+ else
+ virBufferVSprintf(&buf, ">\n%s </filterref>\n", attrs);
+
+ if (virBufferError(&buf)) {
+ virReportOOMError();
+ virBufferFreeAndReset(&buf);
+ return NULL;
+ }
+
+ return virBufferContentAndReset(&buf);
+}
+
+
+static char *
+virNWFilterEntryFormat(virConnectPtr conn,
+ virNWFilterEntryPtr entry)
+{
+ if (entry->rule)
+ return virNWFilterRuleDefFormat(conn, entry->rule);
+ return virNWFilterIncludeDefFormat(entry->include);
+}
+
+
+char *
+virNWFilterDefFormat(virConnectPtr conn,
+ virNWFilterDefPtr def)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ char uuid[VIR_UUID_STRING_BUFLEN];
+ int i;
+ char *xml;
+
+ virBufferVSprintf(&buf, "<filter name='%s' chain='%s'",
+ def->name,
+
virNWFilterChainSuffixTypeToString(def->chainsuffix));
+ virBufferAddLit(&buf, ">\n");
+
+ virUUIDFormat(def->uuid, uuid);
+ virBufferVSprintf(&buf," <uuid>%s</uuid>\n", uuid);
+
+ for (i = 0; i < def->nentries; i++) {
+ xml = virNWFilterEntryFormat(conn, def->filterEntries[i]);
+ if (!xml)
+ goto err_exit;
+ virBufferVSprintf(&buf, "%s", xml);
+ VIR_FREE(xml);
+ }
+
+ virBufferAddLit(&buf, "</filter>\n");
+
+ if (virBufferError(&buf))
+ goto no_memory;
+
+ return virBufferContentAndReset(&buf);
+
+ no_memory:
+ virReportOOMError();
+
+ err_exit:
+ virBufferFreeAndReset(&buf);
+ return NULL;
+}
+
+
+char *virNWFilterConfigFile(virConnectPtr conn ATTRIBUTE_UNUSED,
+ const char *dir,
+ const char *name)
+{
+ char *ret = NULL;
+
+ if (virAsprintf(&ret, "%s/%s.xml", dir, name) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ return ret;
+}
+
+
+int virNWFilterConfLayerInit(void) {
+ if (virMutexInit(&updateMutex))
+ return 1;
+
+ if (regcomp(®ex_nam, "^[a-zA-Z0-9_]+$" , REG_NOSUB|
REG_EXTENDED) != 0)
+ return -1;
+
+ if (regcomp(®ex_val, "^[a-zA-Z0-9_.:]+$", REG_NOSUB|
REG_EXTENDED) != 0) {
+ regfree(®ex_nam);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void virNWFilterConfLayerShutdown(void) {
+ regfree(®ex_nam);
+ regfree(®ex_val);
+}
+
+
+void virNWFilterPoolObjLock(virNWFilterPoolObjPtr obj)
+{
+ virMutexLock(&obj->lock);
+}
+
+void virNWFilterPoolObjUnlock(virNWFilterPoolObjPtr obj)
+{
+ virMutexUnlock(&obj->lock);
+}
Index: libvirt-acl/src/conf/nwfilter_conf.h
===================================================================
--- /dev/null
+++ libvirt-acl/src/conf/nwfilter_conf.h
@@ -0,0 +1,472 @@
+/*
+ * nwfilter_conf.h: network filter XML processing
+ * (derived from storage_conf.h)
+ *
+ * Copyright (C) 2006-2010 Red Hat, Inc.
+ * Copyright (C) 2006-2008 Daniel P. Berrange
+ *
+ * Copyright (C) 2010 IBM Corporation
+ *
+ * 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(a)us.ibm.com>
+ */
+#ifndef NWFILTER_CONF_H
+#define NWFILTER_CONF_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include "internal.h"
+#include "util.h"
+#include "hash.h"
+#include "xml.h"
+
+/**
+ * Chain suffix size is:
+ * max. user define table name length -
+ * sizeof("FO-") -
+ * max. interface name size -
+ * sizeof("-") -
+ * terminating '0' =
+ * 32-3-15-1-1 = 12
+ */
+#define MAX_CHAIN_SUFFIX_SIZE 12
+
+
+enum virNWFilterEntryItemFlags {
+ NWFILTER_ENTRY_ITEM_FLAG_EXISTS = 1 << 0,
+ NWFILTER_ENTRY_ITEM_FLAG_IS_NEG = 1 << 1,
+ NWFILTER_ENTRY_ITEM_FLAG_HAS_VAR = 1 << 2,
+};
+
+
+#define HAS_ENTRY_ITEM(data) \
+ (((data)->flags) & NWFILTER_ENTRY_ITEM_FLAG_EXISTS)
+
+#define ENTRY_GET_NEG_SIGN(data) \
+ ((((data)->flags) & NWFILTER_ENTRY_ITEM_FLAG_IS_NEG) ? "!" : "")
+
+// datatypes appearing in rule attributes
+enum attrDatatype {
+ DATATYPE_UINT16 = (1 << 0),
+ DATATYPE_UINT8 = (1 << 1),
+ DATATYPE_MACADDR = (1 << 2),
+ DATATYPE_MACMASK = (1 << 3),
+ DATATYPE_IPADDR = (1 << 4),
+ DATATYPE_IPMASK = (1 << 5),
+ DATATYPE_STRING = (1 << 6),
+
+ DATATYPE_LAST = (1 << 7),
+};
+
+
+typedef struct _nwMACAddress nwMACAddress;
+typedef nwMACAddress *nwMACAddressPtr;
+struct _nwMACAddress {
+ unsigned char addr[6];
+};
+
+
+typedef struct _nwIPAddress nwIPAddress;
+typedef nwIPAddress *nwIPAddressPtr;
+struct _nwIPAddress {
+ int isIPv6;
+ union {
+ unsigned char ipv4Addr[4];
+ /* unsigned char ipv6Addr[16]; future :-) */
+ } addr;
+};
+
+
+typedef struct _nwItemDesc nwItemDesc;
+typedef nwItemDesc *nwItemDescPtr;
+struct _nwItemDesc {
+ enum virNWFilterEntryItemFlags flags;
+ char *var;
+ enum attrDatatype datatype;
+ union {
+ nwMACAddress macaddr;
+ nwIPAddress ipaddr;
+ uint8_t u8;
+ uint16_t u16;
+ char protocolID[10];
+ } u;
+};
+
+
+typedef struct _ethHdrFilterDef ethHdrFilterDef;
+typedef ethHdrFilterDef *ethHdrFilterDefPtr;
+struct _ethHdrFilterDef {
+ nwItemDesc dataSrcMACAddr;
+ nwItemDesc dataSrcMACMask;
+ nwItemDesc dataDstMACAddr;
+ nwItemDesc dataDstMACMask;
+ nwItemDesc dataProtocolID;
+ nwItemDesc dataPriority;
+ nwItemDesc dataVLANID;
+};
+
+
+typedef struct _arpHdrFilterDef arpHdrFilterDef;
+typedef arpHdrFilterDef *arpHdrFilterDefPtr;
+struct _arpHdrFilterDef {
+ nwItemDesc dataHWType;
+ nwItemDesc dataProtocolType;
+ nwItemDesc dataOpcode;
+ nwItemDesc dataSrcMACAddr;
+ nwItemDesc dataSrcIPAddr;
+ nwItemDesc dataDstMACAddr;
+ nwItemDesc dataDstIPAddr;
+};
+
+
+typedef struct _ipHdrDataDef ipHdrDataDef;
+typedef ipHdrDataDef *ipHdrDataDefPtr;
+struct _ipHdrDataDef {
+ nwItemDesc dataIPVersion;
+ nwItemDesc dataSrcAddr;
+ nwItemDesc dataSrcMask;
+ nwItemDesc dataDstAddr;
+ nwItemDesc dataDstMask;
+ nwItemDesc dataProtocolID;
+};
+
+
+typedef struct _portDataDef portDataDef;
+typedef portDataDef *portDataDefPtr;
+struct _portDataDef {
+ nwItemDesc dataSrcPortStart;
+ nwItemDesc dataSrcPortEnd;
+ nwItemDesc dataDstPortStart;
+ nwItemDesc dataDstPortEnd;
+};
+
+
+typedef struct _ipHdrFilterDef ipHdrFilterDef;
+typedef ipHdrFilterDef *ipHdrFilterDefPtr;
+struct _ipHdrFilterDef {
+ ipHdrDataDef ipHdr;
+ portDataDef portData;
+ nwItemDesc dataDSCP;
+};
+
+
+enum virNWFilterRuleActionType {
+ VIR_NWFILTER_RULE_ACTION_DROP = 0,
+ VIR_NWFILTER_RULE_ACTION_ACCEPT,
+
+ VIR_NWFILTER_RULE_ACTION_LAST,
+};
+
+enum virNWFilterRuleDirectionType {
+ VIR_NWFILTER_RULE_DIRECTION_IN = 0,
+ VIR_NWFILTER_RULE_DIRECTION_OUT,
+ VIR_NWFILTER_RULE_DIRECTION_INOUT,
+
+ VIR_NWFILTER_RULE_DIRECTION_LAST,
+};
+
+enum virNWFilterChainPolicyType {
+ VIR_NWFILTER_CHAIN_POLICY_ACCEPT = 0,
+ VIR_NWFILTER_CHAIN_POLICY_DROP,
+
+ VIR_NWFILTER_CHAIN_POLICY_LAST,
+};
+
+enum virNWFilterRuleProtocolType {
+ VIR_NWFILTER_RULE_PROTOCOL_NONE = 0,
+ VIR_NWFILTER_RULE_PROTOCOL_MAC,
+ VIR_NWFILTER_RULE_PROTOCOL_ARP,
+ VIR_NWFILTER_RULE_PROTOCOL_IP,
+};
+
+enum virNWFilterEbtablesTableType {
+ VIR_NWFILTER_EBTABLES_TABLE_FILTER = 0,
+ VIR_NWFILTER_EBTABLES_TABLE_NAT,
+ VIR_NWFILTER_EBTABLES_TABLE_BROUTE,
+
+ VIR_NWFILTER_EBTABLES_TABLE_LAST,
+};
+
+
+#define MAX_RULE_PRIORITY 1000
+
+
+typedef struct _virNWFilterRuleDef virNWFilterRuleDef;
+typedef virNWFilterRuleDef *virNWFilterRuleDefPtr;
+struct _virNWFilterRuleDef {
+ unsigned int priority;
+ int action; /*enum virNWFilterRuleActionType*/
+ int tt; /*enum virNWFilterRuleDirectionType*/
+ enum virNWFilterRuleProtocolType prtclType;
+ union {
+ ethHdrFilterDef ethHdrFilter;
+ arpHdrFilterDef arpHdrFilter;
+ ipHdrFilterDef ipHdrFilter;
+ } p;
+
+ int nvars;
+ char **vars;
+};
+
+
+typedef struct _virNWFilterHashTable virNWFilterHashTable;
+typedef virNWFilterHashTable *virNWFilterHashTablePtr;
+struct _virNWFilterHashTable {
+ virHashTablePtr hashTable;
+
+ int nNames;
+ char **names;
+};
+
+
+typedef struct _virNWFilterIncludeDef virNWFilterIncludeDef;
+typedef virNWFilterIncludeDef *virNWFilterIncludeDefPtr;
+struct _virNWFilterIncludeDef {
+ char *filterref;
+ virNWFilterHashTablePtr params;
+};
+
+
+typedef struct _virNWFilterEntry virNWFilterEntry;
+typedef virNWFilterEntry *virNWFilterEntryPtr;
+struct _virNWFilterEntry {
+ virNWFilterRuleDef *rule;
+ virNWFilterIncludeDef *include;
+};
+
+enum virNWFilterChainSuffixType {
+ VIR_NWFILTER_CHAINSUFFIX_ROOT = 0,
+ VIR_NWFILTER_CHAINSUFFIX_ARP,
+ VIR_NWFILTER_CHAINSUFFIX_IPv4,
+
+ VIR_NWFILTER_CHAINSUFFIX_LAST,
+};
+
+
+typedef struct _virNWFilterDef virNWFilterDef;
+typedef virNWFilterDef *virNWFilterDefPtr;
+
+struct _virNWFilterDef {
+ char *name;
+ unsigned char uuid[VIR_UUID_BUFLEN];
+
+ int chainsuffix; /*enum virNWFilterChainSuffixType */
+
+ int nentries;
+ virNWFilterEntryPtr *filterEntries;
+};
+
+
+typedef struct _virNWFilterPoolObj virNWFilterPoolObj;
+typedef virNWFilterPoolObj *virNWFilterPoolObjPtr;
+
+struct _virNWFilterPoolObj {
+ virMutex lock;
+
+ char *configFile;
+ int active;
+ int wantRemoved;
+
+ virNWFilterDefPtr def;
+ virNWFilterDefPtr newDef;
+};
+
+
+typedef struct _virNWFilterPoolObjList virNWFilterPoolObjList;
+typedef virNWFilterPoolObjList *virNWFilterPoolObjListPtr;
+struct _virNWFilterPoolObjList {
+ unsigned int count;
+ virNWFilterPoolObjPtr *objs;
+};
+
+
+typedef struct _virNWFilterDriverState virNWFilterDriverState;
+typedef virNWFilterDriverState *virNWFilterDriverStatePtr;
+struct _virNWFilterDriverState {
+ virMutex lock;
+
+ virNWFilterPoolObjList pools;
+
+ char *configDir;
+};
+
+
+typedef struct _virNWFilterTechDriver virNWFilterTechDriver;
+typedef virNWFilterTechDriver *virNWFilterTechDriverPtr;
+
+
+typedef struct _virNWFilterRuleInst virNWFilterRuleInst;
+typedef virNWFilterRuleInst *virNWFilterRuleInstPtr;
+struct _virNWFilterRuleInst {
+ int ndata;
+ void **data;
+ virNWFilterTechDriverPtr techdriver;
+};
+
+
+enum virDomainNetType;
+
+typedef int (*virNWFilterRuleCreateInstance)(virConnectPtr conn,
+ enum virDomainNetType
nettype,
+ virNWFilterDefPtr filter,
+ virNWFilterRuleDefPtr
rule,
+ const char *ifname,
+ virNWFilterHashTablePtr
vars,
+ virNWFilterRuleInstPtr
res);
+
+typedef int (*virNWFilterRuleApplyRules)(virConnectPtr conn,
+ const char *ifname,
+ int nruleInstances,
+ void **_inst);
+
+typedef int (*virNWFilterRuleRemoveRules)(virConnectPtr conn,
+ const char *ifname,
+ int nruleInstances,
+ void **_inst);
+
+typedef int (*virNWFilterRuleAllTeardown)(const char *ifname);
+
+typedef int (*virNWFilterRuleFreeInstanceData)(void * _inst);
+
+typedef int (*virNWFilterRuleDisplayInstanceData)(virConnectPtr conn,
+ void *_inst);
+
+
+struct _virNWFilterTechDriver {
+ const char *name;
+
+ virNWFilterRuleCreateInstance createRuleInstance;
+ virNWFilterRuleApplyRules applyRules;
+ virNWFilterRuleRemoveRules removeRules;
+ virNWFilterRuleAllTeardown allTeardown;
+ virNWFilterRuleFreeInstanceData freeRuleInstance;
+ virNWFilterRuleDisplayInstanceData displayRuleInstance;
+};
+
+
+virNWFilterHashTablePtr virNWFilterParseParamAttributes(xmlNodePtr
cur);
+char * virNWFilterFormatParamAttributes(virNWFilterHashTablePtr table,
+ const char *indent);
+
+virNWFilterHashTablePtr virNWFilterHashTableCreate(int n);
+void virNWFilterHashTableFree(virNWFilterHashTablePtr table);
+int virNWFilterHashTablePut(virNWFilterHashTablePtr table,
+ const char *name,
+ char *val,
+ int freeName);
+int virNWFilterHashTableRemoveEntry(virNWFilterHashTablePtr table,
+ const char *name);
+int virNWFilterHashTablePutAll(virConnectPtr conn,
+ virNWFilterHashTablePtr src,
+ virNWFilterHashTablePtr dest);
+
+void virNWFilterRuleDefFree(virNWFilterRuleDefPtr def);
+
+void virNWFilterDefFree(virNWFilterDefPtr def);
+void virNWFilterPoolObjListFree(virNWFilterPoolObjListPtr pools);
+void virNWFilterPoolObjRemove(virNWFilterPoolObjListPtr pools,
+ virNWFilterPoolObjPtr pool);
+
+void virNWFilterPoolObjFree(virNWFilterPoolObjPtr obj);
+
+virNWFilterPoolObjPtr
+ virNWFilterPoolObjFindByUUID(virNWFilterPoolObjListPtr pools,
+ const unsigned char *uuid);
+
+virNWFilterPoolObjPtr
+ virNWFilterPoolObjFindByName(virNWFilterPoolObjListPtr pools,
+ const char *name);
+
+
+int virNWFilterPoolObjSaveDef(virConnectPtr conn,
+ virNWFilterDriverStatePtr driver,
+ virNWFilterPoolObjPtr pool,
+ virNWFilterDefPtr def);
+
+int virNWFilterPoolObjDeleteDef(virConnectPtr conn,
+ virNWFilterPoolObjPtr pool);
+
+virNWFilterPoolObjPtr virNWFilterPoolObjAssignDef(virConnectPtr conn,
+
virNWFilterPoolObjListPtr pools,
+ virNWFilterDefPtr
def);
+
+int virNWFilterTestUnassignDef(virConnectPtr conn,
+ virNWFilterPoolObjPtr pool);
+
+virNWFilterDefPtr virNWFilterDefParseNode(virConnectPtr conn,
+ xmlDocPtr xml,
+ xmlNodePtr root);
+
+char *virNWFilterDefFormat(virConnectPtr conn,
+ virNWFilterDefPtr def);
+
+int virNWFilterSaveXML(virConnectPtr conn,
+ const char *configDir,
+ virNWFilterDefPtr def,
+ const char *xml);
+
+int virNWFilterSaveConfig(virConnectPtr conn,
+ const char *configDir,
+ virNWFilterDefPtr def);
+
+int virNWFilterPoolLoadAllConfigs(virConnectPtr conn,
+ virNWFilterPoolObjListPtr pools,
+ const char *configDir);
+
+char *virNWFilterConfigFile(virConnectPtr conn,
+ const char *dir,
+ const char *name);
+
+virNWFilterDefPtr virNWFilterDefParseString(virConnectPtr conn,
+ const char *xml);
+virNWFilterDefPtr virNWFilterDefParseFile(virConnectPtr conn,
+ const char *filename);
+
+void virNWFilterPoolObjLock(virNWFilterPoolObjPtr obj);
+void virNWFilterPoolObjUnlock(virNWFilterPoolObjPtr obj);
+
+int virNWFilterConfLayerInit(void);
+void virNWFilterConfLayerShutdown(void);
+
+#define virNWFilterReportError(conn, code, fmt...)
\
+ virReportErrorHelper(conn, VIR_FROM_NWFILTER, code, __FILE__,
\
+ __FUNCTION__, __LINE__, fmt)
+
+
+typedef int (*virNWFilterRebuild)(virConnectPtr conn,
+ virHashIterator, void *data);
+
+typedef struct _virNWFilterCallbackDriver virNWFilterCallbackDriver;
+typedef virNWFilterCallbackDriver *virNWFilterCallbackDriverPtr;
+struct _virNWFilterCallbackDriver {
+ const char *name;
+
+ virNWFilterRebuild vmFilterRebuild;
+};
+
+void virNWFilterRegisterCallbackDriver(virNWFilterCallbackDriverPtr);
+
+
+VIR_ENUM_DECL(virNWFilterRuleAction);
+VIR_ENUM_DECL(virNWFilterRuleDirection);
+VIR_ENUM_DECL(virNWFilterRuleProtocol);
+VIR_ENUM_DECL(virNWFilterJumpTarget);
+VIR_ENUM_DECL(virNWFilterChainPolicy);
+VIR_ENUM_DECL(virNWFilterEbtablesTable);
+VIR_ENUM_DECL(virNWFilterChainSuffix);
+
+#endif
Index: libvirt-acl/include/libvirt/virterror.h
===================================================================
--- libvirt-acl.orig/include/libvirt/virterror.h
+++ libvirt-acl/include/libvirt/virterror.h
@@ -69,6 +69,7 @@ typedef enum {
VIR_FROM_PHYP, /* Error from IBM power hypervisor */
VIR_FROM_SECRET, /* Error from secret storage */
VIR_FROM_CPU, /* Error from CPU driver */
+ VIR_FROM_NWFILTER, /* Error from network filter driver */
} virErrorDomain;
@@ -168,6 +169,10 @@ typedef enum {
VIR_ERR_NO_INTERFACE, /* interface driver not running */
VIR_ERR_INVALID_INTERFACE, /* invalid interface object */
VIR_ERR_MULTIPLE_INTERFACES, /* more than one matching interface
found */
+ VIR_WAR_NO_NWFILTER, /* failed to start nwfilter driver */
+ VIR_ERR_INVALID_NWFILTER, /* invalid nwfilter object */
+ VIR_ERR_NO_NWFILTER, /* nw filter pool not found */
+ VIR_ERR_BUILD_FIREWALL, /* nw filter pool not found */
VIR_WAR_NO_SECRET, /* failed to start secret storage */
VIR_ERR_INVALID_SECRET, /* invalid secret */
VIR_ERR_NO_SECRET, /* secret not found */
Index: libvirt-acl/src/util/virterror.c
===================================================================
--- libvirt-acl.orig/src/util/virterror.c
+++ libvirt-acl/src/util/virterror.c
@@ -175,6 +175,9 @@ static const char *virErrorDomainName(vi
case VIR_FROM_CPU:
dom = "CPU ";
break;
+ case VIR_FROM_NWFILTER:
+ dom = "Network Filter";
+ break;
}
return(dom);
}
@@ -1097,6 +1100,30 @@ virErrorMsg(virErrorNumber error, const
else
errmsg = _("Secret not found: %s");
break;
+ case VIR_WAR_NO_NWFILTER:
+ if (info == NULL)
+ errmsg = _("Failed to start the nwfilter driver");
+ else
+ errmsg = _("Failed to start the nwfilter driver: %s");
+ break;
+ case VIR_ERR_INVALID_NWFILTER:
+ if (info == NULL)
+ errmsg = _("Invalid network filter");
+ else
+ errmsg = _("Invalid network filter: %s");
+ break;
+ case VIR_ERR_NO_NWFILTER:
+ if (info == NULL)
+ errmsg = _("Network filter not found");
+ else
+ errmsg = _("Network filter not found: %s");
+ break;
+ case VIR_ERR_BUILD_FIREWALL:
+ if (info == NULL)
+ errmsg = _("Error while building firewall");
+ else
+ errmsg = _("Error while building firewall: %s");
+ break;
case VIR_ERR_CONFIG_UNSUPPORTED:
if (info == NULL)
errmsg = _("unsupported configuration");
Index: libvirt-acl/src/nwfilter/nwfilter_driver.c
===================================================================
--- /dev/null
+++ libvirt-acl/src/nwfilter/nwfilter_driver.c
@@ -0,0 +1,429 @@
+/*
+ * 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(a)redhat.com>
+ * Stefan Berger <stefanb(a)us.ibm.com>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#if HAVE_PWD_H
+#include <pwd.h>
+#endif
+#include <errno.h>
+#include <string.h>
+
+#include "virterror_internal.h"
+#include "datatypes.h"
+#include "driver.h"
+#include "util.h"
+#include "nwfilter_driver.h"
+#include "nwfilter_conf.h"
+#include "memory.h"
+
+#include "domain_conf.h"
+#include "nwfilter_conf.h"
+#include "nwfilter_gentech_driver.h"
+#include "nwfilter_ebiptables_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;
+}
Index: libvirt-acl/src/nwfilter/nwfilter_driver.h
===================================================================
--- /dev/null
+++ libvirt-acl/src/nwfilter/nwfilter_driver.h
@@ -0,0 +1,35 @@
+/*
+ * 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(a)redhat.com>
+ * Stefan Berger <stefanb(a)us.ibm.com>
+ */
+
+#ifndef __VIR_NWFILTER_DRIVER_H__
+#define __VIR_NWFILTER_DRIVER_H__
+
+#include "nwfilter_conf.h"
+
+int nwfilterRegister(void);
+
+#endif /* __VIR_NWFILTER_DRIVER_H__ */
Index: libvirt-acl/src/datatypes.h
===================================================================
--- libvirt-acl.orig/src/datatypes.h
+++ libvirt-acl/src/datatypes.h
@@ -121,6 +121,17 @@
/**
+ * VIR_NWFILTER_MAGIC:
+ *
+ * magic value used to protect the API when pointers to network filter
+ * pool structures are passed down by the users.
+ */
+#define VIR_NWFILTER_MAGIC 0xDEAD7777
+#define VIR_IS_NWFILTER(obj) ((obj) &&
(obj)->magic==VIR_NWFILTER_MAGIC)
+#define VIR_IS_CONNECTED_NWFILTER(obj) (VIR_IS_NWFILTER(obj) &&
VIR_IS_CONNECT((obj)->conn))
+
+
+/**
* _virConnect:
*
* Internal structure associated to a connection
@@ -141,6 +152,7 @@ struct _virConnect {
virStorageDriverPtr storageDriver;
virDeviceMonitorPtr deviceMonitor;
virSecretDriverPtr secretDriver;
+ virNWFilterDriverPtr nwfilterDriver;
/* Private data pointer which can be used by driver and
* network driver as they wish.
@@ -152,6 +164,7 @@ struct _virConnect {
void * storagePrivateData;
void * devMonPrivateData;
void * secretPrivateData;
+ void * nwfilterPrivateData;
/*
* The lock mutex must be acquired before accessing/changing
@@ -173,6 +186,7 @@ struct _virConnect {
virHashTablePtr storageVols;/* hash table for known storage vols */
virHashTablePtr nodeDevices; /* hash table for known node devices
*/
virHashTablePtr secrets; /* hash taboe for known secrets */
+ virHashTablePtr nwfilterPools; /* hash tables ofr known nw filter
pools */
int refs; /* reference count */
};
@@ -336,4 +350,22 @@ int virUnrefSecret(virSecretPtr secret);
virStreamPtr virGetStream(virConnectPtr conn);
int virUnrefStream(virStreamPtr st);
+/**
+* _virNWFilter:
+*
+* Internal structure associated to a network filter
+*/
+struct _virNWFilter {
+ unsigned int magic; /* specific value to check */
+ int refs; /* reference count */
+ virConnectPtr conn; /* pointer back to the
connection */
+ char *name; /* the network filter external
name */
+ unsigned char uuid[VIR_UUID_BUFLEN]; /* the network filter unique
identifier */
+};
+
+virNWFilterPtr virGetNWFilter(virConnectPtr conn,
+ const char *name,
+ const unsigned char *uuid);
+int virUnrefNWFilter(virNWFilterPtr pool);
+
#endif
Index: libvirt-acl/src/datatypes.c
===================================================================
--- libvirt-acl.orig/src/datatypes.c
+++ libvirt-acl/src/datatypes.c
@@ -175,6 +175,9 @@ virGetConnect(void) {
ret->secrets = virHashCreate(20);
if (ret->secrets == NULL)
goto failed;
+ ret->nwfilterPools = virHashCreate(20);
+ if (ret->nwfilterPools == NULL)
+ goto failed;
ret->refs = 1;
return(ret);
@@ -1362,3 +1365,142 @@ int virUnrefStream(virStreamPtr st) {
virMutexUnlock(&st->conn->lock);
return (refs);
}
+
+
+/**
+ * virGetNWFilter:
+ * @conn: the hypervisor connection
+ * @name: pointer to the network filter pool name
+ * @uuid: pointer to the uuid
+ *
+ * Lookup if the network filter is already registered for that
connection,
+ * if yes return a new pointer to it, if no allocate a new structure,
+ * and register it in the table. In any case a corresponding call to
+ * virFreeNWFilterPool() is needed to not leak data.
+ *
+ * Returns a pointer to the network, or NULL in case of failure
+ */
+virNWFilterPtr
+virGetNWFilter(virConnectPtr conn, const char *name, const unsigned
char *uuid) {
+ virNWFilterPtr ret = NULL;
+
+ if ((!VIR_IS_CONNECT(conn)) || (name == NULL) || (uuid == NULL)) {
+ virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return(NULL);
+ }
+ virMutexLock(&conn->lock);
+
+ /* TODO search by UUID first as they are better differenciators */
+
+ ret = (virNWFilterPtr) virHashLookup(conn->nwfilterPools, name);
+ /* TODO check the UUID */
+ if (ret == NULL) {
+ if (VIR_ALLOC(ret) < 0) {
+ virMutexUnlock(&conn->lock);
+ virReportOOMError();
+ goto error;
+ }
+ ret->name = strdup(name);
+ if (ret->name == NULL) {
+ virMutexUnlock(&conn->lock);
+ virReportOOMError();
+ goto error;
+ }
+ ret->magic = VIR_NWFILTER_MAGIC;
+ ret->conn = conn;
+ if (uuid != NULL)
+ memcpy(&(ret->uuid[0]), uuid, VIR_UUID_BUFLEN);
+
+ if (virHashAddEntry(conn->nwfilterPools, name, ret) < 0) {
+ virMutexUnlock(&conn->lock);
+ virLibConnError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("failed to add network filter pool
to connection hash table"));
+ goto error;
+ }
+ conn->refs++;
+ }
+ ret->refs++;
+ virMutexUnlock(&conn->lock);
+ return(ret);
+
+error:
+ if (ret != NULL) {
+ VIR_FREE(ret->name);
+ VIR_FREE(ret);
+ }
+ return(NULL);
+}
+
+
+/**
+ * virReleaseNWFilterPool:
+ * @pool: the pool to release
+ *
+ * Unconditionally release all memory associated with a pool.
+ * The conn.lock mutex must be held prior to calling this, and will
+ * be released prior to this returning. The pool obj must not
+ * be used once this method returns.
+ *
+ * It will also unreference the associated connection object,
+ * which may also be released if its ref count hits zero.
+ */
+static void
+virReleaseNWFilterPool(virNWFilterPtr pool) {
+ virConnectPtr conn = pool->conn;
+ DEBUG("release pool %p %s", pool, pool->name);
+
+ /* TODO search by UUID first as they are better differenciators */
+ if (virHashRemoveEntry(conn->nwfilterPools, pool->name, NULL) < 0)
{
+ virMutexUnlock(&conn->lock);
+ virLibConnError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("pool missing from connection hash
table"));
+ conn = NULL;
+ }
+
+ pool->magic = -1;
+ VIR_FREE(pool->name);
+ VIR_FREE(pool);
+
+ if (conn) {
+ DEBUG("unref connection %p %d", conn, conn->refs);
+ conn->refs--;
+ if (conn->refs == 0) {
+ virReleaseConnect(conn);
+ /* Already unlocked mutex */
+ return;
+ }
+ virMutexUnlock(&conn->lock);
+ }
+}
+
+
+/**
+ * virUnrefNWFilter:
+ * @pool: the nwfilter to unreference
+ *
+ * Unreference the networkf itler. If the use count drops to zero, the
+ * structure is actually freed.
+ *
+ * Returns the reference count or -1 in case of failure.
+ */
+int
+virUnrefNWFilter(virNWFilterPtr pool) {
+ int refs;
+
+ if (!VIR_IS_CONNECTED_NWFILTER(pool)) {
+ virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return(-1);
+ }
+ virMutexLock(&pool->conn->lock);
+ DEBUG("unref pool %p %s %d", pool, pool->name, pool->refs);
+ pool->refs--;
+ refs = pool->refs;
+ if (refs == 0) {
+ virReleaseNWFilterPool(pool);
+ /* Already unlocked mutex */
+ return (0);
+ }
+
+ virMutexUnlock(&pool->conn->lock);
+ return (refs);
+}
Index: libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.c
===================================================================
--- /dev/null
+++ libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.c
@@ -0,0 +1,1313 @@
+/*
+ * nwfilter_ebiptables_driver.c: driver for ebtables/iptables on tap
devices
+ *
+ * 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(a)us.ibm.com>
+ */
+
+#include <config.h>
+
+#include <stdint.h>
+#include <sys/stat.h>
+
+#include "internal.h"
+
+#include "buf.h"
+#include "memory.h"
+#include "logging.h"
+#include "datatypes.h"
+#include "virterror_internal.h"
+#include "domain_conf.h"
+#include "nwfilter_conf.h"
+#include "nwfilter_driver.h"
+#include "nwfilter_gentech_driver.h"
+#include "nwfilter_ebiptables_driver.h"
+
+#define VIR_FROM_THIS VIR_FROM_NWFILTER
+
+
+
+#define EBTABLES_DEFAULT_TABLE "nat"
+#define EBTABLES_CHAIN_INCOMING "PREROUTING"
+#define EBTABLES_CHAIN_OUTGOING "POSTROUTING"
+
+#define CHAINPREFIX_HOST_IN 'I'
+#define CHAINPREFIX_HOST_OUT 'O'
+#define CHAINPREFIX_HOST_IN_TEMP 'J'
+#define CHAINPREFIX_HOST_OUT_TEMP 'P'
+
+
+#define CMD_SEPARATOR "\n"
+#define CMD_DEF_PRE "cmd=\""
+#define CMD_DEF_POST "\""
+#define CMD_DEF(X) CMD_DEF_PRE X CMD_DEF_POST
+#define CMD_EXEC "res=`${cmd}`" CMD_SEPARATOR
+#define CMD_STOPONERR(X) \
+ X ? "if [ $? -ne 0 ]; then" \
+ " echo \"Failure to execute command '${cmd}'.\";" \
+ " exit 1;" \
+ "fi" CMD_SEPARATOR \
+ : ""
+
+
+#define EBTABLES_CMD EBTABLES_PATH
+#define BASH_CMD BASH_PATH
+
+#define PRINT_ROOT_CHAIN(buf, prefix, ifname) \
+ snprintf(buf, sizeof(buf), "%c-%s", prefix, ifname)
+#define PRINT_CHAIN(buf, prefix, ifname, suffix) \
+ snprintf(buf, sizeof(buf), "%c-%s-%s", prefix, ifname, suffix)
+
+
+static const char *supported_protocols[] = {
+ "ipv4",
+ "arp",
+ NULL,
+};
+
+
+static int
+printVar(virConnectPtr conn,
+ virNWFilterHashTablePtr vars,
+ char *buf, int bufsize,
+ nwItemDescPtr item,
+ int *done)
+{
+ *done = 0;
+
+ if ((item->flags & NWFILTER_ENTRY_ITEM_FLAG_HAS_VAR)) {
+ char *val = (char *)virHashLookup(vars->hashTable, item->var);
+ if (!val) {
+ virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
+ _("cannot find value for '%s'"),
+ item->var);
+ return 1;
+ }
+
+ if (!virStrcpy(buf, val, bufsize)) {
+ virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
+ _("Buffer to small to print MAC
address "
+ "'%s' into"),
+ item->var);
+ return 1;
+ }
+
+ *done = 1;
+ }
+ return 0;
+}
+
+
+static int
+printDataType(virConnectPtr conn,
+ virNWFilterHashTablePtr vars,
+ char *buf, int bufsize,
+ nwItemDescPtr item)
+{
+ int done;
+ if (printVar(conn, vars, buf, bufsize, item, &done))
+ return 1;
+
+ if (done)
+ return 0;
+
+ switch (item->datatype) {
+ case DATATYPE_IPADDR:
+ if (snprintf(buf, bufsize, "%d.%d.%d.%d",
+ item->u.ipaddr.addr.ipv4Addr[0],
+ item->u.ipaddr.addr.ipv4Addr[1],
+ item->u.ipaddr.addr.ipv4Addr[2],
+ item->u.ipaddr.addr.ipv4Addr[3]) >= bufsize) {
+ virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
+ _("Buffer too small for IP
address"));
+ return 1;
+ }
+ break;
+
+ case DATATYPE_MACADDR:
+ if (bufsize < VIR_MAC_STRING_BUFLEN) {
+ virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
+ _("Buffer too small for MAC
address"));
+ return 1;
+ }
+
+ virFormatMacAddr(item->u.macaddr.addr, buf);
+ break;
+
+ case DATATYPE_UINT16:
+ if (snprintf(buf, bufsize, "%d",
+ item->u.u16) >= bufsize) {
+ virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
+ _("Buffer too small for port
number"));
+ return 1;
+ }
+ break;
+ default:
+ virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
+ _("Unhandled datatype"));
+ return 1;
+ break;
+ }
+
+ return 0;
+}
+
+
+static void
+ebiptablesRuleInstFree(ebiptablesRuleInstPtr inst)
+{
+ if (!inst)
+ return;
+
+ VIR_FREE(inst->commandTemplate);
+ VIR_FREE(inst);
+}
+
+
+static int
+ebiptablesAddRuleInst(virConnectPtr conn,
+ virNWFilterRuleInstPtr res,
+ char *commandTemplate,
+ enum virNWFilterChainSuffixType neededChain,
+ char chainprefix,
+ unsigned int priority)
+{
+ ebiptablesRuleInstPtr inst;
+
+ if (VIR_ALLOC(inst) < 0) {
+ virReportOOMError();
+ return 1;
+ }
+
+ inst->commandTemplate = commandTemplate;
+ inst->neededProtocolChain = neededChain;
+ inst->chainprefix = chainprefix;
+ inst->priority = priority;
+
+ return virNWFilterRuleInstAddData(conn, res, inst);
+}
+
+/*
+ * ebtablesCreateRuleInstance:
+ * @conn : Pointer to a virConnect object
+ * @chainPrefix : The prefix to put in front of the name of the chain
+ * @nwfilter : The filter
+ * @rule: The rule of the filter to convert
+ * @ifname : The name of the interface to apply the rule to
+ * @vars : A map containing the variables to resolve
+ * @res : The data structure to store the result(s) into
+ *
+ * Convert a single rule into its representation for later
instantiation
+ *
+ * Returns 0 in case of success with the result stored in the data
structure
+ * pointed to by res, != 0 otherwise with the error message stored in
the
+ * virConnect object.
+ */
+static int
+ebtablesCreateRuleInstance(virConnectPtr conn,
+ char chainPrefix,
+ virNWFilterDefPtr nwfilter,
+ virNWFilterRuleDefPtr rule,
+ const char *ifname,
+ virNWFilterHashTablePtr vars,
+ virNWFilterRuleInstPtr res)
+{
+ char macaddr[VIR_MAC_STRING_BUFLEN],
+ ipaddr[INET_ADDRSTRLEN],
+ portstr[20];
+ char chain[MAX_CHAINNAME_LENGTH];
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ if (nwfilter->chainsuffix == VIR_NWFILTER_CHAINSUFFIX_ROOT)
+ PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
+ else
+ PRINT_CHAIN(chain, chainPrefix, ifname,
+
virNWFilterChainSuffixTypeToString(nwfilter->chainsuffix));
+
+
+ switch (rule->prtclType) {
+ case VIR_NWFILTER_RULE_PROTOCOL_MAC:
+
+ virBufferVSprintf(&buf,
+ CMD_DEF_PRE EBTABLES_CMD " -t %s -%%c %s %%
s",
+ EBTABLES_DEFAULT_TABLE, chain);
+
+
+ if (HAS_ENTRY_ITEM(&rule->p.ethHdrFilter.dataProtocolID)) {
+ virBufferVSprintf(&buf,
+ " -p %s %d",
+
ENTRY_GET_NEG_SIGN(&rule->p.ethHdrFilter.dataProtocolID),
+ rule->p.ethHdrFilter.dataProtocolID.u.u16);
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.ethHdrFilter.dataSrcMACAddr)) {
+ if (printDataType(conn,
+ vars,
+ macaddr, sizeof(macaddr),
+ &rule->p.ethHdrFilter.dataSrcMACAddr))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " -s %s %s",
+
ENTRY_GET_NEG_SIGN(&rule->p.ethHdrFilter.dataSrcMACAddr),
+ macaddr);
+
+ if (HAS_ENTRY_ITEM(&rule->p.ethHdrFilter.dataSrcMACMask)) {
+ if (printDataType(conn,
+ vars,
+ macaddr, sizeof(macaddr),
+
&rule->p.ethHdrFilter.dataSrcMACMask))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ "/%s",
+ macaddr);
+ }
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.ethHdrFilter.dataDstMACAddr)) {
+ if (printDataType(conn,
+ vars,
+ macaddr, sizeof(macaddr),
+ &rule->p.ethHdrFilter.dataDstMACAddr))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " -d %s %s",
+
ENTRY_GET_NEG_SIGN(&rule->p.ethHdrFilter.dataDstMACAddr),
+ macaddr);
+
+ if (HAS_ENTRY_ITEM(&rule->p.ethHdrFilter.dataDstMACMask)) {
+ if (printDataType(conn,
+ vars,
+ macaddr, sizeof(macaddr),
+
&rule->p.ethHdrFilter.dataDstMACMask))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ "/%s",
+ macaddr);
+ }
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.ethHdrFilter.dataPriority)) {
+ virBufferVSprintf(&buf,
+ " --vlan-prio %s %d",
+
ENTRY_GET_NEG_SIGN(&rule->p.ethHdrFilter.dataPriority),
+ rule->p.ethHdrFilter.dataPriority.u.u8);
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.ethHdrFilter.dataVLANID)) {
+ virBufferVSprintf(&buf,
+ " --vlan-id %s %d",
+
ENTRY_GET_NEG_SIGN(&rule->p.ethHdrFilter.dataVLANID),
+ rule->p.ethHdrFilter.dataVLANID.u.u16);
+ }
+ break;
+
+ case VIR_NWFILTER_RULE_PROTOCOL_ARP:
+
+ virBufferVSprintf(&buf,
+ CMD_DEF_PRE EBTABLES_CMD " -t %s -%%c %s %%
s",
+ EBTABLES_DEFAULT_TABLE, chain);
+
+ virBufferAddLit(&buf, " -p arp");
+
+ if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataHWType)) {
+ virBufferVSprintf(&buf,
+ " --arp-htype %s %d",
+
ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataHWType),
+ rule->p.arpHdrFilter.dataHWType.u.u16);
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataOpcode)) {
+ virBufferVSprintf(&buf,
+ " --arp-opcode %s %d",
+
ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataOpcode),
+ rule->p.arpHdrFilter.dataOpcode.u.u16);
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataProtocolType)) {
+ virBufferVSprintf(&buf,
+ " --arp-ptype %s %d",
+
ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataProtocolType),
+ rule->p.arpHdrFilter.dataProtocolType.u.u16);
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataSrcIPAddr)) {
+ if (printDataType(conn,
+ vars,
+ ipaddr, sizeof(ipaddr),
+ &rule->p.arpHdrFilter.dataSrcIPAddr))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --arp-ip-src %s %s",
+
ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataSrcIPAddr),
+ ipaddr);
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataDstIPAddr)) {
+ if (printDataType(conn,
+ vars,
+ ipaddr, sizeof(ipaddr),
+ &rule->p.arpHdrFilter.dataDstIPAddr))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --arp-ip-dst %s %s",
+
ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataDstIPAddr),
+ ipaddr);
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataSrcMACAddr)) {
+ if (printDataType(conn,
+ vars,
+ macaddr, sizeof(macaddr),
+ &rule->p.arpHdrFilter.dataSrcMACAddr))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --arp-mac-src %s %s",
+
ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataSrcMACAddr),
+ macaddr);
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataDstMACAddr)) {
+ if (printDataType(conn,
+ vars,
+ macaddr, sizeof(macaddr),
+ &rule->p.arpHdrFilter.dataDstMACAddr))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --arp-mac-dst %s %s",
+
ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataDstMACAddr),
+ macaddr);
+ }
+ break;
+
+ case VIR_NWFILTER_RULE_PROTOCOL_IP:
+ virBufferVSprintf(&buf,
+ CMD_DEF_PRE EBTABLES_CMD " -t %s -%%c %s %%
s",
+ EBTABLES_DEFAULT_TABLE, chain);
+
+ // FIXME -- may not be necessary if rule is in IPv4 user
defined
+ // table...
+ virBufferAddLit(&buf,
+ " -p ipv4");
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataSrcAddr)) {
+ if (printDataType(conn,
+ vars,
+ ipaddr, sizeof(ipaddr),
+ &rule->p.ipHdrFilter.ipHdr.dataSrcAddr))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --ip-source %s %s",
+
ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataSrcAddr),
+ ipaddr);
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataSrcMask))
{
+ virBufferVSprintf(&buf,
+ "/%d",
+
rule->p.ipHdrFilter.ipHdr.dataSrcMask.u.u8);
+ }
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataDstAddr)) {
+
+ if (printDataType(conn,
+ vars,
+ ipaddr, sizeof(ipaddr),
+ &rule->p.ipHdrFilter.ipHdr.dataDstAddr))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --ip-destination %s %s",
+
ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataDstAddr),
+ ipaddr);
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataDstMask))
{
+ virBufferVSprintf(&buf,
+ "/%d",
+
rule->p.ipHdrFilter.ipHdr.dataDstMask.u.u8);
+ }
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataProtocolID))
{
+ virBufferVSprintf(&buf,
+ " --ip-protocol %s %d",
+
ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataProtocolID),
+
rule->p.ipHdrFilter.ipHdr.dataProtocolID.u.u16);
+ }
+
+ if
(HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataSrcPortStart)) {
+
+ if (printDataType(conn,
+ vars,
+ portstr, sizeof(portstr),
+
&rule->p.ipHdrFilter.portData.dataSrcPortStart))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --ip-source-port %s %s",
+
ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.portData.dataSrcPortStart),
+ portstr);
+
+ if
(HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataSrcPortEnd)) {
+ if (printDataType(conn,
+ vars,
+ portstr, sizeof(portstr),
+
&rule->p.ipHdrFilter.portData.dataSrcPortEnd))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ ":%s",
+ portstr);
+ }
+ }
+
+ if
(HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataDstPortStart)) {
+
+ if (printDataType(conn,
+ vars,
+ portstr, sizeof(portstr),
+
&rule->p.ipHdrFilter.portData.dataDstPortStart))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --ip-destination-port %s %s",
+
ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.portData.dataDstPortStart),
+ portstr);
+
+ if
(HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataDstPortEnd)) {
+ if (printDataType(conn,
+ vars,
+ portstr, sizeof(portstr),
+
&rule->p.ipHdrFilter.portData.dataDstPortEnd))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ ":%s",
+ portstr);
+ }
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.dataDSCP)) {
+ virBufferVSprintf(&buf,
+ " --ip-tos %s %d",
+
ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.dataDSCP),
+ rule->p.ipHdrFilter.dataDSCP.u.u8);
+ }
+ break;
+
+ case VIR_NWFILTER_RULE_PROTOCOL_NONE:
+ virBufferVSprintf(&buf,
+ CMD_DEF_PRE EBTABLES_CMD " -t %s -%%c %s %%
s",
+ EBTABLES_DEFAULT_TABLE, chain);
+ break;
+ }
+
+ virBufferVSprintf(&buf,
+ " -j %s" CMD_DEF_POST CMD_SEPARATOR
+ CMD_EXEC,
+ virNWFilterJumpTargetTypeToString(rule->action));
+
+ if (virBufferError(&buf)) {
+ virBufferFreeAndReset(&buf);
+ virReportOOMError();
+ return -1;
+ }
+
+ return ebiptablesAddRuleInst(conn,
+ res,
+ virBufferContentAndReset(&buf),
+ nwfilter->chainsuffix,
+ chainPrefix,
+ rule->priority);
+
+err_exit:
+ virBufferFreeAndReset(&buf);
+
+ return -1;
+}
+
+
+/*
+ * ebiptablesCreateRuleInstance:
+ * @conn : Pointer to a virConnect object
+ * @nwfilter : The filter
+ * @rule: The rule of the filter to convert
+ * @ifname : The name of the interface to apply the rule to
+ * @vars : A map containing the variables to resolve
+ * @res : The data structure to store the result(s) into
+ *
+ * Convert a single rule into its representation for later
instantiation
+ *
+ * Returns 0 in case of success with the result stored in the data
structure
+ * pointed to by res, != 0 otherwise with the error message stored in
the
+ * virConnect object.
+ */
+static int
+ebiptablesCreateRuleInstance(virConnectPtr conn,
+ enum virDomainNetType nettype
ATTRIBUTE_UNUSED,
+ virNWFilterDefPtr nwfilter,
+ virNWFilterRuleDefPtr rule,
+ const char *ifname,
+ virNWFilterHashTablePtr vars,
+ virNWFilterRuleInstPtr res)
+{
+ int rc = 0;
+
+ switch (rule->prtclType) {
+ case VIR_NWFILTER_RULE_PROTOCOL_IP:
+ case VIR_NWFILTER_RULE_PROTOCOL_MAC:
+ case VIR_NWFILTER_RULE_PROTOCOL_ARP:
+ case VIR_NWFILTER_RULE_PROTOCOL_NONE:
+
+ if (rule->tt == VIR_NWFILTER_RULE_DIRECTION_OUT ||
+ rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT) {
+ rc = ebtablesCreateRuleInstance(conn,
+ CHAINPREFIX_HOST_IN_TEMP,
+ nwfilter,
+ rule,
+ ifname,
+ vars,
+ res);
+ if (rc)
+ return rc;
+ }
+
+ if (rule->tt == VIR_NWFILTER_RULE_DIRECTION_IN ||
+ rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT) {
+ rc = ebtablesCreateRuleInstance(conn,
+ CHAINPREFIX_HOST_OUT_TEMP,
+ nwfilter,
+ rule,
+ ifname,
+ vars,
+ res);
+ }
+ break;
+ }
+
+ return rc;
+}
+
+
+static int
+ebiptablesFreeRuleInstance(void *_inst)
+{
+ ebiptablesRuleInstFree((ebiptablesRuleInstPtr)_inst);
+ return 0;
+}
+
+
+static int
+ebiptablesDisplayRuleInstance(virConnectPtr conn ATTRIBUTE_UNUSED,
+ void *_inst)
+{
+ ebiptablesRuleInstPtr inst = (ebiptablesRuleInstPtr)_inst;
+ printf("Command Template: %s\nNeeded protocol: %s\n\n",
+ inst->commandTemplate,
+
virNWFilterChainSuffixTypeToString(inst->neededProtocolChain));
+ return 0;
+}
+
+
+/**
+ * ebiptablesWriteToTempFile:
+ * @conn: pointer to virConnect object
+ * @string : the string to write into the file
+ *
+ * Returns the tempory filename where the string was written into,
+ * NULL in case of error with the error reported.
+ *
+ * Write the string into a temporary file and return the name of
+ * the temporary file. The string is assumed to contain executable
+ * commands. A line '#!/bin/bash' will automatically be written
+ * as the first line in the file. The permissions of the file are
+ * set so that the file can be run as an executable script.
+ */
+static char *
+ebiptablesWriteToTempFile(virConnectPtr conn,
+ const char *string) {
+ char filename[] = "/tmp/virtdXXXXXX";
+ int len;
+ char *filnam;
+ const char header[] = "#!" BASH_CMD "\n";
+ size_t written;
+
+ int fd = mkstemp(filename);
+
+ if (fd < 0) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s",
+ _("cannot create temporary file"));
+ return NULL;
+ }
+
+ if (fchmod(fd, S_IXUSR| S_IRUSR | S_IWUSR) < 0) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s",
+ _("cannot change permissions on temp.
file"));
+ goto err_exit;
+ }
+
+ len = strlen(header);
+ written = safewrite(fd, header, len);
+ if (written != len) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s",
+ _("cannot write string to file"));
+ goto err_exit;
+ }
+
+ len = strlen(string);
+ written = safewrite(fd, string, len);
+ if (written != len) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s",
+ _("cannot write string to file"));
+ goto err_exit;
+ }
+
+ filnam = strdup(filename);
+ if (!filnam) {
+ virReportOOMError();
+ goto err_exit;
+ }
+
+ close(fd);
+ return filnam;
+
+err_exit:
+ close(fd);
+ unlink(filename);
+ return NULL;
+}
+
+
+/**
+ * ebiptablesExecCLI:
+ * @conn : pointer to virConnect object
+ * @buf : pointer to virBuffer containing the string with the commands
to
+ * execute.
+ * @status: Pointer to an integer for returning the status of the
+ * commands executed via the script the was run.
+ *
+ * Returns 0 in case of success, != 0 in case of an error. The returned
+ * value is NOT the result of running the commands inside the bash
+ * script.
+ *
+ * Execute a sequence of commands (held in the given buffer) as a bash
+ * script and return the status of the execution.
+ */
+static int
+ebiptablesExecCLI(virConnectPtr conn,
+ virBufferPtr buf,
+ int *status)
+{
+ char *cmds;
+ char *filename;
+ int rc;
+ const char *argv[] = {NULL, NULL};
+
+ if (virBufferError(buf)) {
+ virReportOOMError();
+ virBufferFreeAndReset(buf);
+ return 1;
+ }
+
+ *status = 0;
+
+ cmds = virBufferContentAndReset(buf);
+
+ VIR_DEBUG("%s", cmds);
+
+ if (!cmds)
+ return 0;
+
+ filename = ebiptablesWriteToTempFile(conn, cmds);
+ VIR_FREE(cmds);
+
+ if (!filename)
+ return 1;
+
+ argv[0] = filename;
+ rc = virRun(argv, status);
+
+ *status >>= 8;
+
+ VIR_DEBUG("rc = %d, status = %d\n",rc, *status);
+
+ unlink(filename);
+
+ VIR_FREE(filename);
+
+ return rc;
+}
+
+
+static int
+ebtablesCreateTmpRootChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ int incoming, const char *ifname,
+ int stopOnError)
+{
+ char chain[MAX_CHAINNAME_LENGTH];
+ char chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
+ : CHAINPREFIX_HOST_OUT_TEMP;
+
+ PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
+
+ virBufferVSprintf(buf,
+ CMD_DEF(EBTABLES_CMD " -t %s -N %s")
CMD_SEPARATOR
+ CMD_EXEC
+ "%s",
+ EBTABLES_DEFAULT_TABLE, chain,
+ CMD_STOPONERR(stopOnError));
+
+ return 0;
+}
+
+
+static int
+ebtablesLinkTmpRootChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ int incoming, const char *ifname,
+ int stopOnError)
+{
+ char chain[MAX_CHAINNAME_LENGTH];
+ char chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
+ : CHAINPREFIX_HOST_OUT_TEMP;
+ char iodev = (incoming) ? 'i' : 'o';
+
+ PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
+
+ virBufferVSprintf(buf,
+ CMD_DEF(EBTABLES_CMD " -t %s -A %s -%c %s -j %s")
CMD_SEPARATOR
+ CMD_EXEC
+ "%s",
+ EBTABLES_DEFAULT_TABLE,
+ (incoming) ? EBTABLES_CHAIN_INCOMING
+ : EBTABLES_CHAIN_OUTGOING,
+ iodev, ifname, chain,
+
+ CMD_STOPONERR(stopOnError));
+
+ return 0;
+}
+
+
+static int
+_ebtablesRemoveRootChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ int incoming, const char *ifname,
+ int isTempChain)
+{
+ char chain[MAX_CHAINNAME_LENGTH];
+ char chainPrefix;
+ if (isTempChain)
+ chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
+ : CHAINPREFIX_HOST_OUT_TEMP;
+ else
+ chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN
+ : CHAINPREFIX_HOST_OUT;
+
+ PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
+
+ virBufferVSprintf(buf,
+ EBTABLES_CMD " -t %s -F %s" CMD_SEPARATOR
+ EBTABLES_CMD " -t %s -X %s" CMD_SEPARATOR,
+ EBTABLES_DEFAULT_TABLE, chain,
+ EBTABLES_DEFAULT_TABLE, chain);
+
+ return 0;
+}
+
+
+static int
+ebtablesRemoveRootChain(virConnectPtr conn,
+ virBufferPtr buf,
+ int incoming, const char *ifname)
+{
+ return _ebtablesRemoveRootChain(conn, buf, incoming, ifname, 0);
+}
+
+
+static int
+ebtablesRemoveTmpRootChain(virConnectPtr conn,
+ virBufferPtr buf,
+ int incoming, const char *ifname)
+{
+ return _ebtablesRemoveRootChain(conn, buf, incoming, ifname, 1);
+}
+
+
+static int
+_ebtablesUnlinkRootChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ int incoming, const char *ifname,
+ int isTempChain)
+{
+ char chain[MAX_CHAINNAME_LENGTH];
+ char iodev = (incoming) ? 'i' : 'o';
+ char chainPrefix;
+
+ if (isTempChain) {
+ chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
+ : CHAINPREFIX_HOST_OUT_TEMP;
+ } else {
+ chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN
+ : CHAINPREFIX_HOST_OUT;
+ }
+
+ PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
+
+ virBufferVSprintf(buf,
+ EBTABLES_CMD " -t %s -D %s -%c %s -j %s"
CMD_SEPARATOR,
+ EBTABLES_DEFAULT_TABLE,
+ (incoming) ? EBTABLES_CHAIN_INCOMING
+ : EBTABLES_CHAIN_OUTGOING,
+ iodev, ifname, chain);
+
+ return 0;
+}
+
+
+static int
+ebtablesUnlinkRootChain(virConnectPtr conn,
+ virBufferPtr buf,
+ int incoming, const char *ifname)
+{
+ return _ebtablesUnlinkRootChain(conn, buf, incoming, ifname, 0);
+}
+
+
+static int
+ebtablesUnlinkTmpRootChain(virConnectPtr conn,
+ virBufferPtr buf,
+ int incoming, const char *ifname)
+{
+ return _ebtablesUnlinkRootChain(conn, buf, incoming, ifname, 1);
+}
+
+
+static int
+ebtablesCreateTmpSubChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ int incoming,
+ const char *ifname,
+ const char *protocol,
+ int stopOnError)
+{
+ char rootchain[MAX_CHAINNAME_LENGTH], chain[MAX_CHAINNAME_LENGTH];
+ char chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
+ : CHAINPREFIX_HOST_OUT_TEMP;
+
+ PRINT_ROOT_CHAIN(rootchain, chainPrefix, ifname);
+ PRINT_CHAIN(chain, chainPrefix, ifname, protocol);
+
+ virBufferVSprintf(buf,
+ CMD_DEF(EBTABLES_CMD " -t %s -N %s")
CMD_SEPARATOR
+ CMD_EXEC
+ "%s"
+ CMD_DEF(EBTABLES_CMD " -t %s -A %s -p %s -j %s")
CMD_SEPARATOR
+ CMD_EXEC
+ "%s",
+
+ EBTABLES_DEFAULT_TABLE, chain,
+
+ CMD_STOPONERR(stopOnError),
+
+ EBTABLES_DEFAULT_TABLE,
+ rootchain,
+ protocol, chain,
+
+ CMD_STOPONERR(stopOnError));
+
+ return 0;
+}
+
+
+static int
+_ebtablesRemoveSubChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ int incoming,
+ const char *ifname,
+ const char *protocol,
+ int isTempChain)
+{
+ char rootchain[MAX_CHAINNAME_LENGTH], chain[MAX_CHAINNAME_LENGTH];
+ char chainPrefix;
+ if (isTempChain) {
+ chainPrefix =(incoming) ? CHAINPREFIX_HOST_IN_TEMP
+ : CHAINPREFIX_HOST_OUT_TEMP;
+ } else {
+ chainPrefix =(incoming) ? CHAINPREFIX_HOST_IN
+ : CHAINPREFIX_HOST_OUT;
+ }
+
+ PRINT_ROOT_CHAIN(rootchain, chainPrefix, ifname);
+ PRINT_CHAIN(chain, chainPrefix, ifname, protocol);
+
+ virBufferVSprintf(buf,
+ EBTABLES_CMD " -t %s -D %s -p %s -j %s"
CMD_SEPARATOR
+ EBTABLES_CMD " -t %s -F %s" CMD_SEPARATOR
+ EBTABLES_CMD " -t %s -X %s" CMD_SEPARATOR,
+ EBTABLES_DEFAULT_TABLE,
+ rootchain,
+ protocol, chain,
+
+ EBTABLES_DEFAULT_TABLE, chain,
+
+ EBTABLES_DEFAULT_TABLE, chain);
+
+ return 0;
+}
+
+
+static int
+ebtablesRemoveSubChain(virConnectPtr conn,
+ virBufferPtr buf,
+ int incoming,
+ const char *ifname,
+ const char *protocol)
+{
+ return _ebtablesRemoveSubChain(conn, buf,
+ incoming, ifname, protocol, 0);
+}
+
+
+static int
+ebtablesRemoveSubChains(virConnectPtr conn,
+ virBufferPtr buf,
+ const char *ifname)
+{
+ int i;
+ for (i = 0; supported_protocols[i]; i++) {
+ ebtablesRemoveSubChain(conn, buf, 1, ifname,
supported_protocols[i]);
+ ebtablesRemoveSubChain(conn, buf, 0, ifname,
supported_protocols[i]);
+ }
+
+ return 0;
+}
+
+
+static int
+ebtablesRemoveTmpSubChain(virConnectPtr conn,
+ virBufferPtr buf,
+ int incoming,
+ const char *ifname,
+ const char *protocol)
+{
+ return _ebtablesRemoveSubChain(conn, buf,
+ incoming, ifname, protocol, 1);
+}
+
+
+static int
+ebtablesRemoveTmpSubChains(virConnectPtr conn,
+ virBufferPtr buf,
+ const char *ifname)
+{
+ int i;
+ for (i = 0; supported_protocols[i]; i++) {
+ ebtablesRemoveTmpSubChain(conn, buf, 1, ifname,
+ supported_protocols[i]);
+ ebtablesRemoveTmpSubChain(conn, buf, 0, ifname,
+ supported_protocols[i]);
+ }
+
+ return 0;
+}
+
+
+static int
+ebtablesRenameTmpSubChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ int incoming,
+ const char *ifname,
+ const char *protocol)
+{
+ char tmpchain[MAX_CHAINNAME_LENGTH], chain[MAX_CHAINNAME_LENGTH];
+ char tmpChainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
+ : CHAINPREFIX_HOST_OUT_TEMP;
+ char chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN
+ : CHAINPREFIX_HOST_OUT;
+
+ if (protocol) {
+ PRINT_CHAIN(tmpchain, tmpChainPrefix, ifname, protocol);
+ PRINT_CHAIN( chain, chainPrefix, ifname, protocol);
+ } else {
+ PRINT_ROOT_CHAIN(tmpchain, tmpChainPrefix, ifname);
+ PRINT_ROOT_CHAIN( chain, chainPrefix, ifname);
+ }
+
+ virBufferVSprintf(buf,
+ EBTABLES_CMD " -t %s -E %s %s" CMD_SEPARATOR,
+ EBTABLES_DEFAULT_TABLE,
+ tmpchain,
+ chain);
+ return 0;
+}
+
+
+static int
+ebtablesRenameTmpSubChains(virConnectPtr conn,
+ virBufferPtr buf,
+ const char *ifname)
+{
+ int i;
+ for (i = 0; supported_protocols[i]; i++) {
+ ebtablesRenameTmpSubChain (conn, buf, 1, ifname,
+ supported_protocols[i]);
+ ebtablesRenameTmpSubChain (conn, buf, 0, ifname,
+ supported_protocols[i]);
+ }
+
+ return 0;
+}
+
+
+static int
+ebtablesRenameTmpRootChain(virConnectPtr conn,
+ virBufferPtr buf,
+ int incoming,
+ const char *ifname)
+{
+ return ebtablesRenameTmpSubChain(conn, buf, incoming, ifname,
NULL);
+}
+
+
+static void
+ebiptablesInstCommand(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ const char *templ, char cmd, int pos,
+ int stopOnError)
+{
+ char position[10] = { 0 };
+ if (pos >= 0)
+ snprintf(position, sizeof(position), "%d", pos);
+ virBufferVSprintf(buf, templ, cmd, position);
+ virBufferVSprintf(buf, CMD_SEPARATOR "%s",
+ CMD_STOPONERR(stopOnError));
+}
+
+
+static int
+ebiptablesRuleOrderSort(const void *a, const void *b)
+{
+ const ebiptablesRuleInstPtr *insta = a;
+ const ebiptablesRuleInstPtr *instb = b;
+ return ((*insta)->priority - (*instb)->priority);
+}
+
+
+static int
+ebiptablesApplyRules(virConnectPtr conn,
+ const char *ifname,
+ int nruleInstances,
+ void **_inst)
+{
+ int i;
+ int cli_status;
+ ebiptablesRuleInstPtr *inst = (ebiptablesRuleInstPtr *)_inst;
+ int chains_in = 0, chains_out = 0;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ if (inst)
+ qsort(inst, nruleInstances, sizeof(inst[0]),
+ ebiptablesRuleOrderSort);
+
+ for (i = 0; i < nruleInstances; i++) {
+ if (inst[i]->chainprefix == CHAINPREFIX_HOST_IN_TEMP)
+ chains_in |= (1 << inst[i]->neededProtocolChain);
+ else
+ chains_out |= (1 << inst[i]->neededProtocolChain);
+ }
+
+ ebtablesUnlinkTmpRootChain(conn, &buf, 1, ifname);
+ ebtablesUnlinkTmpRootChain(conn, &buf, 0, ifname);
+ ebtablesRemoveTmpSubChains(conn, &buf, ifname);
+ ebtablesRemoveTmpRootChain(conn, &buf, 1, ifname);
+ ebtablesRemoveTmpRootChain(conn, &buf, 0, ifname);
+
+ if (chains_in != 0)
+ ebtablesCreateTmpRootChain(conn, &buf, 1, ifname, 1);
+ if (chains_out != 0)
+ ebtablesCreateTmpRootChain(conn, &buf, 0, ifname, 1);
+
+ if (chains_in & (1 << VIR_NWFILTER_CHAINSUFFIX_IPv4))
+ ebtablesCreateTmpSubChain(conn, &buf, 1, ifname, "ipv4", 1);
+ if (chains_out & (1 << VIR_NWFILTER_CHAINSUFFIX_IPv4))
+ ebtablesCreateTmpSubChain(conn, &buf, 0, ifname, "ipv4", 1);
+
+ // keep arp as last
+ if (chains_in & (1 << VIR_NWFILTER_CHAINSUFFIX_ARP))
+ ebtablesCreateTmpSubChain(conn, &buf, 1, ifname, "arp", 1);
+ if (chains_out & (1 << VIR_NWFILTER_CHAINSUFFIX_ARP))
+ ebtablesCreateTmpSubChain(conn, &buf, 0, ifname, "arp", 1);
+
+ if (ebiptablesExecCLI(conn, &buf, &cli_status) || cli_status != 0)
+ goto tear_down_tmpebchains;
+
+ for (i = 0; i < nruleInstances; i++)
+ ebiptablesInstCommand(conn, &buf,
+ inst[i]->commandTemplate,
+ 'A', -1, 1);
+
+ if (ebiptablesExecCLI(conn, &buf, &cli_status) || cli_status != 0)
+ goto tear_down_tmpebchains;
+
+ // FIXME: establishment of iptables user define table tree goes
here
+
+ // END IPTABLES stuff
+
+ if (chains_in != 0)
+ ebtablesLinkTmpRootChain(conn, &buf, 1, ifname, 1);
+ if (chains_out != 0)
+ ebtablesLinkTmpRootChain(conn, &buf, 0, ifname, 1);
+
+ if (ebiptablesExecCLI(conn, &buf, &cli_status) || cli_status != 0)
+ goto tear_down_ebsubchains_and_unlink;
+
+ ebtablesUnlinkRootChain(conn, &buf, 1, ifname);
+ ebtablesUnlinkRootChain(conn, &buf, 0, ifname);
+
+ ebtablesRemoveSubChains(conn, &buf, ifname);
+
+ ebtablesRemoveRootChain(conn, &buf, 1, ifname);
+ ebtablesRemoveRootChain(conn, &buf, 0, ifname);
+
+ ebtablesRenameTmpSubChains(conn, &buf, ifname);
+ ebtablesRenameTmpRootChain(conn, &buf, 1, ifname);
+ ebtablesRenameTmpRootChain(conn, &buf, 0, ifname);
+
+ ebiptablesExecCLI(conn, &buf, &cli_status);
+
+ return 0;
+
+tear_down_ebsubchains_and_unlink:
+ ebtablesUnlinkTmpRootChain(conn, &buf, 1, ifname);
+ ebtablesUnlinkTmpRootChain(conn, &buf, 0, ifname);
+
+tear_down_tmpebchains:
+ ebtablesRemoveTmpSubChains(conn, &buf, ifname);
+ ebtablesRemoveTmpRootChain(conn, &buf, 1, ifname);
+ ebtablesRemoveTmpRootChain(conn, &buf, 0, ifname);
+
+ ebiptablesExecCLI(conn, &buf, &cli_status);
+
+ virNWFilterReportError(conn, VIR_ERR_BUILD_FIREWALL,
+ "%s",
+ _("Some rules could not be created."));
+
+ return 1;
+}
+
+
+/**
+ * ebiptablesRemoveRules:
+ * @conn : pointer to virConnect object
+ * @ifname : the name of the interface to which the rules apply
+ * @nRuleInstance : the number of given rules
+ * @_inst : array of rule instantiation data
+ *
+ * Remove all rules one after the other
+ *
+ * Return 0 on success, 1 if execution of one or more cleanup
+ * commands failed.
+ */
+static int
+ebiptablesRemoveRules(virConnectPtr conn,
+ const char *ifname ATTRIBUTE_UNUSED,
+ int nruleInstances,
+ void **_inst)
+{
+ int rc = 0;
+ int cli_status;
+ int i;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ ebiptablesRuleInstPtr *inst = (ebiptablesRuleInstPtr *)_inst;
+
+ for (i = 0; i < nruleInstances; i++)
+ ebiptablesInstCommand(conn, &buf,
+ inst[i]->commandTemplate,
+ 'D', -1,
+ 0);
+
+ if (ebiptablesExecCLI(conn, &buf, &cli_status))
+ goto err_exit;
+
+ if (cli_status) {
+ virNWFilterReportError(conn, VIR_ERR_BUILD_FIREWALL,
+ "%s",
+ _("error while executing CLI
commands"));
+ rc = 1;
+ }
+
+err_exit:
+ return rc;
+}
+
+
+/**
+ * ebiptablesAllTeardown:
+ * @ifname : the name of the interface to which the rules apply
+ *
+ * Unconditionally remove all possible user defined tables and rules
+ * that were created for the given interface (ifname).
+ *
+ * Always returns 0.
+ */
+static int
+ebiptablesAllTeardown(const char *ifname)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ int cli_status;
+ virConnectPtr conn = NULL;
+
+ ebtablesUnlinkRootChain(conn, &buf, 1, ifname);
+ ebtablesUnlinkRootChain(conn, &buf, 0, ifname);
+
+ ebtablesRemoveRootChain(conn, &buf, 1, ifname);
+ ebtablesRemoveRootChain(conn, &buf, 0, ifname);
+
+ ebtablesRemoveSubChains(conn, &buf, ifname);
+
+ ebiptablesExecCLI(conn, &buf, &cli_status);
+
+ return 0;
+}
+
+
+virNWFilterTechDriver ebiptables_driver = {
+ .name = EBIPTABLES_DRIVER_ID,
+
+ .createRuleInstance = ebiptablesCreateRuleInstance,
+ .applyRules = ebiptablesApplyRules,
+ .allTeardown = ebiptablesAllTeardown,
+ .removeRules = ebiptablesRemoveRules,
+ .freeRuleInstance = ebiptablesFreeRuleInstance,
+ .displayRuleInstance = ebiptablesDisplayRuleInstance,
+};
Index: libvirt-acl/src/nwfilter/nwfilter_gentech_driver.c
===================================================================
--- /dev/null
+++ libvirt-acl/src/nwfilter/nwfilter_gentech_driver.c
@@ -0,0 +1,656 @@
+/*
+ * 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(a)us.ibm.com>
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include "config.h"
+
+#include "memory.h"
+#include "logging.h"
+#include "datatypes.h"
+#include "domain_conf.h"
+#include "nwfilter_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 (!strcmp(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_ROLLBACK_NEWFILTER:
+ if (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)
+{
+ 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_ROLLBACK_NEWFILTER:
+ 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->applyRules(conn, ifname, nptrs, ptrs);
+
+ 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,
+ 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_ROLLBACK_NEWFILTER:
+ if (obj->newDef)
+ foundNewFilter = 1;
+ break;
+
+ case INSTANTIATE_ALWAYS:
+ break;
+ }
+
+ rc = virNWFilterInstantiate(conn,
+ techdriver,
+ net->type,
+ filter,
+ net->ifname,
+ vars,
+ useNewFilter, &foundNewFilter);
+
+ 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,
+ INSTANTIATE_ALWAYS);
+}
+
+
+int
+virNWFilterUpdateInstantiateFilter(virConnectPtr conn,
+ const virDomainNetDefPtr net)
+{
+ return _virNWFilterInstantiateFilter(conn, net,
+ INSTANTIATE_FOLLOW_NEWFILTER);
+}
+
+int virNWFilterRollbackUpdateFilter(virConnectPtr conn,
+ const virDomainNetDefPtr net)
+{
+ return _virNWFilterInstantiateFilter(conn, net,
+
INSTANTIATE_ROLLBACK_NEWFILTER);
+}
+
+
+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;
+}
Index: libvirt-acl/src/nwfilter/nwfilter_gentech_driver.h
===================================================================
--- /dev/null
+++ libvirt-acl/src/nwfilter/nwfilter_gentech_driver.h
@@ -0,0 +1,52 @@
+/*
+ * 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(a)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,
+ INSTANTIATE_ROLLBACK_NEWFILTER,
+};
+
+
+int virNWFilterInstantiateFilter(virConnectPtr conn,
+ const virDomainNetDefPtr net);
+int virNWFilterUpdateInstantiateFilter(virConnectPtr conn,
+ const virDomainNetDefPtr net);
+int virNWFilterRollbackUpdateFilter(virConnectPtr conn,
+ const virDomainNetDefPtr net);
+
+int virNWFilterTeardownFilter(const virDomainNetDefPtr net);
+
+virNWFilterHashTablePtr virNWFilterCreateVarHashmap(virConnectPtr conn,
+ char *macaddr);
+
+#endif
Index: libvirt-acl/daemon/libvirtd.c
===================================================================
--- libvirt-acl.orig/daemon/libvirtd.c
+++ libvirt-acl/daemon/libvirtd.c
@@ -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 *qemudInitial
virDriverLoadModule("lxc");
virDriverLoadModule("uml");
virDriverLoadModule("one");
+ virDriverLoadModule("nwfilter");
#else
# ifdef WITH_NETWORK
networkRegister();
@@ -892,6 +896,9 @@ static struct qemud_server *qemudInitial
# ifdef WITH_SECRETS
secretRegister();
# endif
+# ifdef WITH_NWFILTER
+ nwfilterRegister();
+# endif
# ifdef WITH_QEMU
qemuRegister();
# endif
Index: libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.h
===================================================================
--- /dev/null
+++ libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.h
@@ -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(a)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
Index: libvirt-acl/python/generator.py
===================================================================
--- libvirt-acl.orig/python/generator.py
+++ libvirt-acl/python/generator.py
@@ -170,6 +170,7 @@ skipped_types = {
# 'int *': "usually a return type",
'virConnectDomainEventCallback': "No function types in python",
'virEventAddHandleFunc': "No function types in python",
+ 'virNWFilterPoolPtr': "No function types in python",
}
#######################################################################
@@ -268,6 +269,7 @@ skip_impl = (
'virConnectListStorageVols',
'virConnectListDefinedStorageVols',
'virConnectListDefinedInterfaces',
+ 'virConnectListNWFilters',
'virConnGetLastError',
'virGetLastError',
'virDomainGetInfo',
Index: libvirt-acl/configure.ac
===================================================================
--- libvirt-acl.orig/configure.ac
+++ libvirt-acl/configure.ac
@@ -291,6 +291,9 @@ if test x"$with_rhel5_api" = x"yes"; the
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])
14 years, 7 months
[libvirt] [APPENDIX] Sample filters
by Stefan Berger
Attached are some sample filter templates. Some of these should probably
become available through libvirt repository later on as 'standard
filters'.
One may copy the XML files into /etc/libvirt/nwfilter or use 'virsh
nwfilter-define <filename>' to make them known to libvirt. Using 'virsh
nwfilter-list' one can then list the filters.
The simpleloop.xml filter will not be accepted since it would directly
introduce a loop. More complex loops are also detected.
Regards,
Stefan, Gerhard
14 years, 7 months
[libvirt] [PATCH 13/13] Extension for iptables rules
by Stefan Berger
This patch adds support for L3/L4 filtering using iptables. This adds
support for 'tcp', 'udp', 'icmp', 'igmp', 'sctp' etc. filtering.
As mentioned in the introduction, a .c file provided by this patch
is #include'd into a .c file. This will need work, but should be alright
for review.
Signed-off-by: Stefan Berger <stefanb(a)us.ibm.com>
14 years, 7 months
[libvirt] [PATCH 12/13] Core driver implementation with ebtables support
by Stefan Berger
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(a)us.ibm.com>
14 years, 7 months
[libvirt] [PATCH 11/13] Add qemu support
by Stefan Berger
Add support for Qemu to have firewall rules applied and removed on VM
startup and shutdown respectively. This patch also provides support for
the updating of a filter that causes all VMs that reference the filter
to have their ebtables/iptables rules updated.
Signed-off-by: Stefan Berger <stefanb(a)us.ibm.com>
14 years, 7 months
[libvirt] [PATCH 10/13] Add XML parser extensions to the domain XML processing
by Stefan Berger
This patch extends the domain XML processing to parse the top level
referenced filter along with potentially provided parameters and also
converts the internal data back into XML representation.
Signed-off-by: Stefan Berger <stefanb(a)us.ibm.com>
Signed-off-by: Gerhard Stenzel <gerhard.stenzel(a)de.ibm.com>
14 years, 7 months