diff options
author | Eric Dumazet <dada1@cosmosbay.com> | 2009-02-18 11:47:50 -0500 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2009-02-18 11:47:50 -0500 |
commit | ddc214c43a923e89741e04da2f10e3037a64e222 (patch) | |
tree | 106bd4feb8edb426683c9c46c50095f71ef8da0d | |
parent | 55df4ac0c927c7f1f84e6d75532f0ca45d391e64 (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>
-rw-r--r-- | net/ipv4/netfilter/arp_tables.c | 44 |
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 | */ | ||
80 | static 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. */ |
77 | static inline int arp_packet_match(const struct arphdr *arphdr, | 107 | static 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; |