]> git.hungrycats.org Git - linux/commitdiff
[EBTABLES]: Add ebt_limit match.
authorBart De Schuymer <bdschuym@pandora.be>
Mon, 29 Sep 2003 19:00:00 +0000 (12:00 -0700)
committerDavid S. Miller <davem@nuts.ninka.net>
Mon, 29 Sep 2003 19:00:00 +0000 (12:00 -0700)
The patch below adds the ebt_limit match, which is the equivalent of
the iptables limit match. This enables limiting the number of frames
processed per time unit.

The patch is from Tom Marshall <tommy_at_home.tig-grr.com>.

include/linux/netfilter_bridge/ebt_limit.h [new file with mode: 0644]
net/bridge/netfilter/Kconfig
net/bridge/netfilter/Makefile
net/bridge/netfilter/ebt_limit.c [new file with mode: 0644]

diff --git a/include/linux/netfilter_bridge/ebt_limit.h b/include/linux/netfilter_bridge/ebt_limit.h
new file mode 100644 (file)
index 0000000..d8b6500
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef __LINUX_BRIDGE_EBT_LIMIT_H
+#define __LINUX_BRIDGE_EBT_LIMIT_H
+
+#define EBT_LIMIT_MATCH "limit"
+
+/* timings are in milliseconds. */
+#define EBT_LIMIT_SCALE 10000
+
+/* 1/10,000 sec period => max of 10,000/sec.  Min rate is then 429490
+   seconds, or one every 59 hours. */
+
+struct ebt_limit_info
+{
+       u_int32_t avg;    /* Average secs between packets * scale */
+       u_int32_t burst;  /* Period multiplier for upper limit. */
+
+       /* Used internally by the kernel */
+       unsigned long prev;
+       u_int32_t credit;
+       u_int32_t credit_cap, cost;
+};
+
+#endif
index 34e535ca157c1545749a036493a69ecef9d290e2..a30214c0a524e987099dbcf3770c3ac2ae64ed7b 100644 (file)
@@ -73,6 +73,17 @@ config BRIDGE_EBT_IP
 
          To compile it as a module, choose M here.  If unsure, say N.
 
+config BRIDGE_EBT_LIMIT
+       tristate "ebt: limit match support"
+       depends on BRIDGE_NF_EBTABLES
+       help
+         This option adds the limit match, which allows you to control
+         the rate at which a rule can be matched. This match is the
+         equivalent of the iptables limit match.
+
+         If you want to compile it as a module, say M here and read
+         <file:Documentation/modules.txt>.  If unsure, say `N'.
+
 config BRIDGE_EBT_MARK
        tristate "ebt: mark filter support"
        depends on BRIDGE_NF_EBTABLES
index f4e69939f7a907c82de45b0c232017cd76bf3e2d..a3bd9221ba58e608005453d90a8e00d86aaa5d89 100644 (file)
@@ -13,6 +13,7 @@ obj-$(CONFIG_BRIDGE_EBT_T_NAT) += ebtable_nat.o
 obj-$(CONFIG_BRIDGE_EBT_802_3) += ebt_802_3.o
 obj-$(CONFIG_BRIDGE_EBT_ARP) += ebt_arp.o
 obj-$(CONFIG_BRIDGE_EBT_IP) += ebt_ip.o
+obj-$(CONFIG_BRIDGE_EBT_LIMIT) += ebt_limit.o
 obj-$(CONFIG_BRIDGE_EBT_MARK) += ebt_mark_m.o
 obj-$(CONFIG_BRIDGE_EBT_PKTTYPE) += ebt_pkttype.o
 obj-$(CONFIG_BRIDGE_EBT_STP) += ebt_stp.o
diff --git a/net/bridge/netfilter/ebt_limit.c b/net/bridge/netfilter/ebt_limit.c
new file mode 100644 (file)
index 0000000..f816ec4
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ *  ebt_limit
+ *
+ *     Authors:
+ *     Tom Marshall <tommy@home.tig-grr.com>
+ *
+ *     Mostly copied from netfilter's ipt_limit.c, see that file for
+ *     more explanation
+ *
+ *  September, 2003
+ *
+ */
+
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_limit.h>
+#include <linux/module.h>
+
+#include <linux/netdevice.h>
+#include <linux/spinlock.h>
+
+static spinlock_t limit_lock = SPIN_LOCK_UNLOCKED;
+
+#define CREDITS_PER_JIFFY 128
+
+static int ebt_limit_match(const struct sk_buff *skb,
+   const struct net_device *in, const struct net_device *out,
+   const void *data, unsigned int datalen)
+{
+       struct ebt_limit_info *info = (struct ebt_limit_info *)data;
+       unsigned long now = jiffies;
+
+       spin_lock_bh(&limit_lock);
+       info->credit += (now - xchg(&info->prev, now)) * CREDITS_PER_JIFFY;
+       if (info->credit > info->credit_cap)
+               info->credit = info->credit_cap;
+
+       if (info->credit >= info->cost) {
+               /* We're not limited. */
+               info->credit -= info->cost;
+               spin_unlock_bh(&limit_lock);
+               return EBT_MATCH;
+       }
+
+       spin_unlock_bh(&limit_lock);
+       return EBT_NOMATCH;
+}
+
+/* Precision saver. */
+static u_int32_t
+user2credits(u_int32_t user)
+{
+       /* If multiplying would overflow... */
+       if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
+               /* Divide first. */
+               return (user / EBT_LIMIT_SCALE) * HZ * CREDITS_PER_JIFFY;
+
+       return (user * HZ * CREDITS_PER_JIFFY) / EBT_LIMIT_SCALE;
+}
+
+static int ebt_limit_check(const char *tablename, unsigned int hookmask,
+   const struct ebt_entry *e, void *data, unsigned int datalen)
+{
+       struct ebt_limit_info *info = (struct ebt_limit_info *)data;
+
+       if (datalen != EBT_ALIGN(sizeof(struct ebt_limit_info)))
+               return -EINVAL;
+
+       /* Check for overflow. */
+       if (info->burst == 0 ||
+           user2credits(info->avg * info->burst) < user2credits(info->avg)) {
+               printk("Overflow in ebt_limit: %u/%u\n",
+                       info->avg, info->burst);
+               return -EINVAL;
+       }
+
+       /* User avg in seconds * EBT_LIMIT_SCALE: convert to jiffies * 128. */
+       info->prev = jiffies;
+       info->credit = user2credits(info->avg * info->burst);
+       info->credit_cap = user2credits(info->avg * info->burst);
+       info->cost = user2credits(info->avg);
+       return 0;
+}
+
+static struct ebt_match ebt_limit_reg =
+{
+       .name           = EBT_LIMIT_MATCH,
+       .match          = ebt_limit_match,
+       .check          = ebt_limit_check,
+       .me             = THIS_MODULE,
+};
+
+static int __init init(void)
+{
+       return ebt_register_match(&ebt_limit_reg);
+}
+
+static void __exit fini(void)
+{
+       ebt_unregister_match(&ebt_limit_reg);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");