blob: 0e3d08e4b1d3e59fa101607d88e4c66f7664566d [file] [log] [blame]
Martin Josefssonf6180122006-11-29 02:35:01 +01001/*
2 * connection tracking event cache.
3 */
4
5#ifndef _NF_CONNTRACK_ECACHE_H
6#define _NF_CONNTRACK_ECACHE_H
7#include <net/netfilter/nf_conntrack.h>
8
Alexey Dobriyan6058fa62008-10-08 11:35:07 +02009#include <net/net_namespace.h>
Martin Josefssonf6180122006-11-29 02:35:01 +010010#include <net/netfilter/nf_conntrack_expect.h>
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +020011#include <linux/netfilter/nf_conntrack_common.h>
12#include <linux/netfilter/nf_conntrack_tuple_common.h>
13#include <net/netfilter/nf_conntrack_extend.h>
Martin Josefssonf6180122006-11-29 02:35:01 +010014
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +020015struct nf_conntrack_ecache {
Patrick McHardy0cebe4b2010-02-03 13:51:51 +010016 unsigned long cache; /* bitops want long */
17 unsigned long missed; /* missed events */
18 u16 ctmask; /* bitmask of ct events to be delivered */
19 u16 expmask; /* bitmask of expect events to be delivered */
Eric W. Biederman15e47302012-09-07 20:12:54 +000020 u32 portid; /* netlink portid of destroyer */
Pablo Neira Ayuso5b423f62012-08-29 16:25:49 +000021 struct timer_list timeout;
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +020022};
23
24static inline struct nf_conntrack_ecache *
25nf_ct_ecache_find(const struct nf_conn *ct)
26{
Changli Gaoe0e76c82010-11-15 12:23:24 +010027#ifdef CONFIG_NF_CONNTRACK_EVENTS
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +020028 return nf_ct_ext_find(ct, NF_CT_EXT_ECACHE);
Changli Gaoe0e76c82010-11-15 12:23:24 +010029#else
30 return NULL;
31#endif
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +020032}
33
34static inline struct nf_conntrack_ecache *
Patrick McHardy0cebe4b2010-02-03 13:51:51 +010035nf_ct_ecache_ext_add(struct nf_conn *ct, u16 ctmask, u16 expmask, gfp_t gfp)
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +020036{
Changli Gaoe0e76c82010-11-15 12:23:24 +010037#ifdef CONFIG_NF_CONNTRACK_EVENTS
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +020038 struct net *net = nf_ct_net(ct);
Patrick McHardy0cebe4b2010-02-03 13:51:51 +010039 struct nf_conntrack_ecache *e;
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +020040
Patrick McHardy0cebe4b2010-02-03 13:51:51 +010041 if (!ctmask && !expmask && net->ct.sysctl_events) {
42 ctmask = ~0;
43 expmask = ~0;
44 }
45 if (!ctmask && !expmask)
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +020046 return NULL;
47
Patrick McHardy0cebe4b2010-02-03 13:51:51 +010048 e = nf_ct_ext_add(ct, NF_CT_EXT_ECACHE, gfp);
49 if (e) {
50 e->ctmask = ctmask;
51 e->expmask = expmask;
52 }
53 return e;
Changli Gaoe0e76c82010-11-15 12:23:24 +010054#else
55 return NULL;
56#endif
Pablo Neira Ayuso6bfea192009-06-02 20:08:44 +020057};
58
Martin Josefssonf6180122006-11-29 02:35:01 +010059#ifdef CONFIG_NF_CONNTRACK_EVENTS
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +010060/* This structure is passed to event handler */
61struct nf_ct_event {
62 struct nf_conn *ct;
Eric W. Biederman15e47302012-09-07 20:12:54 +000063 u32 portid;
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +010064 int report;
65};
66
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +020067struct nf_ct_event_notifier {
68 int (*fcn)(unsigned int events, struct nf_ct_event *item);
69};
70
Joe Perches4e77be42013-09-23 11:37:48 -070071int nf_conntrack_register_notifier(struct net *net,
72 struct nf_ct_event_notifier *nb);
73void nf_conntrack_unregister_notifier(struct net *net,
74 struct nf_ct_event_notifier *nb);
Martin Josefssonf6180122006-11-29 02:35:01 +010075
Joe Perches4e77be42013-09-23 11:37:48 -070076void nf_ct_deliver_cached_events(struct nf_conn *ct);
Martin Josefssonf6180122006-11-29 02:35:01 +010077
78static inline void
Alexey Dobriyana71996f2008-10-08 11:35:07 +020079nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct)
Martin Josefssonf6180122006-11-29 02:35:01 +010080{
Pablo Neira Ayuso70e99422011-11-22 00:16:51 +010081 struct net *net = nf_ct_net(ct);
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +020082 struct nf_conntrack_ecache *e;
Martin Josefssonf6180122006-11-29 02:35:01 +010083
Pablo Neira Ayuso6bd04052012-07-05 15:42:10 +020084 if (!rcu_access_pointer(net->ct.nf_conntrack_event_cb))
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +020085 return;
86
87 e = nf_ct_ecache_find(ct);
88 if (e == NULL)
89 return;
90
91 set_bit(event, &e->cache);
Martin Josefssonf6180122006-11-29 02:35:01 +010092}
93
Pablo Neira Ayusodd7669a2009-06-13 12:30:52 +020094static inline int
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +020095nf_conntrack_eventmask_report(unsigned int eventmask,
96 struct nf_conn *ct,
Eric W. Biederman15e47302012-09-07 20:12:54 +000097 u32 portid,
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +020098 int report)
Martin Josefssonf6180122006-11-29 02:35:01 +010099{
Pablo Neira Ayusodd7669a2009-06-13 12:30:52 +0200100 int ret = 0;
Pablo Neira Ayuso70e99422011-11-22 00:16:51 +0100101 struct net *net = nf_ct_net(ct);
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +0200102 struct nf_ct_event_notifier *notify;
Pablo Neira Ayusodd7669a2009-06-13 12:30:52 +0200103 struct nf_conntrack_ecache *e;
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +0200104
105 rcu_read_lock();
Pablo Neira Ayuso70e99422011-11-22 00:16:51 +0100106 notify = rcu_dereference(net->ct.nf_conntrack_event_cb);
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +0200107 if (notify == NULL)
108 goto out_unlock;
109
Pablo Neira Ayusodd7669a2009-06-13 12:30:52 +0200110 e = nf_ct_ecache_find(ct);
111 if (e == NULL)
112 goto out_unlock;
113
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +0200114 if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct)) {
115 struct nf_ct_event item = {
116 .ct = ct,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000117 .portid = e->portid ? e->portid : portid,
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +0200118 .report = report
119 };
Pablo Neira Ayusodd7669a2009-06-13 12:30:52 +0200120 /* This is a resent of a destroy event? If so, skip missed */
Eric W. Biederman15e47302012-09-07 20:12:54 +0000121 unsigned long missed = e->portid ? 0 : e->missed;
Pablo Neira Ayusodd7669a2009-06-13 12:30:52 +0200122
Patrick McHardy0cebe4b2010-02-03 13:51:51 +0100123 if (!((eventmask | missed) & e->ctmask))
124 goto out_unlock;
125
Pablo Neira Ayusodd7669a2009-06-13 12:30:52 +0200126 ret = notify->fcn(eventmask | missed, &item);
127 if (unlikely(ret < 0 || missed)) {
128 spin_lock_bh(&ct->lock);
129 if (ret < 0) {
130 /* This is a destroy event that has been
Eric W. Biederman15e47302012-09-07 20:12:54 +0000131 * triggered by a process, we store the PORTID
Pablo Neira Ayusodd7669a2009-06-13 12:30:52 +0200132 * to include it in the retransmission. */
133 if (eventmask & (1 << IPCT_DESTROY) &&
Eric W. Biederman15e47302012-09-07 20:12:54 +0000134 e->portid == 0 && portid != 0)
135 e->portid = portid;
Pablo Neira Ayusodd7669a2009-06-13 12:30:52 +0200136 else
137 e->missed |= eventmask;
138 } else
139 e->missed &= ~missed;
140 spin_unlock_bh(&ct->lock);
141 }
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +0200142 }
143out_unlock:
144 rcu_read_unlock();
Pablo Neira Ayusodd7669a2009-06-13 12:30:52 +0200145 return ret;
Martin Josefssonf6180122006-11-29 02:35:01 +0100146}
147
Pablo Neira Ayusodd7669a2009-06-13 12:30:52 +0200148static inline int
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +0200149nf_conntrack_event_report(enum ip_conntrack_events event, struct nf_conn *ct,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000150 u32 portid, int report)
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +0200151{
Eric W. Biederman15e47302012-09-07 20:12:54 +0000152 return nf_conntrack_eventmask_report(1 << event, ct, portid, report);
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +0200153}
154
Pablo Neira Ayusodd7669a2009-06-13 12:30:52 +0200155static inline int
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +0100156nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct)
157{
Pablo Neira Ayusodd7669a2009-06-13 12:30:52 +0200158 return nf_conntrack_eventmask_report(1 << event, ct, 0, 0);
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +0100159}
160
161struct nf_exp_event {
162 struct nf_conntrack_expect *exp;
Eric W. Biederman15e47302012-09-07 20:12:54 +0000163 u32 portid;
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +0100164 int report;
165};
166
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +0200167struct nf_exp_event_notifier {
168 int (*fcn)(unsigned int events, struct nf_exp_event *item);
169};
170
Joe Perches4e77be42013-09-23 11:37:48 -0700171int nf_ct_expect_register_notifier(struct net *net,
172 struct nf_exp_event_notifier *nb);
173void nf_ct_expect_unregister_notifier(struct net *net,
174 struct nf_exp_event_notifier *nb);
Patrick McHardy010c7d62007-03-14 16:40:10 -0700175
Martin Josefssonf6180122006-11-29 02:35:01 +0100176static inline void
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +0100177nf_ct_expect_event_report(enum ip_conntrack_expect_events event,
178 struct nf_conntrack_expect *exp,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000179 u32 portid,
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +0100180 int report)
181{
Pablo Neira Ayuso70e99422011-11-22 00:16:51 +0100182 struct net *net = nf_ct_exp_net(exp);
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +0200183 struct nf_exp_event_notifier *notify;
Patrick McHardy0cebe4b2010-02-03 13:51:51 +0100184 struct nf_conntrack_ecache *e;
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +0200185
186 rcu_read_lock();
Pablo Neira Ayuso70e99422011-11-22 00:16:51 +0100187 notify = rcu_dereference(net->ct.nf_expect_event_cb);
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +0200188 if (notify == NULL)
189 goto out_unlock;
190
Patrick McHardy0cebe4b2010-02-03 13:51:51 +0100191 e = nf_ct_ecache_find(exp->master);
192 if (e == NULL)
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +0200193 goto out_unlock;
194
Patrick McHardy0cebe4b2010-02-03 13:51:51 +0100195 if (e->expmask & (1 << event)) {
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +0200196 struct nf_exp_event item = {
197 .exp = exp,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000198 .portid = portid,
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +0200199 .report = report
200 };
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +0200201 notify->fcn(1 << event, &item);
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +0200202 }
203out_unlock:
204 rcu_read_unlock();
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +0100205}
206
207static inline void
Patrick McHardy68236452007-07-07 22:30:49 -0700208nf_ct_expect_event(enum ip_conntrack_expect_events event,
209 struct nf_conntrack_expect *exp)
Martin Josefssonf6180122006-11-29 02:35:01 +0100210{
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +0100211 nf_ct_expect_event_report(event, exp, 0, 0);
Martin Josefssonf6180122006-11-29 02:35:01 +0100212}
213
Joe Perches4e77be42013-09-23 11:37:48 -0700214int nf_conntrack_ecache_pernet_init(struct net *net);
215void nf_conntrack_ecache_pernet_fini(struct net *net);
Alexey Dobriyan6058fa62008-10-08 11:35:07 +0200216
Joe Perches4e77be42013-09-23 11:37:48 -0700217int nf_conntrack_ecache_init(void);
218void nf_conntrack_ecache_fini(void);
Martin Josefssonf6180122006-11-29 02:35:01 +0100219#else /* CONFIG_NF_CONNTRACK_EVENTS */
220
221static inline void nf_conntrack_event_cache(enum ip_conntrack_events event,
Linus Torvalds64f1b6532008-10-11 09:46:24 -0700222 struct nf_conn *ct) {}
Pablo Neira Ayusodd7669a2009-06-13 12:30:52 +0200223static inline int nf_conntrack_eventmask_report(unsigned int eventmask,
224 struct nf_conn *ct,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000225 u32 portid,
Pablo Neira Ayusodd7669a2009-06-13 12:30:52 +0200226 int report) { return 0; }
227static inline int nf_conntrack_event(enum ip_conntrack_events event,
228 struct nf_conn *ct) { return 0; }
229static inline int nf_conntrack_event_report(enum ip_conntrack_events event,
230 struct nf_conn *ct,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000231 u32 portid,
Pablo Neira Ayusodd7669a2009-06-13 12:30:52 +0200232 int report) { return 0; }
Martin Josefssonf6180122006-11-29 02:35:01 +0100233static inline void nf_ct_deliver_cached_events(const struct nf_conn *ct) {}
Patrick McHardy68236452007-07-07 22:30:49 -0700234static inline void nf_ct_expect_event(enum ip_conntrack_expect_events event,
235 struct nf_conntrack_expect *exp) {}
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +0100236static inline void nf_ct_expect_event_report(enum ip_conntrack_expect_events e,
237 struct nf_conntrack_expect *exp,
Eric W. Biederman15e47302012-09-07 20:12:54 +0000238 u32 portid,
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +0100239 int report) {}
Alexey Dobriyan6058fa62008-10-08 11:35:07 +0200240
Gao feng3fe0f942013-01-21 22:10:28 +0000241static inline int nf_conntrack_ecache_pernet_init(struct net *net)
Alexey Dobriyan6058fa62008-10-08 11:35:07 +0200242{
243 return 0;
Guo-Fu Tsengbb21c952008-10-09 21:10:36 -0700244}
Alexey Dobriyan6058fa62008-10-08 11:35:07 +0200245
Gao feng3fe0f942013-01-21 22:10:28 +0000246static inline void nf_conntrack_ecache_pernet_fini(struct net *net)
247{
248}
249
250static inline int nf_conntrack_ecache_init(void)
251{
252 return 0;
253}
254
255static inline void nf_conntrack_ecache_fini(void)
Alexey Dobriyan6058fa62008-10-08 11:35:07 +0200256{
257}
Martin Josefssonf6180122006-11-29 02:35:01 +0100258#endif /* CONFIG_NF_CONNTRACK_EVENTS */
259
260#endif /*_NF_CONNTRACK_ECACHE_H*/
261