Re: [PATCH] fix ulog

"David S. Miller" <davem-fT/PcQaiUtIeIZ0/[email protected]>
Newsgroups gmane.linux.network.bridge.ebtables.devel
Message-ID <[email protected]>
On Tue, 7 Dec 2004 21:49:04 +0100
Bart De Schuymer <[email protected]> wrote:

> The following patch is incremental to the patch that adds the ebtables
> ulog watcher, which you have in your backlog for post 2.6.10.
> The internal function call had to change (ulog needs the hook number) and
> I somehow forgot to change the log watcher.

It has the hook number in the patch you sent to me, which
causes this incremental patch to obviously not apply.

Here is the ulog patch you originally sent to me.  It already
has the correct function arg list.

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/11/23 23:47:34-08:00 [email protected] 
#   [EBTABLES]: Add userspace logging via netlink socket.
#   
#   The patch below adds the ebtables ulog watcher, that sends packets
#   to userspace. It is based on ipt_ULOG.c.
#   
#   The complete packet, including Ethernet header, is sent to userspace.
#   The in and out bridge ports are also sent to userspace. Logging is
#   of course not restricted to IP packets.
#   An example of a userspace program that receives and parses packets
#   sent by the ulog watcher is in the ebtables CVS tree under
#   examples/ulog/
#   
#   Signed-off-by: Bart De Schuymer <[email protected]>
#   Signed-off-by: David S. Miller <davem-fT/PcQaiUtIeIZ0/[email protected]>
# 
# net/bridge/netfilter/ebtables.c
#   2004/11/23 23:46:46-08:00 [email protected] +3 -3
#   [EBTABLES]: Add userspace logging via netlink socket.
# 
# net/bridge/netfilter/ebt_log.c
#   2004/11/23 23:46:46-08:00 [email protected] +3 -2
#   [EBTABLES]: Add userspace logging via netlink socket.
# 
# net/bridge/netfilter/Makefile
#   2004/11/23 23:46:46-08:00 [email protected] +1 -0
#   [EBTABLES]: Add userspace logging via netlink socket.
# 
# net/bridge/netfilter/Kconfig
#   2004/11/23 23:46:46-08:00 [email protected] +16 -2
#   [EBTABLES]: Add userspace logging via netlink socket.
# 
# include/linux/netfilter_bridge/ebtables.h
#   2004/11/23 23:46:46-08:00 [email protected] +3 -3
#   [EBTABLES]: Add userspace logging via netlink socket.
# 
# net/bridge/netfilter/ebt_ulog.c
#   2004/11/23 23:46:41-08:00 [email protected] +295 -0
#   [EBTABLES]: Add userspace logging via netlink socket.
# 
# net/bridge/netfilter/ebt_ulog.c
#   2004/11/23 23:46:41-08:00 [email protected] +0 -0
#   BitKeeper file /disk1/BK/net-2.6.11/net/bridge/netfilter/ebt_ulog.c
# 
# include/linux/netfilter_bridge/ebt_ulog.h
#   2004/11/23 23:46:38-08:00 [email protected] +36 -0
#   [EBTABLES]: Add userspace logging via netlink socket.
# 
# include/linux/netfilter_bridge/ebt_ulog.h
#   2004/11/23 23:46:38-08:00 [email protected] +0 -0
#   BitKeeper file /disk1/BK/net-2.6.11/include/linux/netfilter_bridge/ebt_ulog.h
# 
diff -Nru a/include/linux/netfilter_bridge/ebt_ulog.h b/include/linux/netfilter_bridge/ebt_ulog.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/include/linux/netfilter_bridge/ebt_ulog.h	2004-12-07 21:12:54 -08:00
@@ -0,0 +1,36 @@
+#ifndef _EBT_ULOG_H
+#define _EBT_ULOG_H
+
+#define EBT_ULOG_DEFAULT_NLGROUP 0
+#define EBT_ULOG_DEFAULT_QTHRESHOLD 1
+#define EBT_ULOG_MAXNLGROUPS 32 /* hardcoded netlink max */
+#define EBT_ULOG_PREFIX_LEN 32
+#define EBT_ULOG_MAX_QLEN 50
+#define EBT_ULOG_WATCHER "ulog"
+#define EBT_ULOG_VERSION 1
+
+struct ebt_ulog_info {
+	uint32_t nlgroup;
+	unsigned int cprange;
+	unsigned int qthreshold;
+	char prefix[EBT_ULOG_PREFIX_LEN];
+};
+
+typedef struct ebt_ulog_packet_msg {
+	int version;
+	char indev[IFNAMSIZ];
+	char outdev[IFNAMSIZ];
+	char physindev[IFNAMSIZ];
+	char physoutdev[IFNAMSIZ];
+	char prefix[EBT_ULOG_PREFIX_LEN];
+	struct timeval stamp;
+	unsigned long mark;
+	unsigned int hook;
+	size_t data_len;
+	/* The complete packet, including Ethernet header and perhaps
+	 * the VLAN header is appended */
+	unsigned char data[0] __attribute__
+	                      ((aligned (__alignof__(struct ebt_ulog_info))));
+} ebt_ulog_packet_msg_t;
+
+#endif /* _EBT_ULOG_H */
diff -Nru a/include/linux/netfilter_bridge/ebtables.h b/include/linux/netfilter_bridge/ebtables.h
--- a/include/linux/netfilter_bridge/ebtables.h	2004-12-07 21:12:54 -08:00
+++ b/include/linux/netfilter_bridge/ebtables.h	2004-12-07 21:12:54 -08:00
@@ -201,9 +201,9 @@
 {
 	struct list_head list;
 	const char name[EBT_FUNCTION_MAXNAMELEN];
-	void (*watcher)(const struct sk_buff *skb, const struct net_device *in,
-	   const struct net_device *out, const void *watcherdata,
-	   unsigned int datalen);
+	void (*watcher)(const struct sk_buff *skb, unsigned int hooknr,
+	   const struct net_device *in, const struct net_device *out,
+	   const void *watcherdata, unsigned int datalen);
 	/* 0 == let it in */
 	int (*check)(const char *tablename, unsigned int hookmask,
 	   const struct ebt_entry *e, void *watcherdata, unsigned int datalen);
diff -Nru a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig
--- a/net/bridge/netfilter/Kconfig	2004-12-07 21:12:54 -08:00
+++ b/net/bridge/netfilter/Kconfig	2004-12-07 21:12:54 -08:00
@@ -189,8 +189,22 @@
 	tristate "ebt: log support"
 	depends on BRIDGE_NF_EBTABLES
 	help
-	  This option adds the log target, that you can use in any rule in
-	  any ebtables table. It records the frame header to the syslog.
+	  This option adds the log watcher, that you can use in any rule
+	  in any ebtables table. It records info about the frame header
+	  to the syslog.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
+config BRIDGE_EBT_ULOG
+	tristate "ebt: ulog support"
+	depends on BRIDGE_NF_EBTABLES
+	help
+	  This option adds the ulog watcher, that you can use in any rule
+	  in any ebtables table. The packet is passed to a userspace
+	  logging daemon using netlink multicast sockets. This differs
+	  from the log watcher in the sense that the complete packet is
+	  sent to userspace instead of a descriptive text and that
+	  netlink multicast sockets are used instead of the syslog.
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
diff -Nru a/net/bridge/netfilter/Makefile b/net/bridge/netfilter/Makefile
--- a/net/bridge/netfilter/Makefile	2004-12-07 21:12:54 -08:00
+++ b/net/bridge/netfilter/Makefile	2004-12-07 21:12:54 -08:00
@@ -29,3 +29,4 @@
 
 # watchers
 obj-$(CONFIG_BRIDGE_EBT_LOG) += ebt_log.o
+obj-$(CONFIG_BRIDGE_EBT_LOG) += ebt_ulog.o
diff -Nru a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c
--- a/net/bridge/netfilter/ebt_log.c	2004-12-07 21:12:54 -08:00
+++ b/net/bridge/netfilter/ebt_log.c	2004-12-07 21:12:54 -08:00
@@ -55,8 +55,9 @@
 }
 
 #define myNIPQUAD(a) a[0], a[1], a[2], a[3]
