[libvirt] Memory leak in libvirt / gnutls
by Richard W.M. Jones
I'm trying to track down:
https://bugzilla.redhat.com/show_bug.cgi?id=810613
I *think* this is a libvirt bug, but I can only reproduce it on one
machine, not on another machine that has a virtually identical setup.
Anyway, something is confusing me about libvirt. In this commit:
----------------------------------------------------------------------
commit 74c75671331d284e1f777f9692b72e9737520bf0
Author: Michal Privoznik <mprivozn(a)redhat.com>
Date: Thu Aug 18 10:44:08 2011 +0200
daemon: initialize GnuTLS
When spice_tls is set but listen_tls is not, we don't initialize
GnuTLS library. So any later gnutls call (e.g. during migration,
where we initialize a certificate) will access uninitialized GnuTLS
internal structs and throws an error.
Although, we might now initialize GnuTLS twice, it is safe according
to the documentation:
This function can be called many times,
but will only do something the first time.
This patch creates 2 functions: virNetTLSInit and virNetTLSDeinit
with respect to written above.
----------------------------------------------------------------------
... a pair of functions called virNetTLSInit & virNetTLSDeinit are
introduced, which would appear to do the right thing, calling first
gnutls_global_init, then gnutls_global_deinit. This looks correct to
me.
However the above commit is later amended by this commit:
----------------------------------------------------------------------
commit eaddec976ef06457fee4a4ce86b8c7ee906183b7
Author: Michal Privoznik <mprivozn(a)redhat.com>
Date: Wed Aug 24 16:16:45 2011 +0200
daemon: Move TLS initialization to virInitialize
My previous patch 74c75671331d284e1f777f9692b72e9737520bf0
introduced a regression by removing TLS initialization from client.
----------------------------------------------------------------------
which removes virNetTLSDeinit. This appears to be a mistake, or at
least I can't see the logical reason for it, and according to the
gnutls docs, it would introduce a memory leak looking exactly like the
one I am chasing down.
The current code mentions virNetTLSDeinit only in a comment, and never
calls gnutls_global_deinit.
Any ideas?
Rich.
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
virt-top is 'top' for virtual machines. Tiny program with many
powerful monitoring features, net stats, disk stats, logging, etc.
http://et.redhat.com/~rjones/virt-top
12 years, 7 months
[libvirt] [PATCH] Fix compilation error on 32bit
by Stefan Berger
Below code failed to compile on a 32 bit machine with error
typewrappers.c: In function 'libvirt_intUnwrap':
typewrappers.c:135:5: error: logical 'and' of mutually exclusive tests
is always false [-Werror=logical-op]
cc1: all warnings being treated as errors
The patch fixes this error.
Stefan
---
python/typewrappers.c | 4 ++++
1 file changed, 4 insertions(+)
Index: libvirt-acl/python/typewrappers.c
===================================================================
--- libvirt-acl.orig/python/typewrappers.c
+++ libvirt-acl/python/typewrappers.c
@@ -132,6 +132,7 @@ libvirt_intUnwrap(PyObject *obj, int *va
if ((long_val == -1) && PyErr_Occurred())
return -1;
+#if LONG_MAX != INT_MAX
if (long_val >= INT_MIN && long_val <= INT_MAX) {
*val = long_val;
} else {
@@ -139,6 +140,9 @@ libvirt_intUnwrap(PyObject *obj, int *va
"Python int too large to convert to C int");
return -1;
}
+#else
+ *val = long_val;
+#endif
return 0;
}
12 years, 7 months
[libvirt] [PATCH 0/4] Replace daemon-conf test case
by Daniel P. Berrange
The daemon-conf test case is terminally broken by design, despite
numerous patches over the years, due to its need to test functionality
indirectly by running libvirtd. Replace it with a test case which
directly unit tests the code in question.
12 years, 7 months
[libvirt] [test-API PATCH 1/3] test-API: Get rid of utils/Python
by Osier Yang
test-API tends to only support testing via libvirt Python
binding now, and moving it to utils makes sense.
---
utils/{Python => }/XMLParser.py | 0
utils/{Python => }/check.py | 0
utils/{Python => }/env_parser.py | 0
utils/{Python => }/format.py | 0
utils/{Python => }/log.py | 0
utils/{Python => }/utils.py | 0
utils/{Python => }/xmlbuilder.py | 0
utils/{Python => }/xmlgenerator.py | 0
8 files changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 utils/Python/__init__.py
rename utils/{Python => }/XMLParser.py (100%)
rename utils/{Python => }/check.py (100%)
rename utils/{Python => }/env_parser.py (100%)
rename utils/{Python => }/format.py (100%)
rename utils/{Python => }/log.py (100%)
rename utils/{Python => }/utils.py (100%)
rename utils/{Python => }/xmlbuilder.py (100%)
rename utils/{Python => }/xmlgenerator.py (100%)
diff --git a/utils/Python/__init__.py b/utils/Python/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/utils/Python/XMLParser.py b/utils/XMLParser.py
similarity index 100%
rename from utils/Python/XMLParser.py
rename to utils/XMLParser.py
diff --git a/utils/Python/check.py b/utils/check.py
similarity index 100%
rename from utils/Python/check.py
rename to utils/check.py
diff --git a/utils/Python/env_parser.py b/utils/env_parser.py
similarity index 100%
rename from utils/Python/env_parser.py
rename to utils/env_parser.py
diff --git a/utils/Python/format.py b/utils/format.py
similarity index 100%
rename from utils/Python/format.py
rename to utils/format.py
diff --git a/utils/Python/log.py b/utils/log.py
similarity index 100%
rename from utils/Python/log.py
rename to utils/log.py
diff --git a/utils/Python/utils.py b/utils/utils.py
similarity index 100%
rename from utils/Python/utils.py
rename to utils/utils.py
diff --git a/utils/Python/xmlbuilder.py b/utils/xmlbuilder.py
similarity index 100%
rename from utils/Python/xmlbuilder.py
rename to utils/xmlbuilder.py
diff --git a/utils/Python/xmlgenerator.py b/utils/xmlgenerator.py
similarity index 100%
rename from utils/Python/xmlgenerator.py
rename to utils/xmlgenerator.py
--
1.7.7.5
12 years, 7 months
[libvirt] help for libvirt0.9.8 compile
by hero
my redhat6.1 has a libvirt0.8.7, and I got a libvirt0.9.8.tar that I want to update the old one.
when I use
'./configure --prefix=/usr --libdir=/usr/lib64 --localstatedir=/var --sysconfdir=/etc'
it siad 'configure: error: You must install device-mapper-devel/libdevmapper >= 1.0.0 to compile libvirt'
please tell me how to do if you know.
thanks.
best wishes!
SunYongGang
12 years, 7 months
[libvirt] [PATCHv3 00/16] live block migration via virDomainBlockCopy
by Eric Blake
v1 was here:
https://www.redhat.com/archives/libvir-list/2012-April/msg00068.html
v2 was here:
https://www.redhat.com/archives/libvir-list/2012-April/msg00222.html
changes from v2: added patch 12/16, addressed some review comments
and made minor changes from more of my own testing
CAVEAT: Paolo and I had an IRC conversation, where we decided that
'drive-mirror' might do better to take a mandatory 'full':'bool'
(or an even more powerful optional '*base':'str') argument for
determining how much to stream (full vs. shallow, or even the
backing file of the copy as matching the base argument of
'block_stream') rather than overloading the 'mode':'no-backing-file'
as the only way to get a full pull. If that change goes in qemu,
then we will need a v4, to tweak how the 'drive-mirror' monitor
command is called, and take advantage of the additional flexibility
it offers.
changes from v1: Paolo has updated the qemu side of things, and built
a scratch image for RHEL that I was able to test with for the new
semantics. I was actually able to successfully run two different
block copy jobs, one canceled and one pivoted, with SELinux disabled
and this patch series.
Patch 13/16 is for reference only when working with Paolo's build;
it will not go upstream.
Patches 14-16 are optional; the extra flexibility might be nice, but
I haven't yet played with those three enough to know if Paolo's build
behaves like I was expecting.
Adam Litke (2):
blockjob: add API for async virDomainBlockJobAbort
blockjob: wire up qemu async virDomainBlockJobAbort
Eric Blake (14):
blockjob: allow for fast-finishing job
blockjob: add new API flags
blockjob: add 'blockcopy' to virsh
blockjob: enhance xml to track mirrors across libvirtd restart
blockjob: react to active block copy
blockjob: expose qemu commands for mirrored storage migration
blockjob: return appropriate event and info
blockjob: support pivot operation on cancel
blockjob: implement block copy for qemu
blockjob: allow for existing files
blockjob: accommodate RHEL backport names
blockjob: add virDomainBlockCopy
blockjob: enhance virsh 'blockcopy'
blockjob: wire up qemu and RPC for block copy
docs/apibuild.py | 1 +
docs/formatdomain.html.in | 11 ++
docs/schemas/domaincommon.rng | 19 ++-
include/libvirt/libvirt.h.in | 50 +++++-
include/libvirt/virterror.h | 1 +
src/conf/domain_conf.c | 54 ++++++
src/conf/domain_conf.h | 6 +
src/driver.h | 5 +
src/libvirt.c | 220 +++++++++++++++++++++++-
src/libvirt_private.syms | 1 +
src/libvirt_public.syms | 5 +
src/qemu/qemu_capabilities.c | 3 +
src/qemu/qemu_capabilities.h | 2 +
src/qemu/qemu_driver.c | 379 +++++++++++++++++++++++++++++++++++++++--
src/qemu/qemu_hotplug.c | 7 +
src/qemu/qemu_monitor.c | 50 ++++++
src/qemu/qemu_monitor.h | 26 +++-
src/qemu/qemu_monitor_json.c | 166 +++++++++++++++---
src/qemu/qemu_monitor_json.h | 19 ++-
src/remote/remote_driver.c | 1 +
src/remote/remote_protocol.x | 12 ++-
src/remote_protocol-structs | 9 +
src/rpc/gendispatch.pl | 1 +
src/util/virterror.c | 6 +
tools/virsh.c | 140 ++++++++++++---
tools/virsh.pod | 40 ++++-
26 files changed, 1143 insertions(+), 91 deletions(-)
--
1.7.7.6
12 years, 7 months
[libvirt] [libvirt PATCHv8 1/1] add DHCP snooping
by David L Stevens
This patch adds DHCP snooping support to libvirt. The learning method for
IP addresses is specified by setting the "ip_learning" variable to one of
"any" [default] (existing IP learning code), "none" (static only addresses)
or "dhcp" (DHCP snooping).
Active leases are saved in a lease file and reloaded on restart or HUP.
Changes since v7:
- renamed functions as suggested
- collected local state into "virNWFilterSnoopState" struct
- cleaned up include file list
- misc code cleanups per review comments
Signed-off-by: David L Stevens <dlstevens(a)us.ibm.com>
---
docs/formatnwfilter.html.in | 17 +
po/POTFILES.in | 1 +
src/Makefile.am | 2 +
src/nwfilter/nwfilter_dhcpsnoop.c | 1197 ++++++++++++++++++++++++++++++++
src/nwfilter/nwfilter_dhcpsnoop.h | 38 +
src/nwfilter/nwfilter_driver.c | 6 +
src/nwfilter/nwfilter_gentech_driver.c | 59 ++-
7 files changed, 1307 insertions(+), 13 deletions(-)
create mode 100644 src/nwfilter/nwfilter_dhcpsnoop.c
create mode 100644 src/nwfilter/nwfilter_dhcpsnoop.h
diff --git a/docs/formatnwfilter.html.in b/docs/formatnwfilter.html.in
index 9cb7644..ad10765 100644
--- a/docs/formatnwfilter.html.in
+++ b/docs/formatnwfilter.html.in
@@ -2189,6 +2189,23 @@
<br/><br/>
In case a VM is resumed after suspension or migrated, IP address
detection will be restarted.
+ <br/><br/>
+ Variable <i>ip_learning</i> may be used to specify
+ the IP address learning method. Valid values are <i>any</i>, <i>dhcp</i>,
+ or <i>none</i>. The default value is <i>any</i>, meaning that libvirt
+ may use any packet to determine the address in use by a VM. A value of
+ <i>dhcp</i> specifies that libvirt should only honor DHCP server-assigned
+ addresses with valid leases. If <i>ip_learning</i> is set to <i>none</i>,
+ libvirt does not do address learning and referencing <i>IP</i> without
+ assigning it an explicit value is an error.
+ <br/><br/>
+ Use of <i>ip_learning=dhcp</i> (DHCP snooping) provides additional
+ anti-spoofing security, especially when combined with a filter allowing
+ only trusted DHCP servers to assign addresses. If the DHCP lease expires,
+ the VM will no longer be able to use the IP address until it acquires a
+ new, valid lease from a DHCP server. If the VM is migrated, it must get
+ a new valid DHCP lease to use an IP address (e.g., by
+ bringing the VM interface down and up again).
</p>
<h3><a name="nwflimitsmigr">VM Migration</a></h3>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 88be04e..d4b0a86 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -51,6 +51,7 @@ src/node_device/node_device_hal.c
src/node_device/node_device_linux_sysfs.c
src/node_device/node_device_udev.c
src/nodeinfo.c
+src/nwfilter/nwfilter_dhcpsnoop.c
src/nwfilter/nwfilter_driver.c
src/nwfilter/nwfilter_ebiptables_driver.c
src/nwfilter/nwfilter_gentech_driver.c
diff --git a/src/Makefile.am b/src/Makefile.am
index a2aae9d..4382caf 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -509,6 +509,8 @@ NWFILTER_DRIVER_SOURCES = \
nwfilter/nwfilter_driver.h nwfilter/nwfilter_driver.c \
nwfilter/nwfilter_gentech_driver.c \
nwfilter/nwfilter_gentech_driver.h \
+ nwfilter/nwfilter_dhcpsnoop.c \
+ nwfilter/nwfilter_dhcpsnoop.h \
nwfilter/nwfilter_ebiptables_driver.c \
nwfilter/nwfilter_ebiptables_driver.h \
nwfilter/nwfilter_learnipaddr.c \
diff --git a/src/nwfilter/nwfilter_dhcpsnoop.c b/src/nwfilter/nwfilter_dhcpsnoop.c
new file mode 100644
index 0000000..8c2ff50
--- /dev/null
+++ b/src/nwfilter/nwfilter_dhcpsnoop.c
@@ -0,0 +1,1197 @@
+/*
+ * nwfilter_dhcpsnoop.c: support for DHCP snooping used by a VM
+ * on an interface
+ *
+ * Copyright (C) 2011 IBM Corp.
+ * Copyright (C) 2011 David L Stevens
+ *
+ * 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: David L Stevens <dlstevens(a)us.ibm.com>
+ * Based in part on work by Stefan Berger <stefanb(a)us.ibm.com>
+ */
+
+#include <config.h>
+
+#ifdef HAVE_LIBPCAP
+#include <pcap.h>
+#endif
+
+#include <fcntl.h>
+
+#include <arpa/inet.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <net/if.h>
+
+#include "memory.h"
+#include "logging.h"
+#include "datatypes.h"
+#include "virterror_internal.h"
+#include "conf/domain_conf.h"
+#include "nwfilter_gentech_driver.h"
+#include "nwfilter_dhcpsnoop.h"
+#include "virnetdev.h"
+#include "virfile.h"
+#include "configmake.h"
+
+#define VIR_FROM_THIS VIR_FROM_NWFILTER
+
+#ifdef HAVE_LIBPCAP
+
+#define LEASEFILE LOCALSTATEDIR "/run/libvirt/network/nwfilter.leases"
+#define TMPLEASEFILE LOCALSTATEDIR "/run/libvirt/network/nwfilter.ltmp"
+
+static struct {
+/* lease file */
+ int LeaseFD;
+ int nLeases; /* number of active leases */
+ int wLeases; /* number of written leases */
+/* thread management */
+ virHashTablePtr SnoopReqs;
+ virHashTablePtr IfnameToKey;
+ virHashTablePtr Active;
+ virMutex SnoopLock;
+ virMutex ActiveLock;
+} virNWFilterSnoopState = {
+ .LeaseFD = -1,
+ .SnoopLock = { .lock=PTHREAD_MUTEX_INITIALIZER },
+ .ActiveLock = { .lock=PTHREAD_MUTEX_INITIALIZER },
+};
+
+#define virNWFilterSnoopLock() \
+ { virMutexLock(&virNWFilterSnoopState.SnoopLock); }
+#define virNWFilterSnoopUnlock() \
+ { virMutexUnlock(&virNWFilterSnoopState.SnoopLock); }
+#define virNWFilterSnoopLockActive() \
+ { virMutexLock(&virNWFilterSnoopState.ActiveLock); }
+#define virNWFilterSnoopUnlockActive() \
+ { virMutexUnlock(&virNWFilterSnoopState.ActiveLock); }
+
+static char *
+virNWFilterSnoopActivate(virThreadPtr thread)
+{
+ char *key, *data;
+ unsigned long threadID = (unsigned long int)thread->thread;
+
+ if (virAsprintf(&key, "0x%0*lX", (int)sizeof(threadID)*2, threadID) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ virNWFilterSnoopLockActive();
+ data = strdup("1");
+ if (data == NULL) {
+ virReportOOMError();
+ VIR_FREE(key);
+ } else if (virHashAddEntry(virNWFilterSnoopState.Active, key, data)) {
+ VIR_FREE(key);
+ VIR_FREE(data);
+ }
+ virNWFilterSnoopUnlockActive();
+ return key;
+}
+
+static void
+virNWFilterSnoopCancel(char **ThreadKey)
+{
+ if (*ThreadKey == NULL)
+ return;
+
+ virNWFilterSnoopLockActive();
+ (void) virHashRemoveEntry(virNWFilterSnoopState.Active, *ThreadKey);
+ *ThreadKey = NULL;
+ virNWFilterSnoopUnlockActive();
+}
+
+static bool
+virNWFilterSnoopIsActive(char *ThreadKey)
+{
+ void *entry;
+
+ if (ThreadKey == NULL)
+ return 0;
+ virNWFilterSnoopLockActive();
+ entry = virHashLookup(virNWFilterSnoopState.Active, ThreadKey);
+ virNWFilterSnoopUnlockActive();
+ return entry != NULL;
+}
+
+#define VIR_IFKEY_LEN ((VIR_UUID_STRING_BUFLEN) + (VIR_MAC_STRING_BUFLEN))
+
+struct virNWFilterSnoopReq {
+ virNWFilterTechDriverPtr techdriver;
+ const char *ifname;
+ int ifindex;
+ const char *linkdev;
+ enum virDomainNetType nettype;
+ char ifkey[VIR_IFKEY_LEN];
+ unsigned char macaddr[VIR_MAC_BUFLEN];
+ const char *filtername;
+ virNWFilterHashTablePtr vars;
+ virNWFilterDriverStatePtr driver;
+ /* start and end of lease list, ordered by lease time */
+ struct virNWFilterSnoopIPLease *start;
+ struct virNWFilterSnoopIPLease *end;
+ char *threadkey;
+};
+
+#define POLL_INTERVAL 10*1000 /* 10 secs */
+#define MAXERRS 25 /* retries on failing device */
+
+struct virNWFilterSnoopIPLease {
+ uint32_t IPAddress;
+ uint32_t IPServer;
+ struct virNWFilterSnoopReq *SnoopReq;
+ unsigned int Timeout;
+ /* timer list */
+ struct virNWFilterSnoopIPLease *prev;
+ struct virNWFilterSnoopIPLease *next;
+};
+
+static struct virNWFilterSnoopIPLease *
+ virNWFilterSnoopGetByIP(struct virNWFilterSnoopIPLease *start,
+ uint32_t ipaddr);
+static void virNWFilterSnoopUpdateLease(struct virNWFilterSnoopIPLease *pl,
+ time_t timeout);
+
+static struct virNWFilterSnoopReq *virNWFilterSnoopNewReq(const char *ifkey);
+
+static void virNWFilterSnoopLeaseFileOpen(void);
+static void virNWFilterSnoopLeaseFileClose(void);
+static void virNWFilterSnoopLeaseFileLoad(void);
+static void virNWFilterSnoopLeaseFileSave(struct virNWFilterSnoopIPLease *ipl);
+static void virNWFilterSnoopLeaseFileRestore(struct virNWFilterSnoopReq *req);
+static void virNWFilterSnoopLeaseFileRefresh(void);
+
+/*
+ * virNWFilterSnoopListAdd - add an IP lease to a list
+ */
+static void
+virNWFilterSnoopListAdd(struct virNWFilterSnoopIPLease *plnew,
+ struct virNWFilterSnoopIPLease **start,
+ struct virNWFilterSnoopIPLease **end)
+{
+ struct virNWFilterSnoopIPLease *pl;
+
+ plnew->next = plnew->prev = 0;
+ if (!*start) {
+ *start = *end = plnew;
+ return;
+ }
+ for (pl = *end; pl && plnew->Timeout < pl->Timeout;
+ pl = pl->prev)
+ /* empty */ ;
+ if (!pl) {
+ plnew->next = *start;
+ *start = plnew;
+ } else {
+ plnew->next = pl->next;
+ pl->next = plnew;
+ }
+ plnew->prev = pl;
+ if (plnew->next)
+ plnew->next->prev = plnew;
+ else
+ *end = plnew;
+}
+
+/*
+ * virNWFilterSnoopTimerAdd - add an IP lease to the timer list
+ */
+static void
+virNWFilterSnoopTimerAdd(struct virNWFilterSnoopIPLease *plnew)
+{
+ struct virNWFilterSnoopReq *req = plnew->SnoopReq;
+
+ virNWFilterSnoopListAdd(plnew, &req->start, &req->end);
+}
+
+/*
+ * virNWFilterSnoopInstallRule - install rule for a lease
+ */
+static int
+virNWFilterSnoopInstallRule(struct virNWFilterSnoopIPLease *ipl)
+{
+ char ipbuf[INET_ADDRSTRLEN];
+ int rc;
+ virNWFilterVarValuePtr ipVar;
+
+ if (!inet_ntop(AF_INET, &ipl->IPAddress, ipbuf, sizeof(ipbuf))) {
+ virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
+ _("virNWFilterSnoopInstallRule inet_ntop failed "
+ " (0x%08X)"), ipl->IPAddress);
+ return -1;
+ }
+ ipVar = virNWFilterVarValueCreateSimpleCopyValue(ipbuf);
+ if (!ipVar) {
+ virReportOOMError();
+ return -1;
+ }
+ if (virNWFilterHashTablePut(ipl->SnoopReq->vars, "IP", ipVar, 1)) {
+ virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Could not add variable \"IP\" to hashmap"));
+ virNWFilterVarValueFree(ipVar);
+ return -1;
+ }
+ rc = virNWFilterInstantiateFilterLate(NULL,
+ ipl->SnoopReq->ifname,
+ ipl->SnoopReq->ifindex,
+ ipl->SnoopReq->linkdev,
+ ipl->SnoopReq->nettype,
+ ipl->SnoopReq->macaddr,
+ ipl->SnoopReq->filtername,
+ ipl->SnoopReq->vars,
+ ipl->SnoopReq->driver);
+ if (rc)
+ return -1;
+ return 0;
+}
+
+/*
+ * virNWFilterSnoopLeaseAdd - create or update an IP lease
+ */
+static void
+virNWFilterSnoopLeaseAdd(struct virNWFilterSnoopIPLease *plnew,
+ bool update_leasefile)
+{
+ struct virNWFilterSnoopIPLease *pl;
+ struct virNWFilterSnoopReq *req = plnew->SnoopReq;
+
+ pl = virNWFilterSnoopGetByIP(req->start, plnew->IPAddress);
+ if (pl) {
+ virNWFilterSnoopUpdateLease(pl, plnew->Timeout);
+ if (update_leasefile)
+ virNWFilterSnoopLeaseFileSave(pl);
+ return;
+ }
+ /* support for multiple addresses requires the ability to add filters
+ * to existing chains, or to instantiate address lists via
+ * virNWFilterInstantiateFilterLate(). Until one of those capabilities
+ * is added, don't allow a new address when one is already assigned to
+ * this interface.
+ */
+ if (req->start)
+ return; /* silently ignore multiple addresses */
+
+ if (VIR_ALLOC(pl) < 0) {
+ virReportOOMError();
+ return;
+ }
+ *pl = *plnew;
+
+ if (req->threadkey && virNWFilterSnoopInstallRule(pl) < 0) {
+ VIR_FREE(pl);
+ return;
+ }
+ virNWFilterSnoopTimerAdd(pl);
+ virNWFilterSnoopState.nLeases++;
+ if (update_leasefile)
+ virNWFilterSnoopLeaseFileSave(pl);
+}
+
+/*
+ * virNWFilterSnoopListDel - remove an IP lease from a list
+ */
+static void
+virNWFilterSnoopListDel(struct virNWFilterSnoopIPLease *ipl,
+ struct virNWFilterSnoopIPLease **start,
+ struct virNWFilterSnoopIPLease **end)
+{
+ if (ipl->prev)
+ ipl->prev->next = ipl->next;
+ else
+ *start = ipl->next;
+ if (ipl->next)
+ ipl->next->prev = ipl->prev;
+ else
+ *end = ipl->prev;
+ ipl->next = ipl->prev = 0;
+}
+
+/*
+ * virNWFilterSnoopTimerDel - remove an IP lease from the timer list
+ */
+static void
+virNWFilterSnoopTimerDel(struct virNWFilterSnoopIPLease *ipl)
+{
+ struct virNWFilterSnoopReq *req = ipl->SnoopReq;
+
+ virNWFilterSnoopListDel(ipl, &req->start, &req->end);
+ ipl->Timeout = 0;
+}
+
+/*
+ * virNWFilterSnoopLeaseDel - delete an IP lease
+ */
+static void
+virNWFilterSnoopLeaseDel(struct virNWFilterSnoopReq *req,
+ uint32_t ipaddr, bool update_leasefile)
+{
+ struct virNWFilterSnoopIPLease *ipl;
+
+ ipl = virNWFilterSnoopGetByIP(req->start, ipaddr);
+ if (ipl == NULL)
+ return;
+
+ virNWFilterSnoopTimerDel(ipl);
+
+ if (update_leasefile) {
+ virNWFilterSnoopLeaseFileSave(ipl);
+
+ /*
+ * for multiple address support, this needs to remove those rules
+ * referencing "IP" with ipl's ip value.
+ */
+ if (req->techdriver->applyDHCPOnlyRules(req->ifname, req->macaddr,
+ NULL, false))
+ virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
+ _("virNWFilterSnoopListDel failed"));
+ }
+ VIR_FREE(ipl);
+ virNWFilterSnoopState.nLeases--;
+}
+
+/*
+ * virNWFilterSnoopUpdateLease - update the timeout on an IP lease
+ */
+static void
+virNWFilterSnoopUpdateLease(struct virNWFilterSnoopIPLease *ipl, time_t timeout)
+{
+ if (timeout < ipl->Timeout)
+ return; /* no take-backs */
+ virNWFilterSnoopTimerDel(ipl);
+ ipl->Timeout = timeout;
+ virNWFilterSnoopTimerAdd(ipl);
+ return;
+}
+
+/*
+ * virNWFilterSnoopGetByIP - lookup IP lease by IP address
+ */
+static struct virNWFilterSnoopIPLease *
+virNWFilterSnoopGetByIP(struct virNWFilterSnoopIPLease *start, uint32_t ipaddr)
+{
+ struct virNWFilterSnoopIPLease *pl;
+
+ for (pl = start; pl && pl->IPAddress != ipaddr; pl = pl->next)
+ /* empty */ ;
+ return pl;
+}
+
+/*
+ * virNWFilterSnoopTimerRun - run the IP lease timeout list
+ */
+static unsigned int
+virNWFilterSnoopTimerRun(struct virNWFilterSnoopReq *req)
+{
+ time_t now;
+
+ now = time(0);
+ while (req->start && req->start->Timeout <= now)
+ virNWFilterSnoopLeaseDel(req, req->start->IPAddress, 1);
+ return 0;
+}
+
+typedef unsigned char Eaddr[6];
+
+struct virNWFilterSnoopEthHdr {
+ Eaddr eh_dst;
+ Eaddr eh_src;
+ unsigned short eh_type;
+ union {
+ unsigned char eu_data[0];
+ struct vlan_hdr {
+ unsigned short ev_flags;
+ unsigned short ev_type;
+ unsigned char ev_data[0];
+ } eu_vlh;
+ } eth_un;
+} ATTRIBUTE_PACKED;
+
+#define eh_data eth_un.eu_data
+#define ehv_data eth_un.eu_vlh.ev_data
+#define ehv_type eth_un.eu_vlh.ev_type
+
+struct virNWFilterSnoopDHCPHdr {
+ unsigned char d_op;
+ unsigned char d_htype;
+ unsigned char d_hlen;
+ unsigned char d_hops;
+ unsigned int d_xid;
+ unsigned short d_secs;
+ unsigned short d_flags;
+ unsigned int d_ciaddr;
+ unsigned int d_yiaddr;
+ unsigned int d_siaddr;
+ unsigned int d_giaddr;
+ unsigned char d_chaddr[16];
+ char d_sname[64];
+ char d_file[128];
+ unsigned char d_opts[0];
+};
+
+/* DHCP options */
+
+#define DHCPO_PAD 0
+#define DHCPO_LEASE 51 /* lease time in secs */
+#define DHCPO_MTYPE 53 /* message type */
+#define DHCPO_END 255 /* end of options */
+
+/* DHCP message types */
+#define DHCPDECLINE 4
+#define DHCPACK 5
+#define DHCPRELEASE 7
+
+static const unsigned char dhcp_magic[4] = { 99, 130, 83, 99 };
+
+static int
+virNWFilterSnoopDHCPGetOpt(struct virNWFilterSnoopDHCPHdr *pd, int len,
+ int *pmtype, int *pleasetime)
+{
+ int oind, olen;
+ int oend;
+
+ olen = len - sizeof(*pd);
+ oind = 0;
+
+ if (olen < 4) /* bad magic */
+ return -1;
+ if (memcmp(dhcp_magic, pd->d_opts, sizeof(dhcp_magic)) != 0)
+ return -1; /* bad magic */
+ oind += sizeof(dhcp_magic);
+
+ oend = 0;
+
+ *pmtype = *pleasetime = 0;
+
+ while (oind < olen) {
+ switch (pd->d_opts[oind]) {
+ case DHCPO_LEASE:
+ if (olen - oind < 6)
+ goto malformed;
+ if (*pleasetime)
+ return -1; /* duplicate lease time */
+ *pleasetime =
+ ntohl(*(unsigned int *) (pd->d_opts + oind + 2));
+ break;
+ case DHCPO_MTYPE:
+ if (olen - oind < 3)
+ goto malformed;
+ if (*pmtype)
+ return -1; /* duplicate message type */
+ *pmtype = pd->d_opts[oind + 2];
+ break;
+ case DHCPO_PAD:
+ oind++;
+ continue;
+
+ case DHCPO_END:
+ oend = 1;
+ break;
+ default:
+ if (olen - oind < 2)
+ goto malformed;
+ }
+ if (oend)
+ break;
+ oind += pd->d_opts[oind + 1] + 2;
+ }
+ return 0;
+malformed:
+ VIR_WARN("got lost in the options!");
+ return -1;
+}
+
+static void
+virNWFilterSnoopDHCPDecode(struct virNWFilterSnoopReq *req,
+ struct virNWFilterSnoopEthHdr *pep,
+ int len)
+{
+ struct iphdr *pip;
+ struct udphdr *pup;
+ struct virNWFilterSnoopDHCPHdr *pd;
+ struct virNWFilterSnoopIPLease ipl;
+ int mtype, leasetime;
+
+ /* go through the protocol headers */
+ switch (ntohs(pep->eh_type)) {
+ case ETHERTYPE_IP:
+ pip = (struct iphdr *) pep->eh_data;
+ len -= offsetof(struct virNWFilterSnoopEthHdr, eh_data);
+ break;
+ case ETHERTYPE_VLAN:
+ if (ntohs(pep->ehv_type) != ETHERTYPE_IP)
+ return;
+ pip = (struct iphdr *) pep->ehv_data;
+ len -= offsetof(struct virNWFilterSnoopEthHdr, ehv_data);
+ break;
+ default:
+ return;
+ }
+ pip = (struct iphdr *) pep->eh_data;
+ len -= sizeof(*pep);
+ if (len < 0)
+ return;
+ pup = (struct udphdr *) ((char *) pip + (pip->ihl << 2));
+ len -= pip->ihl << 2;
+ if (len < 0)
+ return;
+ pd = (struct virNWFilterSnoopDHCPHdr *) ((char *) pup + sizeof(*pup));
+ len -= sizeof(*pup);
+ if (len < 0)
+ return; /* invalid packet length */
+ if (virNWFilterSnoopDHCPGetOpt(pd, len, &mtype, &leasetime) < 0)
+ return;
+
+ memset(&ipl, 0, sizeof(ipl));
+ ipl.IPAddress = pd->d_yiaddr;
+ ipl.IPServer = pd->d_siaddr;
+ if (leasetime == ~0)
+ ipl.Timeout = ~0;
+ else
+ ipl.Timeout = time(0) + leasetime;
+ ipl.SnoopReq = req;
+
+ switch (mtype) {
+ case DHCPACK:
+ virNWFilterSnoopLeaseAdd(&ipl, 1);
+ break;
+ case DHCPDECLINE:
+ case DHCPRELEASE:
+ virNWFilterSnoopLeaseDel(req, ipl.IPAddress, 1);
+ break;
+ default:
+ break;
+ }
+}
+
+#define PBUFSIZE 576 /* >= IP/TCP/DHCP headers */
+#define TIMEOUT 30 /* secs */
+
+static pcap_t *
+virNWFilterSnoopDHCPOpen(const char *intf)
+{
+ pcap_t *handle = NULL;
+ struct bpf_program fp;
+ char filter[64];
+ char pcap_errbuf[PCAP_ERRBUF_SIZE];
+ time_t start;
+
+ start = time(0);
+ while (handle == NULL && time(0) - start < TIMEOUT)
+ handle = pcap_open_live(intf, PBUFSIZE, 0, POLL_INTERVAL, pcap_errbuf);
+
+ if (handle == NULL) {
+ virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
+ _("pcap_open_live: %s"), pcap_errbuf);
+ return 0;
+ }
+
+ sprintf(filter, "port 67 or dst port 68");
+ if (pcap_compile(handle, &fp, filter, 1, PCAP_NETMASK_UNKNOWN) != 0) {
+ virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
+ _("pcap_compile: %s"), pcap_geterr(handle));
+ return 0;
+ }
+ if (pcap_setfilter(handle, &fp) != 0) {
+ virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
+ _("pcap_setfilter: %s"), pcap_geterr(handle));
+ pcap_freecode(&fp);
+ return 0;
+ }
+ pcap_freecode(&fp);
+ return handle;
+}
+
+static void
+virNWFilterSnoopReqFree(struct virNWFilterSnoopReq *req)
+{
+ struct virNWFilterSnoopIPLease *ipl;
+
+ if (!req)
+ return;
+
+ /* free all leases */
+ for (ipl = req->start; ipl; ipl = req->start)
+ virNWFilterSnoopLeaseDel(req, ipl->IPAddress, 0);
+
+ /* free all req data */
+ VIR_FREE(req->ifname);
+ VIR_FREE(req->linkdev);
+ VIR_FREE(req->filtername);
+ virNWFilterHashTableFree(req->vars);
+ VIR_FREE(req);
+}
+
+static void
+virNWFilterDHCPSnoop(void *req0)
+{
+ struct virNWFilterSnoopReq *req = req0;
+ pcap_t *handle;
+ struct pcap_pkthdr *hdr;
+ struct virNWFilterSnoopEthHdr *packet;
+ int ifindex;
+ int errcount;
+ char *threadkey;
+ virThread thread;
+
+ handle = virNWFilterSnoopDHCPOpen(req->ifname);
+ if (!handle)
+ return;
+
+ virThreadSelf(&thread);
+ req->threadkey = virNWFilterSnoopActivate(&thread);
+ threadkey = strdup(req->threadkey);
+ if (threadkey == NULL) {
+ virReportOOMError();
+ pcap_close(handle);
+ return;
+ }
+
+ ifindex = if_nametoindex(req->ifname);
+
+ virNWFilterSnoopLock();
+ virNWFilterSnoopLeaseFileRestore(req);
+ virNWFilterSnoopUnlock();
+
+ errcount = 0;
+ while (1) {
+ int rv;
+
+ virNWFilterSnoopLock();
+ virNWFilterSnoopTimerRun(req);
+ virNWFilterSnoopUnlock();
+
+ rv = pcap_next_ex(handle, &hdr, (const u_char **)&packet);
+
+ if (!virNWFilterSnoopIsActive(threadkey)) {
+ VIR_FREE(threadkey);
+ pcap_close(handle);
+ return;
+ }
+ if (rv < 0) {
+ if (virNetDevValidateConfig(req->ifname, NULL, ifindex) <= 0)
+ break;
+ if (++errcount > MAXERRS) {
+ virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
+ _("ifname \"%s\" failing; reopening"),
+ req->ifname);
+ pcap_close(handle);
+ handle = virNWFilterSnoopDHCPOpen(req->ifname);
+ if (!handle)
+ break;
+ }
+ continue;
+ }
+ errcount = 0;
+ if (rv) {
+ virNWFilterSnoopLock();
+ virNWFilterSnoopDHCPDecode(req, packet, hdr->caplen);
+ virNWFilterSnoopUnlock();
+ }
+ }
+ virNWFilterSnoopCancel(&req->threadkey);
+ (void) virHashRemoveEntry(virNWFilterSnoopState.IfnameToKey, req->ifname);
+ VIR_FREE(req->ifname);
+ /* if we still have a valid lease, keep the req for restarts */
+ if (!req->start || req->start->Timeout < time(0))
+ (void) virHashRemoveEntry(virNWFilterSnoopState.SnoopReqs, req->ifkey);
+ VIR_FREE(threadkey);
+ pcap_close(handle);
+ return;
+}
+
+static void
+virNWFilterSnoopIFKeyFMT(char *ifkey, const unsigned char *vmuuid,
+ unsigned const char *macaddr)
+{
+ virUUIDFormat(vmuuid, ifkey);
+ ifkey[VIR_UUID_STRING_BUFLEN-1] = '-';
+ virMacAddrFormat(macaddr, ifkey + VIR_UUID_STRING_BUFLEN);
+}
+
+int
+virNWFilterDHCPSnoopReq(virNWFilterTechDriverPtr techdriver,
+ const char *ifname,
+ const char *linkdev,
+ enum virDomainNetType nettype,
+ const unsigned char *vmuuid,
+ const unsigned char *macaddr,
+ const char *filtername,
+ virNWFilterHashTablePtr filterparams,
+ virNWFilterDriverStatePtr driver)
+{
+ struct virNWFilterSnoopReq *req;
+ bool isnewreq;
+ char ifkey[VIR_IFKEY_LEN];
+ virThread thread;
+
+ virNWFilterSnoopIFKeyFMT(ifkey, vmuuid, macaddr);
+ virNWFilterSnoopLock();
+ req = virHashLookup(virNWFilterSnoopState.SnoopReqs, ifkey);
+ isnewreq = req == NULL;
+ if (!isnewreq) {
+ if (req->threadkey) {
+ virNWFilterSnoopUnlock();
+ return 0;
+ }
+ } else {
+ req = virNWFilterSnoopNewReq(ifkey);
+ if (!req) {
+ virNWFilterSnoopUnlock();
+ return -1;
+ }
+ }
+
+ req->techdriver = techdriver;
+ req->ifindex = if_nametoindex(ifname);
+ req->linkdev = linkdev ? strdup(linkdev) : NULL;
+ req->nettype = nettype;
+ req->ifname = strdup(ifname);
+ memcpy(req->macaddr, macaddr, sizeof(req->macaddr));
+ req->filtername = strdup(filtername);
+ if (req->ifname == NULL || req->filtername == NULL) {
+ virNWFilterSnoopUnlock();
+ virNWFilterSnoopReqFree(req);
+ virReportOOMError();
+ return -1;
+ }
+
+ if (techdriver->applyDHCPOnlyRules(req->ifname, req->macaddr, NULL,
+ false)) {
+ virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, _("applyDHCPOnlyRules "
+ "failed - spoofing not protected!"));
+ }
+
+ req->vars = virNWFilterHashTableCreate(0);
+ if (!req->vars) {
+ virNWFilterSnoopUnlock();
+ virNWFilterSnoopReqFree(req);
+ virReportOOMError();
+ return -1;
+ }
+ if (virNWFilterHashTablePutAll(filterparams, req->vars)) {
+ virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
+ _("virNWFilterDHCPSnoopReq: can't copy variables"
+ " on if %s"), ifkey);
+ virNWFilterSnoopUnlock();
+ virNWFilterSnoopReqFree(req);
+ return -1;
+ }
+ req->driver = driver;
+
+ if (virHashAddEntry(virNWFilterSnoopState.IfnameToKey, ifname,
+ req->ifkey)) {
+ virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
+ _("virNWFilterDHCPSnoopReq ifname map failed"
+ " on interface \"%s\" key \"%s\""), ifname,
+ ifkey);
+ virNWFilterSnoopUnlock();
+ virNWFilterSnoopReqFree(req);
+ return -1;
+ }
+ if (isnewreq &&
+ virHashAddEntry(virNWFilterSnoopState.SnoopReqs, ifkey, req)) {
+ virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
+ _("virNWFilterDHCPSnoopReq req add failed on"
+ " interface \"%s\" ifkey \"%s\""), ifname,
+ ifkey);
+ (void) virHashRemoveEntry(virNWFilterSnoopState.IfnameToKey, ifname);
+ virNWFilterSnoopUnlock();
+ virNWFilterSnoopReqFree(req);
+ return -1;
+ }
+ virNWFilterSnoopUnlock();
+ if (virThreadCreate(&thread, false, virNWFilterDHCPSnoop, req) != 0) {
+ virNWFilterSnoopLock();
+ (void) virHashRemoveEntry(virNWFilterSnoopState.IfnameToKey, ifname);
+ (void) virHashRemoveEntry(virNWFilterSnoopState.SnoopReqs, ifkey);
+ virNWFilterSnoopUnlock();
+ virNWFilterSnoopReqFree(req);
+ virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
+ _("virNWFilterDHCPSnoopReq virThreadCreate "
+ "failed on interface \"%s\""), ifname);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * virNWFilterSnoopReqRelease - hash table free function to kill a request
+ */
+static void
+virNWFilterSnoopReqRelease(void *req0, const void *name ATTRIBUTE_UNUSED)
+{
+ struct virNWFilterSnoopReq *req = (struct virNWFilterSnoopReq *) req0;
+
+ if (!req)
+ return;
+
+ if (req->threadkey)
+ virNWFilterSnoopCancel(&req->threadkey);
+ virNWFilterSnoopReqFree(req);
+}
+
+static void
+virNWFilterSnoopLeaseFileClose(void)
+{
+ VIR_FORCE_CLOSE(virNWFilterSnoopState.LeaseFD);
+}
+
+static void
+virNWFilterSnoopLeaseFileOpen(void)
+{
+ virNWFilterSnoopLeaseFileClose();
+
+ virNWFilterSnoopState.LeaseFD = open(LEASEFILE, O_CREAT|O_RDWR|O_APPEND,
+ 0644);
+}
+
+int
+virNWFilterDHCPSnoopInit(void)
+{
+ if (virNWFilterSnoopState.SnoopReqs)
+ return 0;
+
+ virNWFilterSnoopLock();
+ virNWFilterSnoopState.IfnameToKey = virHashCreate(0, NULL);
+ virNWFilterSnoopState.SnoopReqs =
+ virHashCreate(0, virNWFilterSnoopReqRelease);
+ if (!virNWFilterSnoopState.IfnameToKey ||
+ !virNWFilterSnoopState.SnoopReqs) {
+ virNWFilterSnoopUnlock();
+ virReportOOMError();
+ goto errexit;
+ }
+ virNWFilterSnoopLeaseFileLoad();
+ virNWFilterSnoopLeaseFileOpen();
+
+ virNWFilterSnoopUnlock();
+
+ virNWFilterSnoopLockActive();
+ virNWFilterSnoopState.Active = virHashCreate(0, 0);
+ if (!virNWFilterSnoopState.Active) {
+ virNWFilterSnoopUnlockActive();
+ virReportOOMError();
+ goto errexit;
+ }
+ virNWFilterSnoopUnlockActive();
+ return 0;
+
+errexit:
+ if (virNWFilterSnoopState.IfnameToKey) {
+ virHashFree(virNWFilterSnoopState.IfnameToKey);
+ virNWFilterSnoopState.IfnameToKey = 0;
+ }
+ if (virNWFilterSnoopState.SnoopReqs) {
+ virHashFree(virNWFilterSnoopState.SnoopReqs);
+ virNWFilterSnoopState.SnoopReqs = 0;
+ }
+ if (virNWFilterSnoopState.Active) {
+ virHashFree(virNWFilterSnoopState.Active);
+ virNWFilterSnoopState.Active = 0;
+ }
+ return -1;
+}
+
+void
+virNWFilterDHCPSnoopEnd(const char *ifname)
+{
+ char *ifkey = NULL;
+
+ virNWFilterSnoopLock();
+ if (!virNWFilterSnoopState.SnoopReqs) {
+ virNWFilterSnoopUnlock();
+ return;
+ }
+
+ if (ifname) {
+ ifkey = (char *)virHashLookup(virNWFilterSnoopState.IfnameToKey,ifname);
+ (void) virHashRemoveEntry(virNWFilterSnoopState.IfnameToKey, ifname);
+ if (!ifkey) {
+ virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
+ _("ifname \"%s\" not in key map"), ifname);
+ virNWFilterSnoopUnlock();
+ return;
+ }
+ }
+
+ if (ifkey) {
+ struct virNWFilterSnoopReq *req;
+
+ req = virHashLookup(virNWFilterSnoopState.SnoopReqs, ifkey);
+ if (!req) {
+ virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
+ _("ifkey \"%s\" has no req"), ifkey);
+ virNWFilterSnoopUnlock();
+ return;
+ }
+ if (!req->start || req->start->Timeout < time(0)) {
+ (void) virHashRemoveEntry(virNWFilterSnoopState.SnoopReqs,
+ req->ifkey);
+ virNWFilterSnoopUnlock();
+ return;
+ }
+ /* keep valid lease req; drop interface association */
+ virNWFilterSnoopCancel(&req->threadkey);
+ VIR_FREE(req->ifname);
+ } else { /* free all of them */
+ virNWFilterSnoopLeaseFileClose();
+ virHashFree(virNWFilterSnoopState.IfnameToKey);
+ virHashFree(virNWFilterSnoopState.SnoopReqs);
+ virNWFilterSnoopState.IfnameToKey = virHashCreate(0, 0);
+ if (!virNWFilterSnoopState.IfnameToKey) {
+ virNWFilterSnoopUnlock();
+ virReportOOMError();
+ return;
+ }
+ virNWFilterSnoopState.SnoopReqs =
+ virHashCreate(0, virNWFilterSnoopReqRelease);
+ if (!virNWFilterSnoopState.SnoopReqs) {
+ virHashFree(virNWFilterSnoopState.IfnameToKey);
+ virNWFilterSnoopUnlock();
+ virReportOOMError();
+ return;
+ }
+ virNWFilterSnoopLeaseFileLoad();
+ }
+ virNWFilterSnoopUnlock();
+}
+
+static int
+virNWFilterSnoopLeaseFileWrite(int lfd, const char *ifkey,
+ struct virNWFilterSnoopIPLease *ipl)
+{
+ char lbuf[256], ipstr[INET_ADDRSTRLEN], dhcpstr[INET_ADDRSTRLEN];
+
+ if (inet_ntop(AF_INET, &ipl->IPAddress, ipstr, sizeof(ipstr)) == 0) {
+ virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
+ _("inet_ntop(0x%08X) failed"), ipl->IPAddress);
+ return -1;
+ }
+ if (inet_ntop(AF_INET, &ipl->IPServer, dhcpstr, sizeof(dhcpstr)) == 0) {
+ virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
+ _("inet_ntop(0x%08X) failed"), ipl->IPServer);
+ return -1;
+ }
+ /* time intf ip dhcpserver */
+ snprintf(lbuf, sizeof(lbuf), "%u %s %s %s\n", ipl->Timeout,
+ ifkey, ipstr, dhcpstr);
+ if (write(lfd, lbuf, strlen(lbuf)) < 0) {
+ virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
+ _("lease file write failed: %s"),
+ strerror(errno));
+ return -1;
+ }
+ (void) fsync(lfd);
+ return 0;
+}
+
+static void
+virNWFilterSnoopLeaseFileSave(struct virNWFilterSnoopIPLease *ipl)
+{
+ struct virNWFilterSnoopReq *req = ipl->SnoopReq;
+
+ if (virNWFilterSnoopState.LeaseFD < 0)
+ virNWFilterSnoopLeaseFileOpen();
+ if (virNWFilterSnoopLeaseFileWrite(virNWFilterSnoopState.LeaseFD,
+ req->ifkey, ipl) < 0)
+ return;
+ /* keep dead leases at < ~95% of file size */
+ if (++virNWFilterSnoopState.wLeases >= virNWFilterSnoopState.nLeases*20)
+ virNWFilterSnoopLeaseFileLoad(); /* load & refresh lease file */
+}
+
+static struct virNWFilterSnoopReq *
+virNWFilterSnoopNewReq(const char *ifkey)
+{
+ struct virNWFilterSnoopReq *req;
+
+ if (ifkey == NULL || strlen(ifkey) != VIR_IFKEY_LEN-1) {
+ virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
+ _("virNWFilterSnoopNewReq called with invalid "
+ "key \"%s\" (%d)"),
+ ifkey ? ifkey : "", strlen(ifkey));
+ return NULL;
+ }
+ if (VIR_ALLOC(req) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+ if (virStrcpyStatic(req->ifkey, ifkey) == NULL)
+ VIR_FREE(req);
+
+ return req;
+}
+
+static void
+virNWFilterSnoopSaveIter(void *payload,
+ const void *name ATTRIBUTE_UNUSED,
+ void *data)
+{
+ struct virNWFilterSnoopReq *req = payload;
+ int tfd = *(int *)data;
+ struct virNWFilterSnoopIPLease *ipl;
+
+ /* clean up orphaned, expired leases */
+ if (!req->threadkey) {
+ time_t now;
+
+ now = time(0);
+ for (ipl = req->start; ipl; ipl = ipl->next)
+ if (ipl->Timeout < now)
+ virNWFilterSnoopLeaseDel(req, ipl->IPAddress , 0);
+ if (!req->start) {
+ virNWFilterSnoopReqFree(req);
+ return;
+ }
+ }
+ for (ipl = req->start; ipl; ipl = ipl->next)
+ (void) virNWFilterSnoopLeaseFileWrite(tfd, req->ifkey, ipl);
+}
+
+static void
+virNWFilterSnoopLeaseFileRefresh(void)
+{
+ int tfd;
+
+ (void) unlink(TMPLEASEFILE);
+ /* lease file loaded, delete old one */
+ tfd = open(TMPLEASEFILE, O_CREAT|O_RDWR|O_TRUNC|O_EXCL, 0644);
+ if (tfd < 0) {
+ virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
+ _("open(\"%s\"): %s"),
+ TMPLEASEFILE, strerror(errno));
+ return;
+ }
+ if (virNWFilterSnoopState.SnoopReqs)
+ virHashForEach(virNWFilterSnoopState.SnoopReqs,
+ virNWFilterSnoopSaveIter, (void *)&tfd);
+ VIR_FORCE_CLOSE(tfd);
+ if (rename(TMPLEASEFILE, LEASEFILE) < 0) {
+ virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
+ _("rename(\"%s\", \"%s\"): %s"),
+ TMPLEASEFILE, LEASEFILE, strerror(errno));
+ (void) unlink(TMPLEASEFILE);
+ }
+ virNWFilterSnoopState.wLeases = 0;
+ virNWFilterSnoopLeaseFileOpen();
+}
+
+
+static void
+virNWFilterSnoopLeaseFileLoad(void)
+{
+ char line[256], ifkey[VIR_IFKEY_LEN], ipstr[INET_ADDRSTRLEN],
+ srvstr[INET_ADDRSTRLEN];
+ struct virNWFilterSnoopIPLease ipl;
+ struct virNWFilterSnoopReq *req;
+ time_t now;
+ FILE *fp;
+ int ln = 0;
+
+ fp = fopen(LEASEFILE, "r");
+ time(&now);
+ while (fp && fgets(line, sizeof(line), fp)) {
+ if (line[strlen(line)-1] != '\n') {
+ virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
+ _("virNWFilterSnoopLeaseFileLoad lease file "
+ "line %d corrupt"), ln);
+ break;
+ }
+ ln++;
+ /* key len 55 = "VMUUID"+'-'+"MAC" */
+ if (sscanf(line, "%u %55s %16s %16s", &ipl.Timeout,
+ ifkey, ipstr, srvstr) < 4) {
+ virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
+ _("virNWFilterSnoopLeaseFileLoad lease file "
+ "line %d corrupt"), ln);
+ break;
+ }
+ if (ipl.Timeout && ipl.Timeout < now)
+ continue;
+ req = virHashLookup(virNWFilterSnoopState.SnoopReqs, ifkey);
+ if (!req) {
+ req = virNWFilterSnoopNewReq(ifkey);
+ if (!req)
+ break;
+ if (virHashAddEntry(virNWFilterSnoopState.SnoopReqs, ifkey, req)) {
+ virNWFilterSnoopReqFree(req);
+ virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
+ _("virNWFilterSnoopLeaseFileLoad req add"
+ " failed on interface \"%s\""), ifkey);
+ continue;
+ }
+ }
+
+ if (inet_pton(AF_INET, ipstr, &ipl.IPAddress) <= 0) {
+ virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
+ _("line %d corrupt ipaddr \"%s\""),
+ ln, ipstr);
+ continue;
+ }
+ (void) inet_pton(AF_INET, srvstr, &ipl.IPServer);
+ ipl.SnoopReq = req;
+
+ if (ipl.Timeout)
+ virNWFilterSnoopLeaseAdd(&ipl, 0);
+ else
+ virNWFilterSnoopLeaseDel(req, ipl.IPAddress, 0);
+ }
+ if (fp != NULL)
+ (void) fclose(fp);
+ virNWFilterSnoopLeaseFileRefresh();
+}
+
+static void
+virNWFilterSnoopLeaseFileRestore(struct virNWFilterSnoopReq *req)
+{
+ struct virNWFilterSnoopIPLease *ipl;
+
+ for (ipl=req->start; ipl; ipl=ipl->next)
+ (void) virNWFilterSnoopInstallRule(ipl);
+}
+
+#else /* HAVE_LIBPCAP */
+int
+virNWFilterDHCPSnoopInit(void)
+{
+ return -1;
+}
+
+void
+virNWFilterDHCPSnoopEnd(const char *ifname ATTRIBUTE_UNUSED)
+{
+ return;
+}
+
+int
+virNWFilterDHCPSnoopReq(virNWFilterTechDriverPtr techdriver ATTRIBUTE_UNUSED,
+ const char *ifname ATTRIBUTE_UNUSED,
+ const char *linkdev ATTRIBUTE_UNUSED,
+ enum virDomainNetType nettype ATTRIBUTE_UNUSED,
+ char *vmuuid ATTRIBUTE_UNUSED,
+ const unsigned char *macaddr ATTRIBUTE_UNUSED,
+ const char *filtername ATTRIBUTE_UNUSED,
+ virNWFilterHashTablePtr filterparams ATTRIBUTE_UNUSED,
+ virNWFilterDriverStatePtr driver ATTRIBUTE_UNUSED)
+{
+ virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, _("libvirt was not compiled "
+ "with libpcap and \"ip_learning='dhcp'\" requires"
+ " it."));
+ return 1;
+}
+#endif /* HAVE_LIBPCAP */
diff --git a/src/nwfilter/nwfilter_dhcpsnoop.h b/src/nwfilter/nwfilter_dhcpsnoop.h
new file mode 100644
index 0000000..25500e2
--- /dev/null
+++ b/src/nwfilter/nwfilter_dhcpsnoop.h
@@ -0,0 +1,38 @@
+/*
+ * nwfilter_dhcpsnoop.h: support DHCP snooping for a VM on an interface
+ *
+ * Copyright (C) 2010 IBM Corp.
+ * Copyright (C) 2010 David L Stevens
+ *
+ * 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: David L Stevens <dlstevens(a)us.ibm.com>
+ */
+
+#ifndef __NWFILTER_DHCPSNOOP_H
+#define __NWFILTER_DHCPSNOOP_H
+
+int virNWFilterDHCPSnoopInit(void);
+int virNWFilterDHCPSnoopReq(virNWFilterTechDriverPtr techdriver,
+ const char *ifname,
+ const char *linkdev,
+ enum virDomainNetType nettype,
+ const unsigned char *vmuuid,
+ const unsigned char *macaddr,
+ const char *filtername,
+ virNWFilterHashTablePtr filterparams,
+ virNWFilterDriverStatePtr driver);
+void virNWFilterDHCPSnoopEnd(const char *ifname);
+#endif /* __NWFILTER_DHCPSNOOP_H */
diff --git a/src/nwfilter/nwfilter_driver.c b/src/nwfilter/nwfilter_driver.c
index ffb4b5d..d014a19 100644
--- a/src/nwfilter/nwfilter_driver.c
+++ b/src/nwfilter/nwfilter_driver.c
@@ -39,6 +39,7 @@
#include "nwfilter_gentech_driver.h"
#include "configmake.h"
+#include "nwfilter_dhcpsnoop.h"
#include "nwfilter_learnipaddr.h"
#define VIR_FROM_THIS VIR_FROM_NWFILTER
@@ -66,6 +67,8 @@ static int
nwfilterDriverStartup(int privileged) {
char *base = NULL;
+ if (virNWFilterDHCPSnoopInit() < 0)
+ return -1;
if (virNWFilterLearnInit() < 0)
return -1;
@@ -127,6 +130,7 @@ alloc_err_exit:
conf_init_err:
virNWFilterTechDriversShutdown();
+ virNWFilterDHCPSnoopEnd(0);
virNWFilterLearnShutdown();
return -1;
@@ -149,6 +153,7 @@ nwfilterDriverReload(void) {
conn = virConnectOpen("qemu:///system");
if (conn) {
+ virNWFilterDHCPSnoopEnd(0);
/* shut down all threads -- they will be restarted if necessary */
virNWFilterLearnThreadsTerminate(true);
@@ -203,6 +208,7 @@ nwfilterDriverShutdown(void) {
virNWFilterConfLayerShutdown();
virNWFilterTechDriversShutdown();
+ virNWFilterDHCPSnoopEnd(0);
virNWFilterLearnShutdown();
nwfilterDriverLock(driverState);
diff --git a/src/nwfilter/nwfilter_gentech_driver.c b/src/nwfilter/nwfilter_gentech_driver.c
index fc71e7b..07ae33c 100644
--- a/src/nwfilter/nwfilter_gentech_driver.c
+++ b/src/nwfilter/nwfilter_gentech_driver.c
@@ -32,6 +32,7 @@
#include "virterror_internal.h"
#include "nwfilter_gentech_driver.h"
#include "nwfilter_ebiptables_driver.h"
+#include "nwfilter_dhcpsnoop.h"
#include "nwfilter_learnipaddr.h"
#include "virnetdev.h"
#include "datatypes.h"
@@ -42,6 +43,8 @@
#define NWFILTER_STD_VAR_MAC "MAC"
#define NWFILTER_STD_VAR_IP "IP"
+#define NWFILTER_DFLT_LEARN "any"
+
static int _virNWFilterTeardownFilter(const char *ifname);
@@ -662,6 +665,9 @@ virNWFilterInstantiate(const unsigned char *vmuuid ATTRIBUTE_UNUSED,
void **ptrs = NULL;
int instantiate = 1;
char *buf;
+ virNWFilterVarValuePtr lv;
+ const char *learning;
+ bool reportIP = false;
virNWFilterHashTablePtr missing_vars = virNWFilterHashTableCreate(0);
if (!missing_vars) {
@@ -678,22 +684,47 @@ virNWFilterInstantiate(const unsigned char *vmuuid ATTRIBUTE_UNUSED,
if (rc < 0)
goto err_exit;
+ lv = virHashLookup(vars->hashTable, "ip_learning");
+ if (lv && lv->valType == NWFILTER_VALUE_TYPE_SIMPLE)
+ learning = lv->u.simple.value;
+ else
+ learning = NULL;
+
+ if (learning == NULL)
+ learning = NWFILTER_DFLT_LEARN;
+
if (virHashSize(missing_vars->hashTable) == 1) {
if (virHashLookup(missing_vars->hashTable,
NWFILTER_STD_VAR_IP) != NULL) {
- if (virNWFilterLookupLearnReq(ifindex) == NULL) {
- rc = virNWFilterLearnIPAddress(techdriver,
- ifname,
- ifindex,
- linkdev,
- nettype, macaddr,
- filter->name,
- vars, driver,
- DETECT_DHCP|DETECT_STATIC);
+ if (c_strcasecmp(learning, "none") == 0) { /* no learning */
+ reportIP = true;
+ goto err_unresolvable_vars;
}
- goto err_exit;
- }
- goto err_unresolvable_vars;
+ if (c_strcasecmp(learning, "dhcp") == 0) {
+ rc = virNWFilterDHCPSnoopReq(techdriver, ifname, linkdev,
+ nettype, vmuuid, macaddr,
+ filter->name, vars, driver);
+ goto err_exit;
+ } else if (c_strcasecmp(learning, "any") == 0) {
+ if (virNWFilterLookupLearnReq(ifindex) == NULL) {
+ rc = virNWFilterLearnIPAddress(techdriver,
+ ifname,
+ ifindex,
+ linkdev,
+ nettype, macaddr,
+ filter->name,
+ vars, driver,
+ DETECT_DHCP|DETECT_STATIC);
+ }
+ goto err_exit;
+ } else {
+ rc = -1;
+ virNWFilterReportError(VIR_ERR_PARSE_FAILED, _("filter '%s' "
+ "learning value '%s' invalid."),
+ filter->name, learning);
+ }
+ } else
+ goto err_unresolvable_vars;
} else if (virHashSize(missing_vars->hashTable) > 1) {
goto err_unresolvable_vars;
} else if (!forceWithPendingReq &&
@@ -761,7 +792,7 @@ err_exit:
err_unresolvable_vars:
- buf = virNWFilterPrintVars(missing_vars->hashTable, ", ", false, false);
+ buf = virNWFilterPrintVars(missing_vars->hashTable, ", ", false, reportIP);
if (buf) {
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
_("Cannot instantiate filter due to unresolvable "
@@ -1092,6 +1123,8 @@ _virNWFilterTeardownFilter(const char *ifname)
return -1;
}
+ virNWFilterDHCPSnoopEnd(ifname);
+
virNWFilterTerminateLearnReq(ifname);
if (virNWFilterLockIface(ifname) < 0)
--
1.7.6.5
12 years, 7 months
[libvirt] [PATCH] UML: may be typo
by MATSUDA, Daiki
I found typo in UML driver.
MATSUDA Daiki
--- libvirt-0.9.11/src/uml/uml_driver.c.orig 2012-04-09
11:56:47.105695476 +0900
+++ libvirt-0.9.11/src/uml/uml_driver.c 2012-04-09 11:56:56.653820665 +0900
@@ -249,7 +249,7 @@ umlIdentifyChrPTY(struct uml_driver *dri
{
int i;
- for (i = 0 ; i < dom->def->nserials; i++)
+ for (i = 0 ; i < dom->def->nconsoles; i++)
if (dom->def->consoles[i]->source.type == VIR_DOMAIN_CHR_TYPE_PTY)
if (umlIdentifyOneChrPTY(driver, dom,
dom->def->consoles[i], "con") < 0)
12 years, 7 months
[libvirt] [PATCH 1/2] nwfilter: move code for IP address map into separate file
by Stefan Berger
The goal of this patch is to prepare for support for multiple IP
addresses per interface in the DHCP snooping code.
Move the code for the IP address map that maps interface names to
IP addresses into their own file. Rename the functions on the way
but otherwise leave the code as-is. Initialize this new layer
separately before dependent layers (iplearning, dhcpsnooping)
and shut it down after them.
---
src/Makefile.am | 2
src/nwfilter/nwfilter_driver.c | 11 +-
src/nwfilter/nwfilter_gentech_driver.c | 5
src/nwfilter/nwfilter_ipaddrmap.c | 167
+++++++++++++++++++++++++++++++++
src/nwfilter/nwfilter_ipaddrmap.h | 38 +++++++
src/nwfilter/nwfilter_learnipaddr.c | 127 -------------------------
src/nwfilter/nwfilter_learnipaddr.h | 3
7 files changed, 222 insertions(+), 131 deletions(-)
Index: libvirt-acl/src/nwfilter/nwfilter_ipaddrmap.h
===================================================================
--- /dev/null
+++ libvirt-acl/src/nwfilter/nwfilter_ipaddrmap.h
@@ -0,0 +1,38 @@
+/*
+ * nwfilter_ipaddrmap.h: IP address map for mapping interfaces to their
+ * detected/expected IP addresses
+ *
+ * Copyright (C) 2010, 2012 IBM Corp.
+ *
+ * Author:
+ * Stefan Berger <stefanb(a)linux.vnet.ibm.com>
+ *
+ * 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
+ *
+ */
+
+#ifndef __VIR_NWFILTER_IPADDRMAP_H
+# define __VIR_NWFILTER_IPADDRMAP_H
+
+int virNWFilterIPAddrMapInit(void);
+void virNWFilterIPAddrMapShutdown(void);
+
+int virNWFilterIPAddrMapAddIPAddrForIfname(const char *ifname, char *addr);
+int virNWFilterIPAddrMapDelIPAddrForIfname(const char *ifname,
+ const char *ipaddr);
+virNWFilterVarValuePtr virNWFilterIPAddrMapGetIPAddrForIfname(
+ const char *ifname);
+
+#endif /* __VIR_NWFILTER_IPADDRMAP_H */
Index: libvirt-acl/src/Makefile.am
===================================================================
--- libvirt-acl.orig/src/Makefile.am
+++ libvirt-acl/src/Makefile.am
@@ -513,6 +513,8 @@ NWFILTER_DRIVER_SOURCES = \
nwfilter/nwfilter_dhcpsnoop.h \
nwfilter/nwfilter_ebiptables_driver.c \
nwfilter/nwfilter_ebiptables_driver.h \
+ nwfilter/nwfilter_ipaddrmap.c \
+ nwfilter/nwfilter_ipaddrmap.h \
nwfilter/nwfilter_learnipaddr.c \
nwfilter/nwfilter_learnipaddr.h
Index: libvirt-acl/src/nwfilter/nwfilter_driver.c
===================================================================
--- libvirt-acl.orig/src/nwfilter/nwfilter_driver.c
+++ libvirt-acl/src/nwfilter/nwfilter_driver.c
@@ -39,6 +39,7 @@
#include "nwfilter_gentech_driver.h"
#include "configmake.h"
+#include "nwfilter_ipaddrmap.h"
#include "nwfilter_dhcpsnoop.h"
#include "nwfilter_learnipaddr.h"
@@ -67,10 +68,12 @@ static int
nwfilterDriverStartup(int privileged) {
char *base = NULL;
- if (virNWFilterDHCPSnoopInit() < 0)
+ if (virNWFilterIPAddrMapInit() < 0)
return -1;
if (virNWFilterLearnInit() < 0)
- return -1;
+ goto err_exit_ipaddrmapshutdown;
+ if (virNWFilterDHCPSnoopInit() < 0)
+ goto err_exit_learnshutdown;
virNWFilterTechDriversInit(privileged);
@@ -131,7 +134,10 @@ alloc_err_exit:
conf_init_err:
virNWFilterTechDriversShutdown();
virNWFilterDHCPSnoopShutdown();
+err_exit_learnshutdown:
virNWFilterLearnShutdown();
+err_exit_ipaddrmapshutdown:
+ virNWFilterIPAddrMapShutdown();
return -1;
}
@@ -210,6 +216,7 @@ nwfilterDriverShutdown(void) {
virNWFilterTechDriversShutdown();
virNWFilterDHCPSnoopShutdown();
virNWFilterLearnShutdown();
+ virNWFilterIPAddrMapShutdown();
nwfilterDriverLock(driverState);
Index: libvirt-acl/src/nwfilter/nwfilter_gentech_driver.c
===================================================================
--- libvirt-acl.orig/src/nwfilter/nwfilter_gentech_driver.c
+++ libvirt-acl/src/nwfilter/nwfilter_gentech_driver.c
@@ -33,6 +33,7 @@
#include "nwfilter_gentech_driver.h"
#include "nwfilter_ebiptables_driver.h"
#include "nwfilter_dhcpsnoop.h"
+#include "nwfilter_ipaddrmap.h"
#include "nwfilter_learnipaddr.h"
#include "virnetdev.h"
#include "datatypes.h"
@@ -870,7 +871,7 @@ __virNWFilterInstantiateFilter(const uns
goto err_exit;
}
- ipaddr = virNWFilterGetIpAddrForIfname(ifname);
+ ipaddr = virNWFilterIPAddrMapGetIPAddrForIfname(ifname);
vars1 = virNWFilterCreateVarHashmap(str_macaddr, ipaddr);
if (!vars1) {
@@ -1132,7 +1133,7 @@ _virNWFilterTeardownFilter(const char *i
techdriver->allTeardown(ifname);
- virNWFilterDelIpAddrForIfname(ifname, NULL);
+ virNWFilterIPAddrMapDelIPAddrForIfname(ifname, NULL);
virNWFilterUnlockIface(ifname);
Index: libvirt-acl/src/nwfilter/nwfilter_ipaddrmap.c
===================================================================
--- /dev/null
+++ libvirt-acl/src/nwfilter/nwfilter_ipaddrmap.c
@@ -0,0 +1,167 @@
+/*
+ * nwfilter_ipaddrmap.c: IP address map for mapping interfaces to their
+ * detected/expected IP addresses
+ *
+ * Copyright (C) 2010, 2012 IBM Corp.
+ *
+ * Author:
+ * Stefan Berger <stefanb(a)linux.vnet.ibm.com>
+ *
+ * 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
+ */
+
+#include <config.h>
+
+#include "internal.h"
+
+#include "virterror_internal.h"
+#include "datatypes.h"
+#include "nwfilter_params.h"
+#include "nwfilter_ipaddrmap.h"
+
+#define VIR_FROM_THIS VIR_FROM_NWFILTER
+
+static virMutex ipAddressMapLock;
+static virNWFilterHashTablePtr ipAddressMap;
+
+
+/* Add an IP address to the list of IP addresses an interface is
+ * known to use. This function feeds the per-interface cache that
+ * is used to instantiate filters with variable '$IP'.
+ *
+ * @ifname: The name of the (tap) interface
+ * @addr: An IPv4 address in dotted decimal format that the (tap)
+ * interface is known to use.
+ *
+ * This function returns 0 on success, -1 otherwise
+ */
+int
+virNWFilterIPAddrMapAddIPAddrForIfname(const char *ifname, char *addr)
+{
+ int ret = -1;
+ virNWFilterVarValuePtr val;
+
+ virMutexLock(&ipAddressMapLock);
+
+ val = virHashLookup(ipAddressMap->hashTable, ifname);
+ if (!val) {
+ val = virNWFilterVarValueCreateSimple(addr);
+ if (!val) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ ret = virNWFilterHashTablePut(ipAddressMap, ifname, val, 1);
+ goto cleanup;
+ } else {
+ if (virNWFilterVarValueAddValue(val, addr) < 0)
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ virMutexUnlock(&ipAddressMapLock);
+
+ return ret;
+}
+
+/* Delete all or a specific IP address from an interface. After this
+ * call either all or the given IP address will not be associated
+ * with the interface anymore.
+ *
+ * @ifname: The name of the (tap) interface
+ * @addr: An IPv4 address in dotted decimal format that the (tap)
+ * interface is not using anymore; provide NULL to remove all IP
+ * addresses associated with the given interface
+ *
+ * This function returns the number of IP addresses that are still
+ * known to be associated with this interface, in case of an error
+ * -1 is returned. Error conditions are:
+ * - IP addresses is not known to be associated with the interface
+ */
+int
+virNWFilterIPAddrMapDelIPAddrForIfname(const char *ifname, const char
*ipaddr)
+{
+ int ret = -1;
+ virNWFilterVarValuePtr val = NULL;
+
+ virMutexLock(&ipAddressMapLock);
+
+ if (ipaddr != NULL) {
+ val = virHashLookup(ipAddressMap->hashTable, ifname);
+ if (val) {
+ if (virNWFilterVarValueGetCardinality(val) == 1 &&
+ STREQ(ipaddr,
+ virNWFilterVarValueGetNthValue(val, 0)))
+ goto remove_entry;
+ virNWFilterVarValueDelValue(val, ipaddr);
+ ret = virNWFilterVarValueGetCardinality(val);
+ }
+ } else {
+remove_entry:
+ /* remove whole entry */
+ val = virNWFilterHashTableRemoveEntry(ipAddressMap, ifname);
+ virNWFilterVarValueFree(val);
+ ret = 0;
+ }
+
+ virMutexUnlock(&ipAddressMapLock);
+
+ return ret;
+}
+
+/* Get the list of IP addresses known to be in use by an interface
+ *
+ * This function returns NULL in case no IP address is known to be
+ * associated with the interface, a virNWFilterVarValuePtr otherwise
+ * that then can contain one or multiple entries.
+ */
+virNWFilterVarValuePtr
+virNWFilterIPAddrMapGetIPAddrForIfname(const char *ifname)
+{
+ virNWFilterVarValuePtr res;
+
+ virMutexLock(&ipAddressMapLock);
+
+ res = virHashLookup(ipAddressMap->hashTable, ifname);
+
+ virMutexUnlock(&ipAddressMapLock);
+
+ return res;
+}
+
+int
+virNWFilterIPAddrMapInit(void)
+{
+ ipAddressMap = virNWFilterHashTableCreate(0);
+ if (!ipAddressMap) {
+ virReportOOMError();
+ return -1;
+ }
+
+ if (virMutexInit(&ipAddressMapLock) < 0) {
+ virNWFilterIPAddrMapShutdown();
+ return -1;
+ }
+
+ return 0;
+}
+
+void
+virNWFilterIPAddrMapShutdown(void)
+{
+ virNWFilterHashTableFree(ipAddressMap);
+ ipAddressMap = NULL;
+}
Index: libvirt-acl/src/nwfilter/nwfilter_learnipaddr.c
===================================================================
--- libvirt-acl.orig/src/nwfilter/nwfilter_learnipaddr.c
+++ libvirt-acl/src/nwfilter/nwfilter_learnipaddr.c
@@ -52,6 +52,7 @@
#include "conf/domain_conf.h"
#include "nwfilter_gentech_driver.h"
#include "nwfilter_ebiptables_driver.h"
+#include "nwfilter_ipaddrmap.h"
#include "nwfilter_learnipaddr.h"
#define VIR_FROM_THIS VIR_FROM_NWFILTER
@@ -118,9 +119,6 @@ struct ether_vlan_header
static virMutex pendingLearnReqLock;
static virHashTablePtr pendingLearnReq;
-static virMutex ipAddressMapLock;
-static virNWFilterHashTablePtr ipAddressMap;
-
static virMutex ifaceMapLock;
static virHashTablePtr ifaceLockMap;
@@ -310,113 +308,8 @@ virNWFilterDeregisterLearnReq(int ifinde
return res;
}
-/* Add an IP address to the list of IP addresses an interface is
- * known to use. This function feeds the per-interface cache that
- * is used to instantiate filters with variable '$IP'.
- *
- * @ifname: The name of the (tap) interface
- * @addr: An IPv4 address in dotted decimal format that the (tap)
- * interface is known to use.
- *
- * This function returns 0 on success, -1 otherwise
- */
-static int
-virNWFilterAddIpAddrForIfname(const char *ifname, char *addr)
-{
- int ret = -1;
- virNWFilterVarValuePtr val;
-
- virMutexLock(&ipAddressMapLock);
-
- val = virHashLookup(ipAddressMap->hashTable, ifname);
- if (!val) {
- val = virNWFilterVarValueCreateSimple(addr);
- if (!val) {
- virReportOOMError();
- goto cleanup;
- }
- ret = virNWFilterHashTablePut(ipAddressMap, ifname, val, 1);
- goto cleanup;
- } else {
- if (virNWFilterVarValueAddValue(val, addr) < 0)
- goto cleanup;
- }
-
- ret = 0;
-
-cleanup:
- virMutexUnlock(&ipAddressMapLock);
-
- return ret;
-}
#endif
-/* Delete all or a specific IP address from an interface. After this
- * call either all or the given IP address will not be associated
- * with the interface anymore.
- *
- * @ifname: The name of the (tap) interface
- * @addr: An IPv4 address in dotted decimal format that the (tap)
- * interface is not using anymore; provide NULL to remove all IP
- * addresses associated with the given interface
- *
- * This function returns the number of IP addresses that are still
- * known to be associated with this interface, in case of an error
- * -1 is returned. Error conditions are:
- * - IP addresses is not known to be associated with the interface
- */
-int
-virNWFilterDelIpAddrForIfname(const char *ifname, const char *ipaddr)
-{
- int ret = -1;
- virNWFilterVarValuePtr val = NULL;
-
- virMutexLock(&ipAddressMapLock);
-
- if (ipaddr != NULL) {
- val = virHashLookup(ipAddressMap->hashTable, ifname);
- if (val) {
- if (virNWFilterVarValueGetCardinality(val) == 1 &&
- STREQ(ipaddr,
- virNWFilterVarValueGetNthValue(val, 0)))
- goto remove_entry;
- virNWFilterVarValueDelValue(val, ipaddr);
- ret = virNWFilterVarValueGetCardinality(val);
- }
- } else {
-remove_entry:
- /* remove whole entry */
- val = virNWFilterHashTableRemoveEntry(ipAddressMap, ifname);
- virNWFilterVarValueFree(val);
- ret = 0;
- }
-
- virMutexUnlock(&ipAddressMapLock);
-
- return ret;
-}
-
-/* Get the list of IP addresses known to be in use by an interface
- *
- * This function returns NULL in case no IP address is known to be
- * associated with the interface, a virNWFilterVarValuePtr otherwise
- * that then can contain one or multiple entries.
- */
-virNWFilterVarValuePtr
-virNWFilterGetIpAddrForIfname(const char *ifname)
-{
- virNWFilterVarValuePtr res;
-
- virMutexLock(&ipAddressMapLock);
-
- res = virHashLookup(ipAddressMap->hashTable, ifname);
-
- virMutexUnlock(&ipAddressMapLock);
-
- return res;
-}
-
-
#ifdef HAVE_LIBPCAP
static void
@@ -699,7 +592,8 @@ learnIPAddressThread(void *arg)
char *inetaddr;
if ((inetaddr = virSocketAddrFormat(&sa)) != NULL) {
- if (virNWFilterAddIpAddrForIfname(req->ifname, inetaddr) < 0) {
+ if (virNWFilterIPAddrMapAddIPAddrForIfname(req->ifname,
+ inetaddr) < 0) {
VIR_ERROR(_("Failed to add IP address %s to IP address "
"cache for interface %s"), inetaddr,
req->ifname);
}
@@ -901,18 +795,6 @@ virNWFilterLearnInit(void) {
return -1;
}
- ipAddressMap = virNWFilterHashTableCreate(0);
- if (!ipAddressMap) {
- virReportOOMError();
- virNWFilterLearnShutdown();
- return -1;
- }
-
- if (virMutexInit(&ipAddressMapLock) < 0) {
- virNWFilterLearnShutdown();
- return -1;
- }
-
ifaceLockMap = virHashCreate(0, freeIfaceLock);
if (!ifaceLockMap) {
virNWFilterLearnShutdown();
@@ -954,9 +836,6 @@ virNWFilterLearnShutdown(void)
virHashFree(pendingLearnReq);
pendingLearnReq = NULL;
- virNWFilterHashTableFree(ipAddressMap);
- ipAddressMap = NULL;
-
virHashFree(ifaceLockMap);
ifaceLockMap = NULL;
}
Index: libvirt-acl/src/nwfilter/nwfilter_learnipaddr.h
===================================================================
--- libvirt-acl.orig/src/nwfilter/nwfilter_learnipaddr.h
+++ libvirt-acl/src/nwfilter/nwfilter_learnipaddr.h
@@ -65,9 +65,6 @@ int virNWFilterLearnIPAddress(virNWFilte
virNWFilterIPAddrLearnReqPtr virNWFilterLookupLearnReq(int ifindex);
int virNWFilterTerminateLearnReq(const char *ifname);
-int virNWFilterDelIpAddrForIfname(const char *ifname, const char *ipaddr);
-virNWFilterVarValuePtr virNWFilterGetIpAddrForIfname(const char *ifname);
-
int virNWFilterLockIface(const char *ifname) ATTRIBUTE_RETURN_CHECK;
void virNWFilterUnlockIface(const char *ifname);
12 years, 7 months