]> 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 475facc3051aeb18e3758be90a4b8b61b28b4b66..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                = 0,    /* new conntrack */
-       IPCT_RELATED            = 1,    /* related conntrack */
-       IPCT_DESTROY            = 2,    /* destroyed conntrack */
-       IPCT_STATUS             = 3,    /* status has changed */
-       IPCT_PROTOINFO          = 4,    /* protocol information has changed */
-       IPCT_HELPER             = 5,    /* new helper has been set */
-       IPCT_MARK               = 6,    /* new mark has been set */
-       IPCT_NATSEQADJ          = 7,    /* NAT is doing sequence adjustment */
-       IPCT_SECMARK            = 8,    /* new security mark has been set */
-};
-
-enum ip_conntrack_expect_events {
-       IPEXP_NEW               = 0,    /* 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 *
@@ -42,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
@@ -82,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);
 }
 
@@ -92,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;
 
@@ -101,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;
@@ -117,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);
@@ -172,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,