aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorEric Dumazet <dada1@cosmosbay.com>2009-02-18 11:47:50 -0500
committerPatrick McHardy <kaber@trash.net>2009-02-18 11:47:50 -0500
commitddc214c43a923e89741e04da2f10e3037a64e222 (patch)
tree106bd4feb8edb426683c9c46c50095f71ef8da0d /net/ipv4
parent55df4ac0c927c7f1f84e6d75532f0ca45d391e64 (diff)
netfilter: arp_tables: unfold two critical loops in arp_packet_match()
x86 and powerpc can perform long word accesses in an efficient maner. We can use this to unroll two loops in arp_packet_match(), to perform arithmetic on long words instead of bytes. This is a win on x86_64 for example. Signed-off-by: Eric Dumazet <dada1@cosmosbay.com> Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/netfilter/arp_tables.c44
1 files changed, 34 insertions, 10 deletions
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 7ea88b61cb0d..b5db46342614 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -73,6 +73,36 @@ static inline int arp_devaddr_compare(const struct arpt_devaddr_info *ap,
73 return (ret != 0); 73 return (ret != 0);
74} 74}
75 75
76/*
77 * Unfortunatly, _b and _mask are not aligned to an int (or long int)
78 * Some arches dont care, unrolling the loop is a win on them.
79 */
80static unsigned long ifname_compare(const char *_a, const char *_b, const char *_mask)
81{
82#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
83 const unsigned long *a = (const unsigned long *)_a;
84 const unsigned long *b = (const unsigned long *)_b;
85 const unsigned long *mask = (const unsigned long *)_mask;
86 unsigned long ret;
87
88 ret = (a[0] ^ b[0]) & mask[0];
89 if (IFNAMSIZ > sizeof(unsigned long))
90 ret |= (a[1] ^ b[1]) & mask[1];
91 if (IFNAMSIZ > 2 * sizeof(unsigned long))
92 ret |= (a[2] ^ b[2]) & mask[2];
93 if (IFNAMSIZ > 3 * sizeof(unsigned long))
94 ret |= (a[3] ^ b[3]) & mask[3];
95 BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long));
96#else
97 unsigned long ret = 0;
98 int i;
99
100 for (i = 0; i < IFNAMSIZ; i++)
101 ret |= (_a[i] ^ _b[i]) & _mask[i];
102#endif
103 return ret;
104}
105
76/* Returns whether packet matches rule or not. */ 106/* Returns whether packet matches rule or not. */
77static inline int arp_packet_match(const struct arphdr *arphdr, 107static inline int arp_packet_match(const struct arphdr *arphdr,
78 struct net_device *dev, 108 struct net_device *dev,
@@ -83,7 +113,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
83 const char *arpptr = (char *)(arphdr + 1); 113 const char *arpptr = (char *)(arphdr + 1);
84 const char *src_devaddr, *tgt_devaddr; 114 const char *src_devaddr, *tgt_devaddr;
85 __be32 src_ipaddr, tgt_ipaddr; 115 __be32 src_ipaddr, tgt_ipaddr;
86 int i, ret; 116 long ret;
87 117
88#define FWINV(bool, invflg) ((bool) ^ !!(arpinfo->invflags & (invflg))) 118#define FWINV(bool, invflg) ((bool) ^ !!(arpinfo->invflags & (invflg)))
89 119
@@ -156,10 +186,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
156 } 186 }
157 187
158 /* Look for ifname matches. */ 188 /* Look for ifname matches. */
159 for (i = 0, ret = 0; i < IFNAMSIZ; i++) { 189 ret = ifname_compare(indev, arpinfo->iniface, arpinfo->iniface_mask);
160 ret |= (indev[i] ^ arpinfo->iniface[i])
161 & arpinfo->iniface_mask[i];
162 }
163 190
164 if (FWINV(ret != 0, ARPT_INV_VIA_IN)) { 191 if (FWINV(ret != 0, ARPT_INV_VIA_IN)) {
165 dprintf("VIA in mismatch (%s vs %s).%s\n", 192 dprintf("VIA in mismatch (%s vs %s).%s\n",
@@ -168,10 +195,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
168 return 0; 195 return 0;
169 } 196 }
170 197
171 for (i = 0, ret = 0; i < IFNAMSIZ; i++) { 198 ret = ifname_compare(outdev, arpinfo->outiface, arpinfo->outiface_mask);
172 ret |= (outdev[i] ^ arpinfo->outiface[i])
173 & arpinfo->outiface_mask[i];
174 }
175 199
176 if (FWINV(ret != 0, ARPT_INV_VIA_OUT)) { 200 if (FWINV(ret != 0, ARPT_INV_VIA_OUT)) {
177 dprintf("VIA out mismatch (%s vs %s).%s\n", 201 dprintf("VIA out mismatch (%s vs %s).%s\n",
@@ -221,7 +245,7 @@ unsigned int arpt_do_table(struct sk_buff *skb,
221 const struct net_device *out, 245 const struct net_device *out,
222 struct xt_table *table) 246 struct xt_table *table)
223{ 247{
224 static const char nulldevname[IFNAMSIZ]; 248 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
225 unsigned int verdict = NF_DROP; 249 unsigned int verdict = NF_DROP;
226 const struct arphdr *arp; 250 const struct arphdr *arp;
227 bool hotdrop = false; 251 bool hotdrop = false;