diff options
| -rw-r--r-- | net/ipv6/sit.c | 45 |
1 files changed, 27 insertions, 18 deletions
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 8cdcc2ad048c..b6b16264b305 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
| @@ -77,8 +77,17 @@ struct sit_net { | |||
| 77 | struct net_device *fb_tunnel_dev; | 77 | struct net_device *fb_tunnel_dev; |
| 78 | }; | 78 | }; |
| 79 | 79 | ||
| 80 | static DEFINE_RWLOCK(ipip6_lock); | 80 | /* |
| 81 | * Locking : hash tables are protected by RCU and a spinlock | ||
| 82 | */ | ||
| 83 | static DEFINE_SPINLOCK(ipip6_lock); | ||
| 84 | |||
| 85 | #define for_each_ip_tunnel_rcu(start) \ | ||
| 86 | for (t = rcu_dereference(start); t; t = rcu_dereference(t->next)) | ||
| 81 | 87 | ||
| 88 | /* | ||
| 89 | * Must be invoked with rcu_read_lock | ||
| 90 | */ | ||
| 82 | static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, | 91 | static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, |
| 83 | struct net_device *dev, __be32 remote, __be32 local) | 92 | struct net_device *dev, __be32 remote, __be32 local) |
| 84 | { | 93 | { |
| @@ -87,26 +96,26 @@ static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, | |||
| 87 | struct ip_tunnel *t; | 96 | struct ip_tunnel *t; |
| 88 | struct sit_net *sitn = net_generic(net, sit_net_id); | 97 | struct sit_net *sitn = net_generic(net, sit_net_id); |
| 89 | 98 | ||
| 90 | for (t = sitn->tunnels_r_l[h0^h1]; t; t = t->next) { | 99 | for_each_ip_tunnel_rcu(sitn->tunnels_r_l[h0 ^ h1]) { |
| 91 | if (local == t->parms.iph.saddr && | 100 | if (local == t->parms.iph.saddr && |
| 92 | remote == t->parms.iph.daddr && | 101 | remote == t->parms.iph.daddr && |
| 93 | (!dev || !t->parms.link || dev->iflink == t->parms.link) && | 102 | (!dev || !t->parms.link || dev->iflink == t->parms.link) && |
| 94 | (t->dev->flags & IFF_UP)) | 103 | (t->dev->flags & IFF_UP)) |
| 95 | return t; | 104 | return t; |
| 96 | } | 105 | } |
| 97 | for (t = sitn->tunnels_r[h0]; t; t = t->next) { | 106 | for_each_ip_tunnel_rcu(sitn->tunnels_r[h0]) { |
| 98 | if (remote == t->parms.iph.daddr && | 107 | if (remote == t->parms.iph.daddr && |
| 99 | (!dev || !t->parms.link || dev->iflink == t->parms.link) && | 108 | (!dev || !t->parms.link || dev->iflink == t->parms.link) && |
| 100 | (t->dev->flags & IFF_UP)) | 109 | (t->dev->flags & IFF_UP)) |
| 101 | return t; | 110 | return t; |
| 102 | } | 111 | } |
| 103 | for (t = sitn->tunnels_l[h1]; t; t = t->next) { | 112 | for_each_ip_tunnel_rcu(sitn->tunnels_l[h1]) { |
| 104 | if (local == t->parms.iph.saddr && | 113 | if (local == t->parms.iph.saddr && |
| 105 | (!dev || !t->parms.link || dev->iflink == t->parms.link) && | 114 | (!dev || !t->parms.link || dev->iflink == t->parms.link) && |
| 106 | (t->dev->flags & IFF_UP)) | 115 | (t->dev->flags & IFF_UP)) |
| 107 | return t; | 116 | return t; |
| 108 | } | 117 | } |
| 109 | t = sitn->tunnels_wc[0]; | 118 | t = rcu_dereference(sitn->tunnels_wc[0]); |
| 110 | if ((t != NULL) && (t->dev->flags & IFF_UP)) | 119 | if ((t != NULL) && (t->dev->flags & IFF_UP)) |
| 111 | return t; | 120 | return t; |
| 112 | return NULL; | 121 | return NULL; |
| @@ -143,9 +152,9 @@ static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t) | |||
| 143 | 152 | ||
| 144 | for (tp = ipip6_bucket(sitn, t); *tp; tp = &(*tp)->next) { | 153 | for (tp = ipip6_bucket(sitn, t); *tp; tp = &(*tp)->next) { |
| 145 | if (t == *tp) { | 154 | if (t == *tp) { |
| 146 | write_lock_bh(&ipip6_lock); | 155 | spin_lock_bh(&ipip6_lock); |
| 147 | *tp = t->next; | 156 | *tp = t->next; |
| 148 | write_unlock_bh(&ipip6_lock); | 157 | spin_unlock_bh(&ipip6_lock); |
| 149 | break; | 158 | break; |
| 150 | } | 159 | } |
| 151 | } | 160 | } |
| @@ -155,10 +164,10 @@ static void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t) | |||
| 155 | { | 164 | { |
| 156 | struct ip_tunnel **tp = ipip6_bucket(sitn, t); | 165 | struct ip_tunnel **tp = ipip6_bucket(sitn, t); |
| 157 | 166 | ||
| 167 | spin_lock_bh(&ipip6_lock); | ||
| 158 | t->next = *tp; | 168 | t->next = *tp; |
| 159 | write_lock_bh(&ipip6_lock); | 169 | rcu_assign_pointer(*tp, t); |
| 160 | *tp = t; | 170 | spin_unlock_bh(&ipip6_lock); |
| 161 | write_unlock_bh(&ipip6_lock); | ||
| 162 | } | 171 | } |
| 163 | 172 | ||
| 164 | static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn) | 173 | static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn) |
| @@ -447,9 +456,9 @@ static void ipip6_tunnel_uninit(struct net_device *dev) | |||
| 447 | struct sit_net *sitn = net_generic(net, sit_net_id); | 456 | struct sit_net *sitn = net_generic(net, sit_net_id); |
| 448 | 457 | ||
| 449 | if (dev == sitn->fb_tunnel_dev) { | 458 | if (dev == sitn->fb_tunnel_dev) { |
| 450 | write_lock_bh(&ipip6_lock); | 459 | spin_lock_bh(&ipip6_lock); |
| 451 | sitn->tunnels_wc[0] = NULL; | 460 | sitn->tunnels_wc[0] = NULL; |
| 452 | write_unlock_bh(&ipip6_lock); | 461 | spin_unlock_bh(&ipip6_lock); |
| 453 | dev_put(dev); | 462 | dev_put(dev); |
| 454 | } else { | 463 | } else { |
| 455 | ipip6_tunnel_unlink(sitn, netdev_priv(dev)); | 464 | ipip6_tunnel_unlink(sitn, netdev_priv(dev)); |
| @@ -502,7 +511,7 @@ static int ipip6_err(struct sk_buff *skb, u32 info) | |||
| 502 | 511 | ||
| 503 | err = -ENOENT; | 512 | err = -ENOENT; |
| 504 | 513 | ||
| 505 | read_lock(&ipip6_lock); | 514 | rcu_read_lock(); |
| 506 | t = ipip6_tunnel_lookup(dev_net(skb->dev), | 515 | t = ipip6_tunnel_lookup(dev_net(skb->dev), |
| 507 | skb->dev, | 516 | skb->dev, |
| 508 | iph->daddr, | 517 | iph->daddr, |
| @@ -520,7 +529,7 @@ static int ipip6_err(struct sk_buff *skb, u32 info) | |||
| 520 | t->err_count = 1; | 529 | t->err_count = 1; |
| 521 | t->err_time = jiffies; | 530 | t->err_time = jiffies; |
| 522 | out: | 531 | out: |
| 523 | read_unlock(&ipip6_lock); | 532 | rcu_read_unlock(); |
| 524 | return err; | 533 | return err; |
| 525 | } | 534 | } |
| 526 | 535 | ||
| @@ -540,7 +549,7 @@ static int ipip6_rcv(struct sk_buff *skb) | |||
| 540 | 549 | ||
| 541 | iph = ip_hdr(skb); | 550 | iph = ip_hdr(skb); |
| 542 | 551 | ||
| 543 | read_lock(&ipip6_lock); | 552 | rcu_read_lock(); |
| 544 | tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev, | 553 | tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev, |
| 545 | iph->saddr, iph->daddr); | 554 | iph->saddr, iph->daddr); |
| 546 | if (tunnel != NULL) { | 555 | if (tunnel != NULL) { |
| @@ -554,7 +563,7 @@ static int ipip6_rcv(struct sk_buff *skb) | |||
| 554 | if ((tunnel->dev->priv_flags & IFF_ISATAP) && | 563 | if ((tunnel->dev->priv_flags & IFF_ISATAP) && |
| 555 | !isatap_chksrc(skb, iph, tunnel)) { | 564 | !isatap_chksrc(skb, iph, tunnel)) { |
| 556 | tunnel->dev->stats.rx_errors++; | 565 | tunnel->dev->stats.rx_errors++; |
| 557 | read_unlock(&ipip6_lock); | 566 | rcu_read_unlock(); |
| 558 | kfree_skb(skb); | 567 | kfree_skb(skb); |
| 559 | return 0; | 568 | return 0; |
| 560 | } | 569 | } |
| @@ -565,12 +574,12 @@ static int ipip6_rcv(struct sk_buff *skb) | |||
| 565 | nf_reset(skb); | 574 | nf_reset(skb); |
| 566 | ipip6_ecn_decapsulate(iph, skb); | 575 | ipip6_ecn_decapsulate(iph, skb); |
| 567 | netif_rx(skb); | 576 | netif_rx(skb); |
| 568 | read_unlock(&ipip6_lock); | 577 | rcu_read_unlock(); |
| 569 | return 0; | 578 | return 0; |
| 570 | } | 579 | } |
| 571 | 580 | ||
| 572 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); | 581 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); |
| 573 | read_unlock(&ipip6_lock); | 582 | rcu_read_unlock(); |
| 574 | out: | 583 | out: |
| 575 | kfree_skb(skb); | 584 | kfree_skb(skb); |
| 576 | return 0; | 585 | return 0; |
