History

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.

Hans Schillstrom committed 14 years ago

Commit d1992b11 parent da2e8522 files · +46 −31Browse files

Unified · Split

2 files
  1. include/linux/netfilter/xt_HMARK.h +5 −0
  2. net/netfilter/xt_HMARK.c +41 −31
include/linux/netfilter/xt_HMARK.h+5−0
@@ -27,7 +27,12 @@ union hmark_ports { · 26 unmodified lines
2727 __u16 src;
2828 __u16 dst;
2929 } p16;
30+ struct {
31+ __be16 src;
32+ __be16 dst;
33+ } b16;
3034 __u32 v32;
35+ __be32 b32;
3136 };
3237
3338 struct xt_hmark_info {
net/netfilter/xt_HMARK.c+41−31
@@ -32,13 +32,13 @@ MODULE_ALIAS("ipt_HMARK"); · 31 unmodified lines
3232 MODULE_ALIAS("ip6t_HMARK");
3333
3434 struct hmark_tuple {
35− u32 src;
36− u32 dst;
35+ __be32 src;
36+ __be32 dst;
3737 union hmark_ports uports;
38− uint8_t proto;
38+ u8 proto;
3939 };
4040
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)
4242 {
4343 return (addr32[0] & mask[0]) ^
4444 (addr32[1] & mask[1]) ^
@@ -46,8 +46,8 @@ static inline u32 hmark_addr6_mask(const __u32 *addr32, const __u32 *mask) · 1 unmodified line
4646 (addr32[3] & mask[3]);
4747 }
4848
49−static inline u32
50−hmark_addr_mask(int l3num, const __u32 *addr32, const __u32 *mask)
49+static inline __be32
50+hmark_addr_mask(int l3num, const __be32 *addr32, const __be32 *mask)
5151 {
5252 switch (l3num) {
5353 case AF_INET:
@@ -58,6 +58,22 @@ hmark_addr_mask(int l3num, const __u32 *addr32, const __u32 *mask) · 4 unmodified lines
5858 return 0;
5959 }
6060
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+
6177 static int
6278 hmark_ct_set_htuple(const struct sk_buff *skb, struct hmark_tuple *t,
6379 const struct xt_hmark_info *info)
@@ -74,22 +90,19 @@ hmark_ct_set_htuple(const struct sk_buff *skb, struct hmark_tuple *t, · 10 unmodified lines
7490 otuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
7591 rtuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
7692
77− t->src = hmark_addr_mask(otuple->src.l3num, otuple->src.u3.all,
78− info->src_mask.all);
79− t->dst = hmark_addr_mask(otuple->src.l3num, rtuple->src.u3.all,
80− info->dst_mask.all);
93+ t->src = hmark_addr_mask(otuple->src.l3num, otuple->src.u3.ip6,
94+ info->src_mask.ip6);
95+ t->dst = hmark_addr_mask(otuple->src.l3num, rtuple->src.u3.ip6,
96+ info->dst_mask.ip6);
8197
8298 if (info->flags & XT_HMARK_FLAG(XT_HMARK_METHOD_L3))
8399 return 0;
84100
85101 t->proto = nf_ct_protonum(ct);
86102 if (t->proto != IPPROTO_ICMP) {
87− t->uports.p16.src = otuple->src.u.all;
88− t->uports.p16.dst = rtuple->src.u.all;
89− t->uports.v32 = (t->uports.v32 & info->port_mask.v32) |
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);
103+ t->uports.b16.src = otuple->src.u.all;
104+ t->uports.b16.dst = rtuple->src.u.all;
105+ hmark_swap_ports(&t->uports, info);
93106 }
94107
95108 return 0;
@@ -98,15 +111,19 @@ hmark_ct_set_htuple(const struct sk_buff *skb, struct hmark_tuple *t, · 2 unmodified lines
98111 #endif
99112 }
100113
114+/* This hash function is endian independent, to ensure consistent hashing if
115+ * the cluster is composed of big and little endian systems. */
101116 static inline u32
102117 hmark_hash(struct hmark_tuple *t, const struct xt_hmark_info *info)
103118 {
104119 u32 hash;
120+ u32 src = ntohl(t->src);
121+ u32 dst = ntohl(t->dst);
105122
106− if (t->dst < t->src)
107− swap(t->src, t->dst);
123+ if (dst < src)
124+ swap(src, dst);
108125
109− hash = jhash_3words(t->src, t->dst, t->uports.v32, info->hashrnd);
126+ hash = jhash_3words(src, dst, t->uports.v32, info->hashrnd);
110127 hash = hash ^ (t->proto & info->proto_mask);
111128
112129 return (((u64)hash * info->hmodulus) >> 32) + info->hoffset;
@@ -126,11 +143,7 @@ hmark_set_tuple_ports(const struct sk_buff *skb, unsigned int nhoff, · 13 unmodified lines
126143 if (skb_copy_bits(skb, nhoff, &t->uports, sizeof(t->uports)) < 0)
127144 return;
128145
129− t->uports.v32 = (t->uports.v32 & info->port_mask.v32) |
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);
146+ hmark_swap_ports(&t->uports, info);
134147 }
135148
136149 #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, · 41 unmodified lines
178191 return -1;
179192 }
180193 noicmp:
181− t->src = hmark_addr6_mask(ip6->saddr.s6_addr32, info->src_mask.all);
182− t->dst = hmark_addr6_mask(ip6->daddr.s6_addr32, info->dst_mask.all);
194+ t->src = hmark_addr6_mask(ip6->saddr.s6_addr32, info->src_mask.ip6);
195+ t->dst = hmark_addr6_mask(ip6->daddr.s6_addr32, info->dst_mask.ip6);
183196
184197 if (info->flags & XT_HMARK_FLAG(XT_HMARK_METHOD_L3))
185198 return 0;
@@ -255,11 +268,8 @@ hmark_pkt_set_htuple_ipv4(const struct sk_buff *skb, struct hmark_tuple *t, · 69 unmodified lines
255268 }
256269 }
257270
258− t->src = (__force u32) ip->saddr;
259− t->dst = (__force u32) ip->daddr;
260−
261− t->src &= info->src_mask.ip;
262− t->dst &= info->dst_mask.ip;
271+ t->src = ip->saddr & info->src_mask.ip;
272+ t->dst = ip->daddr & info->dst_mask.ip;
263273
264274 if (info->flags & XT_HMARK_FLAG(XT_HMARK_METHOD_L3))
265275 return 0;