Commit | Line | Data |
---|---|---|
3b49e2e9 PNA |
1 | #ifndef _NF_FLOW_TABLE_H |
2 | #define _NF_FLOW_TABLE_H | |
3 | ||
ac2a6666 PNA |
4 | #include <linux/in.h> |
5 | #include <linux/in6.h> | |
6 | #include <linux/netdevice.h> | |
0eb71a9d | 7 | #include <linux/rhashtable-types.h> |
ac2a6666 | 8 | #include <linux/rcupdate.h> |
a1b2f04e | 9 | #include <linux/netfilter.h> |
af81f9e7 | 10 | #include <linux/netfilter/nf_conntrack_tuple_common.h> |
8bb69f3b | 11 | #include <net/flow_offload.h> |
ac2a6666 | 12 | #include <net/dst.h> |
0492d857 PNA |
13 | #include <linux/if_pppox.h> |
14 | #include <linux/ppp_defs.h> | |
3b49e2e9 PNA |
15 | |
16 | struct nf_flowtable; | |
c29f74e0 PNA |
17 | struct nf_flow_rule; |
18 | struct flow_offload; | |
19 | enum flow_offload_tuple_dir; | |
3b49e2e9 | 20 | |
9c26ba9b PB |
21 | struct nf_flow_key { |
22 | struct flow_dissector_key_meta meta; | |
23 | struct flow_dissector_key_control control; | |
cfab6dbd | 24 | struct flow_dissector_key_control enc_control; |
9c26ba9b | 25 | struct flow_dissector_key_basic basic; |
3e1b0c16 | 26 | struct flow_dissector_key_vlan vlan; |
27 | struct flow_dissector_key_vlan cvlan; | |
9c26ba9b PB |
28 | union { |
29 | struct flow_dissector_key_ipv4_addrs ipv4; | |
30 | struct flow_dissector_key_ipv6_addrs ipv6; | |
31 | }; | |
cfab6dbd | 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 | }; | |
9c26ba9b PB |
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 | ||
3b49e2e9 PNA |
52 | struct nf_flowtable_type { |
53 | struct list_head list; | |
54 | int family; | |
a268de77 | 55 | int (*init)(struct nf_flowtable *ft); |
8bb69f3b PNA |
56 | int (*setup)(struct nf_flowtable *ft, |
57 | struct net_device *dev, | |
58 | enum flow_block_command cmd); | |
c29f74e0 PNA |
59 | int (*action)(struct net *net, |
60 | const struct flow_offload *flow, | |
61 | enum flow_offload_tuple_dir dir, | |
62 | struct nf_flow_rule *flow_rule); | |
b408c5b0 | 63 | void (*free)(struct nf_flowtable *ft); |
3b49e2e9 PNA |
64 | nf_hookfn *hook; |
65 | struct module *owner; | |
66 | }; | |
67 | ||
8bb69f3b | 68 | enum nf_flowtable_flags { |
cfbd1125 | 69 | NF_FLOWTABLE_HW_OFFLOAD = 0x1, /* NFT_FLOWTABLE_HW_OFFLOAD */ |
53c2b289 | 70 | NF_FLOWTABLE_COUNTER = 0x2, /* NFT_FLOWTABLE_COUNTER */ |
8bb69f3b PNA |
71 | }; |
72 | ||
3b49e2e9 | 73 | struct nf_flowtable { |
84453a90 | 74 | struct list_head list; |
3b49e2e9 | 75 | struct rhashtable rhashtable; |
71a8a63b | 76 | int priority; |
3b49e2e9 PNA |
77 | const struct nf_flowtable_type *type; |
78 | struct delayed_work gc_work; | |
8bb69f3b PNA |
79 | unsigned int flags; |
80 | struct flow_block flow_block; | |
422c032a | 81 | struct rw_semaphore flow_block_lock; /* Guards flow_block */ |
8bb69f3b | 82 | possible_net_t net; |
3b49e2e9 PNA |
83 | }; |
84 | ||
a5449cdc PNA |
85 | static inline bool nf_flowtable_hw_offload(struct nf_flowtable *flowtable) |
86 | { | |
87 | return flowtable->flags & NF_FLOWTABLE_HW_OFFLOAD; | |
88 | } | |
89 | ||
ac2a6666 | 90 | enum flow_offload_tuple_dir { |
af81f9e7 FF |
91 | FLOW_OFFLOAD_DIR_ORIGINAL = IP_CT_DIR_ORIGINAL, |
92 | FLOW_OFFLOAD_DIR_REPLY = IP_CT_DIR_REPLY, | |
ac2a6666 | 93 | }; |
4f08f173 | 94 | #define FLOW_OFFLOAD_DIR_MAX IP_CT_DIR_MAX |
ac2a6666 | 95 | |
5139c0c0 | 96 | enum flow_offload_xmit_type { |
78ed0a9b RD |
97 | FLOW_OFFLOAD_XMIT_UNSPEC = 0, |
98 | FLOW_OFFLOAD_XMIT_NEIGH, | |
5139c0c0 | 99 | FLOW_OFFLOAD_XMIT_XFRM, |
7a27f6ab | 100 | FLOW_OFFLOAD_XMIT_DIRECT, |
db6140e5 | 101 | FLOW_OFFLOAD_XMIT_TC, |
5139c0c0 PNA |
102 | }; |
103 | ||
4cd91f7c PNA |
104 | #define NF_FLOW_TABLE_ENCAP_MAX 2 |
105 | ||
ac2a6666 PNA |
106 | struct flow_offload_tuple { |
107 | union { | |
108 | struct in_addr src_v4; | |
109 | struct in6_addr src_v6; | |
110 | }; | |
111 | union { | |
112 | struct in_addr dst_v4; | |
113 | struct in6_addr dst_v6; | |
114 | }; | |
115 | struct { | |
116 | __be16 src_port; | |
117 | __be16 dst_port; | |
118 | }; | |
119 | ||
120 | int iifidx; | |
121 | ||
122 | u8 l3proto; | |
123 | u8 l4proto; | |
4cd91f7c PNA |
124 | struct { |
125 | u16 id; | |
126 | __be16 proto; | |
127 | } encap[NF_FLOW_TABLE_ENCAP_MAX]; | |
dbc859d9 PNA |
128 | |
129 | /* All members above are keys for lookups, see flow_offload_hash(). */ | |
130 | struct { } __hash; | |
131 | ||
26267bf9 | 132 | u8 dir:2, |
db6140e5 | 133 | xmit_type:3, |
26267bf9 FF |
134 | encap_num:2, |
135 | in_vlan_ingress:2; | |
4f3780c0 | 136 | u16 mtu; |
7a27f6ab | 137 | union { |
8b9229d1 PNA |
138 | struct { |
139 | struct dst_entry *dst_cache; | |
140 | u32 dst_cookie; | |
141 | }; | |
7a27f6ab PNA |
142 | struct { |
143 | u32 ifidx; | |
73f97025 | 144 | u32 hw_ifidx; |
7a27f6ab PNA |
145 | u8 h_source[ETH_ALEN]; |
146 | u8 h_dest[ETH_ALEN]; | |
147 | } out; | |
db6140e5 PB |
148 | struct { |
149 | u32 iifidx; | |
150 | } tc; | |
7a27f6ab | 151 | }; |
ac2a6666 PNA |
152 | }; |
153 | ||
154 | struct flow_offload_tuple_rhash { | |
155 | struct rhash_head node; | |
156 | struct flow_offload_tuple tuple; | |
157 | }; | |
158 | ||
355a8b13 PNA |
159 | enum nf_flow_flags { |
160 | NF_FLOW_SNAT, | |
161 | NF_FLOW_DNAT, | |
162 | NF_FLOW_TEARDOWN, | |
163 | NF_FLOW_HW, | |
164 | NF_FLOW_HW_DYING, | |
165 | NF_FLOW_HW_DEAD, | |
2c889795 | 166 | NF_FLOW_HW_PENDING, |
355a8b13 | 167 | }; |
ac2a6666 | 168 | |
f1363e05 PNA |
169 | enum flow_offload_type { |
170 | NF_FLOW_OFFLOAD_UNSPEC = 0, | |
171 | NF_FLOW_OFFLOAD_ROUTE, | |
172 | }; | |
173 | ||
ac2a6666 PNA |
174 | struct flow_offload { |
175 | struct flow_offload_tuple_rhash tuplehash[FLOW_OFFLOAD_DIR_MAX]; | |
b32d2f34 | 176 | struct nf_conn *ct; |
355a8b13 | 177 | unsigned long flags; |
f1363e05 | 178 | u16 type; |
9f48e9bf | 179 | u32 timeout; |
62248df8 | 180 | struct rcu_head rcu_head; |
ac2a6666 PNA |
181 | }; |
182 | ||
183 | #define NF_FLOW_TIMEOUT (30 * HZ) | |
fb46f1b7 PNA |
184 | #define nf_flowtable_time_stamp (u32)jiffies |
185 | ||
1d91d2e1 OS |
186 | unsigned long flow_offload_get_timeout(struct flow_offload *flow); |
187 | ||
fb46f1b7 PNA |
188 | static inline __s32 nf_flow_timeout_delta(unsigned int timeout) |
189 | { | |
190 | return (__s32)(timeout - nf_flowtable_time_stamp); | |
191 | } | |
ac2a6666 PNA |
192 | |
193 | struct nf_flow_route { | |
194 | struct { | |
5139c0c0 | 195 | struct dst_entry *dst; |
c63a7cc4 PNA |
196 | struct { |
197 | u32 ifindex; | |
4cd91f7c PNA |
198 | struct { |
199 | u16 id; | |
200 | __be16 proto; | |
201 | } encap[NF_FLOW_TABLE_ENCAP_MAX]; | |
26267bf9 FF |
202 | u8 num_encaps:2, |
203 | ingress_vlans:2; | |
c63a7cc4 | 204 | } in; |
7a27f6ab PNA |
205 | struct { |
206 | u32 ifindex; | |
73f97025 | 207 | u32 hw_ifindex; |
7a27f6ab PNA |
208 | u8 h_source[ETH_ALEN]; |
209 | u8 h_dest[ETH_ALEN]; | |
210 | } out; | |
5139c0c0 | 211 | enum flow_offload_xmit_type xmit_type; |
ac2a6666 PNA |
212 | } tuple[FLOW_OFFLOAD_DIR_MAX]; |
213 | }; | |
214 | ||
f1363e05 | 215 | struct flow_offload *flow_offload_alloc(struct nf_conn *ct); |
ac2a6666 PNA |
216 | void flow_offload_free(struct flow_offload *flow); |
217 | ||
505ee3a1 AH |
218 | static inline int |
219 | nf_flow_table_offload_add_cb(struct nf_flowtable *flow_table, | |
220 | flow_setup_cb_t *cb, void *cb_priv) | |
221 | { | |
222 | struct flow_block *block = &flow_table->flow_block; | |
223 | struct flow_block_cb *block_cb; | |
224 | int err = 0; | |
225 | ||
226 | down_write(&flow_table->flow_block_lock); | |
227 | block_cb = flow_block_cb_lookup(block, cb, cb_priv); | |
228 | if (block_cb) { | |
229 | err = -EEXIST; | |
230 | goto unlock; | |
231 | } | |
232 | ||
233 | block_cb = flow_block_cb_alloc(cb, cb_priv, cb_priv, NULL); | |
234 | if (IS_ERR(block_cb)) { | |
235 | err = PTR_ERR(block_cb); | |
236 | goto unlock; | |
237 | } | |
238 | ||
239 | list_add_tail(&block_cb->list, &block->cb_list); | |
240 | ||
241 | unlock: | |
242 | up_write(&flow_table->flow_block_lock); | |
243 | return err; | |
244 | } | |
245 | ||
246 | static inline void | |
247 | nf_flow_table_offload_del_cb(struct nf_flowtable *flow_table, | |
248 | flow_setup_cb_t *cb, void *cb_priv) | |
249 | { | |
250 | struct flow_block *block = &flow_table->flow_block; | |
251 | struct flow_block_cb *block_cb; | |
252 | ||
253 | down_write(&flow_table->flow_block_lock); | |
254 | block_cb = flow_block_cb_lookup(block, cb, cb_priv); | |
255 | if (block_cb) { | |
256 | list_del(&block_cb->list); | |
257 | flow_block_cb_free(block_cb); | |
258 | } else { | |
259 | WARN_ON(true); | |
260 | } | |
261 | up_write(&flow_table->flow_block_lock); | |
262 | } | |
978703f4 | 263 | |
f1363e05 PNA |
264 | int flow_offload_route_init(struct flow_offload *flow, |
265 | const struct nf_flow_route *route); | |
266 | ||
ac2a6666 | 267 | int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow); |
8b3646d6 PB |
268 | void flow_offload_refresh(struct nf_flowtable *flow_table, |
269 | struct flow_offload *flow); | |
270 | ||
ac2a6666 PNA |
271 | struct flow_offload_tuple_rhash *flow_offload_lookup(struct nf_flowtable *flow_table, |
272 | struct flow_offload_tuple *tuple); | |
a8284c68 PNA |
273 | void nf_flow_table_gc_cleanup(struct nf_flowtable *flowtable, |
274 | struct net_device *dev); | |
5f1be84a | 275 | void nf_flow_table_cleanup(struct net_device *dev); |
c0ea1bcb | 276 | |
a268de77 | 277 | int nf_flow_table_init(struct nf_flowtable *flow_table); |
b408c5b0 | 278 | void nf_flow_table_free(struct nf_flowtable *flow_table); |
ac2a6666 | 279 | |
59c466dd | 280 | void flow_offload_teardown(struct flow_offload *flow); |
ac2a6666 | 281 | |
f4401262 PNA |
282 | void nf_flow_snat_port(const struct flow_offload *flow, |
283 | struct sk_buff *skb, unsigned int thoff, | |
284 | u8 protocol, enum flow_offload_tuple_dir dir); | |
285 | void nf_flow_dnat_port(const struct flow_offload *flow, | |
286 | struct sk_buff *skb, unsigned int thoff, | |
287 | u8 protocol, enum flow_offload_tuple_dir dir); | |
ac2a6666 PNA |
288 | |
289 | struct flow_ports { | |
290 | __be16 source, dest; | |
291 | }; | |
292 | ||
7c23b629 PNA |
293 | unsigned int nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb, |
294 | const struct nf_hook_state *state); | |
295 | unsigned int nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb, | |
296 | const struct nf_hook_state *state); | |
297 | ||
ac2a6666 PNA |
298 | #define MODULE_ALIAS_NF_FLOWTABLE(family) \ |
299 | MODULE_ALIAS("nf-flowtable-" __stringify(family)) | |
300 | ||
c29f74e0 PNA |
301 | void nf_flow_offload_add(struct nf_flowtable *flowtable, |
302 | struct flow_offload *flow); | |
303 | void nf_flow_offload_del(struct nf_flowtable *flowtable, | |
304 | struct flow_offload *flow); | |
305 | void nf_flow_offload_stats(struct nf_flowtable *flowtable, | |
306 | struct flow_offload *flow); | |
307 | ||
308 | void nf_flow_table_offload_flush(struct nf_flowtable *flowtable); | |
309 | int nf_flow_table_offload_setup(struct nf_flowtable *flowtable, | |
310 | struct net_device *dev, | |
311 | enum flow_block_command cmd); | |
5c27d8d7 PNA |
312 | int nf_flow_rule_route_ipv4(struct net *net, const struct flow_offload *flow, |
313 | enum flow_offload_tuple_dir dir, | |
314 | struct nf_flow_rule *flow_rule); | |
315 | int nf_flow_rule_route_ipv6(struct net *net, const struct flow_offload *flow, | |
316 | enum flow_offload_tuple_dir dir, | |
317 | struct nf_flow_rule *flow_rule); | |
c29f74e0 PNA |
318 | |
319 | int nf_flow_table_offload_init(void); | |
320 | void nf_flow_table_offload_exit(void); | |
8bb69f3b | 321 | |
0492d857 PNA |
322 | static inline __be16 nf_flow_pppoe_proto(const struct sk_buff *skb) |
323 | { | |
324 | __be16 proto; | |
325 | ||
326 | proto = *((__be16 *)(skb_mac_header(skb) + ETH_HLEN + | |
327 | sizeof(struct pppoe_hdr))); | |
328 | switch (proto) { | |
329 | case htons(PPP_IP): | |
330 | return htons(ETH_P_IP); | |
331 | case htons(PPP_IPV6): | |
332 | return htons(ETH_P_IPV6); | |
333 | } | |
334 | ||
335 | return 0; | |
336 | } | |
337 | ||
0286fbc6 | 338 | #endif /* _NF_FLOW_TABLE_H */ |