diff options
| author | Hans Schillstrom <hans@schillstrom.com> | 2012-05-17 18:35:46 -0400 |
|---|---|---|
| committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2012-06-07 08:53:01 -0400 |
| commit | d1992b169d31f339dc5ea4e9f312567c8cf322a3 (patch) | |
| tree | 200649e617e0c1a548e9404989e17ed8a58c6e4b | |
| parent | da2e852612967a53d17de930929574444a67fb52 (diff) | |
netfilter: xt_HMARK: fix endianness and provide consistent hashing
This patch addresses two issues:
a) Fix usage of u32 and __be32 that causes endianess warnings via sparse.
b) Ensure consistent hashing in a cluster that is composed of big and
little endian systems. Thus, we obtain the same hash mark in an
heterogeneous cluster.
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Hans Schillstrom <hans@schillstrom.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
| -rw-r--r-- | include/linux/netfilter/xt_HMARK.h | 5 | ||||
| -rw-r--r-- | net/netfilter/xt_HMARK.c | 72 |
2 files changed, 46 insertions, 31 deletions
diff --git a/include/linux/netfilter/xt_HMARK.h b/include/linux/netfilter/xt_HMARK.h index abb1650940d2..826fc5807577 100644 --- a/include/linux/netfilter/xt_HMARK.h +++ b/include/linux/netfilter/xt_HMARK.h | |||
| @@ -27,7 +27,12 @@ union hmark_ports { | |||
| 27 | __u16 src; | 27 | __u16 src; |
| 28 | __u16 dst; | 28 | __u16 dst; |
| 29 | } p16; | 29 | } p16; |
| 30 | struct { | ||
| 31 | __be16 src; | ||
| 32 | __be16 dst; | ||
| 33 | } b16; | ||
| 30 | __u32 v32; | 34 | __u32 v32; |
| 35 | __be32 b32; | ||
| 31 | }; | 36 | }; |
| 32 | 37 | ||
| 33 | struct xt_hmark_info { | 38 | struct xt_hmark_info { |
diff --git a/net/netfilter/xt_HMARK.c b/net/netfilter/xt_HMARK.c index 0a96a43108ed..1686ca1b53a1 100644 --- a/net/netfilter/xt_HMARK.c +++ b/net/netfilter/xt_HMARK.c | |||
| @@ -32,13 +32,13 @@ MODULE_ALIAS("ipt_HMARK"); | |||
| 32 | MODULE_ALIAS("ip6t_HMARK"); | 32 | MODULE_ALIAS("ip6t_HMARK"); |
| 33 | 33 | ||
| 34 | struct hmark_tuple { | 34 | struct hmark_tuple { |
| 35 | u32 src; | 35 | __be32 src; |
| 36 | u32 dst; | 36 | __be32 dst; |
| 37 | union hmark_ports uports; | 37 | union hmark_ports uports; |
| 38 | uint8_t proto; | 38 | u8 proto; |
| 39 | }; | 39 | }; |
| 40 | 40 | ||
| 41 | static inline u32 hmark_addr6_mask(const __u32 *addr32, const __u32 *mask) | 41 | static inline __be32 hmark_addr6_mask(const __be32 *addr32, const __be32 *mask) |
| 42 | { | 42 | { |
| 43 | return (addr32[0] & mask[0]) ^ | 43 | return (addr32[0] & mask[0]) ^ |
| 44 | (addr32[1] & mask[1]) ^ | 44 | (addr32[1] & mask[1]) ^ |
| @@ -46,8 +46,8 @@ static inline u32 hmark_addr6_mask(const __u32 *addr32, const __u32 *mask) | |||
| 46 | (addr32[3] & mask[3]); | 46 | (addr32[3] & mask[3]); |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | static inline u32 | 49 | static inline __be32 |
| 50 | hmark_addr_mask(int l3num, const __u32 *addr32, const __u32 *mask) | 50 | hmark_addr_mask(int l3num, const __be32 *addr32, const __be32 *mask) |
| 51 | { | 51 | { |
| 52 | switch (l3num) { | 52 | switch (l3num) { |
| 53 | case AF_INET: | 53 | case AF_INET: |
| @@ -58,6 +58,22 @@ hmark_addr_mask(int l3num, const __u32 *addr32, const __u32 *mask) | |||
| 58 | return 0; | 58 | return 0; |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | static inline void hmark_swap_ports(union hmark_ports *uports, | ||
| 62 | const struct xt_hmark_info *info) | ||
| 63 | { | ||
| 64 | union hmark_ports hp; | ||
| 65 | u16 src, dst; | ||
| 66 | |||
| 67 | hp.b32 = (uports->b32 & info->port_mask.b32) | info->port_set.b32; | ||
| 68 | src = ntohs(hp.b16.src); | ||
| 69 | dst = ntohs(hp.b16.dst); | ||
| 70 | |||
| 71 | if (dst > src) | ||
| 72 | uports->v32 = (dst << 16) | src; | ||
| 73 | else | ||
| 74 | uports->v32 = (src << 16) | dst; | ||
| 75 | } | ||
| 76 | |||
| 61 | static int | 77 | static int |
| 62 | hmark_ct_set_htuple(const struct sk_buff *skb, struct hmark_tuple *t, | 78 | hmark_ct_set_htuple(const struct sk_buff *skb, struct hmark_tuple *t, |
| 63 | const struct xt_hmark_info *info) | 79 | const struct xt_hmark_info *info) |
| @@ -74,22 +90,19 @@ hmark_ct_set_htuple(const struct sk_buff *skb, struct hmark_tuple *t, | |||
| 74 | otuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; | 90 | otuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; |
| 75 | rtuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; | 91 | rtuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; |
| 76 | 92 | ||
| 77 | t->src = hmark_addr_mask(otuple->src.l3num, otuple->src.u3.all, | 93 | t->src = hmark_addr_mask(otuple->src.l3num, otuple->src.u3.ip6, |
| 78 | info->src_mask.all); | 94 | info->src_mask.ip6); |
| 79 | t->dst = hmark_addr_mask(otuple->src.l3num, rtuple->src.u3.all, | 95 | t->dst = hmark_addr_mask(otuple->src.l3num, rtuple->src.u3.ip6, |
| 80 | info->dst_mask.all); | 96 | info->dst_mask.ip6); |
| 81 | 97 | ||
| 82 | if (info->flags & XT_HMARK_FLAG(XT_HMARK_METHOD_L3)) | 98 | if (info->flags & XT_HMARK_FLAG(XT_HMARK_METHOD_L3)) |
| 83 | return 0; | 99 | return 0; |
| 84 | 100 | ||
| 85 | t->proto = nf_ct_protonum(ct); | 101 | t->proto = nf_ct_protonum(ct); |
| 86 | if (t->proto != IPPROTO_ICMP) { | 102 | if (t->proto != IPPROTO_ICMP) { |
| 87 | t->uports.p16.src = otuple->src.u.all; | 103 | t->uports.b16.src = otuple->src.u.all; |
| 88 | t->uports.p16.dst = rtuple->src.u.all; | 104 | t->uports.b16.dst = rtuple->src.u.all; |
| 89 | t->uports.v32 = (t->uports.v32 & info->port_mask.v32) | | 105 | hmark_swap_ports(&t->uports, info); |
| 90 | info->port_set.v32; | ||
| 91 | if (t->uports.p16.dst < t->uports.p16.src) | ||
| 92 | swap(t->uports.p16.dst, t->uports.p16.src); | ||
| 93 | } | 106 | } |
| 94 | 107 | ||
| 95 | return 0; | 108 | return 0; |
| @@ -98,15 +111,19 @@ hmark_ct_set_htuple(const struct sk_buff *skb, struct hmark_tuple *t, | |||
| 98 | #endif | 111 | #endif |
| 99 | } | 112 | } |
| 100 | 113 | ||
| 114 | /* This hash function is endian independent, to ensure consistent hashing if | ||
| 115 | * the cluster is composed of big and little endian systems. */ | ||
| 101 | static inline u32 | 116 | static inline u32 |
| 102 | hmark_hash(struct hmark_tuple *t, const struct xt_hmark_info *info) | 117 | hmark_hash(struct hmark_tuple *t, const struct xt_hmark_info *info) |
| 103 | { | 118 | { |
| 104 | u32 hash; | 119 | u32 hash; |
| 120 | u32 src = ntohl(t->src); | ||
| 121 | u32 dst = ntohl(t->dst); | ||
| 105 | 122 | ||
| 106 | if (t->dst < t->src) | 123 | if (dst < src) |
| 107 | swap(t->src, t->dst); | 124 | swap(src, dst); |
| 108 | 125 | ||
| 109 | hash = jhash_3words(t->src, t->dst, t->uports.v32, info->hashrnd); | 126 | hash = jhash_3words(src, dst, t->uports.v32, info->hashrnd); |
| 110 | hash = hash ^ (t->proto & info->proto_mask); | 127 | hash = hash ^ (t->proto & info->proto_mask); |
| 111 | 128 | ||
| 112 | return (((u64)hash * info->hmodulus) >> 32) + info->hoffset; | 129 | return (((u64)hash * info->hmodulus) >> 32) + info->hoffset; |
| @@ -126,11 +143,7 @@ hmark_set_tuple_ports(const struct sk_buff *skb, unsigned int nhoff, | |||
| 126 | if (skb_copy_bits(skb, nhoff, &t->uports, sizeof(t->uports)) < 0) | 143 | if (skb_copy_bits(skb, nhoff, &t->uports, sizeof(t->uports)) < 0) |
| 127 | return; | 144 | return; |
| 128 | 145 | ||
| 129 | t->uports.v32 = (t->uports.v32 & info->port_mask.v32) | | 146 | hmark_swap_ports(&t->uports, info); |
| 130 | info->port_set.v32; | ||
| 131 | |||
| 132 | if (t->uports.p16.dst < t->uports.p16.src) | ||
| 133 | swap(t->uports.p16.dst, t->uports.p16.src); | ||
| 134 | } | 147 | } |
| 135 | 148 | ||
| 136 | #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) | 149 | #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) |
| @@ -178,8 +191,8 @@ hmark_pkt_set_htuple_ipv6(const struct sk_buff *skb, struct hmark_tuple *t, | |||
| 178 | return -1; | 191 | return -1; |
| 179 | } | 192 | } |
| 180 | noicmp: | 193 | noicmp: |
| 181 | t->src = hmark_addr6_mask(ip6->saddr.s6_addr32, info->src_mask.all); | 194 | t->src = hmark_addr6_mask(ip6->saddr.s6_addr32, info->src_mask.ip6); |
| 182 | t->dst = hmark_addr6_mask(ip6->daddr.s6_addr32, info->dst_mask.all); | 195 | t->dst = hmark_addr6_mask(ip6->daddr.s6_addr32, info->dst_mask.ip6); |
| 183 | 196 | ||
| 184 | if (info->flags & XT_HMARK_FLAG(XT_HMARK_METHOD_L3)) | 197 | if (info->flags & XT_HMARK_FLAG(XT_HMARK_METHOD_L3)) |
| 185 | return 0; | 198 | return 0; |
| @@ -255,11 +268,8 @@ hmark_pkt_set_htuple_ipv4(const struct sk_buff *skb, struct hmark_tuple *t, | |||
| 255 | } | 268 | } |
| 256 | } | 269 | } |
| 257 | 270 | ||
| 258 | t->src = (__force u32) ip->saddr; | 271 | t->src = ip->saddr & info->src_mask.ip; |
| 259 | t->dst = (__force u32) ip->daddr; | 272 | t->dst = ip->daddr & info->dst_mask.ip; |
| 260 | |||
| 261 | t->src &= info->src_mask.ip; | ||
| 262 | t->dst &= info->dst_mask.ip; | ||
| 263 | 273 | ||
| 264 | if (info->flags & XT_HMARK_FLAG(XT_HMARK_METHOD_L3)) | 274 | if (info->flags & XT_HMARK_FLAG(XT_HMARK_METHOD_L3)) |
| 265 | return 0; | 275 | return 0; |
