#include <linux/sctp.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
-
-#define ASSERT_READ_LOCK(x)
-#define ASSERT_WRITE_LOCK(x)
-#include <linux/netfilter_ipv4/lockhelp.h>
-#include <linux/netfilter_ipv4/listhelp.h>
+#include <linux/list.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_hashlimit.h>
/* FIXME: this is just for IP_NF_ASSERRT */
#include <linux/netfilter_ipv4/ip_conntrack.h>
-#define MS2JIFFIES(x) ((x*HZ)/1000)
-
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
MODULE_DESCRIPTION("iptables match for limiting per hash-bucket");
struct dsthash_ent {
/* static / read-only parts in the beginning */
- struct list_head list;
+ struct hlist_node node;
struct dsthash_dst dst;
/* modified structure members in the end */
};
struct ipt_hashlimit_htable {
- struct list_head list; /* global list of all htables */
+ struct hlist_node node; /* global list of all htables */
atomic_t use;
struct hashlimit_cfg cfg; /* config */
/* seq_file stuff */
struct proc_dir_entry *pde;
- struct list_head hash[0]; /* hashtable itself */
+ struct hlist_head hash[0]; /* hashtable itself */
};
-static DECLARE_RWLOCK(hashlimit_lock); /* protects htables list */
+static DEFINE_SPINLOCK(hashlimit_lock); /* protects htables list */
static DECLARE_MUTEX(hlimit_mutex); /* additional checkentry protection */
-static LIST_HEAD(hashlimit_htables);
-static kmem_cache_t *hashlimit_cachep;
+static HLIST_HEAD(hashlimit_htables);
+static kmem_cache_t *hashlimit_cachep __read_mostly;
static inline int dst_cmp(const struct dsthash_ent *ent, struct dsthash_dst *b)
{
static inline u_int32_t
hash_dst(const struct ipt_hashlimit_htable *ht, const struct dsthash_dst *dst)
{
- return (jhash_3words(dst->dst_ip, (dst->dst_port<<16 & dst->src_port),
+ return (jhash_3words(dst->dst_ip, (dst->dst_port<<16 | dst->src_port),
dst->src_ip, ht->rnd) % ht->cfg.size);
}
__dsthash_find(const struct ipt_hashlimit_htable *ht, struct dsthash_dst *dst)
{
struct dsthash_ent *ent;
+ struct hlist_node *pos;
u_int32_t hash = hash_dst(ht, dst);
- ent = LIST_FIND(&ht->hash[hash], dst_cmp, struct dsthash_ent *, dst);
- return ent;
+
+ if (!hlist_empty(&ht->hash[hash]))
+ hlist_for_each_entry(ent, pos, &ht->hash[hash], node) {
+ if (dst_cmp(ent, dst)) {
+ return ent;
+ }
+ }
+
+ return NULL;
}
/* allocate dsthash_ent, initialize dst, put in htable and lock it */
ent->dst.src_ip = dst->src_ip;
ent->dst.src_port = dst->src_port;
- list_add(&ent->list, &ht->hash[hash_dst(ht, dst)]);
+ hlist_add_head(&ent->node, &ht->hash[hash_dst(ht, dst)]);
return ent;
}
static inline void
__dsthash_free(struct ipt_hashlimit_htable *ht, struct dsthash_ent *ent)
{
- list_del(&ent->list);
+ hlist_del(&ent->node);
kmem_cache_free(hashlimit_cachep, ent);
atomic_dec(&ht->count);
}
hinfo->cfg.max = hinfo->cfg.size;
for (i = 0; i < hinfo->cfg.size; i++)
- INIT_LIST_HEAD(&hinfo->hash[i]);
+ INIT_HLIST_HEAD(&hinfo->hash[i]);
atomic_set(&hinfo->count, 0);
atomic_set(&hinfo->use, 1);
hinfo->pde->data = hinfo;
init_timer(&hinfo->timer);
- hinfo->timer.expires = jiffies + MS2JIFFIES(hinfo->cfg.gc_interval);
+ hinfo->timer.expires = jiffies + msecs_to_jiffies(hinfo->cfg.gc_interval);
hinfo->timer.data = (unsigned long )hinfo;
hinfo->timer.function = htable_gc;
add_timer(&hinfo->timer);
- WRITE_LOCK(&hashlimit_lock);
- list_add(&hinfo->list, &hashlimit_htables);
- WRITE_UNLOCK(&hashlimit_lock);
+ spin_lock_bh(&hashlimit_lock);
+ hlist_add_head(&hinfo->node, &hashlimit_htables);
+ spin_unlock_bh(&hashlimit_lock);
return 0;
}
/* lock hash table and iterate over it */
spin_lock_bh(&ht->lock);
for (i = 0; i < ht->cfg.size; i++) {
- struct dsthash_ent *dh, *n;
- list_for_each_entry_safe(dh, n, &ht->hash[i], list) {
+ struct dsthash_ent *dh;
+ struct hlist_node *pos, *n;
+ hlist_for_each_entry_safe(dh, pos, n, &ht->hash[i], node) {
if ((*select)(ht, dh))
__dsthash_free(ht, dh);
}
htable_selective_cleanup(ht, select_gc);
/* re-add the timer accordingly */
- ht->timer.expires = jiffies + MS2JIFFIES(ht->cfg.gc_interval);
+ ht->timer.expires = jiffies + msecs_to_jiffies(ht->cfg.gc_interval);
add_timer(&ht->timer);
}
static struct ipt_hashlimit_htable *htable_find_get(char *name)
{
struct ipt_hashlimit_htable *hinfo;
+ struct hlist_node *pos;
- READ_LOCK(&hashlimit_lock);
- list_for_each_entry(hinfo, &hashlimit_htables, list) {
+ spin_lock_bh(&hashlimit_lock);
+ hlist_for_each_entry(hinfo, pos, &hashlimit_htables, node) {
if (!strcmp(name, hinfo->pde->name)) {
atomic_inc(&hinfo->use);
- READ_UNLOCK(&hashlimit_lock);
+ spin_unlock_bh(&hashlimit_lock);
return hinfo;
}
}
- READ_UNLOCK(&hashlimit_lock);
+ spin_unlock_bh(&hashlimit_lock);
return NULL;
}
static void htable_put(struct ipt_hashlimit_htable *hinfo)
{
if (atomic_dec_and_test(&hinfo->use)) {
- WRITE_LOCK(&hashlimit_lock);
- list_del(&hinfo->list);
- WRITE_UNLOCK(&hashlimit_lock);
+ spin_lock_bh(&hashlimit_lock);
+ hlist_del(&hinfo->node);
+ spin_unlock_bh(&hashlimit_lock);
htable_destroy(hinfo);
}
}
const struct net_device *out,
const void *matchinfo,
int offset,
+ unsigned int protoff,
int *hotdrop)
{
struct ipt_hashlimit_info *r =
return 0;
}
- dh->expires = jiffies + MS2JIFFIES(hinfo->cfg.expire);
+ dh->expires = jiffies + msecs_to_jiffies(hinfo->cfg.expire);
dh->rateinfo.prev = jiffies;
dh->rateinfo.credit = user2credits(hinfo->cfg.avg *
}
/* update expiration timeout */
- dh->expires = now + MS2JIFFIES(hinfo->cfg.expire);
+ dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire);
rateinfo_recalc(dh, now);
if (dh->rateinfo.credit >= dh->rateinfo.cost) {
static int
hashlimit_checkentry(const char *tablename,
- const struct ipt_ip *ip,
+ const void *inf,
void *matchinfo,
unsigned int matchsize,
unsigned int hook_mask)
rateinfo_recalc(ent, jiffies);
return seq_printf(s, "%ld %u.%u.%u.%u:%u->%u.%u.%u.%u:%u %u %u %u\n",
- (ent->expires - jiffies)/HZ,
+ (long)(ent->expires - jiffies)/HZ,
NIPQUAD(ent->dst.src_ip), ntohs(ent->dst.src_port),
NIPQUAD(ent->dst.dst_ip), ntohs(ent->dst.dst_port),
ent->rateinfo.credit, ent->rateinfo.credit_cap,
struct proc_dir_entry *pde = s->private;
struct ipt_hashlimit_htable *htable = pde->data;
unsigned int *bucket = (unsigned int *)v;
-
- if (LIST_FIND_W(&htable->hash[*bucket], dl_seq_real_show,
- struct dsthash_ent *, s)) {
- /* buffer was filled and unable to print that tuple */
- return 1;
- }
+ struct dsthash_ent *ent;
+ struct hlist_node *pos;
+
+ if (!hlist_empty(&htable->hash[*bucket]))
+ hlist_for_each_entry(ent, pos, &htable->hash[*bucket], node) {
+ if (dl_seq_real_show(ent, s)) {
+ /* buffer was filled and unable to print that tuple */
+ return 1;
+ }
+ }
+
return 0;
}