1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | /* |
3 | * connection tracking event cache. |
4 | */ |
5 | |
6 | #ifndef _NF_CONNTRACK_ECACHE_H |
7 | #define _NF_CONNTRACK_ECACHE_H |
8 | #include <net/netfilter/nf_conntrack.h> |
9 | |
10 | #include <net/net_namespace.h> |
11 | #include <net/netfilter/nf_conntrack_expect.h> |
12 | #include <linux/netfilter/nf_conntrack_common.h> |
13 | #include <linux/netfilter/nf_conntrack_tuple_common.h> |
14 | #include <net/netfilter/nf_conntrack_extend.h> |
15 | |
16 | enum nf_ct_ecache_state { |
17 | NFCT_ECACHE_DESTROY_FAIL, /* tried but failed to send destroy event */ |
18 | NFCT_ECACHE_DESTROY_SENT, /* sent destroy event after failure */ |
19 | }; |
20 | |
21 | struct nf_conntrack_ecache { |
22 | unsigned long cache; /* bitops want long */ |
23 | u16 ctmask; /* bitmask of ct events to be delivered */ |
24 | u16 expmask; /* bitmask of expect events to be delivered */ |
25 | u32 missed; /* missed events */ |
26 | u32 portid; /* netlink portid of destroyer */ |
27 | }; |
28 | |
29 | static inline struct nf_conntrack_ecache * |
30 | nf_ct_ecache_find(const struct nf_conn *ct) |
31 | { |
32 | #ifdef CONFIG_NF_CONNTRACK_EVENTS |
33 | return nf_ct_ext_find(ct, id: NF_CT_EXT_ECACHE); |
34 | #else |
35 | return NULL; |
36 | #endif |
37 | } |
38 | |
39 | static inline bool nf_ct_ecache_exist(const struct nf_conn *ct) |
40 | { |
41 | #ifdef CONFIG_NF_CONNTRACK_EVENTS |
42 | return nf_ct_ext_exist(ct, id: NF_CT_EXT_ECACHE); |
43 | #else |
44 | return false; |
45 | #endif |
46 | } |
47 | |
48 | #ifdef CONFIG_NF_CONNTRACK_EVENTS |
49 | |
50 | /* This structure is passed to event handler */ |
51 | struct nf_ct_event { |
52 | struct nf_conn *ct; |
53 | u32 portid; |
54 | int report; |
55 | }; |
56 | |
57 | struct nf_exp_event { |
58 | struct nf_conntrack_expect *exp; |
59 | u32 portid; |
60 | int report; |
61 | }; |
62 | |
63 | struct nf_ct_event_notifier { |
64 | int (*ct_event)(unsigned int events, const struct nf_ct_event *item); |
65 | int (*exp_event)(unsigned int events, const struct nf_exp_event *item); |
66 | }; |
67 | |
68 | void nf_conntrack_register_notifier(struct net *net, |
69 | const struct nf_ct_event_notifier *nb); |
70 | void nf_conntrack_unregister_notifier(struct net *net); |
71 | |
72 | void nf_ct_deliver_cached_events(struct nf_conn *ct); |
73 | int nf_conntrack_eventmask_report(unsigned int eventmask, struct nf_conn *ct, |
74 | u32 portid, int report); |
75 | |
76 | bool nf_ct_ecache_ext_add(struct nf_conn *ct, u16 ctmask, u16 expmask, gfp_t gfp); |
77 | #else |
78 | |
79 | static inline void nf_ct_deliver_cached_events(const struct nf_conn *ct) |
80 | { |
81 | } |
82 | |
83 | static inline int nf_conntrack_eventmask_report(unsigned int eventmask, |
84 | struct nf_conn *ct, |
85 | u32 portid, |
86 | int report) |
87 | { |
88 | return 0; |
89 | } |
90 | |
91 | static inline bool nf_ct_ecache_ext_add(struct nf_conn *ct, u16 ctmask, u16 expmask, gfp_t gfp) |
92 | { |
93 | return false; |
94 | } |
95 | #endif |
96 | |
97 | static inline void |
98 | nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct) |
99 | { |
100 | #ifdef CONFIG_NF_CONNTRACK_EVENTS |
101 | struct net *net = nf_ct_net(ct); |
102 | struct nf_conntrack_ecache *e; |
103 | |
104 | if (!rcu_access_pointer(net->ct.nf_conntrack_event_cb)) |
105 | return; |
106 | |
107 | e = nf_ct_ecache_find(ct); |
108 | if (e == NULL) |
109 | return; |
110 | |
111 | set_bit(nr: event, addr: &e->cache); |
112 | #endif |
113 | } |
114 | |
115 | static inline int |
116 | nf_conntrack_event_report(enum ip_conntrack_events event, struct nf_conn *ct, |
117 | u32 portid, int report) |
118 | { |
119 | #ifdef CONFIG_NF_CONNTRACK_EVENTS |
120 | if (nf_ct_ecache_exist(ct)) |
121 | return nf_conntrack_eventmask_report(eventmask: 1 << event, ct, portid, report); |
122 | #endif |
123 | return 0; |
124 | } |
125 | |
126 | static inline int |
127 | nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct) |
128 | { |
129 | #ifdef CONFIG_NF_CONNTRACK_EVENTS |
130 | if (nf_ct_ecache_exist(ct)) |
131 | return nf_conntrack_eventmask_report(eventmask: 1 << event, ct, portid: 0, report: 0); |
132 | #endif |
133 | return 0; |
134 | } |
135 | |
136 | #ifdef CONFIG_NF_CONNTRACK_EVENTS |
137 | void nf_ct_expect_event_report(enum ip_conntrack_expect_events event, |
138 | struct nf_conntrack_expect *exp, |
139 | u32 portid, int report); |
140 | |
141 | void nf_conntrack_ecache_work(struct net *net, enum nf_ct_ecache_state state); |
142 | |
143 | void nf_conntrack_ecache_pernet_init(struct net *net); |
144 | void nf_conntrack_ecache_pernet_fini(struct net *net); |
145 | |
146 | struct nf_conntrack_net_ecache *nf_conn_pernet_ecache(const struct net *net); |
147 | |
148 | static inline bool nf_conntrack_ecache_dwork_pending(const struct net *net) |
149 | { |
150 | return net->ct.ecache_dwork_pending; |
151 | } |
152 | #else /* CONFIG_NF_CONNTRACK_EVENTS */ |
153 | |
154 | static inline void nf_ct_expect_event_report(enum ip_conntrack_expect_events e, |
155 | struct nf_conntrack_expect *exp, |
156 | u32 portid, |
157 | int report) |
158 | { |
159 | } |
160 | |
161 | static inline void nf_conntrack_ecache_work(struct net *net, |
162 | enum nf_ct_ecache_state s) |
163 | { |
164 | } |
165 | |
166 | static inline void nf_conntrack_ecache_pernet_init(struct net *net) |
167 | { |
168 | } |
169 | |
170 | static inline void nf_conntrack_ecache_pernet_fini(struct net *net) |
171 | { |
172 | } |
173 | static inline bool nf_conntrack_ecache_dwork_pending(const struct net *net) { return false; } |
174 | #endif /* CONFIG_NF_CONNTRACK_EVENTS */ |
175 | #endif /*_NF_CONNTRACK_ECACHE_H*/ |
176 | |