-static void ebt_log(const struct sk_buff *skb, const struct net_device *in,
-   const struct net_device *out, const void *data, unsigned int datalen)
+static void ebt_log(const struct sk_buff *skb, unsigned int hooknr,
+   const struct net_device *in, const struct net_device *out,
+   const void *data, unsigned int datalen)
 {
 	struct ebt_log_info *info = (struct ebt_log_info *)data;
 	char level_string[4] = "< >";
diff -Nru a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/net/bridge/netfilter/ebt_ulog.c	2004-12-07 21:12:54 -08:00
@@ -0,0 +1,295 @@
+/*
+ * netfilter module for userspace bridged Ethernet frames logging daemons
+ *
+ *	Authors:
+ *	Bart De Schuymer <[email protected]>
+ *
+ *  November, 2004
+ *
+ * Based on ipt_ULOG.c, which is
+ * (C) 2000-2002 by Harald Welte <laforge-Cap9r6Oaw4JrovVCs/[email protected]>
+ *
+ * This module accepts two parameters: 
+ * 
+ * nlbufsiz:
+ *   The parameter specifies how big the buffer for each netlink multicast
+ * group is. e.g. If you say nlbufsiz=8192, up to eight kb of packets will
+ * get accumulated in the kernel until they are sent to userspace. It is
+ * NOT possible to allocate more than 128kB, and it is strongly discouraged,
+ * because atomically allocating 128kB inside the network rx softirq is not
+ * reliable. Please also keep in mind that this buffer size is allocated for
+ * each nlgroup you are using, so the total kernel memory usage increases
+ * by that factor.
+ *
+ * flushtimeout:
+ *   Specify, after how many hundredths of a second the queue should be
+ *   flushed even if it is not full yet.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/spinlock.h>
+#include <linux/socket.h>
+#include <linux/skbuff.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/netlink.h>
+#include <linux/netdevice.h>
+#include <linux/module.h>
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_ulog.h>
+#include <net/sock.h>
+#include "../br_private.h"
+
+#define PRINTR(format, args...) do { if (net_ratelimit()) \
+                                printk(format , ## args); } while (0)
+
+static unsigned int nlbufsiz = 4096;
+module_param(nlbufsiz, uint, 0600);
+MODULE_PARM_DESC(nlbufsiz, "netlink buffer size (number of bytes) "
+                           "(defaults to 4096)");
+
+static unsigned int flushtimeout = 10;
+module_param(flushtimeout, uint, 0600);
+MODULE_PARM_DESC(flushtimeout, "buffer flush timeout (hundredths ofa second) "
+                               "(defaults to 10)");
+
+typedef struct {
+	unsigned int qlen;		/* number of nlmsgs' in the skb */
+	struct nlmsghdr *lastnlh;	/* netlink header of last msg in skb */
+	struct sk_buff *skb;		/* the pre-allocated skb */
+	struct timer_list timer;	/* the timer function */
+	spinlock_t lock;		/* the per-queue lock */
+} ebt_ulog_buff_t;
+
+static ebt_ulog_buff_t ulog_buffers[EBT_ULOG_MAXNLGROUPS];
+static struct sock *ebtulognl;
+
+/* send one ulog_buff_t to userspace */
+static void ulog_send(unsigned int nlgroup)
+{
+	ebt_ulog_buff_t *ub = &ulog_buffers[nlgroup];
+
+	if (timer_pending(&ub->timer))
+		del_timer(&ub->timer);
+
+	/* last nlmsg needs NLMSG_DONE */
+	if (ub->qlen > 1)
+		ub->lastnlh->nlmsg_type = NLMSG_DONE;
+
+	NETLINK_CB(ub->skb).dst_groups = 1 << nlgroup;
+	netlink_broadcast(ebtulognl, ub->skb, 0, 1 << nlgroup, GFP_ATOMIC);
+
+	ub->qlen = 0;
+	ub->skb = NULL;
+}
+
+/* timer function to flush queue in flushtimeout time */
+static void ulog_timer(unsigned long data)
+{
+	spin_lock_bh(&ulog_buffers[data].lock);
+	if (ulog_buffers[data].skb)
+		ulog_send(data);
+	spin_unlock_bh(&ulog_buffers[data].lock);
+}
+
+static struct sk_buff *ulog_alloc_skb(unsigned int size)
+{
+	struct sk_buff *skb;
+
+	skb = alloc_skb(nlbufsiz, GFP_ATOMIC);
+	if (!skb) {
+		PRINTR(KERN_ERR "ebt_ulog: can't alloc whole buffer "
+		       "of size %ub!\n", nlbufsiz);
+		if (size < nlbufsiz) {
+			/* try to allocate only as much as we need for
+			 * current packet */
+			skb = alloc_skb(size, GFP_ATOMIC);
+			if (!skb)
+				PRINTR(KERN_ERR "ebt_ulog: can't even allocate "
+				       "buffer of size %ub\n", size);
+		}
+	}
+
+	return skb;
+}
+
+static void ebt_ulog(const struct sk_buff *skb, unsigned int hooknr,
+   const struct net_device *in, const struct net_device *out,
+   const void *data, unsigned int datalen)
+{
+	ebt_ulog_packet_msg_t *pm;
+	size_t size, copy_len;
+	struct nlmsghdr *nlh;
+	struct ebt_ulog_info *uloginfo = (struct ebt_ulog_info *)data;
+	unsigned int group = uloginfo->nlgroup;
+	ebt_ulog_buff_t *ub = &ulog_buffers[group];
+	spinlock_t *lock = &ub->lock;
+
+	if ((uloginfo->cprange == 0) ||
+	    (uloginfo->cprange > skb->len + ETH_HLEN))
+		copy_len = skb->len + ETH_HLEN;
+	else
+		copy_len = uloginfo->cprange;
+
+	size = NLMSG_SPACE(sizeof(*pm) + copy_len);
+	if (size > nlbufsiz) {
+		PRINTR("ebt_ulog: Size %d needed, but nlbufsiz=%d\n",
+		       size, nlbufsiz);
+		return;
+	}
+
+	spin_lock_bh(lock);
+
+	if (!ub->skb) {
+		if (!(ub->skb = ulog_alloc_skb(size)))
+			goto alloc_failure;
+	} else if (size > skb_tailroom(ub->skb)) {
+		ulog_send(group);
+
+		if (!(ub->skb = ulog_alloc_skb(size)))
+			goto alloc_failure;
+	}
+
+	nlh = NLMSG_PUT(ub->skb, 0, ub->qlen, 0,
+	                size - NLMSG_ALIGN(sizeof(*nlh)));
+	ub->qlen++;
+
+	pm = NLMSG_DATA(nlh);
+
+	/* Fill in the ulog data */
+	pm->version = EBT_ULOG_VERSION;
+	do_gettimeofday(&pm->stamp);
+	if (ub->qlen == 1)
+		ub->skb->stamp = pm->stamp;
+	pm->data_len = copy_len;
+	pm->mark = skb->nfmark;
+	pm->hook = hooknr;
+	if (uloginfo->prefix != NULL)
+		strcpy(pm->prefix, uloginfo->prefix);
+	else
+		*(pm->prefix) = '\0';
+
+	if (in) {
+		strcpy(pm->physindev, in->name);
+		/* If in isn't a bridge, then physindev==indev */
+		if (in->br_port)
+			strcpy(pm->indev, in->br_port->br->dev->name);
+		else
+			strcpy(pm->indev, in->name);
+	} else
+		pm->indev[0] = pm->physindev[0] = '\0';
+
+	if (out) {
+		/* If out exists, then out is a bridge port */
+		strcpy(pm->physoutdev, out->name);
+		strcpy(pm->outdev, out->br_port->br->dev->name);
+	} else
+		pm->outdev[0] = pm->physoutdev[0] = '\0';
+
+	if (skb_copy_bits(skb, -ETH_HLEN, pm->data, copy_len) < 0)
+		BUG();
+
+	if (ub->qlen > 1)
+		ub->lastnlh->nlmsg_flags |= NLM_F_MULTI;
+
+	ub->lastnlh = nlh;
+
+	if (ub->qlen >= uloginfo->qthreshold)
+		ulog_send(group);
+	else if (!timer_pending(&ub->timer)) {
+		ub->timer.expires = jiffies + flushtimeout * HZ / 100;
+		add_timer(&ub->timer);
+	}
+
+unlock:
+	spin_unlock_bh(lock);
+
+	return;
+
+nlmsg_failure:
+	printk(KERN_CRIT "ebt_ulog: error during NLMSG_PUT. This should "
+	       "not happen, please report to author.\n");
+	goto unlock;
+alloc_failure:
+	goto unlock;
+}
+
+static int ebt_ulog_check(const char *tablename, unsigned int hookmask,
+   const struct ebt_entry *e, void *data, unsigned int datalen)
+{
+	struct ebt_ulog_info *uloginfo = (struct ebt_ulog_info *)data;
+
+	if (datalen != EBT_ALIGN(sizeof(struct ebt_ulog_info)) ||
+	    uloginfo->nlgroup > 31)
+		return -EINVAL;
+
+	uloginfo->prefix[EBT_ULOG_PREFIX_LEN - 1] = '\0';
+
+	if (uloginfo->qthreshold > EBT_ULOG_MAX_QLEN)
+		uloginfo->qthreshold = EBT_ULOG_MAX_QLEN;
+
+	return 0;
+}
+
+static struct ebt_watcher ulog = {
+	.name		= EBT_ULOG_WATCHER,
+	.watcher	= ebt_ulog,
+	.check		= ebt_ulog_check,
+	.me		= THIS_MODULE,
+};
+
+static int __init init(void)
+{
+	int i, ret = 0;
+
+	if (nlbufsiz >= 128*1024) {
+		printk(KERN_NOTICE "ebt_ulog: Netlink buffer has to be <= 128kB,"
+		       " please try a smaller nlbufsiz parameter.\n");
+		return -EINVAL;
+	}
+
+	/* initialize ulog_buffers */
+	for (i = 0; i < EBT_ULOG_MAXNLGROUPS; i++) {
+		init_timer(&ulog_buffers[i].timer);
+		ulog_buffers[i].timer.function = ulog_timer;
+		ulog_buffers[i].timer.data = i;
+		ulog_buffers[i].lock = SPIN_LOCK_UNLOCKED;
+	}
+
+	ebtulognl = netlink_kernel_create(NETLINK_NFLOG, NULL);
+	if (!ebtulognl)
+		ret = -ENOMEM;
+	else if ((ret = ebt_register_watcher(&ulog)))
+		sock_release(ebtulognl->sk_socket);
+
+	return ret;
+}
+
+static void __exit fini(void)
+{
+	ebt_ulog_buff_t *ub;
+	int i;
+
+	ebt_unregister_watcher(&ulog);
+	for (i = 0; i < EBT_ULOG_MAXNLGROUPS; i++) {
+		ub = &ulog_buffers[i];
+		if (timer_pending(&ub->timer))
+			del_timer(&ub->timer);
+		spin_lock_bh(&ub->lock);
+		if (ub->skb) {
+			kfree_skb(ub->skb);
+			ub->skb = NULL;
+		}
+		spin_unlock_bh(&ub->lock);
+	}
+	sock_release(ebtulognl->sk_socket);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Bart De Schuymer <[email protected]>");
+MODULE_DESCRIPTION("ebtables userspace logging module for bridged Ethernet"
+                   " frames");
diff -Nru a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
--- a/net/bridge/netfilter/ebtables.c	2004-12-07 21:12:54 -08:00
+++ b/net/bridge/netfilter/ebtables.c	2004-12-07 21:12:54 -08:00
@@ -90,10 +90,10 @@
 { {NULL, NULL}, EBT_STANDARD_TARGET, NULL, NULL, NULL, NULL};
 
 static inline int ebt_do_watcher (struct ebt_entry_watcher *w,
-   const struct sk_buff *skb, const struct net_device *in,
+   const struct sk_buff *skb, unsigned int hooknr, const struct net_device *in,
    const struct net_device *out)
 {
-	w->u.watcher->watcher(skb, in, out, w->data,
+	w->u.watcher->watcher(skb, hooknr, in, out, w->data,
 	   w->watcher_size);
 	/* watchers don't give a verdict */
 	return 0;
@@ -208,7 +208,7 @@
 
 		/* these should only watch: not modify, nor tell us
 		   what to do with the packet */
-		EBT_WATCHER_ITERATE(point, ebt_do_watcher, *pskb, in,
+		EBT_WATCHER_ITERATE(point, ebt_do_watcher, *pskb, hook, in,
 		   out);
 
 		t = (struct ebt_entry_target *)


-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now. 
http://productguide.itmanagersjournal.com/
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.