diff options
author | Patrick McHardy <kaber@trash.net> | 2007-02-12 14:13:43 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2007-02-12 14:13:43 -0500 |
commit | c0e912d7ed8999f87fa7f084928aac1266e251f3 (patch) | |
tree | ec48a83001871b4e0db78ee9eab520a1fbb02e14 /net | |
parent | abbaccda4c364815b8b1a82c45a94f60760e13e1 (diff) |
[NETFILTER]: nf_conntrack: fix invalid conntrack statistics RCU assumption
NF_CT_STAT_INC assumes rcu_read_lock in nf_hook_slow disables
preemption as well, making it legal to use __get_cpu_var without
disabling preemption manually. The assumption is not correct anymore
with preemptable RCU, additionally we need to protect against softirqs
when not holding nf_conntrack_lock.
Add NF_CT_STAT_INC_ATOMIC macro, which disables local softirqs,
and use where necessary.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | 4 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_core.c | 14 |
2 files changed, 9 insertions, 9 deletions
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index a2353edf4ebc..4b7be4bb4d03 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |||
@@ -154,8 +154,8 @@ ipv6_prepare(struct sk_buff **pskb, unsigned int hooknum, unsigned int *dataoff, | |||
154 | */ | 154 | */ |
155 | if ((protoff < 0) || (protoff > (*pskb)->len)) { | 155 | if ((protoff < 0) || (protoff > (*pskb)->len)) { |
156 | DEBUGP("ip6_conntrack_core: can't find proto in pkt\n"); | 156 | DEBUGP("ip6_conntrack_core: can't find proto in pkt\n"); |
157 | NF_CT_STAT_INC(error); | 157 | NF_CT_STAT_INC_ATOMIC(error); |
158 | NF_CT_STAT_INC(invalid); | 158 | NF_CT_STAT_INC_ATOMIC(invalid); |
159 | return -NF_ACCEPT; | 159 | return -NF_ACCEPT; |
160 | } | 160 | } |
161 | 161 | ||
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 3deeb900263b..d59640e2377b 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c | |||
@@ -563,7 +563,7 @@ static int early_drop(struct list_head *chain) | |||
563 | if (del_timer(&ct->timeout)) { | 563 | if (del_timer(&ct->timeout)) { |
564 | death_by_timeout((unsigned long)ct); | 564 | death_by_timeout((unsigned long)ct); |
565 | dropped = 1; | 565 | dropped = 1; |
566 | NF_CT_STAT_INC(early_drop); | 566 | NF_CT_STAT_INC_ATOMIC(early_drop); |
567 | } | 567 | } |
568 | nf_ct_put(ct); | 568 | nf_ct_put(ct); |
569 | return dropped; | 569 | return dropped; |
@@ -821,7 +821,7 @@ nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff **pskb) | |||
821 | 821 | ||
822 | /* Previously seen (loopback or untracked)? Ignore. */ | 822 | /* Previously seen (loopback or untracked)? Ignore. */ |
823 | if ((*pskb)->nfct) { | 823 | if ((*pskb)->nfct) { |
824 | NF_CT_STAT_INC(ignore); | 824 | NF_CT_STAT_INC_ATOMIC(ignore); |
825 | return NF_ACCEPT; | 825 | return NF_ACCEPT; |
826 | } | 826 | } |
827 | 827 | ||
@@ -840,8 +840,8 @@ nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff **pskb) | |||
840 | * core what to do with the packet. */ | 840 | * core what to do with the packet. */ |
841 | if (l4proto->error != NULL && | 841 | if (l4proto->error != NULL && |
842 | (ret = l4proto->error(*pskb, dataoff, &ctinfo, pf, hooknum)) <= 0) { | 842 | (ret = l4proto->error(*pskb, dataoff, &ctinfo, pf, hooknum)) <= 0) { |
843 | NF_CT_STAT_INC(error); | 843 | NF_CT_STAT_INC_ATOMIC(error); |
844 | NF_CT_STAT_INC(invalid); | 844 | NF_CT_STAT_INC_ATOMIC(invalid); |
845 | return -ret; | 845 | return -ret; |
846 | } | 846 | } |
847 | 847 | ||
@@ -849,13 +849,13 @@ nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff **pskb) | |||
849 | &set_reply, &ctinfo); | 849 | &set_reply, &ctinfo); |
850 | if (!ct) { | 850 | if (!ct) { |
851 | /* Not valid part of a connection */ | 851 | /* Not valid part of a connection */ |
852 | NF_CT_STAT_INC(invalid); | 852 | NF_CT_STAT_INC_ATOMIC(invalid); |
853 | return NF_ACCEPT; | 853 | return NF_ACCEPT; |
854 | } | 854 | } |
855 | 855 | ||
856 | if (IS_ERR(ct)) { | 856 | if (IS_ERR(ct)) { |
857 | /* Too stressed to deal. */ | 857 | /* Too stressed to deal. */ |
858 | NF_CT_STAT_INC(drop); | 858 | NF_CT_STAT_INC_ATOMIC(drop); |
859 | return NF_DROP; | 859 | return NF_DROP; |
860 | } | 860 | } |
861 | 861 | ||
@@ -868,7 +868,7 @@ nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff **pskb) | |||
868 | DEBUGP("nf_conntrack_in: Can't track with proto module\n"); | 868 | DEBUGP("nf_conntrack_in: Can't track with proto module\n"); |
869 | nf_conntrack_put((*pskb)->nfct); | 869 | nf_conntrack_put((*pskb)->nfct); |
870 | (*pskb)->nfct = NULL; | 870 | (*pskb)->nfct = NULL; |
871 | NF_CT_STAT_INC(invalid); | 871 | NF_CT_STAT_INC_ATOMIC(invalid); |
872 | return -ret; | 872 | return -ret; |
873 | } | 873 | } |
874 | 874 | ||