On 03/30/2012 03:07 PM, David L Stevens wrote:
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).
This is the 2nd version to patch on top of this v8. Some more testing
revealed a locking problem that I now fixed.
Cleanup some parts of the DHCP snooping v8 code addressing
- naming consistency
- memory leaks
- if-before-free not being necessary
- separate shutdown function (for avoiding a valgrind reporting memory leak)
- a compilation error ("%d", strlen())
- pass NULL for a pointer rather than 0
- use common exits where possible
- make 'make syntax-check' pass
- due to a locking bug resulting in a deadlock reworked the locking and
introduced a reference counter for the SnoopReq that must be held while
the 'req' variable is accessed; it resulred in finer grained locking with
the virNWFilterSnoopLock()
---
po/POTFILES.in | 1
src/nwfilter/nwfilter_dhcpsnoop.c | 360
+++++++++++++++++++++++++-------------
src/nwfilter/nwfilter_dhcpsnoop.h | 1
src/nwfilter/nwfilter_driver.c | 6
4 files changed, 246 insertions(+), 122 deletions(-)
Index: libvirt-acl/src/nwfilter/nwfilter_dhcpsnoop.c
===================================================================
--- libvirt-acl.orig/src/nwfilter/nwfilter_dhcpsnoop.c
+++ libvirt-acl/src/nwfilter/nwfilter_dhcpsnoop.c
@@ -59,6 +59,7 @@ static struct {
int LeaseFD;
int nLeases; /* number of active leases */
int wLeases; /* number of written leases */
+ int nThreads; /* number of running threads */
/* thread management */
virHashTablePtr SnoopReqs;
virHashTablePtr IfnameToKey;
@@ -67,23 +68,21 @@ static struct {
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() \
+#define virNWFilterSnoopActiveLock() \
{ virMutexLock(&virNWFilterSnoopState.ActiveLock); }
-#define virNWFilterSnoopUnlockActive() \
+#define virNWFilterSnoopActiveUnlock() \
{ virMutexUnlock(&virNWFilterSnoopState.ActiveLock); }
static char *
virNWFilterSnoopActivate(virThreadPtr thread)
{
- char *key, *data;
+ char *key;
unsigned long threadID = (unsigned long int)thread->thread;
if (virAsprintf(&key, "0x%0*lX", (int)sizeof(threadID)*2,
threadID) < 0) {
@@ -91,16 +90,11 @@ virNWFilterSnoopActivate(virThreadPtr th
return NULL;
}
- virNWFilterSnoopLockActive();
- data = strdup("1");
- if (data == NULL) {
- virReportOOMError();
- VIR_FREE(key);
- } else if (virHashAddEntry(virNWFilterSnoopState.Active, key, data)) {
+ virNWFilterSnoopActiveLock();
+ if (virHashAddEntry(virNWFilterSnoopState.Active, key, (void *)0x1)) {
VIR_FREE(key);
- VIR_FREE(data);
}
- virNWFilterSnoopUnlockActive();
+ virNWFilterSnoopActiveUnlock();
return key;
}
@@ -110,10 +104,10 @@ virNWFilterSnoopCancel(char **ThreadKey)
if (*ThreadKey == NULL)
return;
- virNWFilterSnoopLockActive();
+ virNWFilterSnoopActiveLock();
(void) virHashRemoveEntry(virNWFilterSnoopState.Active, *ThreadKey);
- *ThreadKey = NULL;
- virNWFilterSnoopUnlockActive();
+ VIR_FREE(*ThreadKey);
+ virNWFilterSnoopActiveUnlock();
}
static bool
@@ -123,15 +117,18 @@ virNWFilterSnoopIsActive(char *ThreadKey
if (ThreadKey == NULL)
return 0;
- virNWFilterSnoopLockActive();
+
+ virNWFilterSnoopActiveLock();
entry = virHashLookup(virNWFilterSnoopState.Active, ThreadKey);
- virNWFilterSnoopUnlockActive();
+ virNWFilterSnoopActiveUnlock();
+
return entry != NULL;
}
#define VIR_IFKEY_LEN ((VIR_UUID_STRING_BUFLEN) +
(VIR_MAC_STRING_BUFLEN))
struct virNWFilterSnoopReq {
+ unsigned int refctr;
virNWFilterTechDriverPtr techdriver;
const char *ifname;
int ifindex;
@@ -168,6 +165,7 @@ static void virNWFilterSnoopUpdateLease(
time_t timeout);
static struct virNWFilterSnoopReq *virNWFilterSnoopNewReq(const char
*ifkey);
+static void virNWFilterSnoopReqRelease(void *req0, const void *name
ATTRIBUTE_UNUSED);
static void virNWFilterSnoopLeaseFileOpen(void);
static void virNWFilterSnoopLeaseFileClose(void);
@@ -176,6 +174,56 @@ static void virNWFilterSnoopLeaseFileSav
static void virNWFilterSnoopLeaseFileRestore(struct
virNWFilterSnoopReq *req);
static void virNWFilterSnoopLeaseFileRefresh(void);
+static void
+virNWFilterSnoopReqGet(struct virNWFilterSnoopReq *req)
+{
+ req->refctr++;
+}
+
+static struct virNWFilterSnoopReq *
+virNWFilterSnoopReqGetByKey(const char *ifkey)
+{
+ struct virNWFilterSnoopReq *req;
+
+ virNWFilterSnoopLock();
+
+ req = virHashLookup(virNWFilterSnoopState.SnoopReqs, ifkey);
+ if (req)
+ virNWFilterSnoopReqGet(req);
+
+ virNWFilterSnoopUnlock();
+
+ return req;
+}
+
+static void
+virNWFilterSnoopReqPut(struct virNWFilterSnoopReq *req)
+{
+ if (!req)
+ return;
+
+ virNWFilterSnoopLock()
+
+ req->refctr--;
+
+ if (req->refctr == 0) {
+ /*
+ * delete the request:
+ * - if we don't find it on the global list anymore
+ * we would keep the request:
+ * - if we still have a valid lease, keep the req for restarts
+ */
+ if (virHashLookup(virNWFilterSnoopState.SnoopReqs, req->ifkey)
!= req) {
+ virNWFilterSnoopReqRelease(req, NULL);
+ } else if (!req->start || req->start->Timeout < time(0)) {
+ (void) virHashRemoveEntry(virNWFilterSnoopState.SnoopReqs,
+ req->ifkey);
+ }
+ }
+
+ virNWFilterSnoopUnlock();
+}
+
/*
* virNWFilterSnoopListAdd - add an IP lease to a list
*/
@@ -297,7 +345,11 @@ virNWFilterSnoopLeaseAdd(struct virNWFil
return;
}
virNWFilterSnoopTimerAdd(pl);
+
+ virNWFilterSnoopLock();
virNWFilterSnoopState.nLeases++;
+ virNWFilterSnoopUnlock();
+
if (update_leasefile)
virNWFilterSnoopLeaseFileSave(pl);
}
@@ -361,7 +413,10 @@ virNWFilterSnoopLeaseDel(struct virNWFil
_("virNWFilterSnoopListDel failed"));
}
VIR_FREE(ipl);
+
+ virNWFilterSnoopLock();
virNWFilterSnoopState.nLeases--;
+ virNWFilterSnoopUnlock();
}
/*
@@ -624,6 +679,9 @@ virNWFilterSnoopReqFree(struct virNWFilt
if (!req)
return;
+ if (req->refctr != 0)
+ return;
+
/* free all leases */
for (ipl = req->start; ipl; ipl = req->start)
virNWFilterSnoopLeaseDel(req, ipl->IPAddress, 0);
@@ -633,6 +691,7 @@ virNWFilterSnoopReqFree(struct virNWFilt
VIR_FREE(req->linkdev);
VIR_FREE(req->filtername);
virNWFilterHashTableFree(req->vars);
+
VIR_FREE(req);
}
@@ -645,43 +704,38 @@ virNWFilterDHCPSnoop(void *req0)
struct virNWFilterSnoopEthHdr *packet;
int ifindex;
int errcount;
- char *threadkey;
+ char *threadkey = NULL;
virThread thread;
+ /* the thread starting us increased the reference counter for the
req */
+
handle = virNWFilterSnoopDHCPOpen(req->ifname);
if (!handle)
- return;
+ goto exit;
virThreadSelf(&thread);
req->threadkey = virNWFilterSnoopActivate(&thread);
threadkey = strdup(req->threadkey);
if (threadkey == NULL) {
virReportOOMError();
- pcap_close(handle);
- return;
+ goto exit;
}
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 (!virNWFilterSnoopIsActive(threadkey))
+ goto exit;
+
if (rv < 0) {
if (virNetDevValidateConfig(req->ifname, NULL, ifindex) <= 0)
break;
@@ -697,20 +751,31 @@ virNWFilterDHCPSnoop(void *req0)
continue;
}
errcount = 0;
- if (rv) {
- virNWFilterSnoopLock();
+ if (rv)
virNWFilterSnoopDHCPDecode(req, packet, hdr->caplen);
- virNWFilterSnoopUnlock();
- }
}
virNWFilterSnoopCancel(&req->threadkey);
+
+ virNWFilterSnoopLock();
+
(void) virHashRemoveEntry(virNWFilterSnoopState.IfnameToKey,
req->ifname);
+
+ virNWFilterSnoopUnlock();
+
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);
+
+exit:
+ virNWFilterSnoopReqPut(req);
+
VIR_FREE(threadkey);
- pcap_close(handle);
+
+ if (handle)
+ pcap_close(handle);
+
+ virNWFilterSnoopLock();
+ virNWFilterSnoopState.nThreads--;
+ virNWFilterSnoopUnlock();
+
return;
}
@@ -740,22 +805,23 @@ virNWFilterDHCPSnoopReq(virNWFilterTechD
virThread thread;
virNWFilterSnoopIFKeyFMT(ifkey, vmuuid, macaddr);
- virNWFilterSnoopLock();
- req = virHashLookup(virNWFilterSnoopState.SnoopReqs, ifkey);
- isnewreq = req == NULL;
+
+ req = virNWFilterSnoopReqGetByKey(ifkey);
+ isnewreq = (req == NULL);
if (!isnewreq) {
if (req->threadkey) {
- virNWFilterSnoopUnlock();
+ virNWFilterSnoopReqPut(req);
return 0;
}
} else {
req = virNWFilterSnoopNewReq(ifkey);
- if (!req) {
- virNWFilterSnoopUnlock();
+ if (!req)
return -1;
- }
+
+ virNWFilterSnoopReqGet(req);
}
+ req->driver = driver;
req->techdriver = techdriver;
req->ifindex = if_nametoindex(ifname);
req->linkdev = linkdev ? strdup(linkdev) : NULL;
@@ -763,11 +829,10 @@ virNWFilterDHCPSnoopReq(virNWFilterTechD
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;
+ goto exit_snoopreqput;
}
if (techdriver->applyDHCPOnlyRules(req->ifname, req->macaddr, NULL,
@@ -778,20 +843,18 @@ virNWFilterDHCPSnoopReq(virNWFilterTechD
req->vars = virNWFilterHashTableCreate(0);
if (!req->vars) {
- virNWFilterSnoopUnlock();
- virNWFilterSnoopReqFree(req);
virReportOOMError();
- return -1;
+ goto exit_snoopreqput;
}
+
if (virNWFilterHashTablePutAll(filterparams, req->vars)) {
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
_("virNWFilterDHCPSnoopReq: can't copy
variables"
" on if %s"), ifkey);
- virNWFilterSnoopUnlock();
- virNWFilterSnoopReqFree(req);
- return -1;
+ goto exit_snoopreqput;
}
- req->driver = driver;
+
+ virNWFilterSnoopLock();
if (virHashAddEntry(virNWFilterSnoopState.IfnameToKey, ifname,
req->ifkey)) {
@@ -799,9 +862,7 @@ virNWFilterDHCPSnoopReq(virNWFilterTechD
_("virNWFilterDHCPSnoopReq ifname map
failed"
" on interface \"%s\" key
\"%s\""),
ifname,
ifkey);
- virNWFilterSnoopUnlock();
- virNWFilterSnoopReqFree(req);
- return -1;
+ goto exit_snoopunlock;
}
if (isnewreq &&
virHashAddEntry(virNWFilterSnoopState.SnoopReqs, ifkey, req)) {
@@ -810,23 +871,30 @@ virNWFilterDHCPSnoopReq(virNWFilterTechD
" interface \"%s\" ifkey
\"%s\""), ifname,
ifkey);
(void) virHashRemoveEntry(virNWFilterSnoopState.IfnameToKey,
ifname);
- virNWFilterSnoopUnlock();
- virNWFilterSnoopReqFree(req);
- return -1;
+ goto exit_snoopunlock;
}
- virNWFilterSnoopUnlock();
+
+ virNWFilterSnoopState.nThreads++;
+
if (virThreadCreate(&thread, false, virNWFilterDHCPSnoop, req) != 0) {
- virNWFilterSnoopLock();
+ virNWFilterSnoopState.nThreads--;
(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;
+ goto exit_snoopunlock;
}
+
+ virNWFilterSnoopUnlock();
+
return 0;
+
+exit_snoopunlock:
+ virNWFilterSnoopUnlock();
+exit_snoopreqput:
+ virNWFilterSnoopReqPut(req);
+
+ return -1;
}
/*
@@ -842,6 +910,7 @@ virNWFilterSnoopReqRelease(void *req0, c
if (req->threadkey)
virNWFilterSnoopCancel(&req->threadkey);
+
virNWFilterSnoopReqFree(req);
}
@@ -863,13 +932,21 @@ virNWFilterSnoopLeaseFileOpen(void)
int
virNWFilterDHCPSnoopInit(void)
{
- if (virNWFilterSnoopState.SnoopReqs)
+ if (virNWFilterSnoopState.SnoopReqs) {
return 0;
+ }
+
+ if (virMutexInitRecursive(&virNWFilterSnoopState.SnoopLock) < 0)
+ return -1;
+ if (virMutexInit(&virNWFilterSnoopState.ActiveLock) < 0)
+ return -1;
virNWFilterSnoopLock();
+
virNWFilterSnoopState.IfnameToKey = virHashCreate(0, NULL);
virNWFilterSnoopState.SnoopReqs =
virHashCreate(0, virNWFilterSnoopReqRelease);
+
if (!virNWFilterSnoopState.IfnameToKey ||
!virNWFilterSnoopState.SnoopReqs) {
virNWFilterSnoopUnlock();
@@ -881,29 +958,28 @@ virNWFilterDHCPSnoopInit(void)
virNWFilterSnoopUnlock();
- virNWFilterSnoopLockActive();
- virNWFilterSnoopState.Active = virHashCreate(0, 0);
+ virNWFilterSnoopActiveLock();
+
+ virNWFilterSnoopState.Active = virHashCreate(0, NULL);
if (!virNWFilterSnoopState.Active) {
- virNWFilterSnoopUnlockActive();
+ virNWFilterSnoopActiveUnlock();
virReportOOMError();
goto errexit;
}
- virNWFilterSnoopUnlockActive();
+ virNWFilterSnoopActiveUnlock();
+
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;
- }
+ virHashFree(virNWFilterSnoopState.IfnameToKey);
+ virNWFilterSnoopState.IfnameToKey = NULL;
+
+ virHashFree(virNWFilterSnoopState.SnoopReqs);
+ virNWFilterSnoopState.SnoopReqs = NULL;
+
+ virHashFree(virNWFilterSnoopState.Active);
+ virNWFilterSnoopState.Active = NULL;
+
return -1;
}
@@ -913,64 +989,87 @@ virNWFilterDHCPSnoopEnd(const char *ifna
char *ifkey = NULL;
virNWFilterSnoopLock();
- if (!virNWFilterSnoopState.SnoopReqs) {
- virNWFilterSnoopUnlock();
- return;
- }
+ if (!virNWFilterSnoopState.SnoopReqs)
+ goto cleanup;
if (ifname) {
- ifkey = (char
*)virHashLookup(virNWFilterSnoopState.IfnameToKey,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;
+ goto cleanup;
}
}
if (ifkey) {
struct virNWFilterSnoopReq *req;
- req = virHashLookup(virNWFilterSnoopState.SnoopReqs, ifkey);
+ req = virNWFilterSnoopReqGetByKey(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;
+ goto cleanup;
}
/* keep valid lease req; drop interface association */
virNWFilterSnoopCancel(&req->threadkey);
+
VIR_FREE(req->ifname);
+
+ virNWFilterSnoopReqPut(req);
} else { /* free all of them */
virNWFilterSnoopLeaseFileClose();
virHashFree(virNWFilterSnoopState.IfnameToKey);
virHashFree(virNWFilterSnoopState.SnoopReqs);
- virNWFilterSnoopState.IfnameToKey = virHashCreate(0, 0);
+ virNWFilterSnoopState.IfnameToKey = virHashCreate(0, NULL);
if (!virNWFilterSnoopState.IfnameToKey) {
- virNWFilterSnoopUnlock();
virReportOOMError();
- return;
+ goto cleanup;
}
virNWFilterSnoopState.SnoopReqs =
virHashCreate(0, virNWFilterSnoopReqRelease);
if (!virNWFilterSnoopState.SnoopReqs) {
virHashFree(virNWFilterSnoopState.IfnameToKey);
- virNWFilterSnoopUnlock();
virReportOOMError();
- return;
+ goto cleanup;
}
virNWFilterSnoopLeaseFileLoad();
}
+
+cleanup:
virNWFilterSnoopUnlock();
}
+void
+virNWFilterDHCPSnoopShutdown(void)
+{
+ /*
+ * free the SnoopReqs before the 'Active' hash since this will already
+ * clear some of the key / value pairs in the Active hash.
+ */
+
+ virNWFilterSnoopLock();
+
+ virNWFilterSnoopLeaseFileClose();
+ virHashFree(virNWFilterSnoopState.IfnameToKey);
+ virHashFree(virNWFilterSnoopState.SnoopReqs);
+
+ virNWFilterSnoopUnlock();
+
+ virNWFilterSnoopActiveLock();
+ virHashFree(virNWFilterSnoopState.Active);
+ virNWFilterSnoopActiveUnlock();
+
+ while (1) {
+ if (virNWFilterSnoopState.nThreads == 0)
+ break;
+
+ VIR_WARN("Waiting for snooping threads to terminate\n");
+ usleep(1000 * 1000);
+ }
+}
+
static int
virNWFilterSnoopLeaseFileWrite(int lfd, const char *ifkey,
struct virNWFilterSnoopIPLease *ipl)
@@ -990,7 +1089,7 @@ virNWFilterSnoopLeaseFileWrite(int lfd,
/* 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) {
+ if (safewrite(lfd, lbuf, strlen(lbuf)) != strlen(lbuf)) {
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
_("lease file write failed: %s"),
strerror(errno));
@@ -1005,14 +1104,20 @@ virNWFilterSnoopLeaseFileSave(struct vir
{
struct virNWFilterSnoopReq *req = ipl->SnoopReq;
+ virNWFilterSnoopLock();
+
if (virNWFilterSnoopState.LeaseFD < 0)
- virNWFilterSnoopLeaseFileOpen();
+ virNWFilterSnoopLeaseFileOpen();
if (virNWFilterSnoopLeaseFileWrite(virNWFilterSnoopState.LeaseFD,
- req->ifkey, ipl) < 0)
- return;
+ req->ifkey, ipl) < 0) {
+ virNWFilterSnoopUnlock();
+ return;
+ }
/* keep dead leases at < ~95% of file size */
- if (++virNWFilterSnoopState.wLeases >=
virNWFilterSnoopState.nLeases*20)
+ if (++virNWFilterSnoopState.wLeases >=
virNWFilterSnoopState.nLeases * 20)
virNWFilterSnoopLeaseFileLoad(); /* load & refresh lease file */
+
+ virNWFilterSnoopUnlock();
}
static struct virNWFilterSnoopReq *
@@ -1023,14 +1128,17 @@ virNWFilterSnoopNewReq(const char *ifkey
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));
+ "key \"%s\" (%u)"),
+ ifkey ? ifkey : "",
+ (unsigned int)strlen(ifkey));
return NULL;
}
+
if (VIR_ALLOC(req) < 0) {
virReportOOMError();
return NULL;
}
+
if (virStrcpyStatic(req->ifkey, ifkey) == NULL)
VIR_FREE(req);
@@ -1077,6 +1185,9 @@ virNWFilterSnoopLeaseFileRefresh(void)
TMPLEASEFILE, strerror(errno));
return;
}
+
+ virNWFilterSnoopLock();
+
if (virNWFilterSnoopState.SnoopReqs)
virHashForEach(virNWFilterSnoopState.SnoopReqs,
virNWFilterSnoopSaveIter, (void *)&tfd);
@@ -1089,6 +1200,8 @@ virNWFilterSnoopLeaseFileRefresh(void)
}
virNWFilterSnoopState.wLeases = 0;
virNWFilterSnoopLeaseFileOpen();
+
+ virNWFilterSnoopUnlock();
}
@@ -1101,7 +1214,7 @@ virNWFilterSnoopLeaseFileLoad(void)
struct virNWFilterSnoopReq *req;
time_t now;
FILE *fp;
- int ln = 0;
+ int ln = 0, tmp;
fp = fopen(LEASEFILE, "r");
time(&now);
@@ -1123,13 +1236,20 @@ virNWFilterSnoopLeaseFileLoad(void)
}
if (ipl.Timeout && ipl.Timeout < now)
continue;
- req = virHashLookup(virNWFilterSnoopState.SnoopReqs, ifkey);
+ req = virNWFilterSnoopReqGetByKey(ifkey);
if (!req) {
req = virNWFilterSnoopNewReq(ifkey);
if (!req)
break;
- if (virHashAddEntry(virNWFilterSnoopState.SnoopReqs, ifkey,
req)) {
- virNWFilterSnoopReqFree(req);
+
+ virNWFilterSnoopReqGet(req);
+
+ virNWFilterSnoopLock();
+ tmp = virHashAddEntry(virNWFilterSnoopState.SnoopReqs,
ifkey, req);
+ virNWFilterSnoopUnlock();
+
+ if (tmp) {
+ virNWFilterSnoopReqPut(req);
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
_("virNWFilterSnoopLeaseFileLoad req add"
" failed on interface
\"%s\""), ifkey);
@@ -1141,6 +1261,7 @@ virNWFilterSnoopLeaseFileLoad(void)
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
_("line %d corrupt ipaddr
\"%s\""),
ln, ipstr);
+ virNWFilterSnoopReqPut(req);
continue;
}
(void) inet_pton(AF_INET, srvstr, &ipl.IPServer);
@@ -1150,10 +1271,13 @@ virNWFilterSnoopLeaseFileLoad(void)
virNWFilterSnoopLeaseAdd(&ipl, 0);
else
virNWFilterSnoopLeaseDel(req, ipl.IPAddress, 0);
+
+ virNWFilterSnoopReqPut(req);
}
if (fp != NULL)
(void) fclose(fp);
virNWFilterSnoopLeaseFileRefresh();
+
}
static void
@@ -1192,6 +1316,6 @@ virNWFilterDHCPSnoopReq(virNWFilterTechD
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, _("libvirt was not
compiled "
"with libpcap and
\"ip_learning='dhcp'\"
requires"
" it."));
- return 1;
+ return -1;
}
#endif /* HAVE_LIBPCAP */
Index: libvirt-acl/src/nwfilter/nwfilter_dhcpsnoop.h
===================================================================
--- libvirt-acl.orig/src/nwfilter/nwfilter_dhcpsnoop.h
+++ libvirt-acl/src/nwfilter/nwfilter_dhcpsnoop.h
@@ -25,6 +25,7 @@
#define __NWFILTER_DHCPSNOOP_H
int virNWFilterDHCPSnoopInit(void);
+void virNWFilterDHCPSnoopShutdown(void);
int virNWFilterDHCPSnoopReq(virNWFilterTechDriverPtr techdriver,
const char *ifname,
const char *linkdev,
Index: libvirt-acl/src/nwfilter/nwfilter_driver.c
===================================================================
--- libvirt-acl.orig/src/nwfilter/nwfilter_driver.c
+++ libvirt-acl/src/nwfilter/nwfilter_driver.c
@@ -130,7 +130,7 @@ alloc_err_exit:
conf_init_err:
virNWFilterTechDriversShutdown();
- virNWFilterDHCPSnoopEnd(0);
+ virNWFilterDHCPSnoopShutdown();
virNWFilterLearnShutdown();
return -1;
@@ -153,7 +153,7 @@ nwfilterDriverReload(void) {
conn = virConnectOpen("qemu:///system");
if (conn) {
- virNWFilterDHCPSnoopEnd(0);
+ virNWFilterDHCPSnoopEnd(NULL);
/* shut down all threads -- they will be restarted if necessary */
virNWFilterLearnThreadsTerminate(true);
@@ -208,7 +208,7 @@ nwfilterDriverShutdown(void) {
virNWFilterConfLayerShutdown();
virNWFilterTechDriversShutdown();
- virNWFilterDHCPSnoopEnd(0);
+ virNWFilterDHCPSnoopShutdown();
virNWFilterLearnShutdown();
nwfilterDriverLock(driverState);
Index: libvirt-acl/po/POTFILES.in
===================================================================
--- libvirt-acl.orig/po/POTFILES.in
+++ libvirt-acl/po/POTFILES.in
@@ -52,7 +52,6 @@ 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