1 | #ifndef _NF_FLOW_TABLE_H |
2 | #define _NF_FLOW_TABLE_H |
3 | |
4 | #include <linux/in.h> |
5 | #include <linux/in6.h> |
6 | #include <linux/netdevice.h> |
7 | #include <linux/rhashtable-types.h> |
8 | #include <linux/rcupdate.h> |
9 | #include <linux/netfilter.h> |
10 | #include <linux/netfilter/nf_conntrack_tuple_common.h> |
11 | #include <net/flow_offload.h> |
12 | #include <net/dst.h> |
13 | #include <linux/if_pppox.h> |
14 | #include <linux/ppp_defs.h> |
15 | |
16 | struct nf_flowtable; |
17 | struct nf_flow_rule; |
18 | struct flow_offload; |
19 | enum flow_offload_tuple_dir; |
20 | |
21 | struct nf_flow_key { |
22 | struct flow_dissector_key_meta meta; |
23 | struct flow_dissector_key_control control; |
24 | struct flow_dissector_key_control enc_control; |
25 | struct flow_dissector_key_basic basic; |
26 | struct flow_dissector_key_vlan vlan; |
27 | struct flow_dissector_key_vlan cvlan; |
28 | union { |
29 | struct flow_dissector_key_ipv4_addrs ipv4; |
30 | struct flow_dissector_key_ipv6_addrs ipv6; |
31 | }; |
32 | struct flow_dissector_key_keyid enc_key_id; |
33 | union { |
34 | struct flow_dissector_key_ipv4_addrs enc_ipv4; |
35 | struct flow_dissector_key_ipv6_addrs enc_ipv6; |
36 | }; |
37 | struct flow_dissector_key_tcp tcp; |
38 | struct flow_dissector_key_ports tp; |
39 | } __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */ |
40 | |
41 | struct nf_flow_match { |
42 | struct flow_dissector dissector; |
43 | struct nf_flow_key key; |
44 | struct nf_flow_key mask; |
45 | }; |
46 | |
47 | struct nf_flow_rule { |
48 | struct nf_flow_match match; |
49 | struct flow_rule *rule; |
50 | }; |
51 | |
52 | struct nf_flowtable_type { |
53 | struct list_head list; |
54 | int family; |
55 | int (*init)(struct nf_flowtable *ft); |
56 | bool (*gc)(const struct flow_offload *flow); |
57 | int (*setup)(struct nf_flowtable *ft, |
58 | struct net_device *dev, |
59 | enum flow_block_command cmd); |
60 | int (*action)(struct net *net, |
61 | struct flow_offload *flow, |
62 | enum flow_offload_tuple_dir dir, |
63 | struct nf_flow_rule *flow_rule); |
64 | void (*free)(struct nf_flowtable *ft); |
65 | nf_hookfn *hook; |
66 | struct module *owner; |
67 | }; |
68 | |
69 | enum nf_flowtable_flags { |
70 | NF_FLOWTABLE_HW_OFFLOAD = 0x1, /* NFT_FLOWTABLE_HW_OFFLOAD */ |
71 | NF_FLOWTABLE_COUNTER = 0x2, /* NFT_FLOWTABLE_COUNTER */ |
72 | }; |
73 | |
74 | struct nf_flowtable { |
75 | struct list_head list; |
76 | struct rhashtable rhashtable; |
77 | int priority; |
78 | const struct nf_flowtable_type *type; |
79 | struct delayed_work gc_work; |
80 | unsigned int flags; |
81 | struct flow_block flow_block; |
82 | struct rw_semaphore flow_block_lock; /* Guards flow_block */ |
83 | possible_net_t net; |
84 | }; |
85 | |
86 | static inline bool nf_flowtable_hw_offload(struct nf_flowtable *flowtable) |
87 | { |
88 | return flowtable->flags & NF_FLOWTABLE_HW_OFFLOAD; |
89 | } |
90 | |
91 | enum flow_offload_tuple_dir { |
92 | FLOW_OFFLOAD_DIR_ORIGINAL = IP_CT_DIR_ORIGINAL, |
93 | FLOW_OFFLOAD_DIR_REPLY = IP_CT_DIR_REPLY, |
94 | }; |
95 | #define FLOW_OFFLOAD_DIR_MAX IP_CT_DIR_MAX |
96 | |
97 | enum flow_offload_xmit_type { |
98 | FLOW_OFFLOAD_XMIT_UNSPEC = 0, |
99 | FLOW_OFFLOAD_XMIT_NEIGH, |
100 | FLOW_OFFLOAD_XMIT_XFRM, |
101 | FLOW_OFFLOAD_XMIT_DIRECT, |
102 | FLOW_OFFLOAD_XMIT_TC, |
103 | }; |
104 | |
105 | #define NF_FLOW_TABLE_ENCAP_MAX 2 |
106 | |
107 | struct flow_offload_tuple { |
108 | union { |
109 | struct in_addr src_v4; |
110 | struct in6_addr src_v6; |
111 | }; |
112 | union { |
113 | struct in_addr dst_v4; |
114 | struct in6_addr dst_v6; |
115 | }; |
116 | struct { |
117 | __be16 src_port; |
118 | __be16 dst_port; |
119 | }; |
120 | |
121 | int iifidx; |
122 | |
123 | u8 l3proto; |
124 | u8 l4proto; |
125 | struct { |
126 | u16 id; |
127 | __be16 proto; |
128 | } encap[NF_FLOW_TABLE_ENCAP_MAX]; |
129 | |
130 | /* All members above are keys for lookups, see flow_offload_hash(). */ |
131 | struct { } __hash; |
132 | |
133 | u8 dir:2, |
134 | xmit_type:3, |
135 | encap_num:2, |
136 | in_vlan_ingress:2; |
137 | u16 mtu; |
138 | union { |
139 | struct { |
140 | struct dst_entry *dst_cache; |
141 | u32 dst_cookie; |
142 | }; |
143 | struct { |
144 | u32 ifidx; |
145 | u32 hw_ifidx; |
146 | u8 h_source[ETH_ALEN]; |
147 | u8 h_dest[ETH_ALEN]; |
148 | } out; |
149 | struct { |
150 | u32 iifidx; |
151 | } tc; |
152 | }; |
153 | }; |
154 | |
155 | struct flow_offload_tuple_rhash { |
156 | struct rhash_head node; |
157 | struct flow_offload_tuple tuple; |
158 | }; |
159 | |
160 | enum nf_flow_flags { |
161 | NF_FLOW_SNAT, |
162 | NF_FLOW_DNAT, |
163 | NF_FLOW_TEARDOWN, |
164 | NF_FLOW_HW, |
165 | NF_FLOW_HW_DYING, |
166 | NF_FLOW_HW_DEAD, |
167 | NF_FLOW_HW_PENDING, |
168 | NF_FLOW_HW_BIDIRECTIONAL, |
169 | NF_FLOW_HW_ESTABLISHED, |
170 | }; |
171 | |
172 | enum flow_offload_type { |
173 | NF_FLOW_OFFLOAD_UNSPEC = 0, |
174 | NF_FLOW_OFFLOAD_ROUTE, |
175 | }; |
176 | |
177 | struct flow_offload { |
178 | struct flow_offload_tuple_rhash tuplehash[FLOW_OFFLOAD_DIR_MAX]; |
179 | struct nf_conn *ct; |
180 | unsigned long flags; |
181 | u16 type; |
182 | u32 timeout; |
183 | struct rcu_head rcu_head; |
184 | }; |
185 | |
186 | #define NF_FLOW_TIMEOUT (30 * HZ) |
187 | #define nf_flowtable_time_stamp (u32)jiffies |
188 | |
189 | unsigned long flow_offload_get_timeout(struct flow_offload *flow); |
190 | |
191 | static inline __s32 nf_flow_timeout_delta(unsigned int timeout) |
192 | { |
193 | return (__s32)(timeout - nf_flowtable_time_stamp); |
194 | } |
195 | |
196 | struct nf_flow_route { |
197 | struct { |
198 | struct dst_entry *dst; |
199 | struct { |
200 | u32 ifindex; |
201 | struct { |
202 | u16 id; |
203 | __be16 proto; |
204 | } encap[NF_FLOW_TABLE_ENCAP_MAX]; |
205 | u8 num_encaps:2, |
206 | ingress_vlans:2; |
207 | } in; |
208 | struct { |
209 | u32 ifindex; |
210 | u32 hw_ifindex; |
211 | u8 h_source[ETH_ALEN]; |
212 | u8 h_dest[ETH_ALEN]; |
213 | } out; |
214 | enum flow_offload_xmit_type xmit_type; |
215 | } tuple[FLOW_OFFLOAD_DIR_MAX]; |
216 | }; |
217 | |
218 | struct flow_offload *flow_offload_alloc(struct nf_conn *ct); |
219 | void flow_offload_free(struct flow_offload *flow); |
220 | |
221 | static inline int |
222 | nf_flow_table_offload_add_cb(struct nf_flowtable *flow_table, |
223 | flow_setup_cb_t *cb, void *cb_priv) |
224 | { |
225 | struct flow_block *block = &flow_table->flow_block; |
226 | struct flow_block_cb *block_cb; |
227 | int err = 0; |
228 | |
229 | down_write(sem: &flow_table->flow_block_lock); |
230 | block_cb = flow_block_cb_lookup(block, cb, cb_ident: cb_priv); |
231 | if (block_cb) { |
232 | err = -EEXIST; |
233 | goto unlock; |
234 | } |
235 | |
236 | block_cb = flow_block_cb_alloc(cb, cb_ident: cb_priv, cb_priv, NULL); |
237 | if (IS_ERR(ptr: block_cb)) { |
238 | err = PTR_ERR(ptr: block_cb); |
239 | goto unlock; |
240 | } |
241 | |
242 | list_add_tail(new: &block_cb->list, head: &block->cb_list); |
243 | |
244 | unlock: |
245 | up_write(sem: &flow_table->flow_block_lock); |
246 | return err; |
247 | } |
248 | |
249 | static inline void |
250 | nf_flow_table_offload_del_cb(struct nf_flowtable *flow_table, |
251 | flow_setup_cb_t *cb, void *cb_priv) |
252 | { |
253 | struct flow_block *block = &flow_table->flow_block; |
254 | struct flow_block_cb *block_cb; |
255 | |
256 | down_write(sem: &flow_table->flow_block_lock); |
257 | block_cb = flow_block_cb_lookup(block, cb, cb_ident: cb_priv); |
258 | if (block_cb) { |
259 | list_del(entry: &block_cb->list); |
260 | flow_block_cb_free(block_cb); |
261 | } else { |
262 | WARN_ON(true); |
263 | } |
264 | up_write(sem: &flow_table->flow_block_lock); |
265 | } |
266 | |
267 | void flow_offload_route_init(struct flow_offload *flow, |
268 | const struct nf_flow_route *route); |
269 | |
270 | int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow); |
271 | void flow_offload_refresh(struct nf_flowtable *flow_table, |
272 | struct flow_offload *flow, bool force); |
273 | |
274 | struct flow_offload_tuple_rhash *flow_offload_lookup(struct nf_flowtable *flow_table, |
275 | struct flow_offload_tuple *tuple); |
276 | void nf_flow_table_gc_run(struct nf_flowtable *flow_table); |
277 | void nf_flow_table_gc_cleanup(struct nf_flowtable *flowtable, |
278 | struct net_device *dev); |
279 | void nf_flow_table_cleanup(struct net_device *dev); |
280 | |
281 | int nf_flow_table_init(struct nf_flowtable *flow_table); |
282 | void nf_flow_table_free(struct nf_flowtable *flow_table); |
283 | |
284 | void flow_offload_teardown(struct flow_offload *flow); |
285 | |
286 | void nf_flow_snat_port(const struct flow_offload *flow, |
287 | struct sk_buff *skb, unsigned int thoff, |
288 | u8 protocol, enum flow_offload_tuple_dir dir); |
289 | void nf_flow_dnat_port(const struct flow_offload *flow, |
290 | struct sk_buff *skb, unsigned int thoff, |
291 | u8 protocol, enum flow_offload_tuple_dir dir); |
292 | |
293 | struct flow_ports { |
294 | __be16 source, dest; |
295 | }; |
296 | |
297 | unsigned int nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb, |
298 | const struct nf_hook_state *state); |
299 | unsigned int nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb, |
300 | const struct nf_hook_state *state); |
301 | |
302 | #define MODULE_ALIAS_NF_FLOWTABLE(family) \ |
303 | MODULE_ALIAS("nf-flowtable-" __stringify(family)) |
304 | |
305 | void nf_flow_offload_add(struct nf_flowtable *flowtable, |
306 | struct flow_offload *flow); |
307 | void nf_flow_offload_del(struct nf_flowtable *flowtable, |
308 | struct flow_offload *flow); |
309 | void nf_flow_offload_stats(struct nf_flowtable *flowtable, |
310 | struct flow_offload *flow); |
311 | |
312 | void nf_flow_table_offload_flush(struct nf_flowtable *flowtable); |
313 | void nf_flow_table_offload_flush_cleanup(struct nf_flowtable *flowtable); |
314 | |
315 | int nf_flow_table_offload_setup(struct nf_flowtable *flowtable, |
316 | struct net_device *dev, |
317 | enum flow_block_command cmd); |
318 | int nf_flow_rule_route_ipv4(struct net *net, struct flow_offload *flow, |
319 | enum flow_offload_tuple_dir dir, |
320 | struct nf_flow_rule *flow_rule); |
321 | int nf_flow_rule_route_ipv6(struct net *net, struct flow_offload *flow, |
322 | enum flow_offload_tuple_dir dir, |
323 | struct nf_flow_rule *flow_rule); |
324 | |
325 | int nf_flow_table_offload_init(void); |
326 | void nf_flow_table_offload_exit(void); |
327 | |
328 | static inline __be16 nf_flow_pppoe_proto(const struct sk_buff *skb) |
329 | { |
330 | __be16 proto; |
331 | |
332 | proto = *((__be16 *)(skb_mac_header(skb) + ETH_HLEN + |
333 | sizeof(struct pppoe_hdr))); |
334 | switch (proto) { |
335 | case htons(PPP_IP): |
336 | return htons(ETH_P_IP); |
337 | case htons(PPP_IPV6): |
338 | return htons(ETH_P_IPV6); |
339 | } |
340 | |
341 | return 0; |
342 | } |
343 | |
344 | #define NF_FLOW_TABLE_STAT_INC(net, count) __this_cpu_inc((net)->ft.stat->count) |
345 | #define NF_FLOW_TABLE_STAT_DEC(net, count) __this_cpu_dec((net)->ft.stat->count) |
346 | #define NF_FLOW_TABLE_STAT_INC_ATOMIC(net, count) \ |
347 | this_cpu_inc((net)->ft.stat->count) |
348 | #define NF_FLOW_TABLE_STAT_DEC_ATOMIC(net, count) \ |
349 | this_cpu_dec((net)->ft.stat->count) |
350 | |
351 | #ifdef CONFIG_NF_FLOW_TABLE_PROCFS |
352 | int nf_flow_table_init_proc(struct net *net); |
353 | void nf_flow_table_fini_proc(struct net *net); |
354 | #else |
355 | static inline int nf_flow_table_init_proc(struct net *net) |
356 | { |
357 | return 0; |
358 | } |
359 | |
360 | static inline void nf_flow_table_fini_proc(struct net *net) |
361 | { |
362 | } |
363 | #endif /* CONFIG_NF_FLOW_TABLE_PROCFS */ |
364 | |
365 | #endif /* _NF_FLOW_TABLE_H */ |
366 | |