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

[NETFILTER]: Keep conntrack/nat protocols in array instead of linked list

Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c1041076
......@@ -16,10 +16,6 @@ extern int ip_conntrack_init(void);
extern void ip_conntrack_cleanup(void);
struct ip_conntrack_protocol;
extern struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol);
/* Like above, but you already have conntrack read lock. */
extern struct ip_conntrack_protocol *__ip_ct_find_proto(u_int8_t protocol);
extern struct list_head protocol_list;
extern int
ip_ct_get_tuple(const struct iphdr *iph,
......
......@@ -7,9 +7,6 @@ struct seq_file;
struct ip_conntrack_protocol
{
/* Next pointer. */
struct list_head list;
/* Protocol number. */
u_int8_t proto;
......@@ -58,14 +55,23 @@ struct ip_conntrack_protocol
struct module *me;
};
#define MAX_IP_CT_PROTO 256
extern struct ip_conntrack_protocol *ip_ct_protos[MAX_IP_CT_PROTO];
/* Protocol registration. */
extern int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto);
extern void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto);
static inline struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol)
{
return ip_ct_protos[protocol];
}
/* Existing built-in protocols */
extern struct ip_conntrack_protocol ip_conntrack_protocol_tcp;
extern struct ip_conntrack_protocol ip_conntrack_protocol_udp;
extern struct ip_conntrack_protocol ip_conntrack_protocol_icmp;
extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;
extern int ip_conntrack_protocol_tcp_init(void);
/* Log invalid packets */
......
......@@ -14,8 +14,6 @@ extern unsigned int do_bindings(struct ip_conntrack *ct,
unsigned int hooknum,
struct sk_buff **pskb);
extern struct list_head protos;
extern int icmp_reply_translation(struct sk_buff **pskb,
struct ip_conntrack *conntrack,
unsigned int hooknum,
......@@ -26,8 +24,4 @@ extern void replace_in_hashes(struct ip_conntrack *conntrack,
extern void place_in_hashes(struct ip_conntrack *conntrack,
struct ip_nat_info *info);
/* Built-in protocols. */
extern struct ip_nat_protocol ip_nat_protocol_tcp;
extern struct ip_nat_protocol ip_nat_protocol_udp;
extern struct ip_nat_protocol ip_nat_protocol_icmp;
#endif /* _IP_NAT_CORE_H */
......@@ -9,8 +9,6 @@ struct ip_nat_range;
struct ip_nat_protocol
{
struct list_head list;
/* Protocol name */
const char *name;
......@@ -47,10 +45,24 @@ struct ip_nat_protocol
const struct ip_nat_range *range);
};
#define MAX_IP_NAT_PROTO 256
extern struct ip_nat_protocol *ip_nat_protos[MAX_IP_NAT_PROTO];
/* Protocol registration. */
extern int ip_nat_protocol_register(struct ip_nat_protocol *proto);
extern void ip_nat_protocol_unregister(struct ip_nat_protocol *proto);
static inline struct ip_nat_protocol *ip_nat_find_proto(u_int8_t protocol)
{
return ip_nat_protos[protocol];
}
/* Built-in protocols. */
extern struct ip_nat_protocol ip_nat_protocol_tcp;
extern struct ip_nat_protocol ip_nat_protocol_udp;
extern struct ip_nat_protocol ip_nat_protocol_icmp;
extern struct ip_nat_protocol ip_nat_unknown_protocol;
extern int init_protocols(void) __init;
extern void cleanup_protocols(void);
extern struct ip_nat_protocol *find_nat_proto(u_int16_t protonum);
......
......@@ -66,7 +66,7 @@ EXPORT_SYMBOL(ip_conntrack_count);
void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL;
LIST_HEAD(ip_conntrack_expect_list);
LIST_HEAD(protocol_list);
struct ip_conntrack_protocol *ip_ct_protos[MAX_IP_CT_PROTO];
static LIST_HEAD(helpers);
unsigned int ip_conntrack_htable_size = 0;
int ip_conntrack_max;
......@@ -77,37 +77,6 @@ struct ip_conntrack ip_conntrack_untracked;
DEFINE_PER_CPU(struct ip_conntrack_stat, ip_conntrack_stat);
extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;
static inline int proto_cmpfn(const struct ip_conntrack_protocol *curr,
u_int8_t protocol)
{
return protocol == curr->proto;
}
struct ip_conntrack_protocol *__ip_ct_find_proto(u_int8_t protocol)
{
struct ip_conntrack_protocol *p;
MUST_BE_READ_LOCKED(&ip_conntrack_lock);
p = LIST_FIND(&protocol_list, proto_cmpfn,
struct ip_conntrack_protocol *, protocol);
if (!p)
p = &ip_conntrack_generic_protocol;
return p;
}
struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol)
{
struct ip_conntrack_protocol *p;
READ_LOCK(&ip_conntrack_lock);
p = __ip_ct_find_proto(protocol);
READ_UNLOCK(&ip_conntrack_lock);
return p;
}
inline void
ip_conntrack_put(struct ip_conntrack *ct)
{
......@@ -1397,10 +1366,12 @@ int __init ip_conntrack_init(void)
/* Don't NEED lock here, but good form anyway. */
WRITE_LOCK(&ip_conntrack_lock);
for (i = 0; i < MAX_IP_CT_PROTO; i++)
ip_ct_protos[i] = &ip_conntrack_generic_protocol;
/* Sew in builtin protocols. */
list_append(&protocol_list, &ip_conntrack_protocol_tcp);
list_append(&protocol_list, &ip_conntrack_protocol_udp);
list_append(&protocol_list, &ip_conntrack_protocol_icmp);
ip_ct_protos[IPPROTO_TCP] = &ip_conntrack_protocol_tcp;
ip_ct_protos[IPPROTO_UDP] = &ip_conntrack_protocol_udp;
ip_ct_protos[IPPROTO_ICMP] = &ip_conntrack_protocol_icmp;
WRITE_UNLOCK(&ip_conntrack_lock);
for (i = 0; i < ip_conntrack_htable_size; i++)
......
......@@ -496,7 +496,6 @@ static int sctp_exp_matches_pkt(struct ip_conntrack_expect *exp,
}
struct ip_conntrack_protocol ip_conntrack_protocol_sctp = {
.list = { NULL, NULL },
.proto = IPPROTO_SCTP,
.name = "sctp",
.pkt_to_tuple = sctp_pkt_to_tuple,
......
......@@ -112,7 +112,7 @@ static int ct_seq_real_show(const struct ip_conntrack_tuple_hash *hash,
if (DIRECTION(hash))
return 0;
proto = __ip_ct_find_proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
proto = ip_ct_find_proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
.tuple.dst.protonum);
IP_NF_ASSERT(proto);
......@@ -242,7 +242,7 @@ static int exp_seq_show(struct seq_file *s, void *v)
expect->tuple.dst.protonum);
print_tuple(s, &expect->tuple,
__ip_ct_find_proto(expect->tuple.dst.protonum));
ip_ct_find_proto(expect->tuple.dst.protonum));
return seq_putc(s, '\n');
}
......@@ -824,19 +824,13 @@ static int init_or_cleanup(int init)
int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto)
{
int ret = 0;
struct list_head *i;
WRITE_LOCK(&ip_conntrack_lock);
list_for_each(i, &protocol_list) {
if (((struct ip_conntrack_protocol *)i)->proto
== proto->proto) {
ret = -EBUSY;
goto out;
}
if (ip_ct_protos[proto->proto] != &ip_conntrack_generic_protocol) {
ret = -EBUSY;
goto out;
}
list_prepend(&protocol_list, proto);
ip_ct_protos[proto->proto] = proto;
out:
WRITE_UNLOCK(&ip_conntrack_lock);
return ret;
......@@ -845,10 +839,7 @@ int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto)
void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto)
{
WRITE_LOCK(&ip_conntrack_lock);
/* ip_ct_find_proto() returns proto_generic in case there is no protocol
* helper. So this should be enough - HW */
LIST_DELETE(&protocol_list, proto);
ip_ct_protos[proto->proto] = &ip_conntrack_generic_protocol;
WRITE_UNLOCK(&ip_conntrack_lock);
/* Somebody could be still looking at the proto in bh. */
......@@ -888,8 +879,8 @@ EXPORT_SYMBOL(ip_conntrack_helper_register);
EXPORT_SYMBOL(ip_conntrack_helper_unregister);
EXPORT_SYMBOL(ip_ct_selective_cleanup);
EXPORT_SYMBOL(ip_ct_refresh_acct);
EXPORT_SYMBOL(ip_ct_protos);
EXPORT_SYMBOL(ip_ct_find_proto);
EXPORT_SYMBOL(__ip_ct_find_proto);
EXPORT_SYMBOL(ip_ct_find_helper);
EXPORT_SYMBOL(ip_conntrack_expect_alloc);
EXPORT_SYMBOL(ip_conntrack_expect_related);
......
......@@ -48,9 +48,8 @@ static unsigned int ip_nat_htable_size;
static struct list_head *bysource;
static struct list_head *byipsproto;
LIST_HEAD(protos);
struct ip_nat_protocol *ip_nat_protos[MAX_IP_NAT_PROTO];
extern struct ip_nat_protocol unknown_nat_protocol;
/* We keep extra hashes for each conntrack, for fast searching. */
static inline size_t
......@@ -103,23 +102,6 @@ ip_nat_cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
oldcheck^0xFFFF));
}
static inline int cmp_proto(const struct ip_nat_protocol *i, int proto)
{
return i->protonum == proto;
}
struct ip_nat_protocol *
find_nat_proto(u_int16_t protonum)
{
struct ip_nat_protocol *i;
MUST_BE_READ_LOCKED(&ip_nat_lock);
i = LIST_FIND(&protos, cmp_proto, struct ip_nat_protocol *, protonum);
if (!i)
i = &unknown_nat_protocol;
return i;
}
/* Is this tuple already taken? (not by us) */
int
ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple,
......@@ -142,7 +124,7 @@ in_range(const struct ip_conntrack_tuple *tuple,
const struct ip_conntrack_manip *manip,
const struct ip_nat_multi_range *mr)
{
struct ip_nat_protocol *proto = find_nat_proto(tuple->dst.protonum);
struct ip_nat_protocol *proto = ip_nat_find_proto(tuple->dst.protonum);
unsigned int i;
struct ip_conntrack_tuple newtuple = { *manip, tuple->dst };
......@@ -394,7 +376,7 @@ get_unique_tuple(struct ip_conntrack_tuple *tuple,
unsigned int hooknum)
{
struct ip_nat_protocol *proto
= find_nat_proto(orig_tuple->dst.protonum);
= ip_nat_find_proto(orig_tuple->dst.protonum);
struct ip_nat_range *rptr;
unsigned int i;
int ret;
......@@ -705,9 +687,8 @@ manip_pkt(u_int16_t proto,
iph = (void *)(*pskb)->data + iphdroff;
/* Manipulate protcol part. */
if (!find_nat_proto(proto)->manip_pkt(pskb,
iphdroff + iph->ihl*4,
manip, maniptype))
if (!ip_nat_find_proto(proto)->manip_pkt(pskb, iphdroff + iph->ihl*4,
manip, maniptype))
return 0;
iph = (void *)(*pskb)->data + iphdroff;
......@@ -731,7 +712,7 @@ static inline int exp_for_packet(struct ip_conntrack_expect *exp,
int ret = 1;
MUST_BE_READ_LOCKED(&ip_conntrack_lock);
proto = __ip_ct_find_proto(skb->nh.iph->protocol);
proto = ip_ct_find_proto(skb->nh.iph->protocol);
if (proto->exp_matches_pkt)
ret = proto->exp_matches_pkt(exp, skb);
......@@ -976,9 +957,11 @@ int __init ip_nat_init(void)
/* Sew in builtin protocols. */
WRITE_LOCK(&ip_nat_lock);
list_append(&protos, &ip_nat_protocol_tcp);
list_append(&protos, &ip_nat_protocol_udp);
list_append(&protos, &ip_nat_protocol_icmp);
for (i = 0; i < MAX_IP_NAT_PROTO; i++)
ip_nat_protos[i] = &ip_nat_unknown_protocol;
ip_nat_protos[IPPROTO_TCP] = &ip_nat_protocol_tcp;
ip_nat_protos[IPPROTO_UDP] = &ip_nat_protocol_udp;
ip_nat_protos[IPPROTO_ICMP] = &ip_nat_protocol_icmp;
WRITE_UNLOCK(&ip_nat_lock);
for (i = 0; i < ip_nat_htable_size; i++) {
......
......@@ -104,7 +104,7 @@ icmp_print_range(char *buffer, const struct ip_nat_range *range)
}
struct ip_nat_protocol ip_nat_protocol_icmp
= { { NULL, NULL }, "ICMP", IPPROTO_ICMP,
= { "ICMP", IPPROTO_ICMP,
icmp_manip_pkt,
icmp_in_range,
icmp_unique_tuple,
......
......@@ -162,7 +162,7 @@ tcp_print_range(char *buffer, const struct ip_nat_range *range)
}
struct ip_nat_protocol ip_nat_protocol_tcp
= { { NULL, NULL }, "TCP", IPPROTO_TCP,
= { "TCP", IPPROTO_TCP,
tcp_manip_pkt,
tcp_in_range,
tcp_unique_tuple,
......
......@@ -148,7 +148,7 @@ udp_print_range(char *buffer, const struct ip_nat_range *range)
}
struct ip_nat_protocol ip_nat_protocol_udp
= { { NULL, NULL }, "UDP", IPPROTO_UDP,
= { "UDP", IPPROTO_UDP,
udp_manip_pkt,
udp_in_range,
udp_unique_tuple,
......
......@@ -60,8 +60,8 @@ unknown_print_range(char *buffer, const struct ip_nat_range *range)
return 0;
}
struct ip_nat_protocol unknown_nat_protocol = {
{ NULL, NULL }, "unknown", 0,
struct ip_nat_protocol ip_nat_unknown_protocol = {
"unknown", 0,
unknown_manip_pkt,
unknown_in_range,
unknown_unique_tuple,
......
......@@ -283,18 +283,13 @@ static struct nf_hook_ops ip_nat_local_in_ops = {
int ip_nat_protocol_register(struct ip_nat_protocol *proto)
{
int ret = 0;
struct list_head *i;
WRITE_LOCK(&ip_nat_lock);
list_for_each(i, &protos) {
if (((struct ip_nat_protocol *)i)->protonum
== proto->protonum) {
ret = -EBUSY;
goto out;
}
if (ip_nat_protos[proto->protonum] != &ip_nat_unknown_protocol) {
ret = -EBUSY;
goto out;
}
list_prepend(&protos, proto);
ip_nat_protos[proto->protonum] = proto;
out:
WRITE_UNLOCK(&ip_nat_lock);
return ret;
......@@ -304,7 +299,7 @@ int ip_nat_protocol_register(struct ip_nat_protocol *proto)
void ip_nat_protocol_unregister(struct ip_nat_protocol *proto)
{
WRITE_LOCK(&ip_nat_lock);
LIST_DELETE(&protos, proto);
ip_nat_protos[proto->protonum] = &ip_nat_unknown_protocol;
WRITE_UNLOCK(&ip_nat_lock);
/* Someone could be still looking at the proto in a bh. */
......
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