]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
c01cd429 PM |
2 | #ifndef _NF_QUEUE_H |
3 | #define _NF_QUEUE_H | |
4 | ||
97a2d41c EL |
5 | #include <linux/ip.h> |
6 | #include <linux/ipv6.h> | |
7 | #include <linux/jhash.h> | |
8 | ||
c01cd429 | 9 | /* Each queued (to userspace) skbuff has one of these. */ |
02f014d8 PM |
10 | struct nf_queue_entry { |
11 | struct list_head list; | |
12 | struct sk_buff *skb; | |
13 | unsigned int id; | |
960632ec | 14 | unsigned int hook_index; /* index in hook_entries->hook[] */ |
02f014d8 | 15 | |
1d1de89b | 16 | struct nf_hook_state state; |
a5fedd43 | 17 | u16 size; /* sizeof(entry) + saved route keys */ |
a5fedd43 FW |
18 | |
19 | /* extra space to store route keys */ | |
c01cd429 PM |
20 | }; |
21 | ||
02f014d8 | 22 | #define nf_queue_entry_reroute(x) ((void *)x + sizeof(struct nf_queue_entry)) |
c01cd429 PM |
23 | |
24 | /* Packet queuing */ | |
25 | struct nf_queue_handler { | |
54f17bbc AC |
26 | int (*outfn)(struct nf_queue_entry *entry, |
27 | unsigned int queuenum); | |
039b40ee | 28 | unsigned int (*nf_hook_drop)(struct net *net); |
c01cd429 PM |
29 | }; |
30 | ||
dc3ee32e EB |
31 | void nf_register_queue_handler(struct net *net, const struct nf_queue_handler *qh); |
32 | void nf_unregister_queue_handler(struct net *net); | |
4e77be46 | 33 | void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict); |
c01cd429 | 34 | |
ed78d09d | 35 | void nf_queue_entry_get_refs(struct nf_queue_entry *entry); |
a5fedd43 FW |
36 | void nf_queue_entry_release_refs(struct nf_queue_entry *entry); |
37 | ||
97a2d41c EL |
38 | static inline void init_hashrandom(u32 *jhash_initval) |
39 | { | |
40 | while (*jhash_initval == 0) | |
41 | *jhash_initval = prandom_u32(); | |
42 | } | |
43 | ||
2462f3f4 | 44 | static inline u32 hash_v4(const struct iphdr *iph, u32 initval) |
97a2d41c | 45 | { |
97a2d41c EL |
46 | /* packets in either direction go into same queue */ |
47 | if ((__force u32)iph->saddr < (__force u32)iph->daddr) | |
48 | return jhash_3words((__force u32)iph->saddr, | |
2462f3f4 | 49 | (__force u32)iph->daddr, iph->protocol, initval); |
97a2d41c EL |
50 | |
51 | return jhash_3words((__force u32)iph->daddr, | |
2462f3f4 | 52 | (__force u32)iph->saddr, iph->protocol, initval); |
97a2d41c EL |
53 | } |
54 | ||
2462f3f4 | 55 | static inline u32 hash_v6(const struct ipv6hdr *ip6h, u32 initval) |
97a2d41c | 56 | { |
97a2d41c EL |
57 | u32 a, b, c; |
58 | ||
59 | if ((__force u32)ip6h->saddr.s6_addr32[3] < | |
60 | (__force u32)ip6h->daddr.s6_addr32[3]) { | |
61 | a = (__force u32) ip6h->saddr.s6_addr32[3]; | |
62 | b = (__force u32) ip6h->daddr.s6_addr32[3]; | |
63 | } else { | |
64 | b = (__force u32) ip6h->saddr.s6_addr32[3]; | |
65 | a = (__force u32) ip6h->daddr.s6_addr32[3]; | |
66 | } | |
67 | ||
68 | if ((__force u32)ip6h->saddr.s6_addr32[1] < | |
69 | (__force u32)ip6h->daddr.s6_addr32[1]) | |
70 | c = (__force u32) ip6h->saddr.s6_addr32[1]; | |
71 | else | |
72 | c = (__force u32) ip6h->daddr.s6_addr32[1]; | |
73 | ||
2462f3f4 LZ |
74 | return jhash_3words(a, b, c, initval); |
75 | } | |
76 | ||
77 | static inline u32 hash_bridge(const struct sk_buff *skb, u32 initval) | |
78 | { | |
79 | struct ipv6hdr *ip6h, _ip6h; | |
80 | struct iphdr *iph, _iph; | |
81 | ||
82 | switch (eth_hdr(skb)->h_proto) { | |
83 | case htons(ETH_P_IP): | |
84 | iph = skb_header_pointer(skb, skb_network_offset(skb), | |
85 | sizeof(*iph), &_iph); | |
86 | if (iph) | |
87 | return hash_v4(iph, initval); | |
88 | break; | |
89 | case htons(ETH_P_IPV6): | |
90 | ip6h = skb_header_pointer(skb, skb_network_offset(skb), | |
91 | sizeof(*ip6h), &_ip6h); | |
92 | if (ip6h) | |
93 | return hash_v6(ip6h, initval); | |
94 | break; | |
95 | } | |
96 | ||
97 | return 0; | |
97a2d41c | 98 | } |
97a2d41c EL |
99 | |
100 | static inline u32 | |
101 | nfqueue_hash(const struct sk_buff *skb, u16 queue, u16 queues_total, u8 family, | |
2462f3f4 | 102 | u32 initval) |
97a2d41c | 103 | { |
2462f3f4 LZ |
104 | switch (family) { |
105 | case NFPROTO_IPV4: | |
106 | queue += reciprocal_scale(hash_v4(ip_hdr(skb), initval), | |
107 | queues_total); | |
108 | break; | |
109 | case NFPROTO_IPV6: | |
110 | queue += reciprocal_scale(hash_v6(ipv6_hdr(skb), initval), | |
111 | queues_total); | |
112 | break; | |
113 | case NFPROTO_BRIDGE: | |
114 | queue += reciprocal_scale(hash_bridge(skb, initval), | |
115 | queues_total); | |
116 | break; | |
117 | } | |
97a2d41c EL |
118 | |
119 | return queue; | |
120 | } | |
121 | ||
c01cd429 | 122 | #endif /* _NF_QUEUE_H */ |