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