Commit a25a7f56 authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller

[NETFILTER]: kill struct nf_ct_info, saves five pointers per conntrack

The relationship of the skb to the conntrack is stored in a new field
in the skb.
Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6220ce1e
......@@ -178,7 +178,7 @@ extern inline struct ip6t_target *
ip6t_find_target_lock(const char *name, int *error, struct semaphore *mutex);
extern inline struct arpt_target *
arpt_find_target_lock(const char *name, int *error, struct semaphore *mutex);
extern void (*ip_ct_attach)(struct sk_buff *, struct nf_ct_info *);
extern void (*ip_ct_attach)(struct sk_buff *, struct sk_buff *);
#ifdef CONFIG_NETFILTER_DEBUG
extern void nf_dump_skb(int pf, struct sk_buff *skb);
......
......@@ -196,12 +196,7 @@ struct ip_conntrack
/* Helper, if any. */
struct ip_conntrack_helper *helper;
/* Our various nf_ct_info structs specify *what* relation this
packet has to the conntrack */
struct nf_ct_info infos[IP_CT_NUMBER];
/* Storage reserved for other modules: */
union ip_conntrack_proto proto;
union ip_conntrack_help help;
......@@ -238,8 +233,12 @@ ip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple,
const struct ip_conntrack *ignored_conntrack);
/* Return conntrack_info and tuple hash for given skb. */
extern struct ip_conntrack *
ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo);
static inline struct ip_conntrack *
ip_conntrack_get(const struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
{
*ctinfo = skb->nfctinfo;
return (struct ip_conntrack *)skb->nfct;
}
/* decrement reference count on a conntrack */
extern inline void ip_conntrack_put(struct ip_conntrack *ct);
......
......@@ -38,14 +38,14 @@ struct ip_conntrack_tuple_hash *
ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple,
const struct ip_conntrack *ignored_conntrack);
extern int __ip_conntrack_confirm(struct nf_ct_info *nfct);
extern int __ip_conntrack_confirm(struct sk_buff *skb);
/* Confirm a connection: returns NF_DROP if packet must be dropped. */
static inline int ip_conntrack_confirm(struct sk_buff *skb)
{
if (skb->nfct
&& !is_confirmed((struct ip_conntrack *)skb->nfct->master))
return __ip_conntrack_confirm(skb->nfct);
&& !is_confirmed((struct ip_conntrack *)skb->nfct))
return __ip_conntrack_confirm(skb);
return NF_ACCEPT;
}
......
......@@ -97,10 +97,6 @@ struct nf_conntrack {
void (*destroy)(struct nf_conntrack *);
};
struct nf_ct_info {
struct nf_conntrack *master;
};
#ifdef CONFIG_BRIDGE_NETFILTER
struct nf_bridge_info {
atomic_t use;
......@@ -186,6 +182,7 @@ struct skb_shared_info {
* @nfmark: Can be used for communication between hooks
* @nfcache: Cache info
* @nfct: Associated connection, if any
* @nfctinfo: Relationship of this skb to the connection
* @nf_debug: Netfilter debugging
* @nf_bridge: Saved data about a bridged frame - see br_netfilter.c
* @private: Data which is private to the HIPPI implementation
......@@ -253,7 +250,8 @@ struct sk_buff {
#ifdef CONFIG_NETFILTER
unsigned long nfmark;
__u32 nfcache;
struct nf_ct_info *nfct;
struct nf_conntrack *nfct;
__u32 nfctinfo;
#ifdef CONFIG_NETFILTER_DEBUG
unsigned int nf_debug;
#endif
......@@ -1141,15 +1139,15 @@ extern int skb_iter_next(const struct sk_buff *skb, struct skb_iter *i);
extern void skb_iter_abort(const struct sk_buff *skb, struct skb_iter *i);
#ifdef CONFIG_NETFILTER
static inline void nf_conntrack_put(struct nf_ct_info *nfct)
static inline void nf_conntrack_put(struct nf_conntrack *nfct)
{
if (nfct && atomic_dec_and_test(&nfct->master->use))
nfct->master->destroy(nfct->master);
if (nfct && atomic_dec_and_test(&nfct->use))
nfct->destroy(nfct);
}
static inline void nf_conntrack_get(struct nf_ct_info *nfct)
static inline void nf_conntrack_get(struct nf_conntrack *nfct)
{
if (nfct)
atomic_inc(&nfct->master->use);
atomic_inc(&nfct->use);
}
static inline void nf_reset(struct sk_buff *skb)
{
......
......@@ -806,7 +806,7 @@ EXPORT_SYMBOL(nf_log_packet);
tracking in use: without this, connection may not be in hash table,
and hence manufactured ICMP or RST packets will not be associated
with it. */
void (*ip_ct_attach)(struct sk_buff *, struct nf_ct_info *);
void (*ip_ct_attach)(struct sk_buff *, struct sk_buff *);
void __init netfilter_init(void)
{
......
......@@ -311,6 +311,7 @@ struct sk_buff *skb_clone(struct sk_buff *skb, int gfp_mask)
C(nfcache);
C(nfct);
nf_conntrack_get(skb->nfct);
C(nfctinfo);
#ifdef CONFIG_NETFILTER_DEBUG
C(nf_debug);
#endif
......@@ -377,6 +378,7 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
new->nfcache = old->nfcache;
new->nfct = old->nfct;
nf_conntrack_get(old->nfct);
new->nfctinfo = old->nfctinfo;
#ifdef CONFIG_NETFILTER_DEBUG
new->nf_debug = old->nf_debug;
#endif
......
......@@ -422,6 +422,7 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
nf_conntrack_put(to->nfct);
to->nfct = from->nfct;
nf_conntrack_get(to->nfct);
to->nfctinfo = from->nfctinfo;
#ifdef CONFIG_BRIDGE_NETFILTER
nf_bridge_put(to->nf_bridge);
to->nf_bridge = from->nf_bridge;
......
......@@ -112,10 +112,7 @@ inline void
ip_conntrack_put(struct ip_conntrack *ct)
{
IP_NF_ASSERT(ct);
IP_NF_ASSERT(ct->infos[0].master);
/* nf_conntrack_put wants to go via an info struct, so feed it
one at random. */
nf_conntrack_put(&ct->infos[0]);
nf_conntrack_put(&ct->ct_general);
}
static int ip_conntrack_hash_rnd_initted;
......@@ -416,36 +413,15 @@ ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple,
return h;
}
static inline struct ip_conntrack *
__ip_conntrack_get(struct nf_ct_info *nfct, enum ip_conntrack_info *ctinfo)
{
struct ip_conntrack *ct
= (struct ip_conntrack *)nfct->master;
/* ctinfo is the index of the nfct inside the conntrack */
*ctinfo = nfct - ct->infos;
IP_NF_ASSERT(*ctinfo >= 0 && *ctinfo < IP_CT_NUMBER);
return ct;
}
/* Return conntrack and conntrack_info given skb->nfct->master */
struct ip_conntrack *
ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
{
if (skb->nfct)
return __ip_conntrack_get(skb->nfct, ctinfo);
return NULL;
}
/* Confirm a connection given skb->nfct; places it in hash table */
/* Confirm a connection given skb; places it in hash table */
int
__ip_conntrack_confirm(struct nf_ct_info *nfct)
__ip_conntrack_confirm(struct sk_buff *skb)
{
unsigned int hash, repl_hash;
struct ip_conntrack *ct;
enum ip_conntrack_info ctinfo;
ct = __ip_conntrack_get(nfct, &ctinfo);
ct = ip_conntrack_get(skb, &ctinfo);
/* ipt_REJECT uses ip_conntrack_attach to attach related
ICMP/TCP RST packets in other direction. Actual packet
......@@ -570,7 +546,6 @@ init_conntrack(const struct ip_conntrack_tuple *tuple,
struct ip_conntrack_tuple repl_tuple;
size_t hash;
struct ip_conntrack_expect *expected;
int i;
if (!ip_conntrack_hash_rnd_initted) {
get_random_bytes(&ip_conntrack_hash_rnd, 4);
......@@ -609,9 +584,6 @@ init_conntrack(const struct ip_conntrack_tuple *tuple,
conntrack->tuplehash[IP_CT_DIR_ORIGINAL].ctrack = conntrack;
conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = repl_tuple;
conntrack->tuplehash[IP_CT_DIR_REPLY].ctrack = conntrack;
for (i=0; i < IP_CT_NUMBER; i++)
conntrack->infos[i].master = &conntrack->ct_general;
if (!protocol->new(conntrack, skb)) {
kmem_cache_free(ip_conntrack_cachep, conntrack);
return NULL;
......@@ -655,7 +627,7 @@ init_conntrack(const struct ip_conntrack_tuple *tuple,
expected->sibling = conntrack;
LIST_DELETE(&ip_conntrack_expect_list, expected);
expected->expectant->expecting--;
nf_conntrack_get(&master_ct(conntrack)->infos[0]);
nf_conntrack_get(&master_ct(conntrack)->ct_general);
/* this is a braindead... --pablo */
atomic_inc(&ip_conntrack_count);
......@@ -728,7 +700,8 @@ resolve_normal_ct(struct sk_buff *skb,
}
*set_reply = 0;
}
skb->nfct = &h->ctrack->infos[*ctinfo];
skb->nfct = &h->ctrack->ct_general;
skb->nfctinfo = *ctinfo;
return h->ctrack;
}
......@@ -1213,23 +1186,23 @@ ip_ct_gather_frags(struct sk_buff *skb)
}
/* Used by ipt_REJECT. */
static void ip_conntrack_attach(struct sk_buff *nskb, struct nf_ct_info *nfct)
static void ip_conntrack_attach(struct sk_buff *nskb, struct sk_buff *skb)
{
struct ip_conntrack *ct;
enum ip_conntrack_info ctinfo;
ct = __ip_conntrack_get(nfct, &ctinfo);
/* This ICMP is in reverse direction to the packet which
caused it */
/* This ICMP is in reverse direction to the packet which caused it */
ct = ip_conntrack_get(skb, &ctinfo);
if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)
ctinfo = IP_CT_RELATED + IP_CT_IS_REPLY;
else
ctinfo = IP_CT_RELATED;
/* Attach new skbuff, and increment count */
nskb->nfct = &ct->infos[ctinfo];
atomic_inc(&ct->ct_general.use);
/* Attach to new skbuff, and increment count */
nskb->nfct = &ct->ct_general;
nskb->nfctinfo = ctinfo;
nf_conntrack_get(nskb->nfct);
}
static inline int
......@@ -1441,11 +1414,6 @@ int __init ip_conntrack_init(void)
atomic_set(&ip_conntrack_untracked.ct_general.use, 1);
/* - and look it like as a confirmed connection */
set_bit(IPS_CONFIRMED_BIT, &ip_conntrack_untracked.status);
/* - and prepare the ctinfo field for REJECT & NAT. */
ip_conntrack_untracked.infos[IP_CT_NEW].master =
ip_conntrack_untracked.infos[IP_CT_RELATED].master =
ip_conntrack_untracked.infos[IP_CT_RELATED + IP_CT_IS_REPLY].master =
&ip_conntrack_untracked.ct_general;
return ret;
......
......@@ -195,7 +195,8 @@ icmp_error_message(struct sk_buff *skb,
}
/* Update skb to refer to this connection */
skb->nfct = &h->ctrack->infos[*ctinfo];
skb->nfct = &h->ctrack->ct_general;
skb->nfctinfo = *ctinfo;
return -NF_ACCEPT;
}
......
......@@ -146,7 +146,7 @@ check_for_demasq(struct sk_buff **pskb)
case IPPROTO_ICMP:
/* ICMP errors. */
protocol->error(*pskb, &ctinfo, NF_IP_PRE_ROUTING);
ct = (struct ip_conntrack *)(*pskb)->nfct->master;
ct = (struct ip_conntrack *)(*pskb)->nfct;
if (ct) {
/* We only do SNAT in the compatibility layer.
So we can manipulate ICMP errors from
......@@ -187,7 +187,7 @@ check_for_demasq(struct sk_buff **pskb)
NULL, NULL, NULL);
/* Put back the reference gained from find_get */
nf_conntrack_put(&h->ctrack->infos[0]);
nf_conntrack_put(&h->ctrack->ct_general);
if (ret == NF_ACCEPT) {
struct ip_conntrack *ct;
ct = ip_conntrack_get(*pskb, &ctinfo);
......@@ -206,7 +206,7 @@ check_for_demasq(struct sk_buff **pskb)
} else {
if (h)
/* Put back the reference gained from find_get */
nf_conntrack_put(&h->ctrack->infos[0]);
nf_conntrack_put(&h->ctrack->ct_general);
ret = NF_ACCEPT;
}
......
......@@ -23,7 +23,8 @@ target(struct sk_buff **pskb,
If there is a real ct entry correspondig to this packet,
it'll hang aroun till timing out. We don't deal with it
for performance reasons. JK */
(*pskb)->nfct = &ip_conntrack_untracked.infos[IP_CT_NEW];
(*pskb)->nfct = &ip_conntrack_untracked.ct_general;
(*pskb)->nfctinfo = IP_CT_NEW;
nf_conntrack_get((*pskb)->nfct);
return IPT_CONTINUE;
......
......@@ -41,14 +41,14 @@ MODULE_DESCRIPTION("iptables REJECT target module");
/* If the original packet is part of a connection, but the connection
is not confirmed, our manufactured reply will not be associated
with it, so we need to do this manually. */
static void connection_attach(struct sk_buff *new_skb, struct nf_ct_info *nfct)
static void connection_attach(struct sk_buff *new_skb, struct sk_buff *skb)
{
void (*attach)(struct sk_buff *, struct nf_ct_info *);
void (*attach)(struct sk_buff *, struct sk_buff *);
/* Avoid module unload race with ip_ct_attach being NULLed out */
if (nfct && (attach = ip_ct_attach) != NULL) {
if (skb->nfct && (attach = ip_ct_attach) != NULL) {
mb(); /* Just to be sure: must be read before executing this */
attach(new_skb, nfct);
attach(new_skb, skb);
}
}
......@@ -209,7 +209,7 @@ static void send_reset(struct sk_buff *oldskb, int hook)
if (nskb->len > dst_pmtu(nskb->dst))
goto free_nskb;
connection_attach(nskb, oldskb->nfct);
connection_attach(nskb, oldskb);
NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
ip_finish_output);
......@@ -360,7 +360,7 @@ static void send_unreach(struct sk_buff *skb_in, int code)
icmph->checksum = ip_compute_csum((unsigned char *)icmph,
length - sizeof(struct iphdr));
connection_attach(nskb, skb_in->nfct);
connection_attach(nskb, skb_in);
NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
ip_finish_output);
......
......@@ -35,7 +35,7 @@ match(const struct sk_buff *skb,
#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
if (skb->nfct == &ip_conntrack_untracked.infos[IP_CT_NEW])
if (ct == &ip_conntrack_untracked)
statebit = IPT_CONNTRACK_STATE_UNTRACKED;
else if (ct)
statebit = IPT_CONNTRACK_STATE_BIT(ctinfo);
......
......@@ -30,9 +30,9 @@ match(const struct sk_buff *skb,
enum ip_conntrack_info ctinfo;
unsigned int statebit;
if (skb->nfct == &ip_conntrack_untracked.infos[IP_CT_NEW])
if (skb->nfct == &ip_conntrack_untracked.ct_general)
statebit = IPT_STATE_UNTRACKED;
else if (!ip_conntrack_get((struct sk_buff *)skb, &ctinfo))
else if (!ip_conntrack_get(skb, &ctinfo))
statebit = IPT_STATE_INVALID;
else
statebit = IPT_STATE_BIT(ctinfo);
......
......@@ -477,6 +477,7 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from)
/* Connection association is same as pre-frag packet */
to->nfct = from->nfct;
nf_conntrack_get(to->nfct);
to->nfctinfo = from->nfctinfo;
#ifdef CONFIG_BRIDGE_NETFILTER
nf_bridge_put(to->nf_bridge);
to->nf_bridge = from->nf_bridge;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment