Commit b3afdc17 authored by Florian Westphal's avatar Florian Westphal Committed by Pablo Neira Ayuso

netfilter: ecache: add common helper for nf_conntrack_eventmask_report

nf_ct_deliver_cached_events and nf_conntrack_eventmask_report are very
similar.  Split nf_conntrack_eventmask_report into a common helper
function that can be used for both cases.
Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 9291f090
...@@ -130,27 +130,57 @@ static void ecache_work(struct work_struct *work) ...@@ -130,27 +130,57 @@ static void ecache_work(struct work_struct *work)
schedule_delayed_work(&cnet->ecache_dwork, delay); schedule_delayed_work(&cnet->ecache_dwork, delay);
} }
int nf_conntrack_eventmask_report(unsigned int eventmask, struct nf_conn *ct, static int __nf_conntrack_eventmask_report(struct nf_conntrack_ecache *e,
u32 portid, int report) const unsigned int events,
const unsigned long missed,
const struct nf_ct_event *item)
{ {
struct net *net = nf_ct_net(ct); struct nf_conn *ct = item->ct;
struct net *net = nf_ct_net(item->ct);
struct nf_ct_event_notifier *notify; struct nf_ct_event_notifier *notify;
int ret;
if (!((events | missed) & e->ctmask))
return 0;
rcu_read_lock();
notify = rcu_dereference(net->ct.nf_conntrack_event_cb);
if (!notify) {
rcu_read_unlock();
return 0;
}
ret = notify->fcn(events | missed, item);
rcu_read_unlock();
if (likely(ret >= 0 && missed == 0))
return 0;
spin_lock_bh(&ct->lock);
if (ret < 0)
e->missed |= events;
else
e->missed &= ~missed;
spin_unlock_bh(&ct->lock);
return ret;
}
int nf_conntrack_eventmask_report(unsigned int events, struct nf_conn *ct,
u32 portid, int report)
{
struct nf_conntrack_ecache *e; struct nf_conntrack_ecache *e;
struct nf_ct_event item; struct nf_ct_event item;
unsigned long missed; unsigned long missed;
int ret = 0; int ret;
if (!nf_ct_is_confirmed(ct)) if (!nf_ct_is_confirmed(ct))
return ret; return 0;
rcu_read_lock();
notify = rcu_dereference(net->ct.nf_conntrack_event_cb);
if (!notify)
goto out_unlock;
e = nf_ct_ecache_find(ct); e = nf_ct_ecache_find(ct);
if (!e) if (!e)
goto out_unlock; return 0;
memset(&item, 0, sizeof(item)); memset(&item, 0, sizeof(item));
...@@ -161,33 +191,16 @@ int nf_conntrack_eventmask_report(unsigned int eventmask, struct nf_conn *ct, ...@@ -161,33 +191,16 @@ int nf_conntrack_eventmask_report(unsigned int eventmask, struct nf_conn *ct,
/* This is a resent of a destroy event? If so, skip missed */ /* This is a resent of a destroy event? If so, skip missed */
missed = e->portid ? 0 : e->missed; missed = e->portid ? 0 : e->missed;
if (!((eventmask | missed) & e->ctmask)) ret = __nf_conntrack_eventmask_report(e, events, missed, &item);
goto out_unlock; if (unlikely(ret < 0 && (events & (1 << IPCT_DESTROY)))) {
/* This is a destroy event that has been triggered by a process,
ret = notify->fcn(eventmask | missed, &item); * we store the PORTID to include it in the retransmission.
if (likely(ret >= 0 && !missed))
goto out_unlock;
spin_lock_bh(&ct->lock);
if (ret < 0) {
/* This is a destroy event that has been
* triggered by a process, we store the PORTID
* to include it in the retransmission.
*/ */
if (eventmask & (1 << IPCT_DESTROY)) {
if (e->portid == 0 && portid != 0) if (e->portid == 0 && portid != 0)
e->portid = portid; e->portid = portid;
e->state = NFCT_ECACHE_DESTROY_FAIL; e->state = NFCT_ECACHE_DESTROY_FAIL;
} else {
e->missed |= eventmask;
} }
} else {
e->missed &= ~missed;
}
spin_unlock_bh(&ct->lock);
out_unlock:
rcu_read_unlock();
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(nf_conntrack_eventmask_report); EXPORT_SYMBOL_GPL(nf_conntrack_eventmask_report);
...@@ -196,53 +209,28 @@ EXPORT_SYMBOL_GPL(nf_conntrack_eventmask_report); ...@@ -196,53 +209,28 @@ EXPORT_SYMBOL_GPL(nf_conntrack_eventmask_report);
* disabled softirqs */ * disabled softirqs */
void nf_ct_deliver_cached_events(struct nf_conn *ct) void nf_ct_deliver_cached_events(struct nf_conn *ct)
{ {
struct net *net = nf_ct_net(ct);
unsigned long events, missed;
struct nf_ct_event_notifier *notify;
struct nf_conntrack_ecache *e; struct nf_conntrack_ecache *e;
struct nf_ct_event item; struct nf_ct_event item;
int ret; unsigned long events;
rcu_read_lock();
notify = rcu_dereference(net->ct.nf_conntrack_event_cb);
if (notify == NULL)
goto out_unlock;
if (!nf_ct_is_confirmed(ct) || nf_ct_is_dying(ct)) if (!nf_ct_is_confirmed(ct) || nf_ct_is_dying(ct))
goto out_unlock; return;
e = nf_ct_ecache_find(ct); e = nf_ct_ecache_find(ct);
if (e == NULL) if (e == NULL)
goto out_unlock; return;
events = xchg(&e->cache, 0); events = xchg(&e->cache, 0);
/* We make a copy of the missed event cache without taking
* the lock, thus we may send missed events twice. However,
* this does not harm and it happens very rarely. */
missed = e->missed;
if (!((events | missed) & e->ctmask))
goto out_unlock;
item.ct = ct; item.ct = ct;
item.portid = 0; item.portid = 0;
item.report = 0; item.report = 0;
ret = notify->fcn(events | missed, &item); /* We make a copy of the missed event cache without taking
* the lock, thus we may send missed events twice. However,
if (likely(ret == 0 && !missed)) * this does not harm and it happens very rarely.
goto out_unlock; */
__nf_conntrack_eventmask_report(e, events, e->missed, &item);
spin_lock_bh(&ct->lock);
if (ret < 0)
e->missed |= events;
else
e->missed &= ~missed;
spin_unlock_bh(&ct->lock);
out_unlock:
rcu_read_unlock();
} }
EXPORT_SYMBOL_GPL(nf_ct_deliver_cached_events); EXPORT_SYMBOL_GPL(nf_ct_deliver_cached_events);
......
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