[NETFILTER]: connection tracking event notifiers
This adds a notifier chain based event mechanism for ip_conntrack state changes. As opposed to the previous implementations in patch-o-matic, we do no longer need a field in the skb to achieve this. Thanks to the valuable input from Patrick McHardy and Rusty on the idea of a per_cpu implementation. Signed-off-by: Harald Welte <laforge@netfilter.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
abc3bc5804
commit
ac3247baf8
10 changed files with 311 additions and 14 deletions
|
@ -65,6 +65,63 @@ enum ip_conntrack_status {
|
|||
|
||||
/* Both together */
|
||||
IPS_NAT_DONE_MASK = (IPS_DST_NAT_DONE | IPS_SRC_NAT_DONE),
|
||||
|
||||
/* Connection is dying (removed from lists), can not be unset. */
|
||||
IPS_DYING_BIT = 9,
|
||||
IPS_DYING = (1 << IPS_DYING_BIT),
|
||||
};
|
||||
|
||||
/* Connection tracking event bits */
|
||||
enum ip_conntrack_events
|
||||
{
|
||||
/* New conntrack */
|
||||
IPCT_NEW_BIT = 0,
|
||||
IPCT_NEW = (1 << IPCT_NEW_BIT),
|
||||
|
||||
/* Expected connection */
|
||||
IPCT_RELATED_BIT = 1,
|
||||
IPCT_RELATED = (1 << IPCT_RELATED_BIT),
|
||||
|
||||
/* Destroyed conntrack */
|
||||
IPCT_DESTROY_BIT = 2,
|
||||
IPCT_DESTROY = (1 << IPCT_DESTROY_BIT),
|
||||
|
||||
/* Timer has been refreshed */
|
||||
IPCT_REFRESH_BIT = 3,
|
||||
IPCT_REFRESH = (1 << IPCT_REFRESH_BIT),
|
||||
|
||||
/* Status has changed */
|
||||
IPCT_STATUS_BIT = 4,
|
||||
IPCT_STATUS = (1 << IPCT_STATUS_BIT),
|
||||
|
||||
/* Update of protocol info */
|
||||
IPCT_PROTOINFO_BIT = 5,
|
||||
IPCT_PROTOINFO = (1 << IPCT_PROTOINFO_BIT),
|
||||
|
||||
/* Volatile protocol info */
|
||||
IPCT_PROTOINFO_VOLATILE_BIT = 6,
|
||||
IPCT_PROTOINFO_VOLATILE = (1 << IPCT_PROTOINFO_VOLATILE_BIT),
|
||||
|
||||
/* New helper for conntrack */
|
||||
IPCT_HELPER_BIT = 7,
|
||||
IPCT_HELPER = (1 << IPCT_HELPER_BIT),
|
||||
|
||||
/* Update of helper info */
|
||||
IPCT_HELPINFO_BIT = 8,
|
||||
IPCT_HELPINFO = (1 << IPCT_HELPINFO_BIT),
|
||||
|
||||
/* Volatile helper info */
|
||||
IPCT_HELPINFO_VOLATILE_BIT = 9,
|
||||
IPCT_HELPINFO_VOLATILE = (1 << IPCT_HELPINFO_VOLATILE_BIT),
|
||||
|
||||
/* NAT info */
|
||||
IPCT_NATINFO_BIT = 10,
|
||||
IPCT_NATINFO = (1 << IPCT_NATINFO_BIT),
|
||||
};
|
||||
|
||||
enum ip_conntrack_expect_events {
|
||||
IPEXP_NEW_BIT = 0,
|
||||
IPEXP_NEW = (1 << IPEXP_NEW_BIT),
|
||||
};
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
@ -280,6 +337,11 @@ static inline int is_confirmed(struct ip_conntrack *ct)
|
|||
return test_bit(IPS_CONFIRMED_BIT, &ct->status);
|
||||
}
|
||||
|
||||
static inline int is_dying(struct ip_conntrack *ct)
|
||||
{
|
||||
return test_bit(IPS_DYING_BIT, &ct->status);
|
||||
}
|
||||
|
||||
extern unsigned int ip_conntrack_htable_size;
|
||||
|
||||
struct ip_conntrack_stat
|
||||
|
@ -303,6 +365,88 @@ struct ip_conntrack_stat
|
|||
|
||||
#define CONNTRACK_STAT_INC(count) (__get_cpu_var(ip_conntrack_stat).count++)
|
||||
|
||||
#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
|
||||
#include <linux/notifier.h>
|
||||
|
||||
struct ip_conntrack_ecache {
|
||||
struct ip_conntrack *ct;
|
||||
unsigned int events;
|
||||
};
|
||||
DECLARE_PER_CPU(struct ip_conntrack_ecache, ip_conntrack_ecache);
|
||||
|
||||
#define CONNTRACK_ECACHE(x) (__get_cpu_var(ip_conntrack_ecache).x)
|
||||
|
||||
extern struct notifier_block *ip_conntrack_chain;
|
||||
extern struct notifier_block *ip_conntrack_expect_chain;
|
||||
|
||||
static inline int ip_conntrack_register_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return notifier_chain_register(&ip_conntrack_chain, nb);
|
||||
}
|
||||
|
||||
static inline int ip_conntrack_unregister_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return notifier_chain_unregister(&ip_conntrack_chain, nb);
|
||||
}
|
||||
|
||||
static inline int
|
||||
ip_conntrack_expect_register_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return notifier_chain_register(&ip_conntrack_expect_chain, nb);
|
||||
}
|
||||
|
||||
static inline int
|
||||
ip_conntrack_expect_unregister_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return notifier_chain_unregister(&ip_conntrack_expect_chain, nb);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ip_conntrack_event_cache(enum ip_conntrack_events event,
|
||||
const struct sk_buff *skb)
|
||||
{
|
||||
struct ip_conntrack_ecache *ecache =
|
||||
&__get_cpu_var(ip_conntrack_ecache);
|
||||
|
||||
if (unlikely((struct ip_conntrack *) skb->nfct != ecache->ct)) {
|
||||
if (net_ratelimit()) {
|
||||
printk(KERN_ERR "ctevent: skb->ct != ecache->ct !!!\n");
|
||||
dump_stack();
|
||||
}
|
||||
}
|
||||
ecache->events |= event;
|
||||
}
|
||||
|
||||
extern void
|
||||
ip_conntrack_deliver_cached_events_for(const struct ip_conntrack *ct);
|
||||
extern void ip_conntrack_event_cache_init(const struct sk_buff *skb);
|
||||
|
||||
static inline void ip_conntrack_event(enum ip_conntrack_events event,
|
||||
struct ip_conntrack *ct)
|
||||
{
|
||||
if (is_confirmed(ct) && !is_dying(ct))
|
||||
notifier_call_chain(&ip_conntrack_chain, event, ct);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ip_conntrack_expect_event(enum ip_conntrack_expect_events event,
|
||||
struct ip_conntrack_expect *exp)
|
||||
{
|
||||
notifier_call_chain(&ip_conntrack_expect_chain, event, exp);
|
||||
}
|
||||
#else /* CONFIG_IP_NF_CONNTRACK_EVENTS */
|
||||
static inline void ip_conntrack_event_cache(enum ip_conntrack_events event,
|
||||
const struct sk_buff *skb) {}
|
||||
static inline void ip_conntrack_event(enum ip_conntrack_events event,
|
||||
struct ip_conntrack *ct) {}
|
||||
static inline void ip_conntrack_deliver_cached_events_for(
|
||||
struct ip_conntrack *ct) {}
|
||||
static inline void ip_conntrack_event_cache_init(const struct sk_buff *skb) {}
|
||||
static inline void
|
||||
ip_conntrack_expect_event(enum ip_conntrack_expect_events event,
|
||||
struct ip_conntrack_expect *exp) {}
|
||||
#endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */
|
||||
|
||||
#ifdef CONFIG_IP_NF_NAT_NEEDED
|
||||
static inline int ip_nat_initialized(struct ip_conntrack *conntrack,
|
||||
enum ip_nat_manip_type manip)
|
||||
|
|
|
@ -38,12 +38,21 @@ extern int __ip_conntrack_confirm(struct sk_buff **pskb);
|
|||
/* Confirm a connection: returns NF_DROP if packet must be dropped. */
|
||||
static inline int ip_conntrack_confirm(struct sk_buff **pskb)
|
||||
{
|
||||
if ((*pskb)->nfct
|
||||
&& !is_confirmed((struct ip_conntrack *)(*pskb)->nfct))
|
||||
return __ip_conntrack_confirm(pskb);
|
||||
return NF_ACCEPT;
|
||||
struct ip_conntrack *ct = (struct ip_conntrack *)(*pskb)->nfct;
|
||||
int ret = NF_ACCEPT;
|
||||
|
||||
if (ct && !is_confirmed(ct))
|
||||
ret = __ip_conntrack_confirm(pskb);
|
||||
ip_conntrack_deliver_cached_events_for(ct);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
|
||||
struct ip_conntrack_ecache;
|
||||
extern void __ip_ct_deliver_cached_events(struct ip_conntrack_ecache *ec);
|
||||
#endif
|
||||
|
||||
extern struct list_head *ip_conntrack_hash;
|
||||
extern struct list_head ip_conntrack_expect_list;
|
||||
extern rwlock_t ip_conntrack_lock;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue