diff options
author | Eric Dumazet <dada1@cosmosbay.com> | 2009-02-20 05:03:33 -0500 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2009-02-20 05:03:33 -0500 |
commit | 08361aa807ae5e5007cd226ca9e34287512de737 (patch) | |
tree | 2b0a51af98e4df407f7bce90ca8cd1a065691b1c /net/ipv4 | |
parent | 268cb38e1802db560c73167e643f14a3dcb4b07c (diff) |
netfilter: ip_tables: unfold two critical loops in ip_packet_match()
While doing oprofile tests I noticed two loops are not properly unrolled by gcc
Using a hand coded unrolled loop provides nice speedup : ipt_do_table
credited of 2.52 % of cpu instead of 3.29 % in tbench.
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/ip_tables.c | 33 |
1 files changed, 21 insertions, 12 deletions
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 08cde5bd70a5..e5294aec967d 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c | |||
@@ -74,6 +74,25 @@ do { \ | |||
74 | 74 | ||
75 | Hence the start of any table is given by get_table() below. */ | 75 | Hence the start of any table is given by get_table() below. */ |
76 | 76 | ||
77 | static unsigned long ifname_compare(const char *_a, const char *_b, | ||
78 | const unsigned char *_mask) | ||
79 | { | ||
80 | const unsigned long *a = (const unsigned long *)_a; | ||
81 | const unsigned long *b = (const unsigned long *)_b; | ||
82 | const unsigned long *mask = (const unsigned long *)_mask; | ||
83 | unsigned long ret; | ||
84 | |||
85 | ret = (a[0] ^ b[0]) & mask[0]; | ||
86 | if (IFNAMSIZ > sizeof(unsigned long)) | ||
87 | ret |= (a[1] ^ b[1]) & mask[1]; | ||
88 | if (IFNAMSIZ > 2 * sizeof(unsigned long)) | ||
89 | ret |= (a[2] ^ b[2]) & mask[2]; | ||
90 | if (IFNAMSIZ > 3 * sizeof(unsigned long)) | ||
91 | ret |= (a[3] ^ b[3]) & mask[3]; | ||
92 | BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long)); | ||
93 | return ret; | ||
94 | } | ||
95 | |||
77 | /* Returns whether matches rule or not. */ | 96 | /* Returns whether matches rule or not. */ |
78 | /* Performance critical - called for every packet */ | 97 | /* Performance critical - called for every packet */ |
79 | static inline bool | 98 | static inline bool |
@@ -83,7 +102,6 @@ ip_packet_match(const struct iphdr *ip, | |||
83 | const struct ipt_ip *ipinfo, | 102 | const struct ipt_ip *ipinfo, |
84 | int isfrag) | 103 | int isfrag) |
85 | { | 104 | { |
86 | size_t i; | ||
87 | unsigned long ret; | 105 | unsigned long ret; |
88 | 106 | ||
89 | #define FWINV(bool, invflg) ((bool) ^ !!(ipinfo->invflags & (invflg))) | 107 | #define FWINV(bool, invflg) ((bool) ^ !!(ipinfo->invflags & (invflg))) |
@@ -103,12 +121,7 @@ ip_packet_match(const struct iphdr *ip, | |||
103 | return false; | 121 | return false; |
104 | } | 122 | } |
105 | 123 | ||
106 | /* Look for ifname matches; this should unroll nicely. */ | 124 | ret = ifname_compare(indev, ipinfo->iniface, ipinfo->iniface_mask); |
107 | for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) { | ||
108 | ret |= (((const unsigned long *)indev)[i] | ||
109 | ^ ((const unsigned long *)ipinfo->iniface)[i]) | ||
110 | & ((const unsigned long *)ipinfo->iniface_mask)[i]; | ||
111 | } | ||
112 | 125 | ||
113 | if (FWINV(ret != 0, IPT_INV_VIA_IN)) { | 126 | if (FWINV(ret != 0, IPT_INV_VIA_IN)) { |
114 | dprintf("VIA in mismatch (%s vs %s).%s\n", | 127 | dprintf("VIA in mismatch (%s vs %s).%s\n", |
@@ -117,11 +130,7 @@ ip_packet_match(const struct iphdr *ip, | |||
117 | return false; | 130 | return false; |
118 | } | 131 | } |
119 | 132 | ||
120 | for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) { | 133 | ret = ifname_compare(outdev, ipinfo->outiface, ipinfo->outiface_mask); |
121 | ret |= (((const unsigned long *)outdev)[i] | ||
122 | ^ ((const unsigned long *)ipinfo->outiface)[i]) | ||
123 | & ((const unsigned long *)ipinfo->outiface_mask)[i]; | ||
124 | } | ||
125 | 134 | ||
126 | if (FWINV(ret != 0, IPT_INV_VIA_OUT)) { | 135 | if (FWINV(ret != 0, IPT_INV_VIA_OUT)) { |
127 | dprintf("VIA out mismatch (%s vs %s).%s\n", | 136 | dprintf("VIA out mismatch (%s vs %s).%s\n", |