[PATCH 4/8] Netfilter: Use ct_extend for conntrack mark value
Rusty Russell
rusty at rustcorp.com.au
Wed Jan 12 21:58:44 CET 2005
Name: Use ct_extend for conntrack mark value
Status: Tested lightly under nfsim
Signed-off-by: Rusty Russell <rusty at rustcorp.com.au>
Move the connection tracking mark value to ct_extend. While used
frequently, ct_extend_find() is a few cycles and only a single
cacheline access. Certainly cheap if most connections don't have
anything in ct->ext.
Index: linux-2.6.10-bk14-Netfilter/net/ipv4/netfilter/ipt_CONNMARK.c
===================================================================
--- linux-2.6.10-bk14-Netfilter.orig/net/ipv4/netfilter/ipt_CONNMARK.c 2005-01-12 23:29:02.873081376 +1100
+++ linux-2.6.10-bk14-Netfilter/net/ipv4/netfilter/ipt_CONNMARK.c 2005-01-12 23:41:09.570606560 +1100
@@ -30,6 +30,23 @@
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_CONNMARK.h>
#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ct_extend.h>
+
+static unsigned int set_mark(struct ip_conntrack *ct,
+ unsigned long *markp,
+ unsigned long mark)
+{
+ if (!markp) {
+ /* Nonexistent means 0 anyway. */
+ if (mark == 0)
+ return IPT_CONTINUE;
+ markp = ct_extend_add(&ct->ext, CTE_MARK, GFP_ATOMIC);
+ if (!markp)
+ return NF_DROP;
+ }
+ *markp = mark;
+ return IPT_CONTINUE;
+}
static unsigned int
target(struct sk_buff **pskb,
@@ -40,36 +57,51 @@
void *userinfo)
{
const struct ipt_connmark_target_info *markinfo = targinfo;
+ unsigned int ret = IPT_CONTINUE;
unsigned long diff;
unsigned long nfmark;
unsigned long newmark;
-
+ unsigned long mark, *markp;
enum ip_conntrack_info ctinfo;
struct ip_conntrack *ct = ip_conntrack_get((*pskb), &ctinfo);
- if (ct) {
- switch(markinfo->mode) {
- case IPT_CONNMARK_SET:
- newmark = (ct->mark & ~markinfo->mask) | markinfo->mark;
- if (newmark != ct->mark)
- ct->mark = newmark;
- break;
- case IPT_CONNMARK_SAVE:
- newmark = (ct->mark & ~markinfo->mask) | ((*pskb)->nfmark & markinfo->mask);
- if (ct->mark != newmark)
- ct->mark = newmark;
- break;
- case IPT_CONNMARK_RESTORE:
+
+ if (!ct)
+ return IPT_CONTINUE;
+
+ switch(markinfo->mode) {
+ case IPT_CONNMARK_SET:
+ WRITE_LOCK(&ip_conntrack_lock);
+ markp = ct_extend_find(ct->ext, CTE_MARK);
+ mark = markp ? *markp : 0;
+
+ newmark = (mark & ~markinfo->mask) | markinfo->mark;
+ ret = set_mark(ct, markp, newmark);
+ WRITE_UNLOCK(&ip_conntrack_lock);
+ case IPT_CONNMARK_SAVE:
+ WRITE_LOCK(&ip_conntrack_lock);
+ markp = ct_extend_find(ct->ext, CTE_MARK);
+ mark = markp ? *markp : 0;
+
+ newmark = ((mark & ~markinfo->mask)
+ | ((*pskb)->nfmark & markinfo->mask));
+ ret = set_mark(ct, markp, newmark);
+ WRITE_UNLOCK(&ip_conntrack_lock);
+ case IPT_CONNMARK_RESTORE:
+ READ_LOCK(&ip_conntrack_lock);
+ markp = ct_extend_find(ct->ext, CTE_MARK);
+ mark = markp ? *markp : 0;
+
nfmark = (*pskb)->nfmark;
- diff = (ct->mark ^ nfmark) & markinfo->mask;
+ diff = (mark ^ nfmark) & markinfo->mask;
if (diff != 0) {
- (*pskb)->nfmark = nfmark ^ diff;
- (*pskb)->nfcache |= NFC_ALTERED;
+ (*pskb)->nfmark = nfmark ^ diff;
+ (*pskb)->nfcache |= NFC_ALTERED;
}
+ READ_UNLOCK(&ip_conntrack_lock);
break;
- }
}
- return IPT_CONTINUE;
+ return ret;
}
static int
Index: linux-2.6.10-bk14-Netfilter/net/ipv4/netfilter/ip_conntrack_standalone.c
===================================================================
--- linux-2.6.10-bk14-Netfilter.orig/net/ipv4/netfilter/ip_conntrack_standalone.c 2005-01-12 23:29:02.874081224 +1100
+++ linux-2.6.10-bk14-Netfilter/net/ipv4/netfilter/ip_conntrack_standalone.c 2005-01-12 23:41:09.571606408 +1100
@@ -36,6 +36,7 @@
#include <linux/netfilter_ipv4/ip_conntrack_core.h>
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
#include <linux/netfilter_ipv4/listhelp.h>
+#include <linux/netfilter_ipv4/ct_extend.h>
#if 0
#define DEBUGP printk
@@ -96,6 +97,25 @@
return &ip_conntrack_hash[*pos];
}
+#ifdef CONFIG_IP_NF_CONNTRACK_MARK
+static int print_mark(struct seq_file *s, const struct ip_conntrack *conntrack)
+{
+ unsigned long *markp, mark;
+
+ READ_LOCK(&ip_conntrack_lock);
+ markp = ct_extend_find(conntrack->ext, CTE_MARK);
+ mark = markp ? *markp: 0;
+ READ_UNLOCK(&ip_conntrack_lock);
+
+ return seq_printf(s, "mark=%ld ", mark);
+}
+#else
+static int print_mark(struct seq_file *s, const struct ip_conntrack *conntrack)
+{
+ return 0;
+}
+#endif
+
/* return 0 on success, 1 in case of error */
static int ct_seq_real_show(const struct ip_conntrack_tuple_hash *hash,
struct seq_file *s)
@@ -147,10 +167,8 @@
if (seq_printf(s, "[ASSURED] "))
return 1;
-#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
- if (seq_printf(s, "mark=%ld ", conntrack->mark))
+ if (print_mark(s, conntrack) != 0)
return 1;
-#endif
if (seq_printf(s, "use=%u\n", atomic_read(&conntrack->ct_general.use)))
return 1;
Index: linux-2.6.10-bk14-Netfilter/include/linux/netfilter_ipv4/ip_conntrack.h
===================================================================
--- linux-2.6.10-bk14-Netfilter.orig/include/linux/netfilter_ipv4/ip_conntrack.h 2005-01-12 23:40:34.631918048 +1100
+++ linux-2.6.10-bk14-Netfilter/include/linux/netfilter_ipv4/ip_conntrack.h 2005-01-12 23:41:09.573606104 +1100
@@ -187,10 +187,6 @@
} nat;
#endif /* CONFIG_IP_NF_NAT_NEEDED */
-#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
- unsigned long mark;
-#endif
-
/* Traversed often, so hopefully in different cacheline to top */
/* These are my tuples; original and reply */
struct ip_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX];
Index: linux-2.6.10-bk14-Netfilter/net/ipv4/netfilter/ipt_connmark.c
===================================================================
--- linux-2.6.10-bk14-Netfilter.orig/net/ipv4/netfilter/ipt_connmark.c 2005-01-12 23:29:02.874081224 +1100
+++ linux-2.6.10-bk14-Netfilter/net/ipv4/netfilter/ipt_connmark.c 2005-01-12 23:41:09.573606104 +1100
@@ -29,6 +29,7 @@
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_connmark.h>
#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ct_extend.h>
static int
match(const struct sk_buff *skb,
@@ -40,11 +41,19 @@
{
const struct ipt_connmark_info *info = matchinfo;
enum ip_conntrack_info ctinfo;
- struct ip_conntrack *ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
+ struct ip_conntrack *ct;
+ unsigned long *markp, mark;
+
+ ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
if (!ct)
return 0;
- return ((ct->mark & info->mask) == info->mark) ^ info->invert;
+ READ_LOCK(&ip_conntrack_lock);
+ markp = ct_extend_find(ct->ext, CTE_MARK);
+ mark = markp ? *markp : 0;
+ READ_UNLOCK(&ip_conntrack_lock);
+
+ return ((mark & info->mask) == info->mark) ^ info->invert;
}
static int
Index: linux-2.6.10-bk14-Netfilter/net/ipv4/netfilter/ipt_CLUSTERIP.c
===================================================================
--- linux-2.6.10-bk14-Netfilter.orig/net/ipv4/netfilter/ipt_CLUSTERIP.c 2005-01-12 23:29:02.874081224 +1100
+++ linux-2.6.10-bk14-Netfilter/net/ipv4/netfilter/ipt_CLUSTERIP.c 2005-01-12 23:41:09.575605800 +1100
@@ -29,6 +29,7 @@
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_CLUSTERIP.h>
#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ct_extend.h>
#define CLUSTERIP_VERSION "0.6"
@@ -319,6 +320,7 @@
const struct ipt_clusterip_tgt_info *cipinfo = targinfo;
enum ip_conntrack_info ctinfo;
struct ip_conntrack *ct = ip_conntrack_get((*pskb), &ctinfo);
+ unsigned long *mark;
u_int32_t hash;
/* don't need to clusterip_config_get() here, since refcount
@@ -347,8 +349,16 @@
hash = clusterip_hashfn(*pskb, cipinfo->config);
switch (ctinfo) {
- case IP_CT_NEW:
- ct->mark = hash;
+ case IP_CT_NEW: {
+ WRITE_LOCK(&ip_conntrack_lock);
+ mark = ct_extend_find(ct->ext, CTE_MARK);
+ if (!mark && !(mark = ct_extend_add(&ct->ext, CTE_MARK,
+ GFP_ATOMIC))) {
+ WRITE_UNLOCK(&ip_conntrack_lock);
+ return NF_DROP;
+ }
+ *mark = hash;
+ WRITE_UNLOCK(&ip_conntrack_lock);
break;
case IP_CT_RELATED:
case IP_CT_RELATED+IP_CT_IS_REPLY:
@@ -365,7 +375,6 @@
#ifdef DEBUG_CLUSTERP
DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
#endif
- DEBUGP("hash=%u ct_hash=%lu ", hash, ct->mark);
if (!clusterip_responsible(cipinfo->config, hash)) {
DEBUGP("not responsible\n");
return NF_DROP;
Index: linux-2.6.10-bk14-Netfilter/include/linux/netfilter_ipv4/ct_extend.h
===================================================================
--- linux-2.6.10-bk14-Netfilter.orig/include/linux/netfilter_ipv4/ct_extend.h 2005-01-12 23:41:03.500529352 +1100
+++ linux-2.6.10-bk14-Netfilter/include/linux/netfilter_ipv4/ct_extend.h 2005-01-12 23:41:58.520165096 +1100
@@ -6,11 +6,13 @@
{
CTE_MASQ,
CTE_FTP_CONN,
+ CTE_MARK,
CTE_MAX,
} __attribute__((packed));
#define CTE_MASQ_TYPE char /* Actually char[IFNAMSIZ] */
#define CTE_FTP_CONN_TYPE struct ip_ct_ftp_master
+#define CTE_MARK_TYPE unsigned long
/* Extensions: optional stuff which isn't permanently in struct. */
struct ct_extend {
Index: linux-2.6.10-bk14-Netfilter/net/ipv4/netfilter/ip_conntrack_core.c
===================================================================
--- linux-2.6.10-bk14-Netfilter.orig/net/ipv4/netfilter/ip_conntrack_core.c 2005-01-12 23:39:20.531183072 +1100
+++ linux-2.6.10-bk14-Netfilter/net/ipv4/netfilter/ip_conntrack_core.c 2005-01-12 23:41:09.578605344 +1100
@@ -456,6 +456,51 @@
tuple);
}
+#if CONFIG_IP_NF_CONNTRACK_MARK
+static struct ct_extend_type mark_extend =
+{
+ .len = sizeof(unsigned long),
+ .align = __alignof__(unsigned long),
+ .type = CTE_MARK,
+};
+
+static int copy_mark(struct ip_conntrack *new, struct ip_conntrack *old)
+{
+ unsigned long *mark, *newmark;
+
+ mark = ct_extend_find(old, CTE_MARK);
+ if (!mark)
+ return 0;
+
+ newmark = ct_extend_add(&new->ext, CTE_MARK, GFP_ATOMIC);
+ if (!newmark)
+ return -ENOMEM;
+ *newmark = *mark;
+ return 0;
+}
+
+static void register_cte_mark(void)
+{
+ register_ct_extend_type(&mark_extend);
+}
+
+static void unregister_cte_mark(void)
+{
+ unregister_ct_extend_type(&mark_extend);
+}
+#else
+static inline int copy_mark(struct ip_conntrack *new, struct ip_conntrack *old)
+{
+ return 0;
+}
+static void register_cte_mark(void)
+{
+}
+static void unregister_cte_mark(void)
+{
+}
+#endif
+
/* Allocate a new conntrack: we return -ENOMEM if classification
failed due to stress. Otherwise it really is unclassifiable. */
static struct ip_conntrack_tuple_hash *
@@ -520,10 +565,12 @@
conntrack, exp);
/* Welcome, Mr. Bond. We've been expecting you... */
__set_bit(IPS_EXPECTED_BIT, &conntrack->status);
+ if (copy_mark(conntrack, exp->master) < 0) {
+ WRITE_UNLOCK(&ip_conntrack_lock);
+ kmem_cache_free(ip_conntrack_cachep, conntrack);
+ return NULL;
+ }
conntrack->master = exp->master;
-#if CONFIG_IP_NF_CONNTRACK_MARK
- conntrack->mark = exp->master->mark;
-#endif
nf_conntrack_get(&conntrack->master->ct_general);
CONNTRACK_STAT_INC(expect_new);
} else {
@@ -1148,6 +1195,7 @@
goto i_see_dead_people;
}
+ unregister_cte_mark();
kmem_cache_destroy(ip_conntrack_cachep);
kmem_cache_destroy(ip_conntrack_expect_cachep);
free_conntrack_hash();
@@ -1245,6 +1293,8 @@
/* - and look it like as a confirmed connection */
set_bit(IPS_CONFIRMED_BIT, &ip_conntrack_untracked.status);
+ register_cte_mark();
+
return ret;
err_free_conntrack_slab:
More information about the netfilter-devel
mailing list