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