We will allocate per-netns neigh_table in net->neigh_tables[]. Let's replace &arp_tbl with arp_table(net) and remove extern definition for arp_tbl. Three notes: 1. mlx5e_rep_netevent_event() and nfp_tun_neigh_event_handler() have code assuming neigh_table other than &arp_tbl and &nb_tbl, and the part is removed as it will be false once per-netns table is allocated. 2. prestera and rocker uses init_net because they set dev->netns_immutable to true. 3. mlx5e_tc_update_neigh_used_value() dereferences nhe->neigh_dev in trace_mlx5e_tc_update_neigh_used_value(). Signed-off-by: Kuniyuki Iwashima --- v2: Add note about mlx5e_tc_update_neigh_used_value() Cc: Jason Gunthorpe Cc: Leon Romanovsky Cc: Elad Nachman Cc: Saeed Mahameed Cc: Tariq Toukan Cc: Mark Bloch Cc: Boris Pismenny Cc: Petr Machata Cc: Jiri Pirko Cc: Edward Cree Cc: Nikolay Aleksandrov --- drivers/infiniband/ulp/ipoib/ipoib_main.c | 27 ++++-- .../marvell/prestera/prestera_router.c | 10 ++- .../mellanox/mlx5/core/en/rep/neigh.c | 22 ++--- .../mellanox/mlx5/core/en/tc_tun_encap.c | 23 ++--- .../mellanox/mlx5/core/en_accel/ipsec.c | 6 +- .../ethernet/mellanox/mlxsw/spectrum_router.c | 18 ++-- .../ethernet/mellanox/mlxsw/spectrum_span.c | 5 +- .../netronome/nfp/flower/tunnel_conf.c | 10 +-- drivers/net/ethernet/rocker/rocker_main.c | 2 +- drivers/net/ethernet/rocker/rocker_ofdpa.c | 2 +- drivers/net/ethernet/sfc/tc_counters.c | 6 +- drivers/net/ethernet/sfc/tc_encap_actions.c | 2 +- drivers/net/vxlan/vxlan_core.c | 10 ++- include/net/arp.h | 6 +- include/net/route.h | 7 +- net/bridge/br_arp_nd_proxy.c | 2 +- net/ipv4/arp.c | 88 +++++++++++-------- net/ipv4/devinet.c | 18 ++-- net/ipv4/fib_semantics.c | 5 +- net/ipv4/route.c | 2 +- 20 files changed, 159 insertions(+), 112 deletions(-) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 16a015b67206..895a3e3f7310 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -1378,7 +1378,8 @@ struct ipoib_neigh *ipoib_neigh_get(struct net_device *dev, u8 *daddr) return neigh; } -static void __ipoib_reap_neigh(struct ipoib_dev_priv *priv) +static void __ipoib_reap_neigh(struct ipoib_dev_priv *priv, + int gc_interval) { struct ipoib_neigh_table *ntbl = &priv->ntbl; struct ipoib_neigh_hash *htbl; @@ -1397,7 +1398,7 @@ static void __ipoib_reap_neigh(struct ipoib_dev_priv *priv) goto out_unlock; /* neigh is obsolete if it was idle for two GC periods */ - dt = 2 * arp_tbl.gc_interval; + dt = 2 * gc_interval; neigh_obsolete = jiffies - dt; for (i = 0; i < htbl->size; i++) { @@ -1433,11 +1434,16 @@ static void ipoib_reap_neigh(struct work_struct *work) { struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv, neigh_reap_task.work); + struct net_device *dev = priv->dev; + struct net *net = dev_net(dev); + struct neigh_table *tbl; + int gc_interval; - __ipoib_reap_neigh(priv); + tbl = arp_table(net); + gc_interval = tbl->gc_interval; + __ipoib_reap_neigh(priv, gc_interval); - queue_delayed_work(priv->wq, &priv->neigh_reap_task, - arp_tbl.gc_interval); + queue_delayed_work(priv->wq, &priv->neigh_reap_task, gc_interval); } @@ -1590,8 +1596,11 @@ void ipoib_neigh_free(struct ipoib_neigh *neigh) static int ipoib_neigh_hash_init(struct ipoib_dev_priv *priv) { struct ipoib_neigh_table *ntbl = &priv->ntbl; - struct ipoib_neigh_hash *htbl; struct ipoib_neigh __rcu **buckets; + struct net_device *dev = priv->dev; + struct net *net = dev_net(dev); + struct ipoib_neigh_hash *htbl; + struct neigh_table *tbl; u32 size; clear_bit(IPOIB_NEIGH_TBL_FLUSH, &priv->flags); @@ -1599,7 +1608,9 @@ static int ipoib_neigh_hash_init(struct ipoib_dev_priv *priv) htbl = kzalloc_obj(*htbl); if (!htbl) return -ENOMEM; - size = roundup_pow_of_two(arp_tbl.gc_thresh3); + + tbl = arp_table(net); + size = roundup_pow_of_two(tbl->gc_thresh3); buckets = kvzalloc_objs(*buckets, size); if (!buckets) { kfree(htbl); @@ -1614,7 +1625,7 @@ static int ipoib_neigh_hash_init(struct ipoib_dev_priv *priv) /* start garbage collection */ queue_delayed_work(priv->wq, &priv->neigh_reap_task, - arp_tbl.gc_interval); + tbl->gc_interval); return 0; } diff --git a/drivers/net/ethernet/marvell/prestera/prestera_router.c b/drivers/net/ethernet/marvell/prestera/prestera_router.c index 0c4f462baa6e..ba45b61b09bb 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_router.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_router.c @@ -683,7 +683,7 @@ __prestera_k_arb_n_offload_set(struct prestera_switch *sw, { struct neighbour *n; - n = neigh_lookup(&arp_tbl, &nc->key.addr.u.ipv4, + n = neigh_lookup(arp_table(&init_net), &nc->key.addr.u.ipv4, nc->key.dev); if (!n) return; @@ -790,7 +790,7 @@ __prestera_k_arb_nc_kern_n_fetch(struct prestera_switch *sw, int err; memset(&nc->nh_neigh_info, 0, sizeof(nc->nh_neigh_info)); - n = neigh_lookup(&arp_tbl, &nc->key.addr.u.ipv4, nc->key.dev); + n = neigh_lookup(arp_table(&init_net), &nc->key.addr.u.ipv4, nc->key.dev); if (!n) goto out; @@ -1052,10 +1052,12 @@ static void __prestera_k_arb_hw_state_upd(struct prestera_switch *sw, #endif /* PRESTERA_IMPLICITY_RESOLVE_DEAD_NEIGH */ if (nc->key.addr.v == PRESTERA_IPV4) { - n = neigh_lookup(&arp_tbl, &nc->key.addr.u.ipv4, + struct neigh_table *tbl = arp_table(&init_net); + + n = neigh_lookup(tbl, &nc->key.addr.u.ipv4, nc->key.dev); if (!n) - n = neigh_create(&arp_tbl, &nc->key.addr.u.ipv4, + n = neigh_create(tbl, &nc->key.addr.u.ipv4, nc->key.dev); } else { n = NULL; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/neigh.c b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/neigh.c index 648f4521c096..9894a0527789 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/neigh.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/neigh.c @@ -27,10 +27,16 @@ static unsigned long mlx5e_rep_ipv6_interval(void) static void mlx5e_rep_neigh_update_init_interval(struct mlx5e_rep_priv *rpriv) { - unsigned long ipv4_interval = NEIGH_VAR(&arp_tbl.parms, DELAY_PROBE_TIME); unsigned long ipv6_interval = mlx5e_rep_ipv6_interval(); struct net_device *netdev = rpriv->netdev; - struct mlx5e_priv *priv = netdev_priv(netdev); + struct net *net = dev_net(netdev); + unsigned long ipv4_interval; + struct neigh_table *tbl; + struct mlx5e_priv *priv; + + priv = netdev_priv(netdev); + tbl = arp_table(net); + ipv4_interval = NEIGH_VAR(&tbl->parms, DELAY_PROBE_TIME); rpriv->neigh_update.min_interval = min_t(unsigned long, ipv6_interval, ipv4_interval); mlx5_fc_update_sampling_interval(priv->mdev, rpriv->neigh_update.min_interval); @@ -217,12 +223,6 @@ static int mlx5e_rep_netevent_event(struct notifier_block *nb, switch (event) { case NETEVENT_NEIGH_UPDATE: n = ptr; -#if IS_ENABLED(CONFIG_IPV6) - if (n->tbl != &nd_tbl && n->tbl != &arp_tbl) -#else - if (n->tbl != &arp_tbl) -#endif - return NOTIFY_DONE; update_work = mlx5e_alloc_neigh_update_work(priv, n); if (!update_work) @@ -238,11 +238,7 @@ static int mlx5e_rep_netevent_event(struct notifier_block *nb, * changes in the default table, we only care about changes * done per device delay prob time parameter. */ -#if IS_ENABLED(CONFIG_IPV6) - if (!p->dev || (p->tbl != &nd_tbl && p->tbl != &arp_tbl)) -#else - if (!p->dev || p->tbl != &arp_tbl) -#endif + if (!p->dev) return NOTIFY_DONE; rcu_read_lock(); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c index 8b827201935e..33737a29ab97 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c @@ -393,20 +393,10 @@ void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe) struct mlx5e_encap_entry *e = NULL; struct mlx5e_tc_flow *flow; struct mlx5_fc *counter; - struct neigh_table *tbl; bool neigh_used = false; struct neighbour *n; u64 lastuse; - if (m_neigh->family == AF_INET) - tbl = &arp_tbl; -#if IS_ENABLED(CONFIG_IPV6) - else if (m_neigh->family == AF_INET6) - tbl = &nd_tbl; -#endif - else - return; - /* mlx5e_get_next_valid_encap() releases previous encap before returning * next one. */ @@ -447,12 +437,23 @@ void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe) trace_mlx5e_tc_update_neigh_used_value(nhe, neigh_used); if (neigh_used) { + struct net_device *dev = READ_ONCE(nhe->neigh_dev); + struct net *net = dev_net(dev); + struct neigh_table *tbl; + nhe->reported_lastuse = jiffies; +#if IS_ENABLED(CONFIG_IPV6) + if (m_neigh->family != AF_INET) + tbl = &nd_tbl; + else +#endif + tbl = arp_table(net); + /* find the relevant neigh according to the cached device and * dst ip pair */ - n = neigh_lookup(tbl, &m_neigh->dst_ip, READ_ONCE(nhe->neigh_dev)); + n = neigh_lookup(tbl, &m_neigh->dst_ip, dev); if (!n) return; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c index db260e3d1412..37a8ddee3ea1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c @@ -262,6 +262,7 @@ static void mlx5e_ipsec_init_macs(struct mlx5e_ipsec_sa_entry *sa_entry, struct net_device *netdev = sa_entry->dev; struct xfrm_state *x = sa_entry->x; struct dst_entry *rt_dst_entry; + struct neigh_table *tbl; struct flowi4 fl4 = {}; struct flowi6 fl6 = {}; struct neighbour *n; @@ -364,9 +365,10 @@ static void mlx5e_ipsec_init_macs(struct mlx5e_ipsec_sa_entry *sa_entry, return; neigh: - n = neigh_lookup(&arp_tbl, pkey, netdev); + tbl = arp_table(dev_net(netdev)); + n = neigh_lookup(tbl, pkey, netdev); if (!n) { - n = neigh_create(&arp_tbl, pkey, netdev); + n = neigh_create(tbl, pkey, netdev); if (IS_ERR(n)) return; neigh_event_send(n, NULL); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 3d6fdbab05e0..d2a840ce42e3 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -2397,14 +2397,15 @@ mlxsw_sp_neigh_entry_lookup(struct mlxsw_sp *mlxsw_sp, struct neighbour *n) static void mlxsw_sp_router_neighs_update_interval_init(struct mlxsw_sp *mlxsw_sp) { + struct net *net = mlxsw_sp_net(mlxsw_sp); unsigned long interval; #if IS_ENABLED(CONFIG_IPV6) interval = min_t(unsigned long, - NEIGH_VAR(&arp_tbl.parms, DELAY_PROBE_TIME), + NEIGH_VAR(&arp_table(net)->parms, DELAY_PROBE_TIME), NEIGH_VAR(&nd_tbl.parms, DELAY_PROBE_TIME)); #else - interval = NEIGH_VAR(&arp_tbl.parms, DELAY_PROBE_TIME); + interval = NEIGH_VAR(&arp_table(net)->parms, DELAY_PROBE_TIME); #endif mlxsw_sp->router->neighs_update.interval = jiffies_to_msecs(interval); } @@ -2414,6 +2415,8 @@ static void mlxsw_sp_router_neigh_ent_ipv4_process(struct mlxsw_sp *mlxsw_sp, int ent_index) { u64 max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); + struct net *net = mlxsw_sp_net(mlxsw_sp); + struct neigh_table *tbl; struct net_device *dev; struct neighbour *n; __be32 dipn; @@ -2429,9 +2432,10 @@ static void mlxsw_sp_router_neigh_ent_ipv4_process(struct mlxsw_sp *mlxsw_sp, return; } + tbl = arp_table(net); dipn = htonl(dip); dev = mlxsw_sp_rif_dev(mlxsw_sp->router->rifs[rif]); - n = neigh_lookup(&arp_tbl, &dipn, dev); + n = neigh_lookup(tbl, &dipn, dev); if (!n) return; @@ -3014,11 +3018,12 @@ static int mlxsw_sp_neigh_rif_made_sync(struct mlxsw_sp *mlxsw_sp, .mlxsw_sp = mlxsw_sp, .rif = rif, }; + struct net *net = mlxsw_sp_net(mlxsw_sp); if (!mlxsw_sp_dev_lower_is_port(mlxsw_sp_rif_dev(rif))) return 0; - neigh_for_each(&arp_tbl, mlxsw_sp_neigh_rif_made_sync_each, &rms); + neigh_for_each(arp_table(net), mlxsw_sp_neigh_rif_made_sync_each, &rms); if (rms.err) goto err_arp; @@ -4622,7 +4627,7 @@ static int mlxsw_sp_nexthop4_init(struct mlxsw_sp *mlxsw_sp, nh->nh_weight = 1; #endif memcpy(&nh->gw_addr, &fib_nh->fib_nh_gw4, sizeof(fib_nh->fib_nh_gw4)); - nh->neigh_tbl = &arp_tbl; + nh->neigh_tbl = arp_table(mlxsw_sp_net(mlxsw_sp)); err = mlxsw_sp_nexthop_insert(mlxsw_sp, nh); if (err) return err; @@ -5112,6 +5117,7 @@ mlxsw_sp_nexthop_obj_init(struct mlxsw_sp *mlxsw_sp, struct nh_notifier_single_info *nh_obj, int weight) { struct net_device *dev = nh_obj->dev; + struct net *net = dev_net(dev); int err; nh->nhgi = nh_grp->nhgi; @@ -5120,7 +5126,7 @@ mlxsw_sp_nexthop_obj_init(struct mlxsw_sp *mlxsw_sp, switch (nh_obj->gw_family) { case AF_INET: memcpy(&nh->gw_addr, &nh_obj->ipv4, sizeof(nh_obj->ipv4)); - nh->neigh_tbl = &arp_tbl; + nh->neigh_tbl = arp_table(net); break; case AF_INET6: memcpy(&nh->gw_addr, &nh_obj->ipv6, sizeof(nh_obj->ipv6)); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c index ae63d549b542..2e8577b555ca 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c @@ -456,6 +456,7 @@ mlxsw_sp_span_entry_gretap4_parms(struct mlxsw_sp *mlxsw_sp, bool inherit_tos = tparm.iph.tos & 0x1; bool inherit_ttl = !tparm.iph.ttl; union mlxsw_sp_l3addr gw = daddr; + struct neigh_table *tbl = NULL; struct net_device *l3edev; if (!(to_dev->flags & IFF_UP) || @@ -469,9 +470,11 @@ mlxsw_sp_span_entry_gretap4_parms(struct mlxsw_sp *mlxsw_sp, return mlxsw_sp_span_entry_unoffloadable(sparmsp); l3edev = mlxsw_sp_span_gretap4_route(to_dev, &saddr.addr4, &gw.addr4); + if (l3edev) + tbl = arp_table(dev_net(l3edev)); return mlxsw_sp_span_entry_tunnel_parms_common(l3edev, saddr, daddr, gw, tparm.iph.ttl, - &arp_tbl, sparmsp); + tbl, sparmsp); } static int diff --git a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c index ca30702f8878..551db6417405 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c +++ b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c @@ -209,6 +209,7 @@ void nfp_tunnel_keep_alive(struct nfp_app *app, struct sk_buff *skb) { struct nfp_tun_active_tuns *payload; struct net_device *netdev; + struct neigh_table *tbl; int count, i, pay_len; struct neighbour *n; __be32 ipv4_addr; @@ -235,7 +236,8 @@ void nfp_tunnel_keep_alive(struct nfp_app *app, struct sk_buff *skb) if (!netdev) continue; - n = neigh_lookup(&arp_tbl, &ipv4_addr, netdev); + tbl = arp_table(dev_net(netdev)); + n = neigh_lookup(tbl, &ipv4_addr, netdev); if (!n) continue; @@ -729,12 +731,6 @@ nfp_tun_neigh_event_handler(struct notifier_block *nb, unsigned long event, default: return NOTIFY_DONE; } -#if IS_ENABLED(CONFIG_IPV6) - if (n->tbl != &nd_tbl && n->tbl != &arp_tbl) -#else - if (n->tbl != &arp_tbl) -#endif - return NOTIFY_DONE; app_priv = container_of(nb, struct nfp_flower_priv, tun.neigh_nb); app = app_priv->app; diff --git a/drivers/net/ethernet/rocker/rocker_main.c b/drivers/net/ethernet/rocker/rocker_main.c index 84a55f2b48ff..0fcd65fc0af7 100644 --- a/drivers/net/ethernet/rocker/rocker_main.c +++ b/drivers/net/ethernet/rocker/rocker_main.c @@ -3134,7 +3134,7 @@ static int rocker_netevent_event(struct notifier_block *unused, switch (event) { case NETEVENT_NEIGH_UPDATE: - if (n->tbl != &arp_tbl) + if (n->tbl != arp_table(&init_net)) return NOTIFY_DONE; dev = n->dev; if (!rocker_port_dev_check(dev)) diff --git a/drivers/net/ethernet/rocker/rocker_ofdpa.c b/drivers/net/ethernet/rocker/rocker_ofdpa.c index 15d19a8a1710..ead8b447b89c 100644 --- a/drivers/net/ethernet/rocker/rocker_ofdpa.c +++ b/drivers/net/ethernet/rocker/rocker_ofdpa.c @@ -1336,7 +1336,7 @@ static int ofdpa_port_ipv4_resolve(struct ofdpa_port *ofdpa_port, int err = 0; if (!n) { - n = neigh_create(&arp_tbl, &ip_addr, dev); + n = neigh_create(arp_table(&init_net), &ip_addr, dev); if (IS_ERR(n)) return PTR_ERR(n); } diff --git a/drivers/net/ethernet/sfc/tc_counters.c b/drivers/net/ethernet/sfc/tc_counters.c index b84235e93ffe..f039836eaec8 100644 --- a/drivers/net/ethernet/sfc/tc_counters.c +++ b/drivers/net/ethernet/sfc/tc_counters.c @@ -91,6 +91,7 @@ static void efx_tc_counter_work(struct work_struct *work) struct efx_tc_action_set *act; unsigned long touched; struct neighbour *n; + struct net *net; spin_lock_bh(&cnt->lock); touched = READ_ONCE(cnt->touched); @@ -103,12 +104,15 @@ static void efx_tc_counter_work(struct work_struct *work) continue; if (time_after_eq(encap->neigh->used, touched)) continue; + encap->neigh->used = touched; + net = encap->neigh->net; + /* We have passed traffic using this ARP entry, so * indicate to the ARP cache that it's still active */ if (encap->neigh->dst_ip) - n = neigh_lookup(&arp_tbl, &encap->neigh->dst_ip, + n = neigh_lookup(arp_table(net), &encap->neigh->dst_ip, encap->neigh->egdev); else #if IS_ENABLED(CONFIG_IPV6) diff --git a/drivers/net/ethernet/sfc/tc_encap_actions.c b/drivers/net/ethernet/sfc/tc_encap_actions.c index c2ad3a358d20..f75c87b166ea 100644 --- a/drivers/net/ethernet/sfc/tc_encap_actions.c +++ b/drivers/net/ethernet/sfc/tc_encap_actions.c @@ -527,7 +527,7 @@ static int efx_neigh_event(struct efx_nic *efx, struct neighbour *n) if (WARN_ON(!efx->tc)) return NOTIFY_DONE; - if (n->tbl == &arp_tbl) { + if (n->tbl->family == AF_INET) { keysize = sizeof(keys.dst_ip); #if IS_ENABLED(CONFIG_IPV6) } else if (n->tbl == &nd_tbl) { diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index fd5505153d0b..9dd5252019f2 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -1841,11 +1841,12 @@ static int vxlan_err_lookup(struct sock *sk, struct sk_buff *skb) static int arp_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni) { + struct neigh_table *tbl = arp_table(dev_net(dev)); struct vxlan_dev *vxlan = netdev_priv(dev); + struct neighbour *n; struct arphdr *parp; u8 *arpptr, *sha; __be32 sip, tip; - struct neighbour *n; if (dev->flags & IFF_NOARP) goto out; @@ -1877,7 +1878,7 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni) ipv4_is_multicast(tip)) goto out; - n = neigh_lookup(&arp_tbl, &tip, dev); + n = neigh_lookup(tbl, &tip, dev); if (n) { struct vxlan_rdst *rdst = NULL; @@ -2100,6 +2101,7 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni) static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb) { struct vxlan_dev *vxlan = netdev_priv(dev); + struct neigh_table *tbl; struct neighbour *n; if (is_multicast_ether_addr(eth_hdr(skb)->h_dest)) @@ -2113,8 +2115,10 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb) if (!pskb_network_may_pull(skb, sizeof(struct iphdr))) return false; + + tbl = arp_table(dev_net(dev)); pip = ip_hdr(skb); - n = neigh_lookup(&arp_tbl, &pip->daddr, dev); + n = neigh_lookup(tbl, &pip->daddr, dev); if (!n && (vxlan->cfg.flags & VXLAN_F_L3MISS)) { union vxlan_addr ipa = { .sin.sin_addr.s_addr = pip->daddr, diff --git a/include/net/arp.h b/include/net/arp.h index f8d18b1f8b28..e932def63d62 100644 --- a/include/net/arp.h +++ b/include/net/arp.h @@ -7,8 +7,6 @@ #include #include -extern struct neigh_table arp_tbl; - static inline struct neigh_table *arp_table(struct net *net) { return net->neigh_tables[NEIGH_ARP_TABLE]; @@ -25,10 +23,12 @@ static inline u32 arp_hashfn(const void *pkey, const struct net_device *dev, u32 #ifdef CONFIG_INET static inline struct neighbour *__ipv4_neigh_lookup_noref(struct net_device *dev, u32 key) { + struct neigh_table *tbl = arp_table(dev_net(dev)); + if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) key = INADDR_ANY; - return ___neigh_lookup_noref(&arp_tbl, neigh_key_eq32, arp_hashfn, &key, dev); + return ___neigh_lookup_noref(tbl, neigh_key_eq32, arp_hashfn, &key, dev); } #else static inline diff --git a/include/net/route.h b/include/net/route.h index f90106f383c5..38a23f28ee14 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -403,8 +403,11 @@ static inline struct neighbour *ip_neigh_gw4(struct net_device *dev, struct neighbour *neigh; neigh = __ipv4_neigh_lookup_noref(dev, (__force u32)daddr); - if (unlikely(!neigh)) - neigh = __neigh_create(&arp_tbl, &daddr, dev, false); + if (unlikely(!neigh)) { + struct neigh_table *tbl = arp_table(dev_net(dev)); + + neigh = __neigh_create(tbl, &daddr, dev, false); + } return neigh; } diff --git a/net/bridge/br_arp_nd_proxy.c b/net/bridge/br_arp_nd_proxy.c index 23eb6931a2b4..e73c92284558 100644 --- a/net/bridge/br_arp_nd_proxy.c +++ b/net/bridge/br_arp_nd_proxy.c @@ -192,7 +192,7 @@ void br_do_proxy_suppress_arp(struct sk_buff *skb, struct net_bridge *br, return; } - n = neigh_lookup(&arp_tbl, &tip, vlandev); + n = neigh_lookup(arp_table(dev_net(vlandev)), &tip, vlandev); if (n) { struct net_bridge_fdb_entry *f; diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 824c65c70408..a44fa68fdd07 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -149,7 +149,7 @@ static const struct neigh_ops arp_direct_ops = { .connected_output = neigh_direct_output, }; -struct neigh_table arp_tbl = { +static struct neigh_table arp_tbl = { .family = AF_INET, .key_len = 4, .protocol = cpu_to_be16(ETH_P_IP), @@ -182,7 +182,6 @@ struct neigh_table arp_tbl = { .gc_thresh2 = 512, .gc_thresh3 = 1024, }; -EXPORT_SYMBOL(arp_tbl); int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir) { @@ -222,14 +221,18 @@ static bool arp_key_eq(const struct neighbour *neigh, const void *pkey) static int arp_constructor(struct neighbour *neigh) { - __be32 addr; struct net_device *dev = neigh->dev; - struct in_device *in_dev; - struct neigh_parms *parms; + struct net *net = dev_net(dev); u32 inaddr_any = INADDR_ANY; + struct neigh_parms *parms; + struct in_device *in_dev; + struct neigh_table *tbl; + __be32 addr; + + tbl = arp_table(net); if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) - memcpy(neigh->primary_key, &inaddr_any, arp_tbl.key_len); + memcpy(neigh->primary_key, &inaddr_any, tbl->key_len); addr = *(__be32 *)neigh->primary_key; rcu_read_lock(); @@ -239,7 +242,7 @@ static int arp_constructor(struct neighbour *neigh) return -EINVAL; } - neigh->type = inet_addr_type_dev_table(dev_net(dev), dev, addr); + neigh->type = inet_addr_type_dev_table(net, dev, addr); parms = in_dev->arp_parms; __neigh_parms_put(neigh->parms); @@ -701,24 +704,24 @@ static bool arp_is_garp(struct net *net, struct net_device *dev, static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb) { + struct neigh_table *tbl = arp_table(net); + struct dst_entry *reply_dst = NULL; struct net_device *dev = skb->dev; - struct in_device *in_dev = __in_dev_get_rcu(dev); - struct arphdr *arp; + unsigned char *sha, *tha = NULL; + struct in_device *in_dev; + u16 dev_type = dev->type; unsigned char *arp_ptr; + bool is_garp = false; + struct neighbour *n; + struct arphdr *arp; struct rtable *rt; - unsigned char *sha; - unsigned char *tha = NULL; __be32 sip, tip; - u16 dev_type = dev->type; int addr_type; - struct neighbour *n; - struct dst_entry *reply_dst = NULL; - bool is_garp = false; /* arp_rcv below verifies the ARP header and verifies the device * is ARP'able. */ - + in_dev = __in_dev_get_rcu(dev); if (!in_dev) goto out_free_skb; @@ -850,7 +853,7 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb) if (!dont_send && IN_DEV_ARPFILTER(in_dev)) dont_send = arp_filter(sip, tip, dev); if (!dont_send) { - n = neigh_event_ns(&arp_tbl, sha, &sip, dev); + n = neigh_event_ns(tbl, sha, &sip, dev); if (n) { arp_send_dst(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha, @@ -865,8 +868,8 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb) (arp_fwd_proxy(in_dev, dev, rt) || arp_fwd_pvlan(in_dev, dev, rt, sip, tip) || (rt->dst.dev != dev && - pneigh_lookup(&arp_tbl, net, &tip, dev)))) { - n = neigh_event_ns(&arp_tbl, sha, &sip, dev); + pneigh_lookup(tbl, net, &tip, dev)))) { + n = neigh_event_ns(tbl, sha, &sip, dev); if (n) neigh_release(n); @@ -878,7 +881,7 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb) dev->dev_addr, sha, reply_dst); } else { - pneigh_enqueue(&arp_tbl, + pneigh_enqueue(tbl, in_dev->arp_parms, skb); goto out_free_dst; } @@ -889,7 +892,7 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb) /* Update our ARP tables */ - n = __neigh_lookup(&arp_tbl, &sip, dev, 0); + n = __neigh_lookup(tbl, &sip, dev, 0); addr_type = -1; if (n || arp_accept(in_dev, sip)) { @@ -910,7 +913,7 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb) /* postpone calculation to as late as possible */ inet_addr_type_dev_table(net, dev, sip) == RTN_UNICAST))))) - n = __neigh_lookup(&arp_tbl, &sip, dev, 1); + n = __neigh_lookup(tbl, &sip, dev, 1); } if (n) { @@ -1077,9 +1080,10 @@ static int arp_req_set_proxy(struct net *net, struct net_device *dev, int on) } static int arp_req_set_public(struct net *net, struct arpreq *r, - struct net_device *dev) + struct net_device *dev) { __be32 mask = ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr; + struct neigh_table *tbl = arp_table(net); if (!dev && (r->arp_flags & ATF_COM)) { dev = dev_getbyhwaddr(net, r->arp_ha.sa_family, @@ -1090,7 +1094,7 @@ static int arp_req_set_public(struct net *net, struct arpreq *r, if (mask) { __be32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; - return pneigh_create(&arp_tbl, net, &ip, dev, 0, 0, false); + return pneigh_create(tbl, net, &ip, dev, 0, 0, false); } return arp_req_set_proxy(net, dev, 1); @@ -1098,6 +1102,7 @@ static int arp_req_set_public(struct net *net, struct arpreq *r, static int arp_req_set(struct net *net, struct arpreq *r) { + struct neigh_table *tbl = arp_table(net); struct neighbour *neigh; struct net_device *dev; __be32 ip; @@ -1133,7 +1138,7 @@ static int arp_req_set(struct net *net, struct arpreq *r) ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; - neigh = __neigh_lookup_errno(&arp_tbl, &ip, dev); + neigh = __neigh_lookup_errno(tbl, &ip, dev); err = PTR_ERR(neigh); if (!IS_ERR(neigh)) { unsigned int state = NUD_STALE; @@ -1169,6 +1174,7 @@ static unsigned int arp_state_to_flags(struct neighbour *neigh) static int arp_req_get(struct net *net, struct arpreq *r) { __be32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr; + struct neigh_table *tbl = arp_table(net); struct neighbour *neigh; struct net_device *dev; @@ -1179,7 +1185,7 @@ static int arp_req_get(struct net *net, struct arpreq *r) if (IS_ERR(dev)) return PTR_ERR(dev); - neigh = neigh_lookup(&arp_tbl, &ip, dev); + neigh = neigh_lookup(tbl, &ip, dev); if (!neigh) return -ENXIO; @@ -1204,10 +1210,11 @@ static int arp_req_get(struct net *net, struct arpreq *r) int arp_invalidate(struct net_device *dev, __be32 ip, bool force) { - struct neighbour *neigh = neigh_lookup(&arp_tbl, &ip, dev); + struct neigh_table *tbl = arp_table(dev_net(dev)); + struct neighbour *neigh; int err = -ENXIO; - struct neigh_table *tbl = &arp_tbl; + neigh = neigh_lookup(tbl, &ip, dev); if (neigh) { if ((READ_ONCE(neigh->nud_state) & NUD_VALID) && !force) { neigh_release(neigh); @@ -1228,14 +1235,15 @@ int arp_invalidate(struct net_device *dev, __be32 ip, bool force) } static int arp_req_delete_public(struct net *net, struct arpreq *r, - struct net_device *dev) + struct net_device *dev) { __be32 mask = ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr; + struct neigh_table *tbl = arp_table(net); if (mask) { __be32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; - return pneigh_delete(&arp_tbl, net, &ip, dev); + return pneigh_delete(tbl, net, &ip, dev); } return arp_req_set_proxy(net, dev, 0); @@ -1325,18 +1333,22 @@ static int arp_netdev_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = netdev_notifier_info_to_dev(ptr); struct netdev_notifier_change_info *change_info; + struct net *net = dev_net(dev); struct in_device *in_dev; + struct neigh_table *tbl; bool evict_nocarrier; + tbl = arp_table(net); + switch (event) { case NETDEV_CHANGEADDR: - neigh_changeaddr(&arp_tbl, dev); - rt_cache_flush(dev_net(dev)); + neigh_changeaddr(tbl, dev); + rt_cache_flush(net); break; case NETDEV_CHANGE: change_info = ptr; if (change_info->flags_changed & IFF_NOARP) - neigh_changeaddr(&arp_tbl, dev); + neigh_changeaddr(tbl, dev); in_dev = __in_dev_get_rtnl(dev); if (!in_dev) @@ -1345,7 +1357,7 @@ static int arp_netdev_event(struct notifier_block *this, unsigned long event, evict_nocarrier = IN_DEV_ARP_EVICT_NOCARRIER(in_dev); if (evict_nocarrier && !netif_carrier_ok(dev)) - neigh_carrier_down(&arp_tbl, dev); + neigh_carrier_down(tbl, dev); break; default: break; @@ -1364,7 +1376,9 @@ static struct notifier_block arp_netdev_notifier = { */ void arp_ifdown(struct net_device *dev) { - neigh_ifdown(&arp_tbl, dev); + struct neigh_table *tbl = arp_table(dev_net(dev)); + + neigh_ifdown(tbl, dev); } @@ -1479,10 +1493,12 @@ static int arp_seq_show(struct seq_file *seq, void *v) static void *arp_seq_start(struct seq_file *seq, loff_t *pos) { + struct neigh_table *tbl = arp_table(seq_file_net(seq)); + /* Don't want to confuse "arp -a" w/ magic entries, * so we tell the generic iterator to skip NUD_NOARP. */ - return neigh_seq_start(seq, pos, &arp_tbl, NEIGH_SEQ_SKIP_NOARP); + return neigh_seq_start(seq, pos, tbl, NEIGH_SEQ_SKIP_NOARP); } static const struct seq_operations arp_seq_ops = { diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 47ded0f607d4..05de597ce086 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -265,7 +265,9 @@ EXPORT_SYMBOL(in_dev_finish_destroy); static struct in_device *inetdev_init(struct net_device *dev) { + struct net *net = dev_net(dev); struct in_device *in_dev; + struct neigh_table *tbl; int err = -ENOMEM; ASSERT_RTNL(); @@ -273,11 +275,12 @@ static struct in_device *inetdev_init(struct net_device *dev) in_dev = kzalloc_obj(*in_dev); if (!in_dev) goto out; - memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt, - sizeof(in_dev->cnf)); + + tbl = arp_table(net); + memcpy(&in_dev->cnf, net->ipv4.devconf_dflt, sizeof(in_dev->cnf)); in_dev->cnf.sysctl = NULL; in_dev->dev = dev; - in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl); + in_dev->arp_parms = neigh_parms_alloc(dev, tbl); if (!in_dev->arp_parms) goto out_kfree; if (IPV4_DEVCONF(in_dev->cnf, FORWARDING)) @@ -291,7 +294,7 @@ static struct in_device *inetdev_init(struct net_device *dev) err = devinet_sysctl_register(in_dev); if (err) { in_dev->dead = 1; - neigh_parms_release(&arp_tbl, in_dev->arp_parms); + neigh_parms_release(tbl, in_dev->arp_parms); in_dev_put(in_dev); in_dev = NULL; goto out; @@ -313,13 +316,12 @@ static struct in_device *inetdev_init(struct net_device *dev) static void inetdev_destroy(struct in_device *in_dev) { - struct net_device *dev; + struct net_device *dev = in_dev->dev; + struct net *net = dev_net(dev); struct in_ifaddr *ifa; ASSERT_RTNL(); - dev = in_dev->dev; - in_dev->dead = 1; RCU_INIT_POINTER(dev->ip_ptr, NULL); @@ -332,7 +334,7 @@ static void inetdev_destroy(struct in_device *in_dev) } devinet_sysctl_unregister(in_dev); - neigh_parms_release(&arp_tbl, in_dev->arp_parms); + neigh_parms_release(arp_table(net), in_dev->arp_parms); arp_ifdown(dev); in_dev_put(in_dev); diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 78f84ae3ee12..c5c3b39cc6f9 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -610,11 +610,12 @@ static int fib_detect_death(struct fib_info *fi, int order, int dflt) { const struct fib_nh_common *nhc = fib_info_nhc(fi, 0); - struct neighbour *n; + struct net *net = fi->fib_net; int state = NUD_NONE; + struct neighbour *n; if (likely(nhc->nhc_gw_family == AF_INET)) - n = neigh_lookup(&arp_tbl, &nhc->nhc_gw.ipv4, nhc->nhc_dev); + n = neigh_lookup(arp_table(net), &nhc->nhc_gw.ipv4, nhc->nhc_dev); else if (IS_ENABLED(CONFIG_IPV6) && nhc->nhc_gw_family == AF_INET6) n = neigh_lookup(&nd_tbl, &nhc->nhc_gw.ipv6, nhc->nhc_dev); else diff --git a/net/ipv4/route.c b/net/ipv4/route.c index fd688e1f879f..b8b6b5d99129 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -788,7 +788,7 @@ static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flow n = __ipv4_neigh_lookup(rt->dst.dev, (__force u32)new_gw); if (!n) - n = neigh_create(&arp_tbl, &new_gw, rt->dst.dev); + n = neigh_create(arp_table(net), &new_gw, rt->dst.dev); if (!IS_ERR(n)) { if (!(READ_ONCE(n->nud_state) & NUD_VALID)) { neigh_event_send(n, NULL); -- 2.55.0.679.g6767b8d81c-goog