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
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
33struct xt_hmark_info {38struct xt_hmark_info {
net/netfilter/xt_HMARK.c+41−31
@@ -32,13 +32,13 @@ MODULE_ALIAS("ipt_HMARK"); · 31 unmodified lines
32MODULE_ALIAS("ip6t_HMARK");32MODULE_ALIAS("ip6t_HMARK");
33 33
34struct hmark_tuple {34struct 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
41static inline u32 hmark_addr6_mask(const __u32 *addr32, const __u32 *mask)41static 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) · 1 unmodified line
46 (addr32[3] & mask[3]);46 (addr32[3] & mask[3]);
47}47}
48 48
49static inline u3249static inline __be32
50hmark_addr_mask(int l3num, const __u32 *addr32, const __u32 *mask)50hmark_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) · 4 unmodified lines
58 return 0;58 return 0;
59}59}
60 60
61static 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
61static int77static int
62hmark_ct_set_htuple(const struct sk_buff *skb, struct hmark_tuple *t,78hmark_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, · 10 unmodified lines
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, · 2 unmodified lines
98#endif111#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. */
101static inline u32116static inline u32
102hmark_hash(struct hmark_tuple *t, const struct xt_hmark_info *info)117hmark_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, · 13 unmodified lines
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, · 41 unmodified lines
178 return -1;191 return -1;
179 }192 }
180noicmp:193noicmp:
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, · 69 unmodified lines
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;