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).
I'd accept it with the following changes merged in:
Cleanup some parts of the DHCP snooping v8 code addressing
- naming consistency
- memory leak
- if-before-free not being necessary
- separate shutdown function (for avoiding 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
Regards,
Stefan
---
po/POTFILES.in | 1
src/nwfilter/nwfilter_dhcpsnoop.c | 154
++++++++++++++++++++------------------
src/nwfilter/nwfilter_dhcpsnoop.h | 1
src/nwfilter/nwfilter_driver.c | 6 -
4 files changed, 87 insertions(+), 75 deletions(-)
Index: libvirt-acl/src/nwfilter/nwfilter_dhcpsnoop.c
===================================================================
--- libvirt-acl.orig/src/nwfilter/nwfilter_dhcpsnoop.c
+++ libvirt-acl/src/nwfilter/nwfilter_dhcpsnoop.c
@@ -75,15 +75,15 @@ static struct {
{ 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 +91,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 +105,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,9 +118,9 @@ virNWFilterSnoopIsActive(char *ThreadKey
if (ThreadKey == NULL)
return 0;
- virNWFilterSnoopLockActive();
+ virNWFilterSnoopActiveLock();
entry = virHashLookup(virNWFilterSnoopState.Active, ThreadKey);
- virNWFilterSnoopUnlockActive();
+ virNWFilterSnoopActiveUnlock();
return entry != NULL;
}
@@ -740,7 +735,9 @@ virNWFilterDHCPSnoopReq(virNWFilterTechD
virThread thread;
virNWFilterSnoopIFKeyFMT(ifkey, vmuuid, macaddr);
+
virNWFilterSnoopLock();
+
req = virHashLookup(virNWFilterSnoopState.SnoopReqs, ifkey);
isnewreq = req == NULL;
if (!isnewreq) {
@@ -763,11 +760,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 err_exit;
}
if (techdriver->applyDHCPOnlyRules(req->ifname, req->macaddr, NULL,
@@ -778,18 +774,14 @@ virNWFilterDHCPSnoopReq(virNWFilterTechD
req->vars = virNWFilterHashTableCreate(0);
if (!req->vars) {
- virNWFilterSnoopUnlock();
- virNWFilterSnoopReqFree(req);
virReportOOMError();
- return -1;
+ goto err_exit;
}
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 err_exit;
}
req->driver = driver;
@@ -799,9 +791,7 @@ virNWFilterDHCPSnoopReq(virNWFilterTechD
_("virNWFilterDHCPSnoopReq ifname map
failed"
" on interface \"%s\" key
\"%s\""),
ifname,
ifkey);
- virNWFilterSnoopUnlock();
- virNWFilterSnoopReqFree(req);
- return -1;
+ goto err_exit;
}
if (isnewreq &&
virHashAddEntry(virNWFilterSnoopState.SnoopReqs, ifkey, req)) {
@@ -810,23 +800,27 @@ virNWFilterDHCPSnoopReq(virNWFilterTechD
" interface \"%s\" ifkey
\"%s\""), ifname,
ifkey);
(void) virHashRemoveEntry(virNWFilterSnoopState.IfnameToKey,
ifname);
- virNWFilterSnoopUnlock();
- virNWFilterSnoopReqFree(req);
- return -1;
+ goto err_exit;
}
- 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;
+ goto err_exit;
}
+
+ virNWFilterSnoopUnlock();
+
return 0;
+
+err_exit:
+ virNWFilterSnoopUnlock();
+ virNWFilterSnoopReqFree(req);
+
+ return -1;
}
/*
@@ -881,29 +875,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,10 +906,8 @@ 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);
@@ -924,8 +915,7 @@ virNWFilterDHCPSnoopEnd(const char *ifna
if (!ifkey) {
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
_("ifname \"%s\" not in key
map"),
ifname);
- virNWFilterSnoopUnlock();
- return;
+ goto cleanup;
}
}
@@ -936,14 +926,12 @@ virNWFilterDHCPSnoopEnd(const char *ifna
if (!req) {
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
_("ifkey \"%s\" has no req"),
ifkey);
- virNWFilterSnoopUnlock();
- return;
+ goto cleanup;
}
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);
@@ -952,23 +940,46 @@ virNWFilterDHCPSnoopEnd(const char *ifna
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 the key / value pairs in the Active hash.
+ */
+
+ virNWFilterSnoopLock();
+
+ virNWFilterSnoopLeaseFileClose();
+ virHashFree(virNWFilterSnoopState.IfnameToKey);
+ virHashFree(virNWFilterSnoopState.SnoopReqs);
+
virNWFilterSnoopUnlock();
+
+ virNWFilterSnoopActiveLock();
+
+ virHashFree(virNWFilterSnoopState.Active);
+
+ virNWFilterSnoopActiveUnlock();
}
static int
@@ -990,7 +1001,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));
@@ -1023,8 +1034,9 @@ 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) {
@@ -1192,6 +1204,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