]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - include/net/netfilter/nf_conntrack_ecache.h
netfilter: ctnetlink: support selective event delivery
[net-next-2.6.git] / include / net / netfilter / nf_conntrack_ecache.h
index 5e05fb883ab119c19ad5159ed233aea2dcf5ae61..96ba5f7dcab60ad26618fa028e5968ecb83310e8 100644 (file)
 #include <linux/netfilter/nf_conntrack_tuple_common.h>
 #include <net/netfilter/nf_conntrack_extend.h>
 
-/* Connection tracking event types */
-enum ip_conntrack_events {
-       IPCT_NEW,               /* new conntrack */
-       IPCT_RELATED,           /* related conntrack */
-       IPCT_DESTROY,           /* destroyed conntrack */
-       IPCT_REPLY,             /* connection has seen two-way traffic */
-       IPCT_ASSURED,           /* connection status has changed to assured */
-       IPCT_PROTOINFO,         /* protocol information has changed */
-       IPCT_HELPER,            /* new helper has been set */
-       IPCT_MARK,              /* new mark has been set */
-       IPCT_NATSEQADJ,         /* NAT is doing sequence adjustment */
-       IPCT_SECMARK,           /* new security mark has been set */
-};
-
-enum ip_conntrack_expect_events {
-       IPEXP_NEW,              /* new expectation */
-};
-
 struct nf_conntrack_ecache {
-       unsigned long cache;            /* bitops want long */
-       unsigned long missed;           /* missed events */
-       u32 pid;                        /* netlink pid of destroyer */
+       unsigned long cache;    /* bitops want long */
+       unsigned long missed;   /* missed events */
+       u16 ctmask;             /* bitmask of ct events to be delivered */
+       u16 expmask;            /* bitmask of expect events to be delivered */
+       u32 pid;                /* netlink pid of destroyer */
 };
 
 static inline struct nf_conntrack_ecache *
@@ -43,14 +27,24 @@ nf_ct_ecache_find(const struct nf_conn *ct)
 }
 
 static inline struct nf_conntrack_ecache *
-nf_ct_ecache_ext_add(struct nf_conn *ct, gfp_t gfp)
+nf_ct_ecache_ext_add(struct nf_conn *ct, u16 ctmask, u16 expmask, gfp_t gfp)
 {
        struct net *net = nf_ct_net(ct);
+       struct nf_conntrack_ecache *e;
 
-       if (!net->ct.sysctl_events)
+       if (!ctmask && !expmask && net->ct.sysctl_events) {
+               ctmask = ~0;
+               expmask = ~0;
+       }
+       if (!ctmask && !expmask)
                return NULL;
 
-       return nf_ct_ext_add(ct, NF_CT_EXT_ECACHE, gfp);
+       e = nf_ct_ext_add(ct, NF_CT_EXT_ECACHE, gfp);
+       if (e) {
+               e->ctmask  = ctmask;
+               e->expmask = expmask;
+       }
+       return e;
 };
 
 #ifdef CONFIG_NF_CONNTRACK_EVENTS
@@ -83,6 +77,9 @@ nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct)
        if (e == NULL)
                return;
 
+       if (!(e->ctmask & (1 << event)))
+               return;
+
        set_bit(event, &e->cache);
 }
 
@@ -93,7 +90,6 @@ nf_conntrack_eventmask_report(unsigned int eventmask,
                              int report)
 {
        int ret = 0;
-       struct net *net = nf_ct_net(ct);
        struct nf_ct_event_notifier *notify;
        struct nf_conntrack_ecache *e;
 
@@ -102,9 +98,6 @@ nf_conntrack_eventmask_report(unsigned int eventmask,
        if (notify == NULL)
                goto out_unlock;
 
-       if (!net->ct.sysctl_events)
-               goto out_unlock;
-
        e = nf_ct_ecache_find(ct);
        if (e == NULL)
                goto out_unlock;
@@ -118,6 +111,9 @@ nf_conntrack_eventmask_report(unsigned int eventmask,
                /* This is a resent of a destroy event? If so, skip missed */
                unsigned long missed = e->pid ? 0 : e->missed;
 
+               if (!((eventmask | missed) & e->ctmask))
+                       goto out_unlock;
+
                ret = notify->fcn(eventmask | missed, &item);
                if (unlikely(ret < 0 || missed)) {
                        spin_lock_bh(&ct->lock);
@@ -173,18 +169,19 @@ nf_ct_expect_event_report(enum ip_conntrack_expect_events event,
                          u32 pid,
                          int report)
 {
-       struct net *net = nf_ct_exp_net(exp);
        struct nf_exp_event_notifier *notify;
+       struct nf_conntrack_ecache *e;
 
        rcu_read_lock();
        notify = rcu_dereference(nf_expect_event_cb);
        if (notify == NULL)
                goto out_unlock;
 
-       if (!net->ct.sysctl_events)
+       e = nf_ct_ecache_find(exp->master);
+       if (e == NULL)
                goto out_unlock;
 
-       {
+       if (e->expmask & (1 << event)) {
                struct nf_exp_event item = {
                        .exp    = exp,
                        .pid    = pid,