Patrick McHardy | c01cd42 | 2007-12-05 01:24:48 -0800 | [diff] [blame] | 1 | #ifndef _NF_QUEUE_H |
| 2 | #define _NF_QUEUE_H |
| 3 | |
Eric Leblond | 97a2d41 | 2013-12-06 00:24:12 +0100 | [diff] [blame] | 4 | #include <linux/ip.h> |
| 5 | #include <linux/ipv6.h> |
| 6 | #include <linux/jhash.h> |
| 7 | |
Patrick McHardy | c01cd42 | 2007-12-05 01:24:48 -0800 | [diff] [blame] | 8 | /* Each queued (to userspace) skbuff has one of these. */ |
Patrick McHardy | 02f014d | 2007-12-05 01:26:33 -0800 | [diff] [blame] | 9 | struct nf_queue_entry { |
| 10 | struct list_head list; |
| 11 | struct sk_buff *skb; |
| 12 | unsigned int id; |
| 13 | |
David S. Miller | 1d1de89 | 2015-04-03 16:31:01 -0400 | [diff] [blame] | 14 | struct nf_hook_state state; |
Florian Westphal | a5fedd43 | 2013-04-19 04:58:25 +0000 | [diff] [blame] | 15 | u16 size; /* sizeof(entry) + saved route keys */ |
Florian Westphal | a5fedd43 | 2013-04-19 04:58:25 +0000 | [diff] [blame] | 16 | |
| 17 | /* extra space to store route keys */ |
Patrick McHardy | c01cd42 | 2007-12-05 01:24:48 -0800 | [diff] [blame] | 18 | }; |
| 19 | |
Patrick McHardy | 02f014d | 2007-12-05 01:26:33 -0800 | [diff] [blame] | 20 | #define nf_queue_entry_reroute(x) ((void *)x + sizeof(struct nf_queue_entry)) |
Patrick McHardy | c01cd42 | 2007-12-05 01:24:48 -0800 | [diff] [blame] | 21 | |
| 22 | /* Packet queuing */ |
| 23 | struct nf_queue_handler { |
Aaron Conole | 54f17bb | 2016-09-21 11:35:06 -0400 | [diff] [blame] | 24 | int (*outfn)(struct nf_queue_entry *entry, |
| 25 | unsigned int queuenum); |
| 26 | void (*nf_hook_drop)(struct net *net, |
Aaron Conole | e3b37f1 | 2016-09-21 11:35:07 -0400 | [diff] [blame] | 27 | const struct nf_hook_entry *hooks); |
Patrick McHardy | c01cd42 | 2007-12-05 01:24:48 -0800 | [diff] [blame] | 28 | }; |
| 29 | |
Eric W. Biederman | dc3ee32 | 2016-05-13 21:18:52 -0500 | [diff] [blame] | 30 | void nf_register_queue_handler(struct net *net, const struct nf_queue_handler *qh); |
| 31 | void nf_unregister_queue_handler(struct net *net); |
Joe Perches | 4e77be4 | 2013-09-23 11:37:48 -0700 | [diff] [blame] | 32 | void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict); |
Patrick McHardy | c01cd42 | 2007-12-05 01:24:48 -0800 | [diff] [blame] | 33 | |
Florian Westphal | ed78d09 | 2015-10-13 14:33:27 +0200 | [diff] [blame] | 34 | void nf_queue_entry_get_refs(struct nf_queue_entry *entry); |
Florian Westphal | a5fedd43 | 2013-04-19 04:58:25 +0000 | [diff] [blame] | 35 | void nf_queue_entry_release_refs(struct nf_queue_entry *entry); |
| 36 | |
Eric Leblond | 97a2d41 | 2013-12-06 00:24:12 +0100 | [diff] [blame] | 37 | static inline void init_hashrandom(u32 *jhash_initval) |
| 38 | { |
| 39 | while (*jhash_initval == 0) |
| 40 | *jhash_initval = prandom_u32(); |
| 41 | } |
| 42 | |
Liping Zhang | 2462f3f | 2016-09-15 20:50:16 +0800 | [diff] [blame] | 43 | static inline u32 hash_v4(const struct iphdr *iph, u32 initval) |
Eric Leblond | 97a2d41 | 2013-12-06 00:24:12 +0100 | [diff] [blame] | 44 | { |
Eric Leblond | 97a2d41 | 2013-12-06 00:24:12 +0100 | [diff] [blame] | 45 | /* packets in either direction go into same queue */ |
| 46 | if ((__force u32)iph->saddr < (__force u32)iph->daddr) |
| 47 | return jhash_3words((__force u32)iph->saddr, |
Liping Zhang | 2462f3f | 2016-09-15 20:50:16 +0800 | [diff] [blame] | 48 | (__force u32)iph->daddr, iph->protocol, initval); |
Eric Leblond | 97a2d41 | 2013-12-06 00:24:12 +0100 | [diff] [blame] | 49 | |
| 50 | return jhash_3words((__force u32)iph->daddr, |
Liping Zhang | 2462f3f | 2016-09-15 20:50:16 +0800 | [diff] [blame] | 51 | (__force u32)iph->saddr, iph->protocol, initval); |
Eric Leblond | 97a2d41 | 2013-12-06 00:24:12 +0100 | [diff] [blame] | 52 | } |
| 53 | |
Liping Zhang | 2462f3f | 2016-09-15 20:50:16 +0800 | [diff] [blame] | 54 | static inline u32 hash_v6(const struct ipv6hdr *ip6h, u32 initval) |
Eric Leblond | 97a2d41 | 2013-12-06 00:24:12 +0100 | [diff] [blame] | 55 | { |
Eric Leblond | 97a2d41 | 2013-12-06 00:24:12 +0100 | [diff] [blame] | 56 | u32 a, b, c; |
| 57 | |
| 58 | if ((__force u32)ip6h->saddr.s6_addr32[3] < |
| 59 | (__force u32)ip6h->daddr.s6_addr32[3]) { |
| 60 | a = (__force u32) ip6h->saddr.s6_addr32[3]; |
| 61 | b = (__force u32) ip6h->daddr.s6_addr32[3]; |
| 62 | } else { |
| 63 | b = (__force u32) ip6h->saddr.s6_addr32[3]; |
| 64 | a = (__force u32) ip6h->daddr.s6_addr32[3]; |
| 65 | } |
| 66 | |
| 67 | if ((__force u32)ip6h->saddr.s6_addr32[1] < |
| 68 | (__force u32)ip6h->daddr.s6_addr32[1]) |
| 69 | c = (__force u32) ip6h->saddr.s6_addr32[1]; |
| 70 | else |
| 71 | c = (__force u32) ip6h->daddr.s6_addr32[1]; |
| 72 | |
Liping Zhang | 2462f3f | 2016-09-15 20:50:16 +0800 | [diff] [blame] | 73 | return jhash_3words(a, b, c, initval); |
| 74 | } |
| 75 | |
| 76 | static inline u32 hash_bridge(const struct sk_buff *skb, u32 initval) |
| 77 | { |
| 78 | struct ipv6hdr *ip6h, _ip6h; |
| 79 | struct iphdr *iph, _iph; |
| 80 | |
| 81 | switch (eth_hdr(skb)->h_proto) { |
| 82 | case htons(ETH_P_IP): |
| 83 | iph = skb_header_pointer(skb, skb_network_offset(skb), |
| 84 | sizeof(*iph), &_iph); |
| 85 | if (iph) |
| 86 | return hash_v4(iph, initval); |
| 87 | break; |
| 88 | case htons(ETH_P_IPV6): |
| 89 | ip6h = skb_header_pointer(skb, skb_network_offset(skb), |
| 90 | sizeof(*ip6h), &_ip6h); |
| 91 | if (ip6h) |
| 92 | return hash_v6(ip6h, initval); |
| 93 | break; |
| 94 | } |
| 95 | |
| 96 | return 0; |
Eric Leblond | 97a2d41 | 2013-12-06 00:24:12 +0100 | [diff] [blame] | 97 | } |
Eric Leblond | 97a2d41 | 2013-12-06 00:24:12 +0100 | [diff] [blame] | 98 | |
| 99 | static inline u32 |
| 100 | nfqueue_hash(const struct sk_buff *skb, u16 queue, u16 queues_total, u8 family, |
Liping Zhang | 2462f3f | 2016-09-15 20:50:16 +0800 | [diff] [blame] | 101 | u32 initval) |
Eric Leblond | 97a2d41 | 2013-12-06 00:24:12 +0100 | [diff] [blame] | 102 | { |
Liping Zhang | 2462f3f | 2016-09-15 20:50:16 +0800 | [diff] [blame] | 103 | switch (family) { |
| 104 | case NFPROTO_IPV4: |
| 105 | queue += reciprocal_scale(hash_v4(ip_hdr(skb), initval), |
| 106 | queues_total); |
| 107 | break; |
| 108 | case NFPROTO_IPV6: |
| 109 | queue += reciprocal_scale(hash_v6(ipv6_hdr(skb), initval), |
| 110 | queues_total); |
| 111 | break; |
| 112 | case NFPROTO_BRIDGE: |
| 113 | queue += reciprocal_scale(hash_bridge(skb, initval), |
| 114 | queues_total); |
| 115 | break; |
| 116 | } |
Eric Leblond | 97a2d41 | 2013-12-06 00:24:12 +0100 | [diff] [blame] | 117 | |
| 118 | return queue; |
| 119 | } |
| 120 | |
Patrick McHardy | c01cd42 | 2007-12-05 01:24:48 -0800 | [diff] [blame] | 121 | #endif /* _NF_QUEUE_H */ |