diff options
| author | Eric Dumazet <eric.dumazet@gmail.com> | 2010-06-08 10:09:52 -0400 |
|---|---|---|
| committer | Patrick McHardy <kaber@trash.net> | 2010-06-08 10:09:52 -0400 |
| commit | 5bfddbd46a95c978f4d3c992339cbdf4f4b790a3 (patch) | |
| tree | 9291ba4e1e3c7bf7ae8b5dfa8271e7127a6a6958 | |
| parent | 339bb99e4a8ba1f8960eed21d50be808b35ad22a (diff) | |
netfilter: nf_conntrack: IPS_UNTRACKED bit
NOTRACK makes all cpus share a cache line on nf_conntrack_untracked
twice per packet. This is bad for performance.
__read_mostly annotation is also a bad choice.
This patch introduces IPS_UNTRACKED bit so that we can use later a
per_cpu untrack structure more easily.
A new helper, nf_ct_untracked_get() returns a pointer to
nf_conntrack_untracked.
Another one, nf_ct_untracked_status_or() is used by nf_nat_init() to add
IPS_NAT_DONE_MASK bits to untracked status.
nf_ct_is_untracked() prototype is changed to work on a nf_conn pointer.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Patrick McHardy <kaber@trash.net>
| -rw-r--r-- | include/linux/netfilter/nf_conntrack_common.h | 4 | ||||
| -rw-r--r-- | include/net/netfilter/nf_conntrack.h | 12 | ||||
| -rw-r--r-- | include/net/netfilter/nf_conntrack_core.h | 2 | ||||
| -rw-r--r-- | net/ipv4/netfilter/nf_nat_core.c | 2 | ||||
| -rw-r--r-- | net/ipv4/netfilter/nf_nat_standalone.c | 2 | ||||
| -rw-r--r-- | net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | 2 | ||||
| -rw-r--r-- | net/netfilter/nf_conntrack_core.c | 11 | ||||
| -rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 2 | ||||
| -rw-r--r-- | net/netfilter/xt_CT.c | 4 | ||||
| -rw-r--r-- | net/netfilter/xt_NOTRACK.c | 2 | ||||
| -rw-r--r-- | net/netfilter/xt_TEE.c | 4 | ||||
| -rw-r--r-- | net/netfilter/xt_cluster.c | 2 | ||||
| -rw-r--r-- | net/netfilter/xt_conntrack.c | 11 | ||||
| -rw-r--r-- | net/netfilter/xt_socket.c | 2 | ||||
| -rw-r--r-- | net/netfilter/xt_state.c | 14 |
15 files changed, 47 insertions, 29 deletions
diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h index 14e6d32002c4..1afd18c855ec 100644 --- a/include/linux/netfilter/nf_conntrack_common.h +++ b/include/linux/netfilter/nf_conntrack_common.h | |||
| @@ -76,6 +76,10 @@ enum ip_conntrack_status { | |||
| 76 | /* Conntrack is a template */ | 76 | /* Conntrack is a template */ |
| 77 | IPS_TEMPLATE_BIT = 11, | 77 | IPS_TEMPLATE_BIT = 11, |
| 78 | IPS_TEMPLATE = (1 << IPS_TEMPLATE_BIT), | 78 | IPS_TEMPLATE = (1 << IPS_TEMPLATE_BIT), |
| 79 | |||
| 80 | /* Conntrack is a fake untracked entry */ | ||
| 81 | IPS_UNTRACKED_BIT = 12, | ||
| 82 | IPS_UNTRACKED = (1 << IPS_UNTRACKED_BIT), | ||
| 79 | }; | 83 | }; |
| 80 | 84 | ||
| 81 | /* Connection tracking event types */ | 85 | /* Connection tracking event types */ |
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index bde095f7e845..3bc38c70bbbe 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h | |||
| @@ -261,7 +261,13 @@ extern s16 (*nf_ct_nat_offset)(const struct nf_conn *ct, | |||
| 261 | u32 seq); | 261 | u32 seq); |
| 262 | 262 | ||
| 263 | /* Fake conntrack entry for untracked connections */ | 263 | /* Fake conntrack entry for untracked connections */ |
| 264 | extern struct nf_conn nf_conntrack_untracked; | 264 | static inline struct nf_conn *nf_ct_untracked_get(void) |
| 265 | { | ||
| 266 | extern struct nf_conn nf_conntrack_untracked; | ||
| 267 | |||
| 268 | return &nf_conntrack_untracked; | ||
| 269 | } | ||
| 270 | extern void nf_ct_untracked_status_or(unsigned long bits); | ||
| 265 | 271 | ||
| 266 | /* Iterate over all conntracks: if iter returns true, it's deleted. */ | 272 | /* Iterate over all conntracks: if iter returns true, it's deleted. */ |
| 267 | extern void | 273 | extern void |
| @@ -289,9 +295,9 @@ static inline int nf_ct_is_dying(struct nf_conn *ct) | |||
| 289 | return test_bit(IPS_DYING_BIT, &ct->status); | 295 | return test_bit(IPS_DYING_BIT, &ct->status); |
| 290 | } | 296 | } |
| 291 | 297 | ||
| 292 | static inline int nf_ct_is_untracked(const struct sk_buff *skb) | 298 | static inline int nf_ct_is_untracked(const struct nf_conn *ct) |
| 293 | { | 299 | { |
| 294 | return (skb->nfct == &nf_conntrack_untracked.ct_general); | 300 | return test_bit(IPS_UNTRACKED_BIT, &ct->status); |
| 295 | } | 301 | } |
| 296 | 302 | ||
| 297 | extern int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp); | 303 | extern int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp); |
diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h index 3d7524fba194..aced085132e7 100644 --- a/include/net/netfilter/nf_conntrack_core.h +++ b/include/net/netfilter/nf_conntrack_core.h | |||
| @@ -60,7 +60,7 @@ static inline int nf_conntrack_confirm(struct sk_buff *skb) | |||
| 60 | struct nf_conn *ct = (struct nf_conn *)skb->nfct; | 60 | struct nf_conn *ct = (struct nf_conn *)skb->nfct; |
| 61 | int ret = NF_ACCEPT; | 61 | int ret = NF_ACCEPT; |
| 62 | 62 | ||
| 63 | if (ct && ct != &nf_conntrack_untracked) { | 63 | if (ct && !nf_ct_is_untracked(ct)) { |
| 64 | if (!nf_ct_is_confirmed(ct)) | 64 | if (!nf_ct_is_confirmed(ct)) |
| 65 | ret = __nf_conntrack_confirm(skb); | 65 | ret = __nf_conntrack_confirm(skb); |
| 66 | if (likely(ret == NF_ACCEPT)) | 66 | if (likely(ret == NF_ACCEPT)) |
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c index 4f8bddb760c9..c7719b283ada 100644 --- a/net/ipv4/netfilter/nf_nat_core.c +++ b/net/ipv4/netfilter/nf_nat_core.c | |||
| @@ -742,7 +742,7 @@ static int __init nf_nat_init(void) | |||
| 742 | spin_unlock_bh(&nf_nat_lock); | 742 | spin_unlock_bh(&nf_nat_lock); |
| 743 | 743 | ||
| 744 | /* Initialize fake conntrack so that NAT will skip it */ | 744 | /* Initialize fake conntrack so that NAT will skip it */ |
| 745 | nf_conntrack_untracked.status |= IPS_NAT_DONE_MASK; | 745 | nf_ct_untracked_status_or(IPS_NAT_DONE_MASK); |
| 746 | 746 | ||
| 747 | l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET); | 747 | l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET); |
| 748 | 748 | ||
diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c index beb25819c9c9..6723c682250d 100644 --- a/net/ipv4/netfilter/nf_nat_standalone.c +++ b/net/ipv4/netfilter/nf_nat_standalone.c | |||
| @@ -98,7 +98,7 @@ nf_nat_fn(unsigned int hooknum, | |||
| 98 | return NF_ACCEPT; | 98 | return NF_ACCEPT; |
| 99 | 99 | ||
| 100 | /* Don't try to NAT if this packet is not conntracked */ | 100 | /* Don't try to NAT if this packet is not conntracked */ |
| 101 | if (ct == &nf_conntrack_untracked) | 101 | if (nf_ct_is_untracked(ct)) |
| 102 | return NF_ACCEPT; | 102 | return NF_ACCEPT; |
| 103 | 103 | ||
| 104 | nat = nfct_nat(ct); | 104 | nat = nfct_nat(ct); |
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index 9be81776415e..1df3c8b6bf47 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | |||
| @@ -208,7 +208,7 @@ icmpv6_error(struct net *net, struct nf_conn *tmpl, | |||
| 208 | type = icmp6h->icmp6_type - 130; | 208 | type = icmp6h->icmp6_type - 130; |
| 209 | if (type >= 0 && type < sizeof(noct_valid_new) && | 209 | if (type >= 0 && type < sizeof(noct_valid_new) && |
| 210 | noct_valid_new[type]) { | 210 | noct_valid_new[type]) { |
| 211 | skb->nfct = &nf_conntrack_untracked.ct_general; | 211 | skb->nfct = &nf_ct_untracked_get()->ct_general; |
| 212 | skb->nfctinfo = IP_CT_NEW; | 212 | skb->nfctinfo = IP_CT_NEW; |
| 213 | nf_conntrack_get(skb->nfct); | 213 | nf_conntrack_get(skb->nfct); |
| 214 | return NF_ACCEPT; | 214 | return NF_ACCEPT; |
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index eeeb8bc73982..6c1da212380d 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c | |||
| @@ -62,7 +62,7 @@ EXPORT_SYMBOL_GPL(nf_conntrack_htable_size); | |||
| 62 | unsigned int nf_conntrack_max __read_mostly; | 62 | unsigned int nf_conntrack_max __read_mostly; |
| 63 | EXPORT_SYMBOL_GPL(nf_conntrack_max); | 63 | EXPORT_SYMBOL_GPL(nf_conntrack_max); |
| 64 | 64 | ||
| 65 | struct nf_conn nf_conntrack_untracked __read_mostly; | 65 | struct nf_conn nf_conntrack_untracked; |
| 66 | EXPORT_SYMBOL_GPL(nf_conntrack_untracked); | 66 | EXPORT_SYMBOL_GPL(nf_conntrack_untracked); |
| 67 | 67 | ||
| 68 | static int nf_conntrack_hash_rnd_initted; | 68 | static int nf_conntrack_hash_rnd_initted; |
| @@ -1321,6 +1321,12 @@ EXPORT_SYMBOL_GPL(nf_conntrack_set_hashsize); | |||
| 1321 | module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint, | 1321 | module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint, |
| 1322 | &nf_conntrack_htable_size, 0600); | 1322 | &nf_conntrack_htable_size, 0600); |
| 1323 | 1323 | ||
| 1324 | void nf_ct_untracked_status_or(unsigned long bits) | ||
| 1325 | { | ||
| 1326 | nf_conntrack_untracked.status |= bits; | ||
| 1327 | } | ||
| 1328 | EXPORT_SYMBOL_GPL(nf_ct_untracked_status_or); | ||
| 1329 | |||
| 1324 | static int nf_conntrack_init_init_net(void) | 1330 | static int nf_conntrack_init_init_net(void) |
| 1325 | { | 1331 | { |
| 1326 | int max_factor = 8; | 1332 | int max_factor = 8; |
| @@ -1368,8 +1374,7 @@ static int nf_conntrack_init_init_net(void) | |||
| 1368 | #endif | 1374 | #endif |
| 1369 | atomic_set(&nf_conntrack_untracked.ct_general.use, 1); | 1375 | atomic_set(&nf_conntrack_untracked.ct_general.use, 1); |
| 1370 | /* - and look it like as a confirmed connection */ | 1376 | /* - and look it like as a confirmed connection */ |
| 1371 | set_bit(IPS_CONFIRMED_BIT, &nf_conntrack_untracked.status); | 1377 | nf_ct_untracked_status_or(IPS_CONFIRMED | IPS_UNTRACKED); |
| 1372 | |||
| 1373 | return 0; | 1378 | return 0; |
| 1374 | 1379 | ||
| 1375 | #ifdef CONFIG_NF_CONNTRACK_ZONES | 1380 | #ifdef CONFIG_NF_CONNTRACK_ZONES |
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index c42ff6aa441d..5bae1cd15eea 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
| @@ -480,7 +480,7 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item) | |||
| 480 | int err; | 480 | int err; |
| 481 | 481 | ||
| 482 | /* ignore our fake conntrack entry */ | 482 | /* ignore our fake conntrack entry */ |
| 483 | if (ct == &nf_conntrack_untracked) | 483 | if (nf_ct_is_untracked(ct)) |
| 484 | return 0; | 484 | return 0; |
| 485 | 485 | ||
| 486 | if (events & (1 << IPCT_DESTROY)) { | 486 | if (events & (1 << IPCT_DESTROY)) { |
diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c index 562bf3266e04..0cb6053f02fd 100644 --- a/net/netfilter/xt_CT.c +++ b/net/netfilter/xt_CT.c | |||
| @@ -67,7 +67,7 @@ static int xt_ct_tg_check(const struct xt_tgchk_param *par) | |||
| 67 | return -EINVAL; | 67 | return -EINVAL; |
| 68 | 68 | ||
| 69 | if (info->flags & XT_CT_NOTRACK) { | 69 | if (info->flags & XT_CT_NOTRACK) { |
| 70 | ct = &nf_conntrack_untracked; | 70 | ct = nf_ct_untracked_get(); |
| 71 | atomic_inc(&ct->ct_general.use); | 71 | atomic_inc(&ct->ct_general.use); |
| 72 | goto out; | 72 | goto out; |
| 73 | } | 73 | } |
| @@ -132,7 +132,7 @@ static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par) | |||
| 132 | struct nf_conn *ct = info->ct; | 132 | struct nf_conn *ct = info->ct; |
| 133 | struct nf_conn_help *help; | 133 | struct nf_conn_help *help; |
| 134 | 134 | ||
| 135 | if (ct != &nf_conntrack_untracked) { | 135 | if (!nf_ct_is_untracked(ct)) { |
| 136 | help = nfct_help(ct); | 136 | help = nfct_help(ct); |
| 137 | if (help) | 137 | if (help) |
| 138 | module_put(help->helper->me); | 138 | module_put(help->helper->me); |
diff --git a/net/netfilter/xt_NOTRACK.c b/net/netfilter/xt_NOTRACK.c index 512b9123252f..9d782181b6c8 100644 --- a/net/netfilter/xt_NOTRACK.c +++ b/net/netfilter/xt_NOTRACK.c | |||
| @@ -23,7 +23,7 @@ notrack_tg(struct sk_buff *skb, const struct xt_action_param *par) | |||
| 23 | If there is a real ct entry correspondig to this packet, | 23 | If there is a real ct entry correspondig to this packet, |
| 24 | it'll hang aroun till timing out. We don't deal with it | 24 | it'll hang aroun till timing out. We don't deal with it |
| 25 | for performance reasons. JK */ | 25 | for performance reasons. JK */ |
| 26 | skb->nfct = &nf_conntrack_untracked.ct_general; | 26 | skb->nfct = &nf_ct_untracked_get()->ct_general; |
| 27 | skb->nfctinfo = IP_CT_NEW; | 27 | skb->nfctinfo = IP_CT_NEW; |
| 28 | nf_conntrack_get(skb->nfct); | 28 | nf_conntrack_get(skb->nfct); |
| 29 | 29 | ||
diff --git a/net/netfilter/xt_TEE.c b/net/netfilter/xt_TEE.c index 859d9fd429c8..7a118267c4c4 100644 --- a/net/netfilter/xt_TEE.c +++ b/net/netfilter/xt_TEE.c | |||
| @@ -104,7 +104,7 @@ tee_tg4(struct sk_buff *skb, const struct xt_action_param *par) | |||
| 104 | #ifdef WITH_CONNTRACK | 104 | #ifdef WITH_CONNTRACK |
| 105 | /* Avoid counting cloned packets towards the original connection. */ | 105 | /* Avoid counting cloned packets towards the original connection. */ |
| 106 | nf_conntrack_put(skb->nfct); | 106 | nf_conntrack_put(skb->nfct); |
| 107 | skb->nfct = &nf_conntrack_untracked.ct_general; | 107 | skb->nfct = &nf_ct_untracked_get()->ct_general; |
| 108 | skb->nfctinfo = IP_CT_NEW; | 108 | skb->nfctinfo = IP_CT_NEW; |
| 109 | nf_conntrack_get(skb->nfct); | 109 | nf_conntrack_get(skb->nfct); |
| 110 | #endif | 110 | #endif |
| @@ -177,7 +177,7 @@ tee_tg6(struct sk_buff *skb, const struct xt_action_param *par) | |||
| 177 | 177 | ||
| 178 | #ifdef WITH_CONNTRACK | 178 | #ifdef WITH_CONNTRACK |
| 179 | nf_conntrack_put(skb->nfct); | 179 | nf_conntrack_put(skb->nfct); |
| 180 | skb->nfct = &nf_conntrack_untracked.ct_general; | 180 | skb->nfct = &nf_ct_untracked_get()->ct_general; |
| 181 | skb->nfctinfo = IP_CT_NEW; | 181 | skb->nfctinfo = IP_CT_NEW; |
| 182 | nf_conntrack_get(skb->nfct); | 182 | nf_conntrack_get(skb->nfct); |
| 183 | #endif | 183 | #endif |
diff --git a/net/netfilter/xt_cluster.c b/net/netfilter/xt_cluster.c index 30b95a1c1c89..f4af1bfafb1c 100644 --- a/net/netfilter/xt_cluster.c +++ b/net/netfilter/xt_cluster.c | |||
| @@ -120,7 +120,7 @@ xt_cluster_mt(const struct sk_buff *skb, struct xt_action_param *par) | |||
| 120 | if (ct == NULL) | 120 | if (ct == NULL) |
| 121 | return false; | 121 | return false; |
| 122 | 122 | ||
| 123 | if (ct == &nf_conntrack_untracked) | 123 | if (nf_ct_is_untracked(ct)) |
| 124 | return false; | 124 | return false; |
| 125 | 125 | ||
| 126 | if (ct->master) | 126 | if (ct->master) |
diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c index 39681f10291c..e536710ad916 100644 --- a/net/netfilter/xt_conntrack.c +++ b/net/netfilter/xt_conntrack.c | |||
| @@ -123,11 +123,12 @@ conntrack_mt(const struct sk_buff *skb, struct xt_action_param *par, | |||
| 123 | 123 | ||
| 124 | ct = nf_ct_get(skb, &ctinfo); | 124 | ct = nf_ct_get(skb, &ctinfo); |
| 125 | 125 | ||
| 126 | if (ct == &nf_conntrack_untracked) | 126 | if (ct) { |
| 127 | statebit = XT_CONNTRACK_STATE_UNTRACKED; | 127 | if (nf_ct_is_untracked(ct)) |
| 128 | else if (ct != NULL) | 128 | statebit = XT_CONNTRACK_STATE_UNTRACKED; |
| 129 | statebit = XT_CONNTRACK_STATE_BIT(ctinfo); | 129 | else |
| 130 | else | 130 | statebit = XT_CONNTRACK_STATE_BIT(ctinfo); |
| 131 | } else | ||
| 131 | statebit = XT_CONNTRACK_STATE_INVALID; | 132 | statebit = XT_CONNTRACK_STATE_INVALID; |
| 132 | 133 | ||
| 133 | if (info->match_flags & XT_CONNTRACK_STATE) { | 134 | if (info->match_flags & XT_CONNTRACK_STATE) { |
diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c index 3d54c236a1ba..1ca89908cbad 100644 --- a/net/netfilter/xt_socket.c +++ b/net/netfilter/xt_socket.c | |||
| @@ -127,7 +127,7 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par, | |||
| 127 | * reply packet of an established SNAT-ted connection. */ | 127 | * reply packet of an established SNAT-ted connection. */ |
| 128 | 128 | ||
| 129 | ct = nf_ct_get(skb, &ctinfo); | 129 | ct = nf_ct_get(skb, &ctinfo); |
| 130 | if (ct && (ct != &nf_conntrack_untracked) && | 130 | if (ct && !nf_ct_is_untracked(ct) && |
| 131 | ((iph->protocol != IPPROTO_ICMP && | 131 | ((iph->protocol != IPPROTO_ICMP && |
| 132 | ctinfo == IP_CT_IS_REPLY + IP_CT_ESTABLISHED) || | 132 | ctinfo == IP_CT_IS_REPLY + IP_CT_ESTABLISHED) || |
| 133 | (iph->protocol == IPPROTO_ICMP && | 133 | (iph->protocol == IPPROTO_ICMP && |
diff --git a/net/netfilter/xt_state.c b/net/netfilter/xt_state.c index e12e053d3782..a507922d80cd 100644 --- a/net/netfilter/xt_state.c +++ b/net/netfilter/xt_state.c | |||
| @@ -26,14 +26,16 @@ state_mt(const struct sk_buff *skb, struct xt_action_param *par) | |||
| 26 | const struct xt_state_info *sinfo = par->matchinfo; | 26 | const struct xt_state_info *sinfo = par->matchinfo; |
| 27 | enum ip_conntrack_info ctinfo; | 27 | enum ip_conntrack_info ctinfo; |
| 28 | unsigned int statebit; | 28 | unsigned int statebit; |
| 29 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | ||
| 29 | 30 | ||
| 30 | if (nf_ct_is_untracked(skb)) | 31 | if (!ct) |
| 31 | statebit = XT_STATE_UNTRACKED; | ||
| 32 | else if (!nf_ct_get(skb, &ctinfo)) | ||
| 33 | statebit = XT_STATE_INVALID; | 32 | statebit = XT_STATE_INVALID; |
| 34 | else | 33 | else { |
| 35 | statebit = XT_STATE_BIT(ctinfo); | 34 | if (nf_ct_is_untracked(ct)) |
| 36 | 35 | statebit = XT_STATE_UNTRACKED; | |
| 36 | else | ||
| 37 | statebit = XT_STATE_BIT(ctinfo); | ||
| 38 | } | ||
| 37 | return (sinfo->statemask & statebit); | 39 | return (sinfo->statemask & statebit); |
| 38 | } | 40 | } |
| 39 | 41 | ||
