diff options
author | Patrick McHardy <kaber@trash.net> | 2007-02-12 14:12:40 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2007-02-12 14:12:40 -0500 |
commit | 642d628b2c92e5283bbd3c849c7099c64ab68856 (patch) | |
tree | 349ed55d878ce0a6ea8ac207d15a344d3d302aa3 /net | |
parent | e22a05486913ccb959281cd6370593bd8e197fa9 (diff) |
[NETFILTER]: ip_conntrack: properly use RCU API for ip_ct_protos array
Replace preempt_{enable,disable} based RCU by proper use of the
RCU API and add missing rcu_read_lock/rcu_read_unlock calls in
all paths not obviously only used within packet process context
(nfnetlink_conntrack).
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/ipv4/netfilter/ip_conntrack_core.c | 26 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_conntrack_standalone.c | 9 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_nat_core.c | 6 |
3 files changed, 26 insertions, 15 deletions
diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index 508e6007a191..e7de6d31b853 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c | |||
@@ -318,9 +318,11 @@ destroy_conntrack(struct nf_conntrack *nfct) | |||
318 | /* To make sure we don't get any weird locking issues here: | 318 | /* To make sure we don't get any weird locking issues here: |
319 | * destroy_conntrack() MUST NOT be called with a write lock | 319 | * destroy_conntrack() MUST NOT be called with a write lock |
320 | * to ip_conntrack_lock!!! -HW */ | 320 | * to ip_conntrack_lock!!! -HW */ |
321 | rcu_read_lock(); | ||
321 | proto = __ip_conntrack_proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum); | 322 | proto = __ip_conntrack_proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum); |
322 | if (proto && proto->destroy) | 323 | if (proto && proto->destroy) |
323 | proto->destroy(ct); | 324 | proto->destroy(ct); |
325 | rcu_read_unlock(); | ||
324 | 326 | ||
325 | if (ip_conntrack_destroyed) | 327 | if (ip_conntrack_destroyed) |
326 | ip_conntrack_destroyed(ct); | 328 | ip_conntrack_destroyed(ct); |
@@ -595,13 +597,13 @@ ip_conntrack_proto_find_get(u_int8_t protocol) | |||
595 | { | 597 | { |
596 | struct ip_conntrack_protocol *p; | 598 | struct ip_conntrack_protocol *p; |
597 | 599 | ||
598 | preempt_disable(); | 600 | rcu_read_lock(); |
599 | p = __ip_conntrack_proto_find(protocol); | 601 | p = __ip_conntrack_proto_find(protocol); |
600 | if (p) { | 602 | if (p) { |
601 | if (!try_module_get(p->me)) | 603 | if (!try_module_get(p->me)) |
602 | p = &ip_conntrack_generic_protocol; | 604 | p = &ip_conntrack_generic_protocol; |
603 | } | 605 | } |
604 | preempt_enable(); | 606 | rcu_read_unlock(); |
605 | 607 | ||
606 | return p; | 608 | return p; |
607 | } | 609 | } |
@@ -830,6 +832,7 @@ unsigned int ip_conntrack_in(unsigned int hooknum, | |||
830 | } | 832 | } |
831 | #endif | 833 | #endif |
832 | 834 | ||
835 | /* rcu_read_lock()ed by nf_hook_slow */ | ||
833 | proto = __ip_conntrack_proto_find((*pskb)->nh.iph->protocol); | 836 | proto = __ip_conntrack_proto_find((*pskb)->nh.iph->protocol); |
834 | 837 | ||
835 | /* It may be an special packet, error, unclean... | 838 | /* It may be an special packet, error, unclean... |
@@ -875,8 +878,15 @@ unsigned int ip_conntrack_in(unsigned int hooknum, | |||
875 | int invert_tuplepr(struct ip_conntrack_tuple *inverse, | 878 | int invert_tuplepr(struct ip_conntrack_tuple *inverse, |
876 | const struct ip_conntrack_tuple *orig) | 879 | const struct ip_conntrack_tuple *orig) |
877 | { | 880 | { |
878 | return ip_ct_invert_tuple(inverse, orig, | 881 | struct ip_conntrack_protocol *proto; |
879 | __ip_conntrack_proto_find(orig->dst.protonum)); | 882 | int ret; |
883 | |||
884 | rcu_read_lock(); | ||
885 | proto = __ip_conntrack_proto_find(orig->dst.protonum); | ||
886 | ret = ip_ct_invert_tuple(inverse, orig, proto); | ||
887 | rcu_read_unlock(); | ||
888 | |||
889 | return ret; | ||
880 | } | 890 | } |
881 | 891 | ||
882 | /* Would two expected things clash? */ | 892 | /* Would two expected things clash? */ |
@@ -1507,11 +1517,11 @@ int __init ip_conntrack_init(void) | |||
1507 | /* Don't NEED lock here, but good form anyway. */ | 1517 | /* Don't NEED lock here, but good form anyway. */ |
1508 | write_lock_bh(&ip_conntrack_lock); | 1518 | write_lock_bh(&ip_conntrack_lock); |
1509 | for (i = 0; i < MAX_IP_CT_PROTO; i++) | 1519 | for (i = 0; i < MAX_IP_CT_PROTO; i++) |
1510 | ip_ct_protos[i] = &ip_conntrack_generic_protocol; | 1520 | rcu_assign_pointer(ip_ct_protos[i], &ip_conntrack_generic_protocol); |
1511 | /* Sew in builtin protocols. */ | 1521 | /* Sew in builtin protocols. */ |
1512 | ip_ct_protos[IPPROTO_TCP] = &ip_conntrack_protocol_tcp; | 1522 | rcu_assign_pointer(ip_ct_protos[IPPROTO_TCP], &ip_conntrack_protocol_tcp); |
1513 | ip_ct_protos[IPPROTO_UDP] = &ip_conntrack_protocol_udp; | 1523 | rcu_assign_pointer(ip_ct_protos[IPPROTO_UDP], &ip_conntrack_protocol_udp); |
1514 | ip_ct_protos[IPPROTO_ICMP] = &ip_conntrack_protocol_icmp; | 1524 | rcu_assign_pointer(ip_ct_protos[IPPROTO_ICMP], &ip_conntrack_protocol_icmp); |
1515 | write_unlock_bh(&ip_conntrack_lock); | 1525 | write_unlock_bh(&ip_conntrack_lock); |
1516 | 1526 | ||
1517 | /* For use by ipt_REJECT */ | 1527 | /* For use by ipt_REJECT */ |
diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index 300ccbbbdac9..c7c1ec61b0f5 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c | |||
@@ -796,7 +796,7 @@ int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto) | |||
796 | ret = -EBUSY; | 796 | ret = -EBUSY; |
797 | goto out; | 797 | goto out; |
798 | } | 798 | } |
799 | ip_ct_protos[proto->proto] = proto; | 799 | rcu_assign_pointer(ip_ct_protos[proto->proto], proto); |
800 | out: | 800 | out: |
801 | write_unlock_bh(&ip_conntrack_lock); | 801 | write_unlock_bh(&ip_conntrack_lock); |
802 | return ret; | 802 | return ret; |
@@ -805,11 +805,10 @@ int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto) | |||
805 | void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto) | 805 | void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto) |
806 | { | 806 | { |
807 | write_lock_bh(&ip_conntrack_lock); | 807 | write_lock_bh(&ip_conntrack_lock); |
808 | ip_ct_protos[proto->proto] = &ip_conntrack_generic_protocol; | 808 | rcu_assign_pointer(ip_ct_protos[proto->proto], |
809 | &ip_conntrack_generic_protocol); | ||
809 | write_unlock_bh(&ip_conntrack_lock); | 810 | write_unlock_bh(&ip_conntrack_lock); |
810 | 811 | synchronize_rcu(); | |
811 | /* Somebody could be still looking at the proto in bh. */ | ||
812 | synchronize_net(); | ||
813 | 812 | ||
814 | /* Remove all contrack entries for this protocol */ | 813 | /* Remove all contrack entries for this protocol */ |
815 | ip_ct_iterate_cleanup(kill_proto, &proto->proto); | 814 | ip_ct_iterate_cleanup(kill_proto, &proto->proto); |
diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c index 85ae0cabc8b5..18daabc22069 100644 --- a/net/ipv4/netfilter/ip_nat_core.c +++ b/net/ipv4/netfilter/ip_nat_core.c | |||
@@ -420,6 +420,7 @@ int ip_nat_icmp_reply_translation(struct ip_conntrack *ct, | |||
420 | struct icmphdr icmp; | 420 | struct icmphdr icmp; |
421 | struct iphdr ip; | 421 | struct iphdr ip; |
422 | } *inside; | 422 | } *inside; |
423 | struct ip_conntrack_protocol *proto; | ||
423 | struct ip_conntrack_tuple inner, target; | 424 | struct ip_conntrack_tuple inner, target; |
424 | int hdrlen = (*pskb)->nh.iph->ihl * 4; | 425 | int hdrlen = (*pskb)->nh.iph->ihl * 4; |
425 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | 426 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
@@ -455,10 +456,11 @@ int ip_nat_icmp_reply_translation(struct ip_conntrack *ct, | |||
455 | DEBUGP("icmp_reply_translation: translating error %p manp %u dir %s\n", | 456 | DEBUGP("icmp_reply_translation: translating error %p manp %u dir %s\n", |
456 | *pskb, manip, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY"); | 457 | *pskb, manip, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY"); |
457 | 458 | ||
459 | /* rcu_read_lock()ed by nf_hook_slow */ | ||
460 | proto = __ip_conntrack_proto_find(inside->ip.protocol); | ||
458 | if (!ip_ct_get_tuple(&inside->ip, *pskb, (*pskb)->nh.iph->ihl*4 + | 461 | if (!ip_ct_get_tuple(&inside->ip, *pskb, (*pskb)->nh.iph->ihl*4 + |
459 | sizeof(struct icmphdr) + inside->ip.ihl*4, | 462 | sizeof(struct icmphdr) + inside->ip.ihl*4, |
460 | &inner, | 463 | &inner, proto)) |
461 | __ip_conntrack_proto_find(inside->ip.protocol))) | ||
462 | return 0; | 464 | return 0; |
463 | 465 | ||
464 | /* Change inner back to look like incoming packet. We do the | 466 | /* Change inner back to look like incoming packet. We do the |