[libvirt] [PATCH V13 2/5] nwfilter: add DHCP snooping
Eric Blake
eblake at redhat.com
Mon Apr 30 23:14:51 UTC 2012
On 04/25/2012 06:59 AM, Stefan Berger wrote:
> This patch adds DHCP snooping support to libvirt. The learning method for
> IP addresses is specified by setting the "CTRL_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.
>
> The following interface XML activates and uses the DHCP snooping:
>
> <interface type='bridge'>
> <source bridge='virbr0'/>
> <filterref filter='clean-traffic'>
> <parameter name='CTRL_IP_LEARNING' value='dhcp'/>
> </filterref>
> </interface>
>
> All filters containig the variable 'IP' are automatically adjusted when
s/containig/containing/
> the VM receives an IP address via DHCP. However, multiple IP addresses per
> interface are silently ignored in this patch, thus only supporting one IP
> address per interface. Multiple IP address support is added in a later
> patch in this series.
>
> Signed-off-by: David L Stevens <dlstevens at us.ibm.com>
> Signed-off-by: Stefan Berger <stefanb at linux.vnet.ibm.com>
>
> ---
>
> Changes since v12:
> - use pcap_create to open pcap to be able to set smaller buffer
> than the 2 MB default buffer used by pcap which leads to processing
> of huge backlog of messages if flooding occurrs
> - use virAtomicInc/Dec
> - use indep. rate controllers, one per direction to tune out of
> flooding in each direction individually (even if flooding was to
> occurr, libvirt doesn't use much CPU [0.3%])
s/occurr/occur/, although this note won't be in the final commit.
> Index: libvirt-acl/docs/formatnwfilter.html.in
> ===================================================================
> --- libvirt-acl.orig/docs/formatnwfilter.html.in
> +++ libvirt-acl/docs/formatnwfilter.html.in
> @@ -371,6 +371,118 @@
> Further, the notation of $VARIABLE is short-hand for $VARIABLE[@0]. The
> former notation always assumes the iterator with Id '0'.
> <p>
> +
> + <h3><a name="nwfelemsRulesAdvIPAddrDetection">Automatic IP address detection</a></h3>
> + <p>
> + The detection of IP addresses used on a virtual machine's interface
> + is automatically activated if the variable <code>IP</code> is referenced
> + but not value has been assign to it.
s/assign/assigned/
> + variable <code>DHCPSERVER</code> to the IP address of a valid DHCP server
> + and provide filters that use this variable to filter incoming DHCP responses.
> + <br/><br/>
> + When DHCP snooping is enable and the DHCP lease expires,
s/enable/enabled/
> + 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).
> + <br/><br/>
> + Note that automatic DHCP detection listens to the DHCP traffic
> + the VM exchanges with the DHCP server of the infrastructure. To avoid
> + denial-of-service attacks on libvirt, the evaluation of those packets
> + is rate-limited, meaning that a VM sending an excessive number of DHCP
> + packets per seconds on an interface will not have all of those packets
s/seconds/second/
> + evaluated and thus filters may not get adapted. Normal DHCP client
> + behavior is assumed to send a low number of DHCP packets per second.
> + Further, it is important to setup approriate filters on all VMs in
s/approriate/appropriate/
> +++ libvirt-acl/src/nwfilter/nwfilter_dhcpsnoop.c
> + *
> + * 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
Not a problem with your patch, per se, but we really should be using the
FSF-preferred form of LGPLv2+ boilerplate that uses a URL rather than a
street address (that's a global cleanup to all of libvirt).
> +#include <config.h>
> +
> +#ifdef HAVE_LIBPCAP
> +#include <pcap.h>
Needs indentation, to pass 'make syntax-check' if cppi is installed.
> +
> +#define VIR_FROM_THIS VIR_FROM_NWFILTER
> +
> +#ifdef HAVE_LIBPCAP
> +
> +#define LEASEFILE LOCALSTATEDIR "/run/libvirt/network/nwfilter.leases"
And more instances of cppi complaints. I'll post a patch at the end...
> +
> +#define VIR_IFKEY_LEN ((VIR_UUID_STRING_BUFLEN) + (VIR_MAC_STRING_BUFLEN))
Technically over-parenthesized (unless VIR_UUID_STRING_BUFLEN is
under-parenthesized); you could get by with:
# define VIR_IFKEY_LEN \
(VIR_UUID_STRING_BUFLEN + VIR_MAC_STRING_BUFLEN)
but I don't mind leaving this line alone (it's easier to have a rule of
thumb of always using extra () in #defines than it is to think about
when () are necessary).
> +
> +struct _virNWFilterSnoopReq {
> + /*
> + * reference counter: while the req is on the
> + * publicSnoopReqs hash, the refctr may only
> + * be modified with the SnoopLock held
> + */
> + virAtomicInt refctr;
> +
> + virNWFilterTechDriverPtr techdriver;
> + const char *ifname;
Why 'const char *'? Are we always going to point ifname to someone
else's (static) storage? Or are we going to strdup() our own copy, in
which case this should be 'char *', not 'const char *', as a hint that
we own the string? (Throughout the struct).
> + int ifindex;
> + const char *linkdev;
> + enum virDomainNetType nettype;
> + char ifkey[VIR_IFKEY_LEN];
> + unsigned char macaddr[VIR_MAC_BUFLEN];
Hmm, wondering if src/util/virmacaddr.h should typedef a MAC address.
[And while thinking about that, I just noticed that virMacAddrCompare
takes 'const char *', but virMacAddrFormat takes 'const unsigned char
*', so we aren't very consistent on whether we are using normal or
unsigned char for mac addrs.]
> + /*
> + * protect those members that can change while the
> + * req is on the public SnoopReq hash and
> + * at least one reference is held:
> + * - ifname
> + * - threadkey
> + * - start
> + * - end
> + * - a lease while it is on the list
> + * - threadStatus
> + * (for refctr, see above)
> + */
> + virMutex lock;
> +};
> +
> +/*
> + * Note about lock-order:
> + * 1st: virNWFilterSnoopLock()
> + * 2nd: virNWFilterSnoopReqLock(req)
> + *
> + * Rationale: Former protects the SnoopReqs hash, latter its contents
Useful comments; thank you.
> +
> +typedef unsigned char Eaddr[6];
All the more reason that we should be typedef'ing a common MAC address
in virmacaddr.h.
> +
> +typedef struct _virNWFilterSnoopEthHdr virNWFilterSnoopEthHdr;
> +typedef virNWFilterSnoopEthHdr *virNWFilterSnoopEthHdrPtr;
> +
> +struct _virNWFilterSnoopEthHdr {
> + Eaddr eh_dst;
> + Eaddr eh_src;
> + unsigned short eh_type;
We should be using uint16_t rather than trusting the size of 'unsigned
short',...
> + union {
> + unsigned char eu_data[0];
> + struct vlan_hdr {
> + unsigned short ev_flags;
> + unsigned short ev_type;
> + unsigned char ev_data[0];
Is a zero-length member really C99 compliant, or it is only a gcc extension?
> + } eu_vlh;
> + } eth_un;
> +} ATTRIBUTE_PACKED;
...especially since you are packing this struct.
> +
> +#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
> +
> +
> +typedef struct _virNWFilterSnoopDHCPHdr virNWFilterSnoopDHCPHdr;
> +typedef virNWFilterSnoopDHCPHdr *virNWFilterSnoopDHCPHdrPtr;
> +
> +struct _virNWFilterSnoopDHCPHdr {
> + uint8_t d_op;
> + uint8_t d_htype;
> + uint8_t d_hlen;
> + uint8_t d_hops;
> + uint32_t d_xid;
> + uint16_t d_secs;
> + uint16_t d_flags;
> + uint32_t d_ciaddr;
> + uint32_t d_yiaddr;
> + uint32_t d_siaddr;
> + uint32_t d_giaddr;
> + uint8_t d_chaddr[16];
> + char d_sname[64];
> + char d_file[128];
> + uint8_t d_opts[0];
Again a question about the validity of a 0-length member.
> +
> +#define MIN_VALID_DHCP_PKT_SIZE \
> + offsetof(virNWFilterSnoopEthHdr, eh_data) + \
> + sizeof(struct udphdr) + \
> + offsetof(virNWFilterSnoopDHCPHdr, d_opts)
Under-parenthesized.
> +
> +typedef struct _virNWFilterSnoopRateLimitConf virNWFilterSnoopRateLimitConf;
> +typedef virNWFilterSnoopRateLimitConf *virNWFilterSnoopRateLimitConfPtr;
> +
> +struct _virNWFilterSnoopRateLimitConf {
> + time_t prev;
> + unsigned int pkt_ctr;
> + time_t burst;
> + const unsigned int rate;
const? Is this really a write-once structure?
> + const unsigned int burstRate;
> + const unsigned int burstInterval;
> +};
> +
> +typedef struct _virNWFilterSnoopPcapConf virNWFilterSnoopPcapConf;
> +typedef virNWFilterSnoopPcapConf *virNWFilterSnoopPcapConfPtr;
> +
> +struct _virNWFilterSnoopPcapConf {
> + pcap_t *handle;
> + const pcap_direction_t dir;
> + const char *filter;
Again, if we malloc filter, this should be 'char *', not 'const char *'.
> + virNWFilterSnoopRateLimitConf rateLimit; /* indep. rate limiters */
> + virAtomicInt qCtr; /* number of jobs in the worker's queue */
> + const unsigned int maxQSize;
Why is this const?
> +static char *
> +virNWFilterSnoopActivate(virThreadPtr thread)
> +{
> + char *key;
> + unsigned long threadID = (unsigned long int)thread->thread;
You are not guaranteed that thread->thread can be converted cleanly to
an integral type; this smells like we are violating type encapsulation.
I'm worried that this cast will provoke compiler warnings on some
platforms. Can you get by with virThreadSelfID/virThreadID instead?
Or, since those functions are mainly for debugging purposes (and not
guaranteed to be unique on platforms that use 64-bit thread ids), what
are you really trying to do here that we should be supporting in
src/utils/threads.h?
> +
> + if (virAsprintf(&key, "0x%0*lX", (int)sizeof(threadID)*2, threadID) < 0) {
Why are you making this string have different length on 32- vs. 64-bit
platforms? Does it really have to be a fixed-width string?
> + virReportOOMError();
> + return NULL;
> + }
> +
> + virNWFilterSnoopActiveLock();
> +
> + if (virHashAddEntry(virNWFilterSnoopState.active, key, (void *)0x1) < 0) {
It looks like you are trying to make a map with a thread as the key; so
maybe the real thing to do here is make a utility function in
src/util/threads.h that can be used to hash a thread as a key without
you having to know the guts of how it works (and especially without you
having to stringize an integer representation of thread->thread).
> +static bool
> +virNWFilterSnoopIsActive(char *threadKey)
If we fix things to hash on a virThreadPtr instead of a stringized name
of the thread, then this function needs to change signature.
> +/*
> + * virNWFilterSnoopListAdd - add an IP lease to a list
> + */
> +static void
> +virNWFilterSnoopListAdd(virNWFilterSnoopIPLeasePtr plnew,
> + virNWFilterSnoopIPLeasePtr *start,
> + virNWFilterSnoopIPLeasePtr *end)
> +{
> + virNWFilterSnoopIPLeasePtr pl;
> +
> + plnew->next = plnew->prev = 0;
Use NULL, not 0, for pointers. (I think newer gcc as shipped on F17 has
a warning that catches this; but I'm not sure if we are yet turning it
on, since I'm still on F16).
> +/*
> + * virNWFilterSnoopListDel - remove an IP lease from a list
> + */
> +static void
> +virNWFilterSnoopListDel(virNWFilterSnoopIPLeasePtr ipl,
> + virNWFilterSnoopIPLeasePtr *start,
> + virNWFilterSnoopIPLeasePtr *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;
Again, NULL, not 0, for pointers.
> +/*
> + * virNWFilterSnoopInstallRule - install rule for a lease
> + *
> + * @instantiate: when calling this function in a loop, indicate
> + * the last call with 'true' here so that the
> + * rules all get instantiated
> + * Always calling this with 'true' is fine, but less
> + * efficient.
> + */
> +static int
> +virNWFilterSnoopIPLeaseInstallRule(virNWFilterSnoopIPLeasePtr ipl,
> + bool instantiate)
> +{
> +
> + if (virNWFilterHashTablePut(req->vars, NWFILTER_VARNAME_IP,
> + ipVar, 1) < 0) {
> + virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Could not add variable \""
> + NWFILTER_VARNAME_IP "\" to hashmap"));
'make syntax-check' doesn't like this unless you apply my patch:
https://www.redhat.com/archives/libvir-list/2012-April/msg01538.html
> +/*
> + * virNWFilterSnoopReqLeaseTimerRun - run the IP lease timeout list
> + */
> +static unsigned int
> +virNWFilterSnoopReqLeaseTimerRun(virNWFilterSnoopReqPtr req)
> +{
> + time_t now = time(0);
Should we be using src/util/virtime.h (with milliseconds) rather than
time() (with seconds)?
> +
> + req->threadStatus = THREAD_STATUS_NONE;
> +
> + if (virAtomicIntInit(&req->refctr) < 0 ||
> + virMutexInitRecursive(&req->lock) < 0 ||
> + virStrcpyStatic(req->ifkey, ifkey) == NULL ||
> + virCondInit(&req->threadStatusCond) < 0)
> + VIR_FREE(req);
Resource leak. If virMutexInitRecursive() succeeds, but virCondInit()
then fails, you've lost a mutex.
> +
> + return req;
> +}
> +
> +/*
> + * Free a snoop request unless it is still referenced.
> + * All its associated leases are also freed.
> + * The lease file is NOT rewritten.
> + */
> +static void
> +virNWFilterSnoopReqFree(virNWFilterSnoopReqPtr req)
> +{
> + virNWFilterSnoopIPLeasePtr ipl;
> +
> + if (!req)
> + return;
> +
> + if (virAtomicIntRead(&req->refctr) != 0)
> + return;
> +
> + /* free all leases */
> + for (ipl = req->start; ipl; ipl = req->start)
> + virNWFilterSnoopReqLeaseDel(req, &ipl->ipAddress, false);
> +
> + /* free all req data */
> + VIR_FREE(req->ifname);
> + VIR_FREE(req->linkdev);
> + VIR_FREE(req->filtername);
> + virNWFilterHashTableFree(req->vars);
> +
> + VIR_FREE(req);
Resource leak; you didn't clean up things like req->lock.
> +
> +/*
> + * virNWFilterSnoopReqRelease - hash table free function to kill a request
> + */
> +static void
> +virNWFilterSnoopReqRelease(void *req0, const void *name ATTRIBUTE_UNUSED)
> +{
> + virNWFilterSnoopReqPtr req = (virNWFilterSnoopReqPtr) req0;
The cast is not necessary in C (void* can be assigned to anything other
pointer without a cast).
> +/*
> + * Drop the reference to the Snoop request. Don't use the req
> + * after this call.
> + */
> +static void
> +virNWFilterSnoopReqPut(virNWFilterSnoopReqPtr req)
> +{
> + if (!req)
> + return;
> +
> + virNWFilterSnoopLock()
How did this compile? Oh, because virNWFilterSnoopLock() is an unusual
macro. I would have made it be a 'do { ... } while (false)' idiom, to
make a semicolon mandatory in all callers, and prevent this unusual
looking construct.
> +static int
> +virNWFilterSnoopDHCPGetOpt(virNWFilterSnoopDHCPHdrPtr 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:
Style nit: We have an inconsistent mix, but more of our code tends to
indent 'case' flush with 'switch' than code that indents 'case' four
spaces beyond 'switch'.
> + if (olen - oind < 6)
> + goto malformed;
> + if (*pleasetime)
> + return -1; /* duplicate lease time */
> + *pleasetime =
> + ntohl(*(unsigned int *) (pd->d_opts + oind + 2));
This type-punning looks dangerous. It may generate unaligned accesses
which fail on some platforms. I think you need to build the int by
bitwise operations on 4 bytes, rather than using type-punning.
> +
> + /* check for spoofed or packets not destined for this VM */
> + if (fromVM) {
> + if (memcmp(req->macaddr, pep->eh_src, 6) != 0)
> + return -2;
> + } else {
> + /*
> + * packets not destined for us can occurr while the bridge is
s/occurr/occur/
> + * learning the MAC addresses on ports
> + */
> + if (memcmp(req->macaddr, pep->eh_dst, 6) != 0)
> + return -2;
> + }
> +
> + pup = (struct udphdr *) ((char *) pip + (pip->ihl << 2));
More type-punning. I hope this doesn't back-fire.
> +static pcap_t *
> +virNWFilterSnoopDHCPOpen(const char *ifname, const unsigned char *mac,
> + const char *filter, pcap_direction_t dir)
> +{
> + pcap_t *handle = NULL;
> + struct bpf_program fp;
> + char pcap_errbuf[PCAP_ERRBUF_SIZE];
> + char *ext_filter = NULL;
> + char macaddr[VIR_MAC_STRING_BUFLEN];
> + const char *ext;
> +
> + virMacAddrFormat(mac, macaddr);
> +
> + if (dir == PCAP_D_IN /* from VM */) {
> + /*
> + * don't want to hear about another VM's DHCP requests
> + *
> + * extend the filter with the macaddr of the VM; filter the
> + * more unlikely parameters first, then go for the MAC
> + */
> + ext = "and ether src";
> + } else {
> + ext = "and ether dst";
> + }
> +
> + if (virAsprintf(&ext_filter, "%s %s %s", filter, ext, macaddr) < 0) {
This is broken for translation. You did not mark the string "and ether
src" for translation.
I'd do:
if (dir == PCAP_D_IN) {
format = _("%s and ether src %s");
else
format = _("%s and ether dst %s");
virAsprintf(&ext_filter, format, filter, macaddr);
or something along those lines.
> + virReportOOMError();
> + return NULL;
> + }
> +
> + handle = pcap_create(ifname, pcap_errbuf);
> +
> + if (handle == NULL) {
> + virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
> + _("pcap_create failed"));
If this is a normal user-visible error, it probably should not be
INTERNAL_ERROR.
> +
> + if (pcap_compile(handle, &fp, ext_filter, 1, PCAP_NETMASK_UNKNOWN) != 0) {
> + virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
> + _("pcap_compile: %s"), pcap_geterr(handle));
Is pcap_geterr() thread-safe? I know that later on you used strerror(),
which is NOT thread-safe, and which violates 'make syntax-check'.
> +/*
> + * Submit a job to the worker thread doing the time-consuming work...
> + */
> +static int
> +virNWFilterSnoopDHCPDecodeJobSubmit(virThreadPoolPtr pool,
> + virNWFilterSnoopEthHdrPtr pep,
> + int len, pcap_direction_t dir,
> + virAtomicIntPtr qCtr)
I've run out of review time today. Here's what I had to add to get
'make syntax-check' to be happy, but there are a lot of other cleanups
I've mentioned above.
From adcdb61e42808821e81a2682ec49f05dbafb0048 Mon Sep 17 00:00:00 2001
From: Eric Blake <eblake at redhat.com>
Date: Mon, 30 Apr 2012 15:50:01 -0600
Subject: [PATCH] fixup to 2/5 dhcp
---
po/POTFILES.in | 1 +
src/nwfilter/nwfilter_dhcpsnoop.c | 74
+++++++++++++++++-------------------
src/nwfilter/nwfilter_dhcpsnoop.h | 2 +-
3 files changed, 37 insertions(+), 40 deletions(-)
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 4ea544b..0e64c96 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -53,6 +53,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/nwfilter/nwfilter_dhcpsnoop.c
b/src/nwfilter/nwfilter_dhcpsnoop.c
index 1ed32ab..35a7908 100644
--- a/src/nwfilter/nwfilter_dhcpsnoop.c
+++ b/src/nwfilter/nwfilter_dhcpsnoop.c
@@ -42,7 +42,7 @@
#include <config.h>
#ifdef HAVE_LIBPCAP
-#include <pcap.h>
+# include <pcap.h>
#endif
#include <fcntl.h>
@@ -70,8 +70,8 @@
#ifdef HAVE_LIBPCAP
-#define LEASEFILE LOCALSTATEDIR "/run/libvirt/network/nwfilter.leases"
-#define TMPLEASEFILE LOCALSTATEDIR "/run/libvirt/network/nwfilter.ltmp"
+# define LEASEFILE LOCALSTATEDIR "/run/libvirt/network/nwfilter.leases"
+# define TMPLEASEFILE LOCALSTATEDIR "/run/libvirt/network/nwfilter.ltmp"
struct virNWFilterSnoopState {
/* lease file */
@@ -87,16 +87,16 @@ struct virNWFilterSnoopState {
virMutex activeLock; /* protects Active */
};
-#define virNWFilterSnoopLock() \
+# define virNWFilterSnoopLock() \
{ virMutexLock(&virNWFilterSnoopState.snoopLock); }
-#define virNWFilterSnoopUnlock() \
+# define virNWFilterSnoopUnlock() \
{ virMutexUnlock(&virNWFilterSnoopState.snoopLock); }
-#define virNWFilterSnoopActiveLock() \
+# define virNWFilterSnoopActiveLock() \
{ virMutexLock(&virNWFilterSnoopState.activeLock); }
-#define virNWFilterSnoopActiveUnlock() \
+# define virNWFilterSnoopActiveUnlock() \
{ virMutexUnlock(&virNWFilterSnoopState.activeLock); }
-#define VIR_IFKEY_LEN ((VIR_UUID_STRING_BUFLEN) +
(VIR_MAC_STRING_BUFLEN))
+# define VIR_IFKEY_LEN ((VIR_UUID_STRING_BUFLEN) +
(VIR_MAC_STRING_BUFLEN))
typedef struct _virNWFilterSnoopReq virNWFilterSnoopReq;
typedef virNWFilterSnoopReq *virNWFilterSnoopReqPtr;
@@ -191,9 +191,9 @@ struct _virNWFilterSnoopEthHdr {
} 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
+# 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
typedef struct _virNWFilterSnoopDHCPHdr virNWFilterSnoopDHCPHdr;
@@ -219,25 +219,25 @@ struct _virNWFilterSnoopDHCPHdr {
/* 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 */
+# 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
+# define DHCPDECLINE 4
+# define DHCPACK 5
+# define DHCPRELEASE 7
-#define MIN_VALID_DHCP_PKT_SIZE \
+# define MIN_VALID_DHCP_PKT_SIZE \
offsetof(virNWFilterSnoopEthHdr, eh_data) + \
sizeof(struct udphdr) + \
offsetof(virNWFilterSnoopDHCPHdr, d_opts)
-#define PCAP_PBUFSIZE 576 /* >= IP/TCP/DHCP headers */
-#define PCAP_READ_MAXERRS 25 /* retries on failing device */
-#define PCAP_FLOOD_TIMEOUT_MS 10 /* ms */
+# define PCAP_PBUFSIZE 576 /* >= IP/TCP/DHCP headers */
+# define PCAP_READ_MAXERRS 25 /* retries on failing device */
+# define PCAP_FLOOD_TIMEOUT_MS 10 /* ms */
typedef struct _virNWFilterDHCPDecodeJob virNWFilterDHCPDecodeJob;
typedef virNWFilterDHCPDecodeJob *virNWFilterDHCPDecodeJobPtr;
@@ -249,13 +249,13 @@ struct _virNWFilterDHCPDecodeJob {
virAtomicIntPtr qCtr;
};
-#define DHCP_PKT_RATE 10 /* pkts/sec */
-#define DHCP_PKT_BURST 50 /* pkts/sec */
-#define DHCP_BURST_INTERVAL_S 10 /* sec */
+# define DHCP_PKT_RATE 10 /* pkts/sec */
+# define DHCP_PKT_BURST 50 /* pkts/sec */
+# define DHCP_BURST_INTERVAL_S 10 /* sec */
-#define PCAP_BUFFERSIZE (DHCP_PKT_BURST * PCAP_PBUFSIZE / 2)
+# define PCAP_BUFFERSIZE (DHCP_PKT_BURST * PCAP_PBUFSIZE / 2)
-#define MAX_QUEUED_JOBS (DHCP_PKT_BURST + 2 * DHCP_PKT_RATE)
+# define MAX_QUEUED_JOBS (DHCP_PKT_BURST + 2 * DHCP_PKT_RATE)
typedef struct _virNWFilterSnoopRateLimitConf
virNWFilterSnoopRateLimitConf;
typedef virNWFilterSnoopRateLimitConf *virNWFilterSnoopRateLimitConfPtr;
@@ -597,8 +597,6 @@ virNWFilterSnoopReqNew(const char *ifkey)
return NULL;
}
- virNWFilterSnoopReqGet(req);
-
req->threadStatus = THREAD_STATUS_NONE;
if (virAtomicIntInit(&req->refctr) < 0 ||
@@ -607,6 +605,9 @@ virNWFilterSnoopReqNew(const char *ifkey)
virCondInit(&req->threadStatusCond) < 0)
VIR_FREE(req);
+ if (req)
+ virNWFilterSnoopReqGet(req);
+
return req;
}
@@ -1208,7 +1209,7 @@
virNWFilterSnoopRateLimit(virNWFilterSnoopRateLimitConfPtr rl)
{
time_t now = time(0);
int diff;
-#define IN_BURST(n,b) ((n)-(b) <= 1) /* bursts span 2 discreet seconds */
+# define IN_BURST(n,b) ((n)-(b) <= 1) /* bursts span 2 discreet seconds */
if (rl->prev != now && !IN_BURST(now, rl->burst)) {
rl->prev = now;
@@ -1754,9 +1755,7 @@ virNWFilterSnoopLeaseFileWrite(int lfd, const char
*ifkey,
len = strlen(lbuf);
if (safewrite(lfd, lbuf, len) != len) {
- virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
- _("lease file write failed: %s"),
- strerror(errno));
+ virReportSystemError(errno, "%s", _("lease file write failed"));
ret = -1;
goto cleanup;
}
@@ -1865,9 +1864,7 @@ virNWFilterSnoopLeaseFileRefresh(void)
/* 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));
+ virReportSystemError(errno, _("open(\"%s\")"), TMPLEASEFILE);
return;
}
@@ -1883,9 +1880,8 @@ virNWFilterSnoopLeaseFileRefresh(void)
VIR_FORCE_CLOSE(tfd);
if (rename(TMPLEASEFILE, LEASEFILE) < 0) {
- virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
- _("rename(\"%s\", \"%s\"): %s"),
- TMPLEASEFILE, LEASEFILE, strerror(errno));
+ virReportSystemError(errno, _("rename(\"%s\", \"%s\")"),
+ TMPLEASEFILE, LEASEFILE);
(void) unlink(TMPLEASEFILE);
}
virAtomicIntSet(&virNWFilterSnoopState.wLeases, 0);
diff --git a/src/nwfilter/nwfilter_dhcpsnoop.h
b/src/nwfilter/nwfilter_dhcpsnoop.h
index 61ea894..9a1d797 100644
--- a/src/nwfilter/nwfilter_dhcpsnoop.h
+++ b/src/nwfilter/nwfilter_dhcpsnoop.h
@@ -22,7 +22,7 @@
*/
#ifndef __NWFILTER_DHCPSNOOP_H
-#define __NWFILTER_DHCPSNOOP_H
+# define __NWFILTER_DHCPSNOOP_H
int virNWFilterDHCPSnoopInit(void);
void virNWFilterDHCPSnoopShutdown(void);
--
1.7.7.6
--
Eric Blake eblake at redhat.com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 620 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20120430/f4be7933/attachment-0001.sig>
More information about the libvir-list
mailing list