--- /dev/null
+From db098b337e98ba2624c2aed1148f03c854d27bb5 Mon Sep 17 00:00:00 2001
+From: Eric Dumazet <eric.dumazet@gmail.com>
+Date: Thu, 9 Feb 2012 16:13:19 -0500
+Subject: [PATCH] net: fix NULL dereferences in check_peer_redir()
+
+From: Eric Dumazet <eric.dumazet@gmail.com>
+
+[ Upstream commit d3aaeb38c40e5a6c08dd31a1b64da65c4352be36, along
+ with dependent backports of commits:
+ 69cce1d1404968f78b177a0314f5822d5afdbbfb
+ 9de79c127cccecb11ae6a21ab1499e87aa222880
+ 218fa90f072e4aeff9003d57e390857f4f35513e
+ 580da35a31f91a594f3090b7a2c39b85cb051a12
+ f7e57044eeb1841847c24aa06766c8290c202583
+ e049f28883126c689cf95859480d9ee4ab23b7fa ]
+
+Gergely Kalman reported crashes in check_peer_redir().
+
+It appears commit f39925dbde778 (ipv4: Cache learned redirect
+information in inetpeer.) added a race, leading to possible NULL ptr
+dereference.
+
+Since we can now change dst neighbour, we should make sure a reader can
+safely use a neighbour.
+
+Add RCU protection to dst neighbour, and make sure check_peer_redir()
+can be called safely by different cpus in parallel.
+
+As neighbours are already freed after one RCU grace period, this patch
+should not add typical RCU penalty (cache cold effects)
+
+Many thanks to Gergely for providing a pretty report pointing to the
+bug.
+
+Reported-by: Gergely Kalman <synapse@hippy.csoma.elte.hu>
+Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/infiniband/core/addr.c | 16 ++++--
+ drivers/infiniband/hw/cxgb3/iwch_cm.c | 16 +++++-
+ drivers/infiniband/hw/cxgb4/cm.c | 46 ++++++++++---------
+ drivers/infiniband/hw/mlx4/qp.c | 2
+ drivers/infiniband/hw/nes/nes_cm.c | 8 ++-
+ drivers/infiniband/ulp/ipoib/ipoib_main.c | 59 ++++++++++++++++---------
+ drivers/infiniband/ulp/ipoib/ipoib_multicast.c | 24 ++++++----
+ drivers/net/cxgb3/cxgb3_offload.c | 8 +--
+ drivers/s390/net/qeth_l3_main.c | 23 +++++++--
+ drivers/scsi/cxgbi/cxgb3i/cxgb3i.c | 2
+ drivers/scsi/cxgbi/cxgb4i/cxgb4i.c | 2
+ drivers/scsi/cxgbi/libcxgbi.c | 4 -
+ include/net/arp.h | 1
+ include/net/dst.h | 27 ++++++++++-
+ net/atm/clip.c | 16 ++++--
+ net/bridge/br_netfilter.c | 6 +-
+ net/core/dst.c | 15 ++++--
+ net/core/neighbour.c | 19 +++++---
+ net/decnet/dn_neigh.c | 8 +--
+ net/decnet/dn_route.c | 18 ++++---
+ net/ipv4/arp.c | 28 +++++++----
+ net/ipv4/ip_gre.c | 2
+ net/ipv4/ip_output.c | 22 +++++++--
+ net/ipv4/route.c | 31 ++++++++-----
+ net/ipv6/addrconf.c | 2
+ net/ipv6/ip6_fib.c | 2
+ net/ipv6/ip6_output.c | 40 +++++++++++++---
+ net/ipv6/ndisc.c | 4 -
+ net/ipv6/route.c | 59 +++++++++++++++----------
+ net/ipv6/sit.c | 4 -
+ net/sched/sch_teql.c | 31 ++++++++-----
+ net/xfrm/xfrm_policy.c | 2
+ 32 files changed, 358 insertions(+), 189 deletions(-)
+
+--- a/drivers/infiniband/core/addr.c
++++ b/drivers/infiniband/core/addr.c
+@@ -215,7 +215,9 @@ static int addr4_resolve(struct sockaddr
+
+ neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, rt->dst.dev);
+ if (!neigh || !(neigh->nud_state & NUD_VALID)) {
+- neigh_event_send(rt->dst.neighbour, NULL);
++ rcu_read_lock();
++ neigh_event_send(dst_get_neighbour(&rt->dst), NULL);
++ rcu_read_unlock();
+ ret = -ENODATA;
+ if (neigh)
+ goto release;
+@@ -273,14 +275,16 @@ static int addr6_resolve(struct sockaddr
+ goto put;
+ }
+
+- neigh = dst->neighbour;
++ rcu_read_lock();
++ neigh = dst_get_neighbour(dst);
+ if (!neigh || !(neigh->nud_state & NUD_VALID)) {
+- neigh_event_send(dst->neighbour, NULL);
++ if (neigh)
++ neigh_event_send(neigh, NULL);
+ ret = -ENODATA;
+- goto put;
++ } else {
++ ret = rdma_copy_addr(addr, dst->dev, neigh->ha);
+ }
+-
+- ret = rdma_copy_addr(addr, dst->dev, neigh->ha);
++ rcu_read_unlock();
+ put:
+ dst_release(dst);
+ return ret;
+--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
++++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
+@@ -1328,6 +1328,7 @@ static int pass_accept_req(struct t3cdev
+ struct iwch_ep *child_ep, *parent_ep = ctx;
+ struct cpl_pass_accept_req *req = cplhdr(skb);
+ unsigned int hwtid = GET_TID(req);
++ struct neighbour *neigh;
+ struct dst_entry *dst;
+ struct l2t_entry *l2t;
+ struct rtable *rt;
+@@ -1364,7 +1365,10 @@ static int pass_accept_req(struct t3cdev
+ goto reject;
+ }
+ dst = &rt->dst;
+- l2t = t3_l2t_get(tdev, dst->neighbour, dst->neighbour->dev);
++ rcu_read_lock();
++ neigh = dst_get_neighbour(dst);
++ l2t = t3_l2t_get(tdev, neigh, neigh->dev);
++ rcu_read_unlock();
+ if (!l2t) {
+ printk(KERN_ERR MOD "%s - failed to allocate l2t entry!\n",
+ __func__);
+@@ -1874,10 +1878,11 @@ static int is_loopback_dst(struct iw_cm_
+
+ int iwch_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
+ {
+- int err = 0;
+ struct iwch_dev *h = to_iwch_dev(cm_id->device);
++ struct neighbour *neigh;
+ struct iwch_ep *ep;
+ struct rtable *rt;
++ int err = 0;
+
+ if (is_loopback_dst(cm_id)) {
+ err = -ENOSYS;
+@@ -1933,9 +1938,12 @@ int iwch_connect(struct iw_cm_id *cm_id,
+ }
+ ep->dst = &rt->dst;
+
++ rcu_read_lock();
++ neigh = dst_get_neighbour(ep->dst);
++
+ /* get a l2t entry */
+- ep->l2t = t3_l2t_get(ep->com.tdev, ep->dst->neighbour,
+- ep->dst->neighbour->dev);
++ ep->l2t = t3_l2t_get(ep->com.tdev, neigh, neigh->dev);
++ rcu_read_unlock();
+ if (!ep->l2t) {
+ printk(KERN_ERR MOD "%s - cannot alloc l2e.\n", __func__);
+ err = -ENOMEM;
+--- a/drivers/infiniband/hw/cxgb4/cm.c
++++ b/drivers/infiniband/hw/cxgb4/cm.c
+@@ -1325,6 +1325,7 @@ static int pass_accept_req(struct c4iw_d
+ unsigned int stid = GET_POPEN_TID(ntohl(req->tos_stid));
+ struct tid_info *t = dev->rdev.lldi.tids;
+ unsigned int hwtid = GET_TID(req);
++ struct neighbour *neigh;
+ struct dst_entry *dst;
+ struct l2t_entry *l2t;
+ struct rtable *rt;
+@@ -1357,11 +1358,12 @@ static int pass_accept_req(struct c4iw_d
+ goto reject;
+ }
+ dst = &rt->dst;
+- if (dst->neighbour->dev->flags & IFF_LOOPBACK) {
++ rcu_read_lock();
++ neigh = dst_get_neighbour(dst);
++ if (neigh->dev->flags & IFF_LOOPBACK) {
+ pdev = ip_dev_find(&init_net, peer_ip);
+ BUG_ON(!pdev);
+- l2t = cxgb4_l2t_get(dev->rdev.lldi.l2t, dst->neighbour,
+- pdev, 0);
++ l2t = cxgb4_l2t_get(dev->rdev.lldi.l2t, neigh, pdev, 0);
+ mtu = pdev->mtu;
+ tx_chan = cxgb4_port_chan(pdev);
+ smac_idx = (cxgb4_port_viid(pdev) & 0x7F) << 1;
+@@ -1372,18 +1374,18 @@ static int pass_accept_req(struct c4iw_d
+ rss_qid = dev->rdev.lldi.rxq_ids[cxgb4_port_idx(pdev) * step];
+ dev_put(pdev);
+ } else {
+- l2t = cxgb4_l2t_get(dev->rdev.lldi.l2t, dst->neighbour,
+- dst->neighbour->dev, 0);
++ l2t = cxgb4_l2t_get(dev->rdev.lldi.l2t, neigh, neigh->dev, 0);
+ mtu = dst_mtu(dst);
+- tx_chan = cxgb4_port_chan(dst->neighbour->dev);
+- smac_idx = (cxgb4_port_viid(dst->neighbour->dev) & 0x7F) << 1;
++ tx_chan = cxgb4_port_chan(neigh->dev);
++ smac_idx = (cxgb4_port_viid(neigh->dev) & 0x7F) << 1;
+ step = dev->rdev.lldi.ntxq / dev->rdev.lldi.nchan;
+- txq_idx = cxgb4_port_idx(dst->neighbour->dev) * step;
+- ctrlq_idx = cxgb4_port_idx(dst->neighbour->dev);
++ txq_idx = cxgb4_port_idx(neigh->dev) * step;
++ ctrlq_idx = cxgb4_port_idx(neigh->dev);
+ step = dev->rdev.lldi.nrxq / dev->rdev.lldi.nchan;
+ rss_qid = dev->rdev.lldi.rxq_ids[
+- cxgb4_port_idx(dst->neighbour->dev) * step];
++ cxgb4_port_idx(neigh->dev) * step];
+ }
++ rcu_read_unlock();
+ if (!l2t) {
+ printk(KERN_ERR MOD "%s - failed to allocate l2t entry!\n",
+ __func__);
+@@ -1847,6 +1849,7 @@ int c4iw_connect(struct iw_cm_id *cm_id,
+ struct c4iw_ep *ep;
+ struct rtable *rt;
+ struct net_device *pdev;
++ struct neighbour *neigh;
+ int step;
+
+ if ((conn_param->ord > c4iw_max_read_depth) ||
+@@ -1908,14 +1911,16 @@ int c4iw_connect(struct iw_cm_id *cm_id,
+ }
+ ep->dst = &rt->dst;
+
++ rcu_read_lock();
++ neigh = dst_get_neighbour(ep->dst);
++
+ /* get a l2t entry */
+- if (ep->dst->neighbour->dev->flags & IFF_LOOPBACK) {
++ if (neigh->dev->flags & IFF_LOOPBACK) {
+ PDBG("%s LOOPBACK\n", __func__);
+ pdev = ip_dev_find(&init_net,
+ cm_id->remote_addr.sin_addr.s_addr);
+ ep->l2t = cxgb4_l2t_get(ep->com.dev->rdev.lldi.l2t,
+- ep->dst->neighbour,
+- pdev, 0);
++ neigh, pdev, 0);
+ ep->mtu = pdev->mtu;
+ ep->tx_chan = cxgb4_port_chan(pdev);
+ ep->smac_idx = (cxgb4_port_viid(pdev) & 0x7F) << 1;
+@@ -1930,21 +1935,20 @@ int c4iw_connect(struct iw_cm_id *cm_id,
+ dev_put(pdev);
+ } else {
+ ep->l2t = cxgb4_l2t_get(ep->com.dev->rdev.lldi.l2t,
+- ep->dst->neighbour,
+- ep->dst->neighbour->dev, 0);
++ neigh, neigh->dev, 0);
+ ep->mtu = dst_mtu(ep->dst);
+- ep->tx_chan = cxgb4_port_chan(ep->dst->neighbour->dev);
+- ep->smac_idx = (cxgb4_port_viid(ep->dst->neighbour->dev) &
+- 0x7F) << 1;
++ ep->tx_chan = cxgb4_port_chan(neigh->dev);
++ ep->smac_idx = (cxgb4_port_viid(neigh->dev) & 0x7F) << 1;
+ step = ep->com.dev->rdev.lldi.ntxq /
+ ep->com.dev->rdev.lldi.nchan;
+- ep->txq_idx = cxgb4_port_idx(ep->dst->neighbour->dev) * step;
+- ep->ctrlq_idx = cxgb4_port_idx(ep->dst->neighbour->dev);
++ ep->txq_idx = cxgb4_port_idx(neigh->dev) * step;
++ ep->ctrlq_idx = cxgb4_port_idx(neigh->dev);
+ step = ep->com.dev->rdev.lldi.nrxq /
+ ep->com.dev->rdev.lldi.nchan;
+ ep->rss_qid = ep->com.dev->rdev.lldi.rxq_ids[
+- cxgb4_port_idx(ep->dst->neighbour->dev) * step];
++ cxgb4_port_idx(neigh->dev) * step];
+ }
++ rcu_read_unlock();
+ if (!ep->l2t) {
+ printk(KERN_ERR MOD "%s - cannot alloc l2e.\n", __func__);
+ err = -ENOMEM;
+--- a/drivers/infiniband/hw/mlx4/qp.c
++++ b/drivers/infiniband/hw/mlx4/qp.c
+@@ -1301,7 +1301,7 @@ static int build_mlx_header(struct mlx4_
+ int is_eth;
+ int is_vlan = 0;
+ int is_grh;
+- u16 vlan;
++ u16 vlan = 0;
+
+ send_size = 0;
+ for (i = 0; i < wr->num_sge; ++i)
+--- a/drivers/infiniband/hw/nes/nes_cm.c
++++ b/drivers/infiniband/hw/nes/nes_cm.c
+@@ -1150,9 +1150,11 @@ static int nes_addr_resolve_neigh(struct
+ neigh_release(neigh);
+ }
+
+- if ((neigh == NULL) || (!(neigh->nud_state & NUD_VALID)))
+- neigh_event_send(rt->dst.neighbour, NULL);
+-
++ if ((neigh == NULL) || (!(neigh->nud_state & NUD_VALID))) {
++ rcu_read_lock();
++ neigh_event_send(dst_get_neighbour(&rt->dst), NULL);
++ rcu_read_unlock();
++ }
+ ip_rt_put(rt);
+ return rc;
+ }
+--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
++++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
+@@ -555,14 +555,17 @@ static int path_rec_start(struct net_dev
+ return 0;
+ }
+
++/* called with rcu_read_lock */
+ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
+ {
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+ struct ipoib_path *path;
+ struct ipoib_neigh *neigh;
++ struct neighbour *n;
+ unsigned long flags;
+
+- neigh = ipoib_neigh_alloc(skb_dst(skb)->neighbour, skb->dev);
++ n = dst_get_neighbour(skb_dst(skb));
++ neigh = ipoib_neigh_alloc(n, skb->dev);
+ if (!neigh) {
+ ++dev->stats.tx_dropped;
+ dev_kfree_skb_any(skb);
+@@ -571,9 +574,9 @@ static void neigh_add_path(struct sk_buf
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+- path = __path_find(dev, skb_dst(skb)->neighbour->ha + 4);
++ path = __path_find(dev, n->ha + 4);
+ if (!path) {
+- path = path_rec_create(dev, skb_dst(skb)->neighbour->ha + 4);
++ path = path_rec_create(dev, n->ha + 4);
+ if (!path)
+ goto err_path;
+
+@@ -607,7 +610,7 @@ static void neigh_add_path(struct sk_buf
+ }
+ } else {
+ spin_unlock_irqrestore(&priv->lock, flags);
+- ipoib_send(dev, skb, path->ah, IPOIB_QPN(skb_dst(skb)->neighbour->ha));
++ ipoib_send(dev, skb, path->ah, IPOIB_QPN(n->ha));
+ return;
+ }
+ } else {
+@@ -634,20 +637,24 @@ err_drop:
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+
++/* called with rcu_read_lock */
+ static void ipoib_path_lookup(struct sk_buff *skb, struct net_device *dev)
+ {
+ struct ipoib_dev_priv *priv = netdev_priv(skb->dev);
++ struct dst_entry *dst = skb_dst(skb);
++ struct neighbour *n;
+
+ /* Look up path record for unicasts */
+- if (skb_dst(skb)->neighbour->ha[4] != 0xff) {
++ n = dst_get_neighbour(dst);
++ if (n->ha[4] != 0xff) {
+ neigh_add_path(skb, dev);
+ return;
+ }
+
+ /* Add in the P_Key for multicasts */
+- skb_dst(skb)->neighbour->ha[8] = (priv->pkey >> 8) & 0xff;
+- skb_dst(skb)->neighbour->ha[9] = priv->pkey & 0xff;
+- ipoib_mcast_send(dev, skb_dst(skb)->neighbour->ha + 4, skb);
++ n->ha[8] = (priv->pkey >> 8) & 0xff;
++ n->ha[9] = priv->pkey & 0xff;
++ ipoib_mcast_send(dev, n->ha + 4, skb);
+ }
+
+ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
+@@ -712,18 +719,23 @@ static int ipoib_start_xmit(struct sk_bu
+ {
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+ struct ipoib_neigh *neigh;
++ struct neighbour *n = NULL;
+ unsigned long flags;
+
+- if (likely(skb_dst(skb) && skb_dst(skb)->neighbour)) {
+- if (unlikely(!*to_ipoib_neigh(skb_dst(skb)->neighbour))) {
++ rcu_read_lock();
++ if (likely(skb_dst(skb)))
++ n = dst_get_neighbour(skb_dst(skb));
++
++ if (likely(n)) {
++ if (unlikely(!*to_ipoib_neigh(n))) {
+ ipoib_path_lookup(skb, dev);
+- return NETDEV_TX_OK;
++ goto unlock;
+ }
+
+- neigh = *to_ipoib_neigh(skb_dst(skb)->neighbour);
++ neigh = *to_ipoib_neigh(n);
+
+ if (unlikely((memcmp(&neigh->dgid.raw,
+- skb_dst(skb)->neighbour->ha + 4,
++ n->ha + 4,
+ sizeof(union ib_gid))) ||
+ (neigh->dev != dev))) {
+ spin_lock_irqsave(&priv->lock, flags);
+@@ -740,17 +752,17 @@ static int ipoib_start_xmit(struct sk_bu
+ ipoib_neigh_free(dev, neigh);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ ipoib_path_lookup(skb, dev);
+- return NETDEV_TX_OK;
++ goto unlock;
+ }
+
+ if (ipoib_cm_get(neigh)) {
+ if (ipoib_cm_up(neigh)) {
+ ipoib_cm_send(dev, skb, ipoib_cm_get(neigh));
+- return NETDEV_TX_OK;
++ goto unlock;
+ }
+ } else if (neigh->ah) {
+- ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(skb_dst(skb)->neighbour->ha));
+- return NETDEV_TX_OK;
++ ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(n->ha));
++ goto unlock;
+ }
+
+ if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
+@@ -784,13 +796,14 @@ static int ipoib_start_xmit(struct sk_bu
+ phdr->hwaddr + 4);
+ dev_kfree_skb_any(skb);
+ ++dev->stats.tx_dropped;
+- return NETDEV_TX_OK;
++ goto unlock;
+ }
+
+ unicast_arp_send(skb, dev, phdr);
+ }
+ }
+-
++unlock:
++ rcu_read_unlock();
+ return NETDEV_TX_OK;
+ }
+
+@@ -812,6 +825,8 @@ static int ipoib_hard_header(struct sk_b
+ const void *daddr, const void *saddr, unsigned len)
+ {
+ struct ipoib_header *header;
++ struct dst_entry *dst;
++ struct neighbour *n;
+
+ header = (struct ipoib_header *) skb_push(skb, sizeof *header);
+
+@@ -823,7 +838,11 @@ static int ipoib_hard_header(struct sk_b
+ * destination address onto the front of the skb so we can
+ * figure out where to send the packet later.
+ */
+- if ((!skb_dst(skb) || !skb_dst(skb)->neighbour) && daddr) {
++ dst = skb_dst(skb);
++ n = NULL;
++ if (dst)
++ n = dst_get_neighbour_raw(dst);
++ if ((!dst || !n) && daddr) {
+ struct ipoib_pseudoheader *phdr =
+ (struct ipoib_pseudoheader *) skb_push(skb, sizeof *phdr);
+ memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN);
+--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
++++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+@@ -258,11 +258,15 @@ static int ipoib_mcast_join_finish(struc
+ netif_tx_lock_bh(dev);
+ while (!skb_queue_empty(&mcast->pkt_queue)) {
+ struct sk_buff *skb = skb_dequeue(&mcast->pkt_queue);
++ struct dst_entry *dst = skb_dst(skb);
++ struct neighbour *n = NULL;
++
+ netif_tx_unlock_bh(dev);
+
+ skb->dev = dev;
+-
+- if (!skb_dst(skb) || !skb_dst(skb)->neighbour) {
++ if (dst)
++ n = dst_get_neighbour_raw(dst);
++ if (!dst || !n) {
+ /* put pseudoheader back on for next time */
+ skb_push(skb, sizeof (struct ipoib_pseudoheader));
+ }
+@@ -715,11 +719,15 @@ void ipoib_mcast_send(struct net_device
+
+ out:
+ if (mcast && mcast->ah) {
+- if (skb_dst(skb) &&
+- skb_dst(skb)->neighbour &&
+- !*to_ipoib_neigh(skb_dst(skb)->neighbour)) {
+- struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb_dst(skb)->neighbour,
+- skb->dev);
++ struct dst_entry *dst = skb_dst(skb);
++ struct neighbour *n = NULL;
++
++ rcu_read_lock();
++ if (dst)
++ n = dst_get_neighbour(dst);
++ if (n && !*to_ipoib_neigh(n)) {
++ struct ipoib_neigh *neigh = ipoib_neigh_alloc(n,
++ skb->dev);
+
+ if (neigh) {
+ kref_get(&mcast->ah->ref);
+@@ -727,7 +735,7 @@ out:
+ list_add_tail(&neigh->list, &mcast->neigh_list);
+ }
+ }
+-
++ rcu_read_unlock();
+ spin_unlock_irqrestore(&priv->lock, flags);
+ ipoib_send(dev, skb, mcast->ah, IB_MULTICAST_QPN);
+ return;
+--- a/drivers/net/cxgb3/cxgb3_offload.c
++++ b/drivers/net/cxgb3/cxgb3_offload.c
+@@ -971,7 +971,7 @@ static int nb_callback(struct notifier_b
+ case (NETEVENT_REDIRECT):{
+ struct netevent_redirect *nr = ctx;
+ cxgb_redirect(nr->old, nr->new);
+- cxgb_neigh_update(nr->new->neighbour);
++ cxgb_neigh_update(dst_get_neighbour(nr->new));
+ break;
+ }
+ default:
+@@ -1116,8 +1116,8 @@ static void cxgb_redirect(struct dst_ent
+ struct l2t_entry *e;
+ struct t3c_tid_entry *te;
+
+- olddev = old->neighbour->dev;
+- newdev = new->neighbour->dev;
++ olddev = dst_get_neighbour(old)->dev;
++ newdev = dst_get_neighbour(new)->dev;
+ if (!is_offloading(olddev))
+ return;
+ if (!is_offloading(newdev)) {
+@@ -1134,7 +1134,7 @@ static void cxgb_redirect(struct dst_ent
+ }
+
+ /* Add new L2T entry */
+- e = t3_l2t_get(tdev, new->neighbour, newdev);
++ e = t3_l2t_get(tdev, dst_get_neighbour(new), newdev);
+ if (!e) {
+ printk(KERN_ERR "%s: couldn't allocate new l2t entry!\n",
+ __func__);
+--- a/drivers/s390/net/qeth_l3_main.c
++++ b/drivers/s390/net/qeth_l3_main.c
+@@ -2742,9 +2742,14 @@ static int qeth_l3_do_ioctl(struct net_d
+ int inline qeth_l3_get_cast_type(struct qeth_card *card, struct sk_buff *skb)
+ {
+ int cast_type = RTN_UNSPEC;
++ struct neighbour *n = NULL;
++ struct dst_entry *dst;
+
+- if (skb_dst(skb) && skb_dst(skb)->neighbour) {
+- cast_type = skb_dst(skb)->neighbour->type;
++ dst = skb_dst(skb);
++ if (dst)
++ n = dst_get_neighbour(dst);
++ if (n) {
++ cast_type = n->type;
+ if ((cast_type == RTN_BROADCAST) ||
+ (cast_type == RTN_MULTICAST) ||
+ (cast_type == RTN_ANYCAST))
+@@ -2787,6 +2792,9 @@ int inline qeth_l3_get_cast_type(struct
+ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
+ struct sk_buff *skb, int ipv, int cast_type)
+ {
++ struct neighbour *n = NULL;
++ struct dst_entry *dst;
++
+ memset(hdr, 0, sizeof(struct qeth_hdr));
+ hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3;
+ hdr->hdr.l3.ext_flags = 0;
+@@ -2804,13 +2812,16 @@ static void qeth_l3_fill_header(struct q
+ }
+
+ hdr->hdr.l3.length = skb->len - sizeof(struct qeth_hdr);
++ dst = skb_dst(skb);
++ if (dst)
++ n = dst_get_neighbour(dst);
+ if (ipv == 4) {
+ /* IPv4 */
+ hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags4(cast_type);
+ memset(hdr->hdr.l3.dest_addr, 0, 12);
+- if ((skb_dst(skb)) && (skb_dst(skb)->neighbour)) {
++ if (n) {
+ *((u32 *) (&hdr->hdr.l3.dest_addr[12])) =
+- *((u32 *) skb_dst(skb)->neighbour->primary_key);
++ *((u32 *) n->primary_key);
+ } else {
+ /* fill in destination address used in ip header */
+ *((u32 *) (&hdr->hdr.l3.dest_addr[12])) =
+@@ -2821,9 +2832,9 @@ static void qeth_l3_fill_header(struct q
+ hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags6(cast_type);
+ if (card->info.type == QETH_CARD_TYPE_IQD)
+ hdr->hdr.l3.flags &= ~QETH_HDR_PASSTHRU;
+- if ((skb_dst(skb)) && (skb_dst(skb)->neighbour)) {
++ if (n) {
+ memcpy(hdr->hdr.l3.dest_addr,
+- skb_dst(skb)->neighbour->primary_key, 16);
++ n->primary_key, 16);
+ } else {
+ /* fill in destination address used in ip header */
+ memcpy(hdr->hdr.l3.dest_addr,
+--- a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
++++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
+@@ -985,7 +985,7 @@ static int init_act_open(struct cxgbi_so
+ csk->saddr.sin_addr.s_addr = chba->ipv4addr;
+
+ csk->rss_qid = 0;
+- csk->l2t = t3_l2t_get(t3dev, dst->neighbour, ndev);
++ csk->l2t = t3_l2t_get(t3dev, dst_get_neighbour(dst), ndev);
+ if (!csk->l2t) {
+ pr_err("NO l2t available.\n");
+ return -EINVAL;
+--- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
++++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
+@@ -1160,7 +1160,7 @@ static int init_act_open(struct cxgbi_so
+ cxgbi_sock_set_flag(csk, CTPF_HAS_ATID);
+ cxgbi_sock_get(csk);
+
+- csk->l2t = cxgb4_l2t_get(lldi->l2t, csk->dst->neighbour, ndev, 0);
++ csk->l2t = cxgb4_l2t_get(lldi->l2t, dst_get_neighbour(csk->dst), ndev, 0);
+ if (!csk->l2t) {
+ pr_err("%s, cannot alloc l2t.\n", ndev->name);
+ goto rel_resource;
+--- a/drivers/scsi/cxgbi/libcxgbi.c
++++ b/drivers/scsi/cxgbi/libcxgbi.c
+@@ -492,7 +492,7 @@ static struct cxgbi_sock *cxgbi_check_ro
+ goto err_out;
+ }
+ dst = &rt->dst;
+- ndev = dst->neighbour->dev;
++ ndev = dst_get_neighbour(dst)->dev;
+
+ if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) {
+ pr_info("multi-cast route %pI4, port %u, dev %s.\n",
+@@ -506,7 +506,7 @@ static struct cxgbi_sock *cxgbi_check_ro
+ ndev = ip_dev_find(&init_net, daddr->sin_addr.s_addr);
+ mtu = ndev->mtu;
+ pr_info("rt dev %s, loopback -> %s, mtu %u.\n",
+- dst->neighbour->dev->name, ndev->name, mtu);
++ dst_get_neighbour(dst)->dev->name, ndev->name, mtu);
+ }
+
+ cdev = cxgbi_device_find_by_netdev(ndev, &port);
+--- a/include/net/arp.h
++++ b/include/net/arp.h
+@@ -16,6 +16,7 @@ extern void arp_send(int type, int p
+ const unsigned char *dest_hw,
+ const unsigned char *src_hw, const unsigned char *th);
+ extern int arp_bind_neighbour(struct dst_entry *dst);
++extern struct neighbour *__arp_bind_neighbour(struct dst_entry *dst, __be32 nexthop);
+ extern int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir);
+ extern void arp_ifdown(struct net_device *dev);
+
+--- a/include/net/dst.h
++++ b/include/net/dst.h
+@@ -37,7 +37,7 @@ struct dst_entry {
+ unsigned long _metrics;
+ unsigned long expires;
+ struct dst_entry *path;
+- struct neighbour *neighbour;
++ struct neighbour __rcu *_neighbour;
+ struct hh_cache *hh;
+ #ifdef CONFIG_XFRM
+ struct xfrm_state *xfrm;
+@@ -86,6 +86,21 @@ struct dst_entry {
+ };
+ };
+
++static inline struct neighbour *dst_get_neighbour(struct dst_entry *dst)
++{
++ return rcu_dereference(dst->_neighbour);
++}
++
++static inline struct neighbour *dst_get_neighbour_raw(struct dst_entry *dst)
++{
++ return rcu_dereference_raw(dst->_neighbour);
++}
++
++static inline void dst_set_neighbour(struct dst_entry *dst, struct neighbour *neigh)
++{
++ rcu_assign_pointer(dst->_neighbour, neigh);
++}
++
+ extern u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old);
+ extern const u32 dst_default_metrics[RTAX_MAX];
+
+@@ -371,8 +386,14 @@ static inline void dst_rcu_free(struct r
+
+ static inline void dst_confirm(struct dst_entry *dst)
+ {
+- if (dst)
+- neigh_confirm(dst->neighbour);
++ if (dst) {
++ struct neighbour *n;
++
++ rcu_read_lock();
++ n = dst_get_neighbour(dst);
++ neigh_confirm(n);
++ rcu_read_unlock();
++ }
+ }
+
+ static inline void dst_link_failure(struct sk_buff *skb)
+--- a/net/atm/clip.c
++++ b/net/atm/clip.c
+@@ -364,33 +364,37 @@ static netdev_tx_t clip_start_xmit(struc
+ struct net_device *dev)
+ {
+ struct clip_priv *clip_priv = PRIV(dev);
++ struct dst_entry *dst = skb_dst(skb);
+ struct atmarp_entry *entry;
++ struct neighbour *n;
+ struct atm_vcc *vcc;
+ int old;
+ unsigned long flags;
+
+ pr_debug("(skb %p)\n", skb);
+- if (!skb_dst(skb)) {
++ if (!dst) {
+ pr_err("skb_dst(skb) == NULL\n");
+ dev_kfree_skb(skb);
+ dev->stats.tx_dropped++;
+ return NETDEV_TX_OK;
+ }
+- if (!skb_dst(skb)->neighbour) {
++ n = dst_get_neighbour(dst);
++ if (!n) {
+ #if 0
+- skb_dst(skb)->neighbour = clip_find_neighbour(skb_dst(skb), 1);
+- if (!skb_dst(skb)->neighbour) {
++ n = clip_find_neighbour(skb_dst(skb), 1);
++ if (!n) {
+ dev_kfree_skb(skb); /* lost that one */
+ dev->stats.tx_dropped++;
+ return 0;
+ }
++ dst_set_neighbour(dst, n);
+ #endif
+ pr_err("NO NEIGHBOUR !\n");
+ dev_kfree_skb(skb);
+ dev->stats.tx_dropped++;
+ return NETDEV_TX_OK;
+ }
+- entry = NEIGH2ENTRY(skb_dst(skb)->neighbour);
++ entry = NEIGH2ENTRY(n);
+ if (!entry->vccs) {
+ if (time_after(jiffies, entry->expires)) {
+ /* should be resolved */
+@@ -407,7 +411,7 @@ static netdev_tx_t clip_start_xmit(struc
+ }
+ pr_debug("neigh %p, vccs %p\n", entry, entry->vccs);
+ ATM_SKB(skb)->vcc = vcc = entry->vccs->vcc;
+- pr_debug("using neighbour %p, vcc %p\n", skb_dst(skb)->neighbour, vcc);
++ pr_debug("using neighbour %p, vcc %p\n", n, vcc);
+ if (entry->vccs->encap) {
+ void *here;
+
+--- a/net/bridge/br_netfilter.c
++++ b/net/bridge/br_netfilter.c
+@@ -343,24 +343,26 @@ static int br_nf_pre_routing_finish_ipv6
+ static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb)
+ {
+ struct nf_bridge_info *nf_bridge = skb->nf_bridge;
++ struct neighbour *neigh;
+ struct dst_entry *dst;
+
+ skb->dev = bridge_parent(skb->dev);
+ if (!skb->dev)
+ goto free_skb;
+ dst = skb_dst(skb);
++ neigh = dst_get_neighbour(dst);
+ if (dst->hh) {
+ neigh_hh_bridge(dst->hh, skb);
+ skb->dev = nf_bridge->physindev;
+ return br_handle_frame_finish(skb);
+- } else if (dst->neighbour) {
++ } else if (neigh) {
+ /* the neighbour function below overwrites the complete
+ * MAC header, so we save the Ethernet source address and
+ * protocol number. */
+ skb_copy_from_linear_data_offset(skb, -(ETH_HLEN-ETH_ALEN), skb->nf_bridge->data, ETH_HLEN-ETH_ALEN);
+ /* tell br_dev_xmit to continue with forwarding */
+ nf_bridge->mask |= BRNF_BRIDGED_DNAT;
+- return dst->neighbour->output(skb);
++ return neigh->output(skb);
+ }
+ free_skb:
+ kfree_skb(skb);
+--- a/net/core/dst.c
++++ b/net/core/dst.c
+@@ -171,7 +171,7 @@ void *dst_alloc(struct dst_ops *ops, str
+ dst_init_metrics(dst, dst_default_metrics, true);
+ dst->expires = 0UL;
+ dst->path = dst;
+- dst->neighbour = NULL;
++ RCU_INIT_POINTER(dst->_neighbour, NULL);
+ dst->hh = NULL;
+ #ifdef CONFIG_XFRM
+ dst->xfrm = NULL;
+@@ -231,7 +231,7 @@ struct dst_entry *dst_destroy(struct dst
+ smp_rmb();
+
+ again:
+- neigh = dst->neighbour;
++ neigh = rcu_dereference_protected(dst->_neighbour, 1);
+ hh = dst->hh;
+ child = dst->child;
+
+@@ -240,7 +240,7 @@ again:
+ hh_cache_put(hh);
+
+ if (neigh) {
+- dst->neighbour = NULL;
++ RCU_INIT_POINTER(dst->_neighbour, NULL);
+ neigh_release(neigh);
+ }
+
+@@ -367,14 +367,19 @@ static void dst_ifdown(struct dst_entry
+ if (!unregister) {
+ dst->input = dst->output = dst_discard;
+ } else {
++ struct neighbour *neigh;
++
+ dst->dev = dev_net(dst->dev)->loopback_dev;
+ dev_hold(dst->dev);
+ dev_put(dev);
+- if (dst->neighbour && dst->neighbour->dev == dev) {
+- dst->neighbour->dev = dst->dev;
++ rcu_read_lock();
++ neigh = dst_get_neighbour(dst);
++ if (neigh && neigh->dev == dev) {
++ neigh->dev = dst->dev;
+ dev_hold(dst->dev);
+ dev_put(dev);
+ }
++ rcu_read_unlock();
+ }
+ }
+
+--- a/net/core/neighbour.c
++++ b/net/core/neighbour.c
+@@ -1173,12 +1173,17 @@ int neigh_update(struct neighbour *neigh
+
+ while (neigh->nud_state & NUD_VALID &&
+ (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
+- struct neighbour *n1 = neigh;
++ struct dst_entry *dst = skb_dst(skb);
++ struct neighbour *n2, *n1 = neigh;
+ write_unlock_bh(&neigh->lock);
++
++ rcu_read_lock();
+ /* On shaper/eql skb->dst->neighbour != neigh :( */
+- if (skb_dst(skb) && skb_dst(skb)->neighbour)
+- n1 = skb_dst(skb)->neighbour;
++ if (dst && (n2 = dst_get_neighbour(dst)) != NULL)
++ n1 = n2;
+ n1->output(skb);
++ rcu_read_unlock();
++
+ write_lock_bh(&neigh->lock);
+ }
+ skb_queue_purge(&neigh->arp_queue);
+@@ -1300,10 +1305,10 @@ EXPORT_SYMBOL(neigh_compat_output);
+ int neigh_resolve_output(struct sk_buff *skb)
+ {
+ struct dst_entry *dst = skb_dst(skb);
+- struct neighbour *neigh;
++ struct neighbour *neigh = dst_get_neighbour(dst);
+ int rc = 0;
+
+- if (!dst || !(neigh = dst->neighbour))
++ if (!dst)
+ goto discard;
+
+ __skb_pull(skb, skb_network_offset(skb));
+@@ -1333,7 +1338,7 @@ out:
+ return rc;
+ discard:
+ NEIGH_PRINTK1("neigh_resolve_output: dst=%p neigh=%p\n",
+- dst, dst ? dst->neighbour : NULL);
++ dst, neigh);
+ out_kfree_skb:
+ rc = -EINVAL;
+ kfree_skb(skb);
+@@ -1347,7 +1352,7 @@ int neigh_connected_output(struct sk_buf
+ {
+ int err;
+ struct dst_entry *dst = skb_dst(skb);
+- struct neighbour *neigh = dst->neighbour;
++ struct neighbour *neigh = dst_get_neighbour(dst);
+ struct net_device *dev = neigh->dev;
+ unsigned int seq;
+
+--- a/net/decnet/dn_neigh.c
++++ b/net/decnet/dn_neigh.c
+@@ -208,7 +208,7 @@ static int dn_neigh_output_packet(struct
+ {
+ struct dst_entry *dst = skb_dst(skb);
+ struct dn_route *rt = (struct dn_route *)dst;
+- struct neighbour *neigh = dst->neighbour;
++ struct neighbour *neigh = dst_get_neighbour(dst);
+ struct net_device *dev = neigh->dev;
+ char mac_addr[ETH_ALEN];
+
+@@ -227,7 +227,7 @@ static int dn_neigh_output_packet(struct
+ static int dn_long_output(struct sk_buff *skb)
+ {
+ struct dst_entry *dst = skb_dst(skb);
+- struct neighbour *neigh = dst->neighbour;
++ struct neighbour *neigh = dst_get_neighbour(dst);
+ struct net_device *dev = neigh->dev;
+ int headroom = dev->hard_header_len + sizeof(struct dn_long_packet) + 3;
+ unsigned char *data;
+@@ -274,7 +274,7 @@ static int dn_long_output(struct sk_buff
+ static int dn_short_output(struct sk_buff *skb)
+ {
+ struct dst_entry *dst = skb_dst(skb);
+- struct neighbour *neigh = dst->neighbour;
++ struct neighbour *neigh = dst_get_neighbour(dst);
+ struct net_device *dev = neigh->dev;
+ int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2;
+ struct dn_short_packet *sp;
+@@ -318,7 +318,7 @@ static int dn_short_output(struct sk_buf
+ static int dn_phase3_output(struct sk_buff *skb)
+ {
+ struct dst_entry *dst = skb_dst(skb);
+- struct neighbour *neigh = dst->neighbour;
++ struct neighbour *neigh = dst_get_neighbour(dst);
+ struct net_device *dev = neigh->dev;
+ int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2;
+ struct dn_short_packet *sp;
+--- a/net/decnet/dn_route.c
++++ b/net/decnet/dn_route.c
+@@ -241,9 +241,11 @@ static int dn_dst_gc(struct dst_ops *ops
+ */
+ static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu)
+ {
++ struct neighbour *n = dst_get_neighbour(dst);
+ u32 min_mtu = 230;
+- struct dn_dev *dn = dst->neighbour ?
+- rcu_dereference_raw(dst->neighbour->dev->dn_ptr) : NULL;
++ struct dn_dev *dn;
++
++ dn = n ? rcu_dereference_raw(n->dev->dn_ptr) : NULL;
+
+ if (dn && dn->use_long == 0)
+ min_mtu -= 6;
+@@ -715,7 +717,7 @@ static int dn_output(struct sk_buff *skb
+
+ int err = -EINVAL;
+
+- if ((neigh = dst->neighbour) == NULL)
++ if ((neigh = dst_get_neighbour(dst)) == NULL)
+ goto error;
+
+ skb->dev = dev;
+@@ -750,7 +752,7 @@ static int dn_forward(struct sk_buff *sk
+ struct dst_entry *dst = skb_dst(skb);
+ struct dn_dev *dn_db = rcu_dereference(dst->dev->dn_ptr);
+ struct dn_route *rt;
+- struct neighbour *neigh = dst->neighbour;
++ struct neighbour *neigh = dst_get_neighbour(dst);
+ int header_len;
+ #ifdef CONFIG_NETFILTER
+ struct net_device *dev = skb->dev;
+@@ -833,11 +835,11 @@ static int dn_rt_set_next_hop(struct dn_
+ }
+ rt->rt_type = res->type;
+
+- if (dev != NULL && rt->dst.neighbour == NULL) {
++ if (dev != NULL && dst_get_neighbour(&rt->dst) == NULL) {
+ n = __neigh_lookup_errno(&dn_neigh_table, &rt->rt_gateway, dev);
+ if (IS_ERR(n))
+ return PTR_ERR(n);
+- rt->dst.neighbour = n;
++ dst_set_neighbour(&rt->dst, n);
+ }
+
+ if (dst_metric(&rt->dst, RTAX_MTU) > rt->dst.dev->mtu)
+@@ -1144,7 +1146,7 @@ make_route:
+ rt->rt_dst_map = fld.daddr;
+ rt->rt_src_map = fld.saddr;
+
+- rt->dst.neighbour = neigh;
++ dst_set_neighbour(&rt->dst, neigh);
+ neigh = NULL;
+
+ rt->dst.lastuse = jiffies;
+@@ -1416,7 +1418,7 @@ make_route:
+ rt->fld.flowidn_iif = in_dev->ifindex;
+ rt->fld.flowidn_mark = fld.flowidn_mark;
+
+- rt->dst.neighbour = neigh;
++ dst_set_neighbour(&rt->dst, neigh);
+ rt->dst.lastuse = jiffies;
+ rt->dst.output = dn_rt_bug;
+ switch(res.type) {
+--- a/net/ipv4/arp.c
++++ b/net/ipv4/arp.c
+@@ -518,26 +518,32 @@ EXPORT_SYMBOL(arp_find);
+
+ /* END OF OBSOLETE FUNCTIONS */
+
++struct neighbour *__arp_bind_neighbour(struct dst_entry *dst, __be32 nexthop)
++{
++ struct net_device *dev = dst->dev;
++
++ if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT))
++ nexthop = 0;
++ return __neigh_lookup_errno(
++#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
++ dev->type == ARPHRD_ATM ?
++ clip_tbl_hook :
++#endif
++ &arp_tbl, &nexthop, dev);
++}
++
+ int arp_bind_neighbour(struct dst_entry *dst)
+ {
+ struct net_device *dev = dst->dev;
+- struct neighbour *n = dst->neighbour;
++ struct neighbour *n = dst_get_neighbour(dst);
+
+ if (dev == NULL)
+ return -EINVAL;
+ if (n == NULL) {
+- __be32 nexthop = ((struct rtable *)dst)->rt_gateway;
+- if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT))
+- nexthop = 0;
+- n = __neigh_lookup_errno(
+-#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
+- dev->type == ARPHRD_ATM ?
+- clip_tbl_hook :
+-#endif
+- &arp_tbl, &nexthop, dev);
++ n = __arp_bind_neighbour(dst, ((struct rtable *)dst)->rt_gateway);
+ if (IS_ERR(n))
+ return PTR_ERR(n);
+- dst->neighbour = n;
++ dst_set_neighbour(dst, n);
+ }
+ return 0;
+ }
+--- a/net/ipv4/ip_gre.c
++++ b/net/ipv4/ip_gre.c
+@@ -731,9 +731,9 @@ static netdev_tx_t ipgre_tunnel_xmit(str
+ }
+ #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ else if (skb->protocol == htons(ETH_P_IPV6)) {
++ struct neighbour *neigh = dst_get_neighbour(skb_dst(skb));
+ const struct in6_addr *addr6;
+ int addr_type;
+- struct neighbour *neigh = skb_dst(skb)->neighbour;
+
+ if (neigh == NULL)
+ goto tx_error;
+--- a/net/ipv4/ip_output.c
++++ b/net/ipv4/ip_output.c
+@@ -182,6 +182,8 @@ static inline int ip_finish_output2(stru
+ struct rtable *rt = (struct rtable *)dst;
+ struct net_device *dev = dst->dev;
+ unsigned int hh_len = LL_RESERVED_SPACE(dev);
++ struct neighbour *neigh;
++ int res;
+
+ if (rt->rt_type == RTN_MULTICAST) {
+ IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUTMCAST, skb->len);
+@@ -202,11 +204,23 @@ static inline int ip_finish_output2(stru
+ kfree_skb(skb);
+ skb = skb2;
+ }
++
++ rcu_read_lock();
++ if (dst->hh) {
++ int res = neigh_hh_output(dst->hh, skb);
+
+- if (dst->hh)
+- return neigh_hh_output(dst->hh, skb);
+- else if (dst->neighbour)
+- return dst->neighbour->output(skb);
++ rcu_read_unlock();
++ return res;
++ } else {
++ neigh = dst_get_neighbour(dst);
++ if (neigh) {
++ res = neigh->output(skb);
++
++ rcu_read_unlock();
++ return res;
++ }
++ rcu_read_unlock();
++ }
+
+ if (net_ratelimit())
+ printk(KERN_DEBUG "ip_finish_output2: No header cache and no neighbour!\n");
+--- a/net/ipv4/route.c
++++ b/net/ipv4/route.c
+@@ -416,7 +416,13 @@ static int rt_cache_seq_show(struct seq_
+ "HHUptod\tSpecDst");
+ else {
+ struct rtable *r = v;
+- int len;
++ struct neighbour *n;
++ int len, HHUptod;
++
++ rcu_read_lock();
++ n = dst_get_neighbour(&r->dst);
++ HHUptod = (n && (n->nud_state & NUD_CONNECTED)) ? 1 : 0;
++ rcu_read_unlock();
+
+ seq_printf(seq, "%s\t%08X\t%08X\t%8X\t%d\t%u\t%d\t"
+ "%08X\t%d\t%u\t%u\t%02X\t%d\t%1d\t%08X%n",
+@@ -431,8 +437,7 @@ static int rt_cache_seq_show(struct seq_
+ dst_metric(&r->dst, RTAX_RTTVAR)),
+ r->rt_key_tos,
+ r->dst.hh ? atomic_read(&r->dst.hh->hh_refcnt) : -1,
+- r->dst.hh ? (r->dst.hh->hh_output ==
+- dev_queue_xmit) : 0,
++ HHUptod,
+ r->rt_spec_dst, &len);
+
+ seq_printf(seq, "%*s\n", 127 - len, "");
+@@ -1688,23 +1693,25 @@ static int check_peer_redir(struct dst_e
+ {
+ struct rtable *rt = (struct rtable *) dst;
+ __be32 orig_gw = rt->rt_gateway;
++ struct neighbour *n, *old_n;
+
+ dst_confirm(&rt->dst);
+
+- neigh_release(rt->dst.neighbour);
+- rt->dst.neighbour = NULL;
+-
+ rt->rt_gateway = peer->redirect_learned.a4;
+- if (arp_bind_neighbour(&rt->dst) ||
+- !(rt->dst.neighbour->nud_state & NUD_VALID)) {
+- if (rt->dst.neighbour)
+- neigh_event_send(rt->dst.neighbour, NULL);
++ n = __arp_bind_neighbour(&rt->dst, rt->rt_gateway);
++ if (IS_ERR(n))
++ return PTR_ERR(n);
++ old_n = xchg(&rt->dst._neighbour, n);
++ if (old_n)
++ neigh_release(old_n);
++ if (!n || !(n->nud_state & NUD_VALID)) {
++ if (n)
++ neigh_event_send(n, NULL);
+ rt->rt_gateway = orig_gw;
+ return -EAGAIN;
+ } else {
+ rt->rt_flags |= RTCF_REDIRECTED;
+- call_netevent_notifiers(NETEVENT_NEIGH_UPDATE,
+- rt->dst.neighbour);
++ call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, n);
+ }
+ return 0;
+ }
+--- a/net/ipv6/addrconf.c
++++ b/net/ipv6/addrconf.c
+@@ -656,7 +656,7 @@ ipv6_add_addr(struct inet6_dev *idev, co
+ * layer address of our nexhop router
+ */
+
+- if (rt->rt6i_nexthop == NULL)
++ if (dst_get_neighbour_raw(&rt->dst) == NULL)
+ ifa->flags &= ~IFA_F_OPTIMISTIC;
+
+ ifa->idev = idev;
+--- a/net/ipv6/ip6_fib.c
++++ b/net/ipv6/ip6_fib.c
+@@ -1455,7 +1455,7 @@ static int fib6_age(struct rt6_info *rt,
+ RT6_TRACE("aging clone %p\n", rt);
+ return -1;
+ } else if ((rt->rt6i_flags & RTF_GATEWAY) &&
+- (!(rt->rt6i_nexthop->flags & NTF_ROUTER))) {
++ (!(dst_get_neighbour_raw(&rt->dst)->flags & NTF_ROUTER))) {
+ RT6_TRACE("purging route %p via non-router but gateway\n",
+ rt);
+ return -1;
+--- a/net/ipv6/ip6_output.c
++++ b/net/ipv6/ip6_output.c
+@@ -100,6 +100,8 @@ static int ip6_finish_output2(struct sk_
+ {
+ struct dst_entry *dst = skb_dst(skb);
+ struct net_device *dev = dst->dev;
++ struct neighbour *neigh;
++ int res;
+
+ skb->protocol = htons(ETH_P_IPV6);
+ skb->dev = dev;
+@@ -134,10 +136,22 @@ static int ip6_finish_output2(struct sk_
+ skb->len);
+ }
+
+- if (dst->hh)
+- return neigh_hh_output(dst->hh, skb);
+- else if (dst->neighbour)
+- return dst->neighbour->output(skb);
++ rcu_read_lock();
++ if (dst->hh) {
++ res = neigh_hh_output(dst->hh, skb);
++
++ rcu_read_unlock();
++ return res;
++ } else {
++ neigh = dst_get_neighbour(dst);
++ if (neigh) {
++ res = neigh->output(skb);
++
++ rcu_read_unlock();
++ return res;
++ }
++ rcu_read_unlock();
++ }
+
+ IP6_INC_STATS_BH(dev_net(dst->dev),
+ ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
+@@ -385,6 +399,7 @@ int ip6_forward(struct sk_buff *skb)
+ struct ipv6hdr *hdr = ipv6_hdr(skb);
+ struct inet6_skb_parm *opt = IP6CB(skb);
+ struct net *net = dev_net(dst->dev);
++ struct neighbour *n;
+ u32 mtu;
+
+ if (net->ipv6.devconf_all->forwarding == 0)
+@@ -459,11 +474,10 @@ int ip6_forward(struct sk_buff *skb)
+ send redirects to source routed frames.
+ We don't send redirects to frames decapsulated from IPsec.
+ */
+- if (skb->dev == dst->dev && dst->neighbour && opt->srcrt == 0 &&
+- !skb_sec_path(skb)) {
++ n = dst_get_neighbour(dst);
++ if (skb->dev == dst->dev && n && opt->srcrt == 0 && !skb_sec_path(skb)) {
+ struct in6_addr *target = NULL;
+ struct rt6_info *rt;
+- struct neighbour *n = dst->neighbour;
+
+ /*
+ * incoming and outgoing devices are the same
+@@ -949,8 +963,11 @@ out:
+ static int ip6_dst_lookup_tail(struct sock *sk,
+ struct dst_entry **dst, struct flowi6 *fl6)
+ {
+- int err;
+ struct net *net = sock_net(sk);
++#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
++ struct neighbour *n;
++#endif
++ int err;
+
+ if (*dst == NULL)
+ *dst = ip6_route_output(net, sk, fl6);
+@@ -976,11 +993,14 @@ static int ip6_dst_lookup_tail(struct so
+ * dst entry and replace it instead with the
+ * dst entry of the nexthop router
+ */
+- if ((*dst)->neighbour && !((*dst)->neighbour->nud_state & NUD_VALID)) {
++ rcu_read_lock();
++ n = dst_get_neighbour(*dst);
++ if (n && !(n->nud_state & NUD_VALID)) {
+ struct inet6_ifaddr *ifp;
+ struct flowi6 fl_gw6;
+ int redirect;
+
++ rcu_read_unlock();
+ ifp = ipv6_get_ifaddr(net, &fl6->saddr,
+ (*dst)->dev, 1);
+
+@@ -1000,6 +1020,8 @@ static int ip6_dst_lookup_tail(struct so
+ if ((err = (*dst)->error))
+ goto out_err_release;
+ }
++ } else {
++ rcu_read_unlock();
+ }
+ #endif
+
+--- a/net/ipv6/ndisc.c
++++ b/net/ipv6/ndisc.c
+@@ -1244,7 +1244,7 @@ static void ndisc_router_discovery(struc
+ rt = rt6_get_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev);
+
+ if (rt)
+- neigh = rt->rt6i_nexthop;
++ neigh = dst_get_neighbour(&rt->dst);
+
+ if (rt && lifetime == 0) {
+ neigh_clone(neigh);
+@@ -1265,7 +1265,7 @@ static void ndisc_router_discovery(struc
+ return;
+ }
+
+- neigh = rt->rt6i_nexthop;
++ neigh = dst_get_neighbour(&rt->dst);
+ if (neigh == NULL) {
+ ND_PRINTK0(KERN_ERR
+ "ICMPv6 RA: %s() got default router without neighbour.\n",
+--- a/net/ipv6/route.c
++++ b/net/ipv6/route.c
+@@ -356,7 +356,7 @@ out:
+ #ifdef CONFIG_IPV6_ROUTER_PREF
+ static void rt6_probe(struct rt6_info *rt)
+ {
+- struct neighbour *neigh = rt ? rt->rt6i_nexthop : NULL;
++ struct neighbour *neigh;
+ /*
+ * Okay, this does not seem to be appropriate
+ * for now, however, we need to check if it
+@@ -365,8 +365,10 @@ static void rt6_probe(struct rt6_info *r
+ * Router Reachability Probe MUST be rate-limited
+ * to no more than one per minute.
+ */
++ rcu_read_lock();
++ neigh = rt ? dst_get_neighbour(&rt->dst) : NULL;
+ if (!neigh || (neigh->nud_state & NUD_VALID))
+- return;
++ goto out;
+ read_lock_bh(&neigh->lock);
+ if (!(neigh->nud_state & NUD_VALID) &&
+ time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) {
+@@ -379,8 +381,11 @@ static void rt6_probe(struct rt6_info *r
+ target = (struct in6_addr *)&neigh->primary_key;
+ addrconf_addr_solict_mult(target, &mcaddr);
+ ndisc_send_ns(rt->rt6i_dev, NULL, target, &mcaddr, NULL);
+- } else
++ } else {
+ read_unlock_bh(&neigh->lock);
++ }
++out:
++ rcu_read_unlock();
+ }
+ #else
+ static inline void rt6_probe(struct rt6_info *rt)
+@@ -404,8 +409,11 @@ static inline int rt6_check_dev(struct r
+
+ static inline int rt6_check_neigh(struct rt6_info *rt)
+ {
+- struct neighbour *neigh = rt->rt6i_nexthop;
++ struct neighbour *neigh;
+ int m;
++
++ rcu_read_lock();
++ neigh = dst_get_neighbour(&rt->dst);
+ if (rt->rt6i_flags & RTF_NONEXTHOP ||
+ !(rt->rt6i_flags & RTF_GATEWAY))
+ m = 1;
+@@ -422,6 +430,7 @@ static inline int rt6_check_neigh(struct
+ read_unlock_bh(&neigh->lock);
+ } else
+ m = 0;
++ rcu_read_unlock();
+ return m;
+ }
+
+@@ -745,8 +754,7 @@ static struct rt6_info *rt6_alloc_cow(st
+ dst_free(&rt->dst);
+ return NULL;
+ }
+- rt->rt6i_nexthop = neigh;
+-
++ dst_set_neighbour(&rt->dst, neigh);
+ }
+
+ return rt;
+@@ -760,7 +768,7 @@ static struct rt6_info *rt6_alloc_clone(
+ rt->rt6i_dst.plen = 128;
+ rt->rt6i_flags |= RTF_CACHE;
+ rt->dst.flags |= DST_HOST;
+- rt->rt6i_nexthop = neigh_clone(ort->rt6i_nexthop);
++ dst_set_neighbour(&rt->dst, neigh_clone(dst_get_neighbour_raw(&ort->dst)));
+ }
+ return rt;
+ }
+@@ -794,7 +802,7 @@ restart:
+ dst_hold(&rt->dst);
+ read_unlock_bh(&table->tb6_lock);
+
+- if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP))
++ if (!dst_get_neighbour_raw(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP))
+ nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr);
+ else if (!(rt->dst.flags & DST_HOST))
+ nrt = rt6_alloc_clone(rt, &fl6->daddr);
+@@ -1058,7 +1066,7 @@ struct dst_entry *icmp6_dst_alloc(struct
+ }
+
+ rt->rt6i_idev = idev;
+- rt->rt6i_nexthop = neigh;
++ dst_set_neighbour(&rt->dst, neigh);
+ atomic_set(&rt->dst.__refcnt, 1);
+ dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 255);
+ rt->dst.output = ip6_output;
+@@ -1338,12 +1346,12 @@ int ip6_route_add(struct fib6_config *cf
+ rt->rt6i_prefsrc.plen = 0;
+
+ if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) {
+- rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev);
+- if (IS_ERR(rt->rt6i_nexthop)) {
+- err = PTR_ERR(rt->rt6i_nexthop);
+- rt->rt6i_nexthop = NULL;
++ struct neighbour *neigh = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev);
++ if (IS_ERR(neigh)) {
++ err = PTR_ERR(neigh);
+ goto out;
+ }
++ dst_set_neighbour(&rt->dst, neigh);
+ }
+
+ rt->rt6i_flags = cfg->fc_flags;
+@@ -1574,7 +1582,7 @@ void rt6_redirect(const struct in6_addr
+ dst_confirm(&rt->dst);
+
+ /* Duplicate redirect: silently ignore. */
+- if (neigh == rt->dst.neighbour)
++ if (neigh == dst_get_neighbour_raw(&rt->dst))
+ goto out;
+
+ nrt = ip6_rt_copy(rt);
+@@ -1590,7 +1598,7 @@ void rt6_redirect(const struct in6_addr
+ nrt->dst.flags |= DST_HOST;
+
+ ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key);
+- nrt->rt6i_nexthop = neigh_clone(neigh);
++ dst_set_neighbour(&nrt->dst, neigh_clone(neigh));
+
+ if (ip6_ins_rt(nrt))
+ goto out;
+@@ -1670,7 +1678,7 @@ again:
+ 1. It is connected route. Action: COW
+ 2. It is gatewayed route or NONEXTHOP route. Action: clone it.
+ */
+- if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP))
++ if (!dst_get_neighbour_raw(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP))
+ nrt = rt6_alloc_cow(rt, daddr, saddr);
+ else
+ nrt = rt6_alloc_clone(rt, daddr);
+@@ -2035,7 +2043,7 @@ struct rt6_info *addrconf_dst_alloc(stru
+
+ return ERR_CAST(neigh);
+ }
+- rt->rt6i_nexthop = neigh;
++ dst_set_neighbour(&rt->dst, neigh);
+
+ ipv6_addr_copy(&rt->rt6i_dst.addr, addr);
+ rt->rt6i_dst.plen = 128;
+@@ -2312,6 +2320,7 @@ static int rt6_fill_node(struct net *net
+ struct nlmsghdr *nlh;
+ long expires;
+ u32 table;
++ struct neighbour *n;
+
+ if (prefix) { /* user wants prefix routes only */
+ if (!(rt->rt6i_flags & RTF_PREFIX_RT)) {
+@@ -2400,8 +2409,11 @@ static int rt6_fill_node(struct net *net
+ if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0)
+ goto nla_put_failure;
+
+- if (rt->dst.neighbour)
+- NLA_PUT(skb, RTA_GATEWAY, 16, &rt->dst.neighbour->primary_key);
++ rcu_read_lock();
++ n = dst_get_neighbour(&rt->dst);
++ if (n)
++ NLA_PUT(skb, RTA_GATEWAY, 16, &n->primary_key);
++ rcu_read_unlock();
+
+ if (rt->dst.dev)
+ NLA_PUT_U32(skb, RTA_OIF, rt->rt6i_dev->ifindex);
+@@ -2585,6 +2597,7 @@ struct rt6_proc_arg
+ static int rt6_info_route(struct rt6_info *rt, void *p_arg)
+ {
+ struct seq_file *m = p_arg;
++ struct neighbour *n;
+
+ seq_printf(m, "%pi6 %02x ", &rt->rt6i_dst.addr, rt->rt6i_dst.plen);
+
+@@ -2593,12 +2606,14 @@ static int rt6_info_route(struct rt6_inf
+ #else
+ seq_puts(m, "00000000000000000000000000000000 00 ");
+ #endif
+-
+- if (rt->rt6i_nexthop) {
+- seq_printf(m, "%pi6", rt->rt6i_nexthop->primary_key);
++ rcu_read_lock();
++ n = dst_get_neighbour(&rt->dst);
++ if (n) {
++ seq_printf(m, "%pi6", n->primary_key);
+ } else {
+ seq_puts(m, "00000000000000000000000000000000");
+ }
++ rcu_read_unlock();
+ seq_printf(m, " %08x %08x %08x %08x %8s\n",
+ rt->rt6i_metric, atomic_read(&rt->dst.__refcnt),
+ rt->dst.__use, rt->rt6i_flags,
+--- a/net/ipv6/sit.c
++++ b/net/ipv6/sit.c
+@@ -679,7 +679,7 @@ static netdev_tx_t ipip6_tunnel_xmit(str
+ struct neighbour *neigh = NULL;
+
+ if (skb_dst(skb))
+- neigh = skb_dst(skb)->neighbour;
++ neigh = dst_get_neighbour(skb_dst(skb));
+
+ if (neigh == NULL) {
+ if (net_ratelimit())
+@@ -704,7 +704,7 @@ static netdev_tx_t ipip6_tunnel_xmit(str
+ struct neighbour *neigh = NULL;
+
+ if (skb_dst(skb))
+- neigh = skb_dst(skb)->neighbour;
++ neigh = dst_get_neighbour(skb_dst(skb));
+
+ if (neigh == NULL) {
+ if (net_ratelimit())
+--- a/net/sched/sch_teql.c
++++ b/net/sched/sch_teql.c
+@@ -225,11 +225,11 @@ static int teql_qdisc_init(struct Qdisc
+
+
+ static int
+-__teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res, struct net_device *dev)
++__teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res,
++ struct net_device *dev, struct netdev_queue *txq,
++ struct neighbour *mn)
+ {
+- struct netdev_queue *dev_queue = netdev_get_tx_queue(dev, 0);
+- struct teql_sched_data *q = qdisc_priv(dev_queue->qdisc);
+- struct neighbour *mn = skb_dst(skb)->neighbour;
++ struct teql_sched_data *q = qdisc_priv(txq->qdisc);
+ struct neighbour *n = q->ncache;
+
+ if (mn->tbl == NULL)
+@@ -262,17 +262,26 @@ __teql_resolve(struct sk_buff *skb, stru
+ }
+
+ static inline int teql_resolve(struct sk_buff *skb,
+- struct sk_buff *skb_res, struct net_device *dev)
++ struct sk_buff *skb_res,
++ struct net_device *dev,
++ struct netdev_queue *txq)
+ {
+- struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
++ struct dst_entry *dst = skb_dst(skb);
++ struct neighbour *mn;
++ int res;
++
+ if (txq->qdisc == &noop_qdisc)
+ return -ENODEV;
+
+- if (dev->header_ops == NULL ||
+- skb_dst(skb) == NULL ||
+- skb_dst(skb)->neighbour == NULL)
++ if (!dev->header_ops || !dst)
+ return 0;
+- return __teql_resolve(skb, skb_res, dev);
++
++ rcu_read_lock();
++ mn = dst_get_neighbour(dst);
++ res = mn ? __teql_resolve(skb, skb_res, dev, txq, mn) : 0;
++ rcu_read_unlock();
++
++ return res;
+ }
+
+ static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev)
+@@ -307,7 +316,7 @@ restart:
+ continue;
+ }
+
+- switch (teql_resolve(skb, skb_res, slave)) {
++ switch (teql_resolve(skb, skb_res, slave, slave_txq)) {
+ case 0:
+ if (__netif_tx_trylock(slave_txq)) {
+ unsigned int length = qdisc_pkt_len(skb);
+--- a/net/xfrm/xfrm_policy.c
++++ b/net/xfrm/xfrm_policy.c
+@@ -1497,7 +1497,7 @@ static struct dst_entry *xfrm_bundle_cre
+ goto free_dst;
+
+ /* Copy neighbour for reachability confirmation */
+- dst0->neighbour = neigh_clone(dst->neighbour);
++ dst_set_neighbour(dst0, neigh_clone(dst_get_neighbour(dst)));
+
+ xfrm_init_path((struct xfrm_dst *)dst0, dst, nfheader_len);
+ xfrm_init_pmtu(dst_prev);