mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
Merge branch 'neighbour-namespacify-arp_tbl-and-nd_tbl'
Kuniyuki Iwashima says:
====================
neighbour: Namespacify arp_tbl and nd_tbl.
The neighbour subsystem is almost ready to drop RTNL.
However, the control paths are serialised by the global
per-table lock.
This series converts arp_tbl and nd_tbl to per-netns table.
With the series, /proc/sys/net/ipv{4,6}/neigh/default/ can
be configured per netns, which was only configurable in
init_net.
To avoid potential regression, all the settings are inherited
from init_net by default, and this behaviour is controlled by
a new sysctl knob, net.core.neigh_inherit_init_net:
# sysctl net.core.neigh_inherit_init_net
net.core.neigh_inherit_init_net = 1
# sysctl net.ipv4.neigh.default.gc_thresh1
net.ipv4.neigh.default.gc_thresh1 = 128
# sysctl net.ipv4.neigh.default.gc_thresh1=129
net.ipv4.neigh.default.gc_thresh1 = 129
# unshare -n sysctl net.ipv4.neigh.default.gc_thresh1
net.ipv4.neigh.default.gc_thresh1 = 129
If it is turned off, all settings are reset in the new netns:
# sysctl net.core.neigh_inherit_init_net=0
net.core.neigh_inherit_init_net = 0
# unshare -n sysctl net.ipv4.neigh.default.gc_thresh1
net.ipv4.neigh.default.gc_thresh1 = 128
Series overview:
Patch 1 deflakes test_neigh.sh.
Patch 2 ~ 3 are misc cleanup.
Patch 4 ~ 7 store arp_tbl/nd_tbl to net->neigh_tables[] and
remove the global neigh_tables[].
Patch 8 ~ 9 replace the direct access to arp_tbl/nd_tbl to
net->neigh_tables[] using new helpers.
Patch 10 ~ 12 finally replace the global table with per-netns
table.
Patch 13 ~ 14 clean up unnecessary net_eq().
Patch 15 updates test_neigh.sh.
Note that some buggy drivers access nd_tbl without checking
disable_ipv6_mod, so nd_tbl's extern definition is still left.
====================
Link: https://patch.msgid.link/20260902203722.926528-1-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
a753848a32
|
|
@ -413,6 +413,20 @@ new netns has been created.
|
|||
|
||||
Default : 0 (for compatibility reasons)
|
||||
|
||||
neigh_inherit_init_net
|
||||
----------------------
|
||||
|
||||
Controls if a new network namespace should inherit all current
|
||||
settings under /proc/sys/net/ipv{4,6}/neigh/default/.
|
||||
|
||||
By default, the value is set to 1, and all settings are inherited
|
||||
from init_net.
|
||||
|
||||
If set to 0, both IPv4 and IPv6 settings are reset to their default
|
||||
values.
|
||||
|
||||
Default : 1 (for compatibility reasons)
|
||||
|
||||
txrehash
|
||||
--------
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -17,20 +17,27 @@
|
|||
#include "fs_core.h"
|
||||
#include "diag/en_rep_tracepoint.h"
|
||||
|
||||
static unsigned long mlx5e_rep_ipv6_interval(void)
|
||||
static unsigned long mlx5e_rep_ipv6_interval(struct net *net)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_IPV6) && ipv6_mod_enabled())
|
||||
return NEIGH_VAR(&nd_tbl.parms, DELAY_PROBE_TIME);
|
||||
return NEIGH_VAR(&nd_table(net)->parms, DELAY_PROBE_TIME);
|
||||
|
||||
return ~0UL;
|
||||
}
|
||||
|
||||
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;
|
||||
unsigned long ipv6_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);
|
||||
ipv6_interval = mlx5e_rep_ipv6_interval(net);
|
||||
|
||||
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 +224,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 +239,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();
|
||||
|
|
|
|||
|
|
@ -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_table(net);
|
||||
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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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(&nd_tbl.parms, DELAY_PROBE_TIME));
|
||||
NEIGH_VAR(&arp_table(net)->parms, DELAY_PROBE_TIME),
|
||||
NEIGH_VAR(&nd_table(net)->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;
|
||||
|
||||
|
|
@ -2445,6 +2449,8 @@ static void mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp *mlxsw_sp,
|
|||
char *rauhtd_pl,
|
||||
int rec_index)
|
||||
{
|
||||
struct net *net = mlxsw_sp_net(mlxsw_sp);
|
||||
struct neigh_table *tbl;
|
||||
struct net_device *dev;
|
||||
struct neighbour *n;
|
||||
struct in6_addr dip;
|
||||
|
|
@ -2458,8 +2464,9 @@ static void mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp *mlxsw_sp,
|
|||
return;
|
||||
}
|
||||
|
||||
tbl = nd_table(net);
|
||||
dev = mlxsw_sp_rif_dev(mlxsw_sp->router->rifs[rif]);
|
||||
n = neigh_lookup(&nd_tbl, &dip, dev);
|
||||
n = neigh_lookup(tbl, &dip, dev);
|
||||
if (!n)
|
||||
return;
|
||||
|
||||
|
|
@ -3014,16 +3021,17 @@ 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;
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
neigh_for_each(&nd_tbl, mlxsw_sp_neigh_rif_made_sync_each, &rms);
|
||||
neigh_for_each(nd_table(net), mlxsw_sp_neigh_rif_made_sync_each, &rms);
|
||||
#endif
|
||||
if (rms.err)
|
||||
goto err_nd;
|
||||
|
|
@ -4622,7 +4630,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 +5120,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,12 +5129,12 @@ 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));
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
nh->neigh_tbl = &nd_tbl;
|
||||
nh->neigh_tbl = nd_table(net);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
|
@ -6981,7 +6990,7 @@ static int mlxsw_sp_nexthop6_init(struct mlxsw_sp *mlxsw_sp,
|
|||
nh->nh_weight = rt->fib6_nh->fib_nh_weight;
|
||||
memcpy(&nh->gw_addr, &rt->fib6_nh->fib_nh_gw6, sizeof(nh->gw_addr));
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
nh->neigh_tbl = &nd_tbl;
|
||||
nh->neigh_tbl = nd_table(mlxsw_sp_net(mlxsw_sp));
|
||||
#endif
|
||||
|
||||
err = mlxsw_sp_nexthop_counter_enable(mlxsw_sp, nh);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -561,6 +564,7 @@ mlxsw_sp_span_entry_gretap6_parms(struct mlxsw_sp *mlxsw_sp,
|
|||
union mlxsw_sp_l3addr daddr = { .addr6 = tparm.raddr };
|
||||
bool inherit_ttl = !tparm.hop_limit;
|
||||
union mlxsw_sp_l3addr gw = daddr;
|
||||
struct neigh_table *tbl = NULL;
|
||||
struct net_device *l3edev;
|
||||
|
||||
if (!(to_dev->flags & IFF_UP) ||
|
||||
|
|
@ -574,9 +578,11 @@ mlxsw_sp_span_entry_gretap6_parms(struct mlxsw_sp *mlxsw_sp,
|
|||
return mlxsw_sp_span_entry_unoffloadable(sparmsp);
|
||||
|
||||
l3edev = mlxsw_sp_span_gretap6_route(to_dev, &saddr.addr6, &gw.addr6);
|
||||
if (l3edev)
|
||||
tbl = nd_table(dev_net(l3edev));
|
||||
return mlxsw_sp_span_entry_tunnel_parms_common(l3edev, saddr, daddr, gw,
|
||||
tparm.hop_limit,
|
||||
&nd_tbl, sparmsp);
|
||||
tbl, sparmsp);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
@ -251,6 +253,7 @@ void nfp_tunnel_keep_alive_v6(struct nfp_app *app, struct sk_buff *skb)
|
|||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
struct nfp_tun_active_tuns_v6 *payload;
|
||||
struct net_device *netdev;
|
||||
struct neigh_table *tbl;
|
||||
int count, i, pay_len;
|
||||
struct neighbour *n;
|
||||
void *ipv6_add;
|
||||
|
|
@ -277,7 +280,8 @@ void nfp_tunnel_keep_alive_v6(struct nfp_app *app, struct sk_buff *skb)
|
|||
if (!netdev)
|
||||
continue;
|
||||
|
||||
n = neigh_lookup(&nd_tbl, ipv6_add, netdev);
|
||||
tbl = nd_table(dev_net(netdev));
|
||||
n = neigh_lookup(tbl, ipv6_add, netdev);
|
||||
if (!n)
|
||||
continue;
|
||||
|
||||
|
|
@ -729,12 +733,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;
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,16 +104,19 @@ 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)
|
||||
n = neigh_lookup(&nd_tbl,
|
||||
n = neigh_lookup(nd_table(net),
|
||||
&encap->neigh->dst_ip6,
|
||||
encap->neigh->egdev);
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -527,10 +527,10 @@ 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) {
|
||||
} else if (n->tbl->family == AF_INET6) {
|
||||
ipv6 = true;
|
||||
keysize = sizeof(keys.dst_ip6);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -616,7 +616,7 @@ static int vrf_finish_output6(struct net *net, struct sock *sk,
|
|||
nexthop = rt6_nexthop(dst_rt6_info(dst), &ipv6_hdr(skb)->daddr);
|
||||
neigh = __ipv6_neigh_lookup_noref(dst->dev, nexthop);
|
||||
if (unlikely(!neigh))
|
||||
neigh = __neigh_create(&nd_tbl, nexthop, dst->dev, false);
|
||||
neigh = __neigh_create(nd_table(net), nexthop, dst->dev, false);
|
||||
if (!IS_ERR(neigh)) {
|
||||
sock_confirm_neigh(skb, neigh);
|
||||
ret = neigh_output(neigh, skb, false);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -2051,7 +2052,7 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni)
|
|||
ipv6_addr_is_multicast(&msg->target))
|
||||
goto out;
|
||||
|
||||
n = neigh_lookup(&nd_tbl, &msg->target, dev);
|
||||
n = neigh_lookup(nd_table(dev_net(dev)), &msg->target, dev);
|
||||
|
||||
if (n) {
|
||||
struct vxlan_rdst *rdst = NULL;
|
||||
|
|
@ -2106,6 +2107,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))
|
||||
|
|
@ -2119,8 +2121,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,
|
||||
|
|
@ -2145,8 +2149,10 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
|
|||
return false;
|
||||
if (!pskb_network_may_pull(skb, sizeof(struct ipv6hdr)))
|
||||
return false;
|
||||
|
||||
tbl = nd_table(dev_net(dev));
|
||||
pip6 = ipv6_hdr(skb);
|
||||
n = neigh_lookup(&nd_tbl, &pip6->daddr, dev);
|
||||
n = neigh_lookup(tbl, &pip6->daddr, dev);
|
||||
if (!n && (vxlan->cfg.flags & VXLAN_F_L3MISS)) {
|
||||
union vxlan_addr ipa = {
|
||||
.sin6.sin6_addr = pip6->daddr,
|
||||
|
|
|
|||
|
|
@ -7,8 +7,10 @@
|
|||
#include <linux/hash.h>
|
||||
#include <net/neighbour.h>
|
||||
|
||||
|
||||
extern struct neigh_table arp_tbl;
|
||||
static inline struct neigh_table *arp_table(struct net *net)
|
||||
{
|
||||
return net->neigh_tables[NEIGH_ARP_TABLE];
|
||||
}
|
||||
|
||||
static inline u32 arp_hashfn(const void *pkey, const struct net_device *dev, u32 *hash_rnd)
|
||||
{
|
||||
|
|
@ -21,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
|
||||
|
|
|
|||
|
|
@ -67,6 +67,15 @@ struct prefix_info;
|
|||
|
||||
extern struct neigh_table nd_tbl;
|
||||
|
||||
static inline struct neigh_table *nd_table(struct net *net)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
if (disable_ipv6_mod)
|
||||
return &nd_tbl;
|
||||
#endif
|
||||
return net->neigh_tables[NEIGH_ND_TABLE];
|
||||
}
|
||||
|
||||
struct nd_msg {
|
||||
struct icmp6hdr icmph;
|
||||
struct in6_addr target;
|
||||
|
|
@ -354,7 +363,9 @@ static inline u32 ndisc_hashfn(const void *pkey, const struct net_device *dev, _
|
|||
|
||||
static inline struct neighbour *__ipv6_neigh_lookup_noref(struct net_device *dev, const void *pkey)
|
||||
{
|
||||
return ___neigh_lookup_noref(&nd_tbl, neigh_key_eq128, ndisc_hashfn, pkey, dev);
|
||||
struct neigh_table *tbl = nd_table(dev_net(dev));
|
||||
|
||||
return ___neigh_lookup_noref(tbl, neigh_key_eq128, ndisc_hashfn, pkey, dev);
|
||||
}
|
||||
|
||||
static inline struct neighbour *__ipv6_neigh_lookup(struct net_device *dev, const void *pkey)
|
||||
|
|
@ -388,8 +399,11 @@ static inline struct neighbour *ip_neigh_gw6(struct net_device *dev,
|
|||
struct neighbour *neigh;
|
||||
|
||||
neigh = __ipv6_neigh_lookup_noref(dev, addr);
|
||||
if (unlikely(!neigh))
|
||||
neigh = __neigh_create(&nd_tbl, addr, dev, false);
|
||||
if (unlikely(!neigh)) {
|
||||
struct neigh_table *tbl = nd_table(dev_net(dev));
|
||||
|
||||
neigh = __neigh_create(tbl, addr, dev, false);
|
||||
}
|
||||
|
||||
return neigh;
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@
|
|||
#include <net/rtnetlink.h>
|
||||
#include <net/neighbour_tables.h>
|
||||
|
||||
extern int sysctl_neigh_inherit_init_net;
|
||||
|
||||
/*
|
||||
* NUD stands for "neighbor unreachability detection"
|
||||
*/
|
||||
|
|
@ -179,7 +181,6 @@ struct neigh_ops {
|
|||
|
||||
struct pneigh_entry {
|
||||
struct pneigh_entry __rcu *next;
|
||||
possible_net_t net;
|
||||
struct net_device *dev;
|
||||
netdevice_tracker dev_tracker;
|
||||
union {
|
||||
|
|
@ -234,7 +235,7 @@ struct neigh_table {
|
|||
struct delayed_work managed_work;
|
||||
struct timer_list proxy_timer;
|
||||
struct sk_buff_head proxy_queue;
|
||||
atomic_t entries;
|
||||
refcount_t entries;
|
||||
atomic_t gc_entries;
|
||||
struct list_head gc_list;
|
||||
struct list_head managed_list;
|
||||
|
|
@ -339,8 +340,8 @@ static inline void neigh_confirm(struct neighbour *n)
|
|||
}
|
||||
}
|
||||
|
||||
void neigh_table_init(int index, struct neigh_table *tbl);
|
||||
int neigh_table_clear(int index, struct neigh_table *tbl);
|
||||
int neigh_table_register(struct net *net, struct neigh_table *tbl, int index);
|
||||
void neigh_table_unregister(struct net *net, int index);
|
||||
struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
|
||||
struct net_device *dev);
|
||||
struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,
|
||||
|
|
@ -389,24 +390,17 @@ static inline void neigh_set_reach_time(struct neigh_parms *p)
|
|||
|
||||
void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
|
||||
struct sk_buff *skb);
|
||||
struct pneigh_entry *pneigh_lookup(struct neigh_table *tbl, struct net *net,
|
||||
struct pneigh_entry *pneigh_lookup(struct neigh_table *tbl,
|
||||
const void *key, struct net_device *dev);
|
||||
int pneigh_create(struct neigh_table *tbl, struct net *net, const void *key,
|
||||
int pneigh_create(struct neigh_table *tbl, const void *key,
|
||||
struct net_device *dev, u32 flags, u8 protocol,
|
||||
bool permanent);
|
||||
int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *key,
|
||||
int pneigh_delete(struct neigh_table *tbl, const void *key,
|
||||
struct net_device *dev);
|
||||
|
||||
static inline struct net *pneigh_net(const struct pneigh_entry *pneigh)
|
||||
{
|
||||
return read_pnet(&pneigh->net);
|
||||
}
|
||||
|
||||
void neigh_app_ns(struct neighbour *n);
|
||||
void neigh_for_each(struct neigh_table *tbl,
|
||||
void (*cb)(struct neighbour *, void *), void *cookie);
|
||||
void __neigh_for_each_release(struct neigh_table *tbl,
|
||||
int (*cb)(struct neighbour *));
|
||||
int neigh_xmit(int fam, struct net_device *, const void *, struct sk_buff *);
|
||||
|
||||
struct neigh_seq_state {
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
#include <net/netns/mctp.h>
|
||||
#include <net/netns/vsock.h>
|
||||
#include <net/net_trackers.h>
|
||||
#include <net/neighbour_tables.h>
|
||||
#include <linux/ns_common.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
|
@ -47,6 +48,7 @@
|
|||
|
||||
struct user_namespace;
|
||||
struct proc_dir_entry;
|
||||
struct neigh_table;
|
||||
struct net_device;
|
||||
struct sock;
|
||||
struct ctl_table_header;
|
||||
|
|
@ -103,6 +105,8 @@ struct net {
|
|||
struct proc_dir_entry *proc_net;
|
||||
struct proc_dir_entry *proc_net_stat;
|
||||
|
||||
struct neigh_table *neigh_tables[NEIGH_NR_TABLES];
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
struct ctl_table_set sysctls;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -405,8 +405,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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -193,7 +193,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;
|
||||
u8 ha[ETH_ALEN] __aligned(2);
|
||||
|
|
@ -470,7 +470,7 @@ void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br,
|
|||
return;
|
||||
}
|
||||
|
||||
n = neigh_lookup(&nd_tbl, &msg->target, vlandev);
|
||||
n = neigh_lookup(nd_table(dev_net(vlandev)), &msg->target, vlandev);
|
||||
if (n) {
|
||||
struct net_bridge_fdb_entry *f;
|
||||
u8 ha[ETH_ALEN] __aligned(2);
|
||||
|
|
|
|||
|
|
@ -55,6 +55,23 @@ static void neigh_notify(struct neighbour *n, int type, int flags, u32 pid);
|
|||
static void __neigh_notify(struct neighbour *n, int type, int flags, u32 pid);
|
||||
static void pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev,
|
||||
bool skip_perm);
|
||||
static void neigh_table_free(struct neigh_table *tbl);
|
||||
|
||||
static void neigh_table_get(struct neigh_table *tbl)
|
||||
{
|
||||
refcount_inc(&tbl->entries);
|
||||
}
|
||||
|
||||
static void neigh_table_put(struct neigh_table *tbl)
|
||||
{
|
||||
if (refcount_dec_and_test(&tbl->entries))
|
||||
neigh_table_free(tbl);
|
||||
}
|
||||
|
||||
static int neigh_table_entries(struct neigh_table *tbl)
|
||||
{
|
||||
return refcount_read(&tbl->entries) - 1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
static const struct seq_operations neigh_stat_seq_ops;
|
||||
|
|
@ -131,10 +148,11 @@ unsigned long neigh_rand_reach_time(unsigned long base)
|
|||
{
|
||||
return base ? get_random_u32_below(base) + (base >> 1) : 0;
|
||||
}
|
||||
EXPORT_SYMBOL(neigh_rand_reach_time);
|
||||
|
||||
static void neigh_mark_dead(struct neighbour *n)
|
||||
{
|
||||
lockdep_assert_held(&n->tbl->lock);
|
||||
|
||||
n->dead = 1;
|
||||
if (!list_empty(&n->gc_list)) {
|
||||
list_del_init(&n->gc_list);
|
||||
|
|
@ -148,11 +166,6 @@ static void neigh_update_gc_list(struct neighbour *n)
|
|||
{
|
||||
bool on_gc_list, exempt_from_gc;
|
||||
|
||||
spin_lock_bh(&n->tbl->lock);
|
||||
write_lock(&n->lock);
|
||||
if (n->dead)
|
||||
goto out;
|
||||
|
||||
/* remove from the gc list if new state is permanent or if neighbor is
|
||||
* externally learned / validated; otherwise entry should be on the gc
|
||||
* list
|
||||
|
|
@ -169,20 +182,12 @@ static void neigh_update_gc_list(struct neighbour *n)
|
|||
list_add_tail(&n->gc_list, &n->tbl->gc_list);
|
||||
atomic_inc(&n->tbl->gc_entries);
|
||||
}
|
||||
out:
|
||||
write_unlock(&n->lock);
|
||||
spin_unlock_bh(&n->tbl->lock);
|
||||
}
|
||||
|
||||
static void neigh_update_managed_list(struct neighbour *n)
|
||||
{
|
||||
bool on_managed_list, add_to_managed;
|
||||
|
||||
spin_lock_bh(&n->tbl->lock);
|
||||
write_lock(&n->lock);
|
||||
if (n->dead)
|
||||
goto out;
|
||||
|
||||
add_to_managed = n->flags & NTF_MANAGED;
|
||||
on_managed_list = !list_empty(&n->managed_list);
|
||||
|
||||
|
|
@ -190,9 +195,6 @@ static void neigh_update_managed_list(struct neighbour *n)
|
|||
list_del_init(&n->managed_list);
|
||||
else if (add_to_managed && !on_managed_list)
|
||||
list_add_tail(&n->managed_list, &n->tbl->managed_list);
|
||||
out:
|
||||
write_unlock(&n->lock);
|
||||
spin_unlock_bh(&n->tbl->lock);
|
||||
}
|
||||
|
||||
static void neigh_update_flags(struct neighbour *neigh, u32 flags, int *notify,
|
||||
|
|
@ -349,8 +351,7 @@ static void neigh_parms_qlen_dec(struct net_device *dev, int family)
|
|||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void pneigh_queue_purge(struct sk_buff_head *list, struct net *net,
|
||||
int family)
|
||||
static void pneigh_queue_purge(struct sk_buff_head *list, int family)
|
||||
{
|
||||
struct sk_buff_head tmp;
|
||||
unsigned long flags;
|
||||
|
|
@ -361,13 +362,11 @@ static void pneigh_queue_purge(struct sk_buff_head *list, struct net *net,
|
|||
skb = skb_peek(list);
|
||||
while (skb != NULL) {
|
||||
struct sk_buff *skb_next = skb_peek_next(skb, list);
|
||||
struct net_device *dev = skb->dev;
|
||||
|
||||
if (net == NULL || net_eq(dev_net(dev), net)) {
|
||||
neigh_parms_qlen_dec(dev, family);
|
||||
__skb_unlink(skb, list);
|
||||
__skb_queue_tail(&tmp, skb);
|
||||
}
|
||||
neigh_parms_qlen_dec(skb->dev, family);
|
||||
__skb_unlink(skb, list);
|
||||
__skb_queue_tail(&tmp, skb);
|
||||
|
||||
skb = skb_next;
|
||||
}
|
||||
spin_unlock_irqrestore(&list->lock, flags);
|
||||
|
|
@ -471,8 +470,7 @@ static int __neigh_ifdown(struct neigh_table *tbl, struct net_device *dev,
|
|||
spin_unlock_bh(&tbl->lock);
|
||||
|
||||
pneigh_ifdown(tbl, dev, skip_perm);
|
||||
pneigh_queue_purge(&tbl->proxy_queue, dev ? dev_net(dev) : NULL,
|
||||
tbl->family);
|
||||
pneigh_queue_purge(&tbl->proxy_queue, tbl->family);
|
||||
if (skb_queue_empty_lockless(&tbl->proxy_queue))
|
||||
timer_delete_sync(&tbl->proxy_timer);
|
||||
return 0;
|
||||
|
|
@ -537,7 +535,7 @@ static struct neighbour *neigh_alloc(struct neigh_table *tbl,
|
|||
INIT_LIST_HEAD(&n->gc_list);
|
||||
INIT_LIST_HEAD(&n->managed_list);
|
||||
|
||||
atomic_inc(&tbl->entries);
|
||||
neigh_table_get(tbl);
|
||||
out:
|
||||
return n;
|
||||
|
||||
|
|
@ -687,7 +685,7 @@ ___neigh_create(struct neigh_table *tbl, const void *pkey,
|
|||
nht = rcu_dereference_protected(tbl->nht,
|
||||
lockdep_is_held(&tbl->lock));
|
||||
|
||||
if (atomic_read(&tbl->entries) > (1 << nht->hash_shift))
|
||||
if (neigh_table_entries(tbl) > (1 << nht->hash_shift))
|
||||
nht = neigh_hash_grow(tbl, nht->hash_shift + 1);
|
||||
|
||||
hash_val = tbl->hash(n->primary_key, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
|
||||
|
|
@ -752,8 +750,7 @@ static u32 pneigh_hash(const void *pkey, unsigned int key_len)
|
|||
}
|
||||
|
||||
struct pneigh_entry *pneigh_lookup(struct neigh_table *tbl,
|
||||
struct net *net, const void *pkey,
|
||||
struct net_device *dev)
|
||||
const void *pkey, struct net_device *dev)
|
||||
{
|
||||
struct pneigh_entry *n;
|
||||
unsigned int key_len;
|
||||
|
|
@ -766,7 +763,6 @@ struct pneigh_entry *pneigh_lookup(struct neigh_table *tbl,
|
|||
|
||||
while (n) {
|
||||
if (!memcmp(n->key, pkey, key_len) &&
|
||||
net_eq(pneigh_net(n), net) &&
|
||||
(n->dev == dev || !n->dev))
|
||||
return n;
|
||||
|
||||
|
|
@ -776,7 +772,7 @@ struct pneigh_entry *pneigh_lookup(struct neigh_table *tbl,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
int pneigh_create(struct neigh_table *tbl, struct net *net,
|
||||
int pneigh_create(struct neigh_table *tbl,
|
||||
const void *pkey, struct net_device *dev,
|
||||
u32 flags, u8 protocol, bool permanent)
|
||||
{
|
||||
|
|
@ -787,7 +783,7 @@ int pneigh_create(struct neigh_table *tbl, struct net *net,
|
|||
|
||||
mutex_lock(&tbl->phash_lock);
|
||||
|
||||
n = pneigh_lookup(tbl, net, pkey, dev);
|
||||
n = pneigh_lookup(tbl, pkey, dev);
|
||||
if (n)
|
||||
goto update;
|
||||
|
||||
|
|
@ -798,7 +794,6 @@ int pneigh_create(struct neigh_table *tbl, struct net *net,
|
|||
goto out;
|
||||
}
|
||||
|
||||
write_pnet(&n->net, net);
|
||||
memcpy(n->key, pkey, key_len);
|
||||
n->dev = dev;
|
||||
netdev_hold(dev, &n->dev_tracker, GFP_KERNEL);
|
||||
|
|
@ -831,7 +826,7 @@ static void pneigh_destroy(struct rcu_head *rcu)
|
|||
kfree(n);
|
||||
}
|
||||
|
||||
int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
|
||||
int pneigh_delete(struct neigh_table *tbl, const void *pkey,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct pneigh_entry *n, __rcu **np;
|
||||
|
|
@ -846,8 +841,7 @@ int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
|
|||
for (np = &tbl->phash_buckets[hash_val];
|
||||
(n = rcu_dereference_protected(*np, 1)) != NULL;
|
||||
np = &n->next) {
|
||||
if (!memcmp(n->key, pkey, key_len) && n->dev == dev &&
|
||||
net_eq(pneigh_net(n), net)) {
|
||||
if (!memcmp(n->key, pkey, key_len) && n->dev == dev) {
|
||||
rcu_assign_pointer(*np, n->next);
|
||||
|
||||
mutex_unlock(&tbl->phash_lock);
|
||||
|
|
@ -939,7 +933,7 @@ void neigh_destroy(struct neighbour *neigh)
|
|||
|
||||
neigh_dbg(2, "neigh %p is destroyed\n", neigh);
|
||||
|
||||
atomic_dec(&neigh->tbl->entries);
|
||||
neigh_table_put(neigh->tbl);
|
||||
kfree_rcu(neigh, rcu);
|
||||
}
|
||||
EXPORT_SYMBOL(neigh_destroy);
|
||||
|
|
@ -994,7 +988,7 @@ static void neigh_periodic_work(struct work_struct *work)
|
|||
neigh_set_reach_time(p);
|
||||
}
|
||||
|
||||
if (atomic_read(&tbl->entries) < READ_ONCE(tbl->gc_thresh1))
|
||||
if (neigh_table_entries(tbl) < READ_ONCE(tbl->gc_thresh1))
|
||||
goto out;
|
||||
|
||||
for (i = 0 ; i < (1 << nht->hash_shift); i++) {
|
||||
|
|
@ -1523,10 +1517,23 @@ static int __neigh_update(struct neighbour *neigh, const u8 *lladdr,
|
|||
|
||||
write_unlock_bh(&neigh->lock);
|
||||
|
||||
if (((new ^ old) & NUD_PERMANENT) || gc_update)
|
||||
neigh_update_gc_list(neigh);
|
||||
if (managed_update)
|
||||
neigh_update_managed_list(neigh);
|
||||
gc_update |= !!((new ^ old) & NUD_PERMANENT);
|
||||
if (gc_update || managed_update) {
|
||||
spin_lock_bh(&neigh->tbl->lock);
|
||||
|
||||
if (!neigh->dead) {
|
||||
write_lock(&neigh->lock);
|
||||
|
||||
if (gc_update)
|
||||
neigh_update_gc_list(neigh);
|
||||
if (managed_update)
|
||||
neigh_update_managed_list(neigh);
|
||||
|
||||
write_unlock(&neigh->lock);
|
||||
}
|
||||
|
||||
spin_unlock_bh(&neigh->tbl->lock);
|
||||
}
|
||||
|
||||
if (notify)
|
||||
call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
|
||||
|
|
@ -1540,7 +1547,6 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
|
|||
{
|
||||
return __neigh_update(neigh, lladdr, new, flags, nlmsg_pid, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL(neigh_update);
|
||||
|
||||
/* Update the neigh to listen temporarily for probe responses, even if it is
|
||||
* in a NUD_FAILED state. The caller has to hold neigh->lock for writing.
|
||||
|
|
@ -1558,7 +1564,6 @@ void __neigh_set_probe_once(struct neighbour *neigh)
|
|||
jiffies + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
|
||||
HZ/100));
|
||||
}
|
||||
EXPORT_SYMBOL(__neigh_set_probe_once);
|
||||
|
||||
struct neighbour *neigh_event_ns(struct neigh_table *tbl,
|
||||
u8 *lladdr, void *saddr,
|
||||
|
|
@ -1571,7 +1576,6 @@ struct neighbour *neigh_event_ns(struct neigh_table *tbl,
|
|||
NEIGH_UPDATE_F_OVERRIDE, 0);
|
||||
return neigh;
|
||||
}
|
||||
EXPORT_SYMBOL(neigh_event_ns);
|
||||
|
||||
/* called with read_lock_bh(&n->lock); */
|
||||
static void neigh_hh_init(struct neighbour *n)
|
||||
|
|
@ -1624,7 +1628,6 @@ int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
|
|||
kfree_skb_reason(skb, SKB_DROP_REASON_NEIGH_HH_FILLFAIL);
|
||||
goto out;
|
||||
}
|
||||
EXPORT_SYMBOL(neigh_resolve_output);
|
||||
|
||||
/* As fast as possible without hh cache */
|
||||
|
||||
|
|
@ -1741,16 +1744,15 @@ void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
|
|||
mod_timer(&tbl->proxy_timer, sched_next);
|
||||
spin_unlock(&tbl->proxy_queue.lock);
|
||||
}
|
||||
EXPORT_SYMBOL(pneigh_enqueue);
|
||||
|
||||
static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
|
||||
struct net *net, int ifindex)
|
||||
int ifindex)
|
||||
{
|
||||
struct neigh_parms *p;
|
||||
|
||||
list_for_each_entry(p, &tbl->parms_list, list) {
|
||||
if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) ||
|
||||
(!p->dev && !ifindex && net_eq(net, &init_net)))
|
||||
if ((p->dev && p->dev->ifindex == ifindex) ||
|
||||
(!p->dev && !ifindex))
|
||||
return p;
|
||||
}
|
||||
|
||||
|
|
@ -1789,7 +1791,6 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
|
|||
}
|
||||
return p;
|
||||
}
|
||||
EXPORT_SYMBOL(neigh_parms_alloc);
|
||||
|
||||
static void neigh_rcu_free_parms(struct rcu_head *head)
|
||||
{
|
||||
|
|
@ -1812,113 +1813,171 @@ void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
|
|||
netdev_put(parms->dev, &parms->dev_tracker);
|
||||
call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
|
||||
}
|
||||
EXPORT_SYMBOL(neigh_parms_release);
|
||||
|
||||
static struct lock_class_key neigh_table_proxy_queue_class;
|
||||
|
||||
static struct neigh_table __rcu *neigh_tables[NEIGH_NR_TABLES] __read_mostly;
|
||||
|
||||
void neigh_table_init(int index, struct neigh_table *tbl)
|
||||
static int neigh_table_init(struct net *net, struct neigh_table *tbl)
|
||||
{
|
||||
unsigned long now = jiffies;
|
||||
unsigned long phsize;
|
||||
|
||||
INIT_LIST_HEAD(&tbl->parms_list);
|
||||
INIT_LIST_HEAD(&tbl->gc_list);
|
||||
INIT_LIST_HEAD(&tbl->managed_list);
|
||||
|
||||
list_add(&tbl->parms.list, &tbl->parms_list);
|
||||
write_pnet(&tbl->parms.net, &init_net);
|
||||
refcount_set(&tbl->parms.refcnt, 1);
|
||||
neigh_set_reach_time(&tbl->parms);
|
||||
tbl->parms.qlen = 0;
|
||||
|
||||
tbl->stats = alloc_percpu(struct neigh_statistics);
|
||||
if (!tbl->stats)
|
||||
panic("cannot create neighbour cache statistics");
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
if (!proc_create_seq_data(tbl->id, 0, init_net.proc_net_stat,
|
||||
&neigh_stat_seq_ops, tbl))
|
||||
panic("cannot create neighbour proc dir entry");
|
||||
#endif
|
||||
|
||||
RCU_INIT_POINTER(tbl->nht, neigh_hash_alloc(3));
|
||||
if (!tbl->nht)
|
||||
goto err_hash;
|
||||
|
||||
phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *);
|
||||
tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL);
|
||||
if (!tbl->phash_buckets)
|
||||
goto err_phash;
|
||||
|
||||
if (!tbl->nht || !tbl->phash_buckets)
|
||||
panic("cannot allocate neighbour cache hashes");
|
||||
tbl->entry_size = ALIGN(offsetof(struct neighbour, primary_key) +
|
||||
tbl->key_len, NEIGH_PRIV_ALIGN);
|
||||
|
||||
if (!tbl->entry_size)
|
||||
tbl->entry_size = ALIGN(offsetof(struct neighbour, primary_key) +
|
||||
tbl->key_len, NEIGH_PRIV_ALIGN);
|
||||
else
|
||||
WARN_ON(tbl->entry_size % NEIGH_PRIV_ALIGN);
|
||||
tbl->stats = alloc_percpu(struct neigh_statistics);
|
||||
if (!tbl->stats)
|
||||
goto err_stats;
|
||||
|
||||
spin_lock_init(&tbl->lock);
|
||||
mutex_init(&tbl->phash_lock);
|
||||
|
||||
INIT_DEFERRABLE_WORK(&tbl->gc_work, neigh_periodic_work);
|
||||
queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
|
||||
tbl->parms.reachable_time);
|
||||
INIT_DEFERRABLE_WORK(&tbl->managed_work, neigh_managed_work);
|
||||
queue_delayed_work(system_power_efficient_wq, &tbl->managed_work, 0);
|
||||
|
||||
timer_setup(&tbl->proxy_timer, neigh_proxy_process, 0);
|
||||
skb_queue_head_init_class(&tbl->proxy_queue,
|
||||
&neigh_table_proxy_queue_class);
|
||||
#ifdef CONFIG_PROC_FS
|
||||
if (!proc_create_net_data(tbl->id, 0, net->proc_net_stat,
|
||||
&neigh_stat_seq_ops,
|
||||
sizeof(struct seq_net_private), tbl))
|
||||
goto err_proc;
|
||||
#endif
|
||||
|
||||
tbl->parms.tbl = tbl;
|
||||
tbl->parms.qlen = 0;
|
||||
INIT_LIST_HEAD(&tbl->parms_list);
|
||||
list_add(&tbl->parms.list, &tbl->parms_list);
|
||||
write_pnet(&tbl->parms.net, net);
|
||||
refcount_set(&tbl->parms.refcnt, 1);
|
||||
neigh_set_reach_time(&tbl->parms);
|
||||
tbl->last_flush = now;
|
||||
tbl->last_rand = now + tbl->parms.reachable_time * 20;
|
||||
|
||||
rcu_assign_pointer(neigh_tables[index], tbl);
|
||||
refcount_set(&tbl->entries, 1);
|
||||
spin_lock_init(&tbl->lock);
|
||||
mutex_init(&tbl->phash_lock);
|
||||
skb_queue_head_init_class(&tbl->proxy_queue,
|
||||
&neigh_table_proxy_queue_class);
|
||||
timer_setup(&tbl->proxy_timer, neigh_proxy_process, 0);
|
||||
|
||||
INIT_LIST_HEAD(&tbl->gc_list);
|
||||
INIT_DEFERRABLE_WORK(&tbl->gc_work, neigh_periodic_work);
|
||||
queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
|
||||
tbl->parms.reachable_time);
|
||||
|
||||
INIT_LIST_HEAD(&tbl->managed_list);
|
||||
INIT_DEFERRABLE_WORK(&tbl->managed_work, neigh_managed_work);
|
||||
queue_delayed_work(system_power_efficient_wq, &tbl->managed_work, 0);
|
||||
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
err_proc:
|
||||
free_percpu(tbl->stats);
|
||||
#endif
|
||||
err_stats:
|
||||
kfree(tbl->phash_buckets);
|
||||
err_phash:
|
||||
neigh_hash_free_rcu(&rcu_dereference_protected(tbl->nht, 1)->rcu);
|
||||
err_hash:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only called from ndisc_cleanup(), which means this is dead code
|
||||
* because we no longer can unload IPv6 module.
|
||||
*/
|
||||
int neigh_table_clear(int index, struct neigh_table *tbl)
|
||||
static void neigh_table_free(struct neigh_table *tbl)
|
||||
{
|
||||
RCU_INIT_POINTER(neigh_tables[index], NULL);
|
||||
synchronize_rcu();
|
||||
|
||||
/* It is not clean... Fix it to unload IPv6 module safely */
|
||||
cancel_delayed_work_sync(&tbl->managed_work);
|
||||
cancel_delayed_work_sync(&tbl->gc_work);
|
||||
timer_delete_sync(&tbl->proxy_timer);
|
||||
pneigh_queue_purge(&tbl->proxy_queue, NULL, tbl->family);
|
||||
neigh_ifdown(tbl, NULL);
|
||||
if (atomic_read(&tbl->entries))
|
||||
pr_crit("neighbour leakage\n");
|
||||
|
||||
call_rcu(&rcu_dereference_protected(tbl->nht, 1)->rcu,
|
||||
neigh_hash_free_rcu);
|
||||
tbl->nht = NULL;
|
||||
|
||||
kfree(tbl->phash_buckets);
|
||||
tbl->phash_buckets = NULL;
|
||||
|
||||
remove_proc_entry(tbl->id, init_net.proc_net_stat);
|
||||
struct neigh_hash_table *nht;
|
||||
|
||||
free_percpu(tbl->stats);
|
||||
tbl->stats = NULL;
|
||||
|
||||
return 0;
|
||||
kfree(tbl->phash_buckets);
|
||||
tbl->phash_buckets = NULL;
|
||||
|
||||
nht = rcu_dereference_protected(tbl->nht, 1);
|
||||
tbl->nht = NULL;
|
||||
neigh_hash_free_rcu(&nht->rcu);
|
||||
|
||||
kfree(tbl);
|
||||
}
|
||||
|
||||
static struct neigh_table *neigh_find_table(int family)
|
||||
static void neigh_table_clear(struct net *net, struct neigh_table *tbl)
|
||||
{
|
||||
cancel_delayed_work_sync(&tbl->managed_work);
|
||||
cancel_delayed_work_sync(&tbl->gc_work);
|
||||
timer_shutdown_sync(&tbl->proxy_timer);
|
||||
|
||||
neigh_ifdown(tbl, NULL);
|
||||
remove_proc_entry(tbl->id, net->proc_net_stat);
|
||||
|
||||
neigh_table_put(tbl);
|
||||
}
|
||||
|
||||
int sysctl_neigh_inherit_init_net __read_mostly = 1;
|
||||
|
||||
static void neigh_table_inherit(struct net *net, struct neigh_table *tbl,
|
||||
int index)
|
||||
{
|
||||
const struct neigh_table *init_tbl = init_net.neigh_tables[index];
|
||||
bool inherit = READ_ONCE(sysctl_neigh_inherit_init_net);
|
||||
int i;
|
||||
|
||||
if (net_eq(net, &init_net) || !inherit)
|
||||
return;
|
||||
|
||||
tbl->gc_interval = READ_ONCE(init_tbl->gc_interval);
|
||||
tbl->gc_thresh1 = READ_ONCE(init_tbl->gc_thresh1);
|
||||
tbl->gc_thresh2 = READ_ONCE(init_tbl->gc_thresh2);
|
||||
tbl->gc_thresh3 = READ_ONCE(init_tbl->gc_thresh3);
|
||||
|
||||
for (i = 0; i < NEIGH_VAR_DATA_MAX; i++)
|
||||
tbl->parms.data[i] = READ_ONCE(init_tbl->parms.data[i]);
|
||||
}
|
||||
|
||||
int neigh_table_register(struct net *net, struct neigh_table *tbl, int index)
|
||||
{
|
||||
int err;
|
||||
|
||||
tbl = kmemdup(tbl, sizeof(*tbl), GFP_KERNEL);
|
||||
if (!tbl) {
|
||||
err = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
neigh_table_inherit(net, tbl, index);
|
||||
|
||||
err = neigh_table_init(net, tbl);
|
||||
if (err)
|
||||
goto free_table;
|
||||
|
||||
net->neigh_tables[index] = tbl;
|
||||
|
||||
return 0;
|
||||
|
||||
free_table:
|
||||
kfree(tbl);
|
||||
err:
|
||||
return err;
|
||||
}
|
||||
|
||||
void neigh_table_unregister(struct net *net, int index)
|
||||
{
|
||||
struct neigh_table *tbl = net->neigh_tables[index];
|
||||
|
||||
net->neigh_tables[index] = NULL;
|
||||
neigh_table_clear(net, tbl);
|
||||
}
|
||||
|
||||
static struct neigh_table *neigh_find_table(struct net *net, int family)
|
||||
{
|
||||
struct neigh_table *tbl = NULL;
|
||||
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
tbl = rcu_dereference_rtnl(neigh_tables[NEIGH_ARP_TABLE]);
|
||||
tbl = net->neigh_tables[NEIGH_ARP_TABLE];
|
||||
break;
|
||||
case AF_INET6:
|
||||
tbl = rcu_dereference_rtnl(neigh_tables[NEIGH_ND_TABLE]);
|
||||
tbl = net->neigh_tables[NEIGH_ND_TABLE];
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1972,7 +2031,7 @@ static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|||
}
|
||||
}
|
||||
|
||||
tbl = neigh_find_table(ndm->ndm_family);
|
||||
tbl = neigh_find_table(net, ndm->ndm_family);
|
||||
if (tbl == NULL)
|
||||
return -EAFNOSUPPORT;
|
||||
|
||||
|
|
@ -1982,7 +2041,7 @@ static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|||
}
|
||||
|
||||
if (ndm->ndm_flags & NTF_PROXY) {
|
||||
err = pneigh_delete(tbl, net, nla_data(dst_attr), dev);
|
||||
err = pneigh_delete(tbl, nla_data(dst_attr), dev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
@ -2058,7 +2117,7 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|||
}
|
||||
}
|
||||
|
||||
tbl = neigh_find_table(ndm->ndm_family);
|
||||
tbl = neigh_find_table(net, ndm->ndm_family);
|
||||
if (tbl == NULL)
|
||||
return -EAFNOSUPPORT;
|
||||
|
||||
|
|
@ -2078,7 +2137,7 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|||
goto out;
|
||||
}
|
||||
|
||||
err = pneigh_create(tbl, net, dst, dev, ndm_flags, protocol,
|
||||
err = pneigh_create(tbl, dst, dev, ndm_flags, protocol,
|
||||
!!(ndm->ndm_state & NUD_PERMANENT));
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -2267,7 +2326,7 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
|
|||
struct ndt_config ndc = {
|
||||
.ndtc_key_len = tbl->key_len,
|
||||
.ndtc_entry_size = tbl->entry_size,
|
||||
.ndtc_entries = atomic_read(&tbl->entries),
|
||||
.ndtc_entries = neigh_table_entries(tbl),
|
||||
.ndtc_last_flush = jiffies_to_msecs(flush_delta),
|
||||
.ndtc_last_rand = jiffies_to_msecs(rand_delta),
|
||||
.ndtc_proxy_qlen = READ_ONCE(tbl->proxy_queue.qlen),
|
||||
|
|
@ -2400,10 +2459,8 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|||
|
||||
ndtmsg = nlmsg_data(nlh);
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
|
||||
tbl = rcu_dereference(neigh_tables[tidx]);
|
||||
tbl = net->neigh_tables[tidx];
|
||||
if (!tbl)
|
||||
continue;
|
||||
|
||||
|
|
@ -2417,7 +2474,6 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|||
}
|
||||
|
||||
if (!found) {
|
||||
rcu_read_unlock();
|
||||
err = -ENOENT;
|
||||
goto errout;
|
||||
}
|
||||
|
|
@ -2442,8 +2498,8 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|||
if (tbp[NDTPA_IFINDEX])
|
||||
ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]);
|
||||
|
||||
p = lookup_neigh_parms(tbl, net, ifindex);
|
||||
if (p == NULL) {
|
||||
p = lookup_neigh_parms(tbl, ifindex);
|
||||
if (!p) {
|
||||
err = -ENOENT;
|
||||
goto errout_tbl_lock;
|
||||
}
|
||||
|
|
@ -2524,12 +2580,6 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|||
}
|
||||
}
|
||||
|
||||
err = -ENOENT;
|
||||
if ((tb[NDTA_THRESH1] || tb[NDTA_THRESH2] ||
|
||||
tb[NDTA_THRESH3] || tb[NDTA_GC_INTERVAL]) &&
|
||||
!net_eq(net, &init_net))
|
||||
goto errout_tbl_lock;
|
||||
|
||||
if (tb[NDTA_THRESH1])
|
||||
WRITE_ONCE(tbl->gc_thresh1, nla_get_u32(tb[NDTA_THRESH1]));
|
||||
|
||||
|
|
@ -2546,7 +2596,6 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|||
|
||||
errout_tbl_lock:
|
||||
spin_unlock_bh(&tbl->lock);
|
||||
rcu_read_unlock();
|
||||
errout:
|
||||
return err;
|
||||
}
|
||||
|
|
@ -2598,7 +2647,7 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
|
||||
struct neigh_parms *p;
|
||||
|
||||
tbl = rcu_dereference(neigh_tables[tidx]);
|
||||
tbl = net->neigh_tables[tidx];
|
||||
if (!tbl)
|
||||
continue;
|
||||
|
||||
|
|
@ -2613,9 +2662,6 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
nidx = 0;
|
||||
p = list_next_entry(&tbl->parms, list);
|
||||
list_for_each_entry_from_rcu(p, &tbl->parms_list, list) {
|
||||
if (!net_eq(neigh_parms_net(p), net))
|
||||
continue;
|
||||
|
||||
if (nidx < neigh_skip)
|
||||
goto next;
|
||||
|
||||
|
|
@ -2793,12 +2839,11 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
|
|||
struct netlink_callback *cb,
|
||||
struct neigh_dump_filter *filter)
|
||||
{
|
||||
struct net *net = sock_net(skb->sk);
|
||||
struct neighbour *n;
|
||||
int err = 0, h, s_h = cb->args[1];
|
||||
int idx, s_idx = idx = cb->args[2];
|
||||
struct neigh_hash_table *nht;
|
||||
int err = 0, h, s_h = cb->args[1];
|
||||
unsigned int flags = NLM_F_MULTI;
|
||||
struct neigh_hash_table *nht;
|
||||
struct neighbour *n;
|
||||
|
||||
if (filter->dev_idx || filter->master_idx)
|
||||
flags |= NLM_F_DUMP_FILTERED;
|
||||
|
|
@ -2810,7 +2855,7 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
|
|||
s_idx = 0;
|
||||
idx = 0;
|
||||
neigh_for_each_in_bucket_rcu(n, &nht->hash_heads[h]) {
|
||||
if (idx < s_idx || !net_eq(dev_net(n->dev), net))
|
||||
if (idx < s_idx)
|
||||
goto next;
|
||||
if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
|
||||
neigh_master_filtered(n->dev, filter->master_idx))
|
||||
|
|
@ -2834,11 +2879,10 @@ static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
|
|||
struct netlink_callback *cb,
|
||||
struct neigh_dump_filter *filter)
|
||||
{
|
||||
struct pneigh_entry *n;
|
||||
struct net *net = sock_net(skb->sk);
|
||||
int err = 0, h, s_h = cb->args[3];
|
||||
int idx, s_idx = idx = cb->args[4];
|
||||
int err = 0, h, s_h = cb->args[3];
|
||||
unsigned int flags = NLM_F_MULTI;
|
||||
struct pneigh_entry *n;
|
||||
|
||||
if (filter->dev_idx || filter->master_idx)
|
||||
flags |= NLM_F_DUMP_FILTERED;
|
||||
|
|
@ -2849,7 +2893,7 @@ static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
|
|||
for (n = rcu_dereference(tbl->phash_buckets[h]), idx = 0;
|
||||
n;
|
||||
n = rcu_dereference(n->next)) {
|
||||
if (idx < s_idx || pneigh_net(n) != net)
|
||||
if (idx < s_idx)
|
||||
goto next;
|
||||
if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
|
||||
neigh_master_filtered(n->dev, filter->master_idx))
|
||||
|
|
@ -2935,6 +2979,7 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
{
|
||||
const struct nlmsghdr *nlh = cb->nlh;
|
||||
struct neigh_dump_filter filter = {};
|
||||
struct net *net = sock_net(skb->sk);
|
||||
struct neigh_table *tbl;
|
||||
int t, family, s_t;
|
||||
int proxy = 0;
|
||||
|
|
@ -2958,8 +3003,7 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
|
||||
rcu_read_lock();
|
||||
for (t = 0; t < NEIGH_NR_TABLES; t++) {
|
||||
tbl = rcu_dereference(neigh_tables[t]);
|
||||
|
||||
tbl = net->neigh_tables[t];
|
||||
if (!tbl)
|
||||
continue;
|
||||
if (t < s_t || (family && tbl->family != family))
|
||||
|
|
@ -3081,7 +3125,7 @@ static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
|
|||
|
||||
rcu_read_lock();
|
||||
|
||||
tbl = neigh_find_table(ndm->ndm_family);
|
||||
tbl = neigh_find_table(net, ndm->ndm_family);
|
||||
if (!tbl) {
|
||||
NL_SET_ERR_MSG(extack, "Unsupported family in header for neighbor get request");
|
||||
err = -EAFNOSUPPORT;
|
||||
|
|
@ -3108,7 +3152,7 @@ static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
|
|||
if (ndm->ndm_flags & NTF_PROXY) {
|
||||
struct pneigh_entry *pn;
|
||||
|
||||
pn = pneigh_lookup(tbl, net, dst, dev);
|
||||
pn = pneigh_lookup(tbl, dst, dev);
|
||||
if (!pn) {
|
||||
NL_SET_ERR_MSG(extack, "Proxy neighbour entry not found");
|
||||
err = -ENOENT;
|
||||
|
|
@ -3161,37 +3205,6 @@ void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void
|
|||
}
|
||||
EXPORT_SYMBOL(neigh_for_each);
|
||||
|
||||
/* The tbl->lock must be held as a writer and BH disabled. */
|
||||
void __neigh_for_each_release(struct neigh_table *tbl,
|
||||
int (*cb)(struct neighbour *))
|
||||
{
|
||||
struct neigh_hash_table *nht;
|
||||
int chain;
|
||||
|
||||
nht = rcu_dereference_protected(tbl->nht,
|
||||
lockdep_is_held(&tbl->lock));
|
||||
for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
|
||||
struct hlist_node *tmp;
|
||||
struct neighbour *n;
|
||||
|
||||
neigh_for_each_in_bucket_safe(n, tmp, &nht->hash_heads[chain]) {
|
||||
int release;
|
||||
|
||||
write_lock(&n->lock);
|
||||
release = cb(n);
|
||||
if (release) {
|
||||
hlist_del_rcu(&n->hash);
|
||||
hlist_del_rcu(&n->dev_list);
|
||||
neigh_mark_dead(n);
|
||||
}
|
||||
write_unlock(&n->lock);
|
||||
if (release)
|
||||
neigh_cleanup_and_release(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(__neigh_for_each_release);
|
||||
|
||||
int neigh_xmit(int index, struct net_device *dev,
|
||||
const void *addr, struct sk_buff *skb)
|
||||
{
|
||||
|
|
@ -3200,9 +3213,11 @@ int neigh_xmit(int index, struct net_device *dev,
|
|||
if (likely(index < NEIGH_NR_TABLES)) {
|
||||
struct neigh_table *tbl;
|
||||
struct neighbour *neigh;
|
||||
struct net *net;
|
||||
|
||||
rcu_read_lock();
|
||||
tbl = rcu_dereference(neigh_tables[index]);
|
||||
net = dev_net_rcu(dev);
|
||||
tbl = net->neigh_tables[index];
|
||||
if (!tbl) {
|
||||
rcu_read_unlock();
|
||||
goto out_kfree_skb;
|
||||
|
|
@ -3245,10 +3260,6 @@ static struct neighbour *neigh_get_valid(struct seq_file *seq,
|
|||
loff_t *pos)
|
||||
{
|
||||
struct neigh_seq_state *state = seq->private;
|
||||
struct net *net = seq_file_net(seq);
|
||||
|
||||
if (!net_eq(dev_net(n->dev), net))
|
||||
return NULL;
|
||||
|
||||
if (state->neigh_sub_iter) {
|
||||
loff_t fakep = 0;
|
||||
|
|
@ -3337,7 +3348,6 @@ static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
|
|||
static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
|
||||
{
|
||||
struct neigh_seq_state *state = seq->private;
|
||||
struct net *net = seq_file_net(seq);
|
||||
struct neigh_table *tbl = state->tbl;
|
||||
struct pneigh_entry *pn = NULL;
|
||||
int bucket;
|
||||
|
|
@ -3345,9 +3355,6 @@ static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
|
|||
state->flags |= NEIGH_SEQ_IS_PNEIGH;
|
||||
for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) {
|
||||
pn = rcu_dereference(tbl->phash_buckets[bucket]);
|
||||
|
||||
while (pn && !net_eq(pneigh_net(pn), net))
|
||||
pn = rcu_dereference(pn->next);
|
||||
if (pn)
|
||||
break;
|
||||
}
|
||||
|
|
@ -3361,21 +3368,15 @@ static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
|
|||
loff_t *pos)
|
||||
{
|
||||
struct neigh_seq_state *state = seq->private;
|
||||
struct net *net = seq_file_net(seq);
|
||||
struct neigh_table *tbl = state->tbl;
|
||||
|
||||
do {
|
||||
pn = rcu_dereference(pn->next);
|
||||
} while (pn && !net_eq(pneigh_net(pn), net));
|
||||
pn = rcu_dereference(pn->next);
|
||||
|
||||
while (!pn) {
|
||||
if (++state->bucket > PNEIGH_HASHMASK)
|
||||
break;
|
||||
|
||||
pn = rcu_dereference(tbl->phash_buckets[state->bucket]);
|
||||
|
||||
while (pn && !net_eq(pneigh_net(pn), net))
|
||||
pn = rcu_dereference(pn->next);
|
||||
if (pn)
|
||||
break;
|
||||
}
|
||||
|
|
@ -3430,7 +3431,6 @@ void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table *tbl
|
|||
|
||||
return *pos ? neigh_get_idx_any(seq, pos) : SEQ_START_TOKEN;
|
||||
}
|
||||
EXPORT_SYMBOL(neigh_seq_start);
|
||||
|
||||
void *neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
||||
{
|
||||
|
|
@ -3457,7 +3457,6 @@ void *neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
|||
++(*pos);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(neigh_seq_next);
|
||||
|
||||
void neigh_seq_stop(struct seq_file *seq, void *v)
|
||||
__releases(tbl->lock)
|
||||
|
|
@ -3469,7 +3468,6 @@ void neigh_seq_stop(struct seq_file *seq, void *v)
|
|||
spin_unlock_bh(&tbl->lock);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
EXPORT_SYMBOL(neigh_seq_stop);
|
||||
|
||||
/* statistics via seq_file */
|
||||
|
||||
|
|
@ -3523,7 +3521,7 @@ static int neigh_stat_seq_show(struct seq_file *seq, void *v)
|
|||
seq_printf(seq, "%08x %08lx %08lx %08lx %08lx %08lx %08lx "
|
||||
"%08lx %08lx %08lx "
|
||||
"%08lx %08lx %08lx\n",
|
||||
atomic_read(&tbl->entries),
|
||||
neigh_table_entries(tbl),
|
||||
|
||||
st->allocs,
|
||||
st->destroys,
|
||||
|
|
@ -3593,7 +3591,6 @@ void neigh_app_ns(struct neighbour *n)
|
|||
{
|
||||
neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(neigh_app_ns);
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
static int unres_qlen_max = INT_MAX / SKB_TRUESIZE(ETH_FRAME_LEN);
|
||||
|
|
@ -3689,7 +3686,6 @@ int neigh_proc_dointvec(const struct ctl_table *ctl, int write, void *buffer,
|
|||
neigh_proc_update(ctl, write);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(neigh_proc_dointvec);
|
||||
|
||||
int neigh_proc_dointvec_jiffies(const struct ctl_table *ctl, int write, void *buffer,
|
||||
size_t *lenp, loff_t *ppos)
|
||||
|
|
@ -3699,7 +3695,6 @@ int neigh_proc_dointvec_jiffies(const struct ctl_table *ctl, int write, void *bu
|
|||
neigh_proc_update(ctl, write);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(neigh_proc_dointvec_jiffies);
|
||||
|
||||
static int neigh_proc_dointvec_userhz_jiffies(const struct ctl_table *ctl, int write,
|
||||
void *buffer, size_t *lenp,
|
||||
|
|
@ -3719,7 +3714,6 @@ int neigh_proc_dointvec_ms_jiffies(const struct ctl_table *ctl, int write,
|
|||
neigh_proc_update(ctl, write);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(neigh_proc_dointvec_ms_jiffies);
|
||||
|
||||
static int neigh_proc_dointvec_unres_qlen(const struct ctl_table *ctl, int write,
|
||||
void *buffer, size_t *lenp,
|
||||
|
|
@ -3926,7 +3920,6 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
|
|||
err:
|
||||
return -ENOBUFS;
|
||||
}
|
||||
EXPORT_SYMBOL(neigh_sysctl_register);
|
||||
|
||||
void neigh_sysctl_unregister(struct neigh_parms *p)
|
||||
{
|
||||
|
|
@ -3937,7 +3930,6 @@ void neigh_sysctl_unregister(struct neigh_parms *p)
|
|||
kfree(t);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(neigh_sysctl_unregister);
|
||||
|
||||
#endif /* CONFIG_SYSCTL */
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include <net/ip.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/neighbour.h>
|
||||
#include <net/net_ratelimit.h>
|
||||
#include <net/busy_poll.h>
|
||||
#include <net/pkt_sched.h>
|
||||
|
|
@ -676,6 +677,15 @@ static struct ctl_table net_core_table[] = {
|
|||
.proc_handler = proc_do_skb_defer_max,
|
||||
.extra1 = SYSCTL_ZERO,
|
||||
},
|
||||
{
|
||||
.procname = "neigh_inherit_init_net",
|
||||
.data = &sysctl_neigh_inherit_init_net,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_minmax,
|
||||
.extra1 = SYSCTL_ZERO,
|
||||
.extra2 = SYSCTL_ONE,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct ctl_table netns_core_table[] = {
|
||||
|
|
|
|||
|
|
@ -58,8 +58,9 @@ int lowpan_header_create(struct sk_buff *skb, struct net_device *ldev,
|
|||
info->daddr.mode = IEEE802154_ADDR_SHORT;
|
||||
} else {
|
||||
__le16 short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC);
|
||||
struct neigh_table *tbl = nd_table(dev_net(ldev));
|
||||
|
||||
n = neigh_lookup(&nd_tbl, &hdr->daddr, ldev);
|
||||
n = neigh_lookup(tbl, &hdr->daddr, ldev);
|
||||
if (n) {
|
||||
llneigh = lowpan_802154_neigh(neighbour_priv(n));
|
||||
read_lock_bh(&n->lock);
|
||||
|
|
|
|||
137
net/ipv4/arp.c
137
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 net_device *dev = skb->dev;
|
||||
struct in_device *in_dev = __in_dev_get_rcu(dev);
|
||||
struct arphdr *arp;
|
||||
unsigned char *arp_ptr;
|
||||
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 neigh_table *tbl = arp_table(net);
|
||||
struct dst_entry *reply_dst = NULL;
|
||||
struct net_device *dev = skb->dev;
|
||||
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;
|
||||
__be32 sip, tip;
|
||||
int addr_type;
|
||||
|
||||
/* 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, &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, &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, &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 = {
|
||||
|
|
@ -1495,15 +1511,47 @@ static const struct seq_operations arp_seq_ops = {
|
|||
|
||||
static int __net_init arp_net_init(struct net *net)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = neigh_table_register(net, &arp_tbl, NEIGH_ARP_TABLE);
|
||||
if (err)
|
||||
goto err;
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#ifdef CONFIG_SYSCTL
|
||||
err = neigh_sysctl_register(NULL, &arp_table(net)->parms, NULL);
|
||||
if (err)
|
||||
goto err_sysctl;
|
||||
#endif
|
||||
|
||||
if (!proc_create_net("arp", 0444, net->proc_net, &arp_seq_ops,
|
||||
sizeof(struct neigh_seq_state)))
|
||||
return -ENOMEM;
|
||||
sizeof(struct neigh_seq_state))) {
|
||||
err = -ENOMEM;
|
||||
goto err_proc_create;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
err_proc_create:
|
||||
#ifdef CONFIG_SYSCTL
|
||||
neigh_sysctl_unregister(&arp_table(net)->parms);
|
||||
err_sysctl:
|
||||
#endif
|
||||
neigh_table_unregister(net, NEIGH_ARP_TABLE);
|
||||
#endif
|
||||
err:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __net_exit arp_net_exit(struct net *net)
|
||||
{
|
||||
remove_proc_entry("arp", net->proc_net);
|
||||
#ifdef CONFIG_SYSCTL
|
||||
neigh_sysctl_unregister(&arp_table(net)->parms);
|
||||
#endif
|
||||
neigh_table_unregister(net, NEIGH_ARP_TABLE);
|
||||
}
|
||||
|
||||
static struct pernet_operations arp_net_ops = {
|
||||
|
|
@ -1513,12 +1561,9 @@ static struct pernet_operations arp_net_ops = {
|
|||
|
||||
void __init arp_init(void)
|
||||
{
|
||||
neigh_table_init(NEIGH_ARP_TABLE, &arp_tbl);
|
||||
if (register_pernet_subsys(&arp_net_ops))
|
||||
panic("Cannot allocate arp table\n");
|
||||
|
||||
dev_add_pack(&arp_packet_type);
|
||||
register_pernet_subsys(&arp_net_ops);
|
||||
#ifdef CONFIG_SYSCTL
|
||||
neigh_sysctl_register(NULL, &arp_tbl.parms, NULL);
|
||||
#endif
|
||||
register_netdevice_notifier(&arp_netdev_notifier);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -610,13 +610,14 @@ 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);
|
||||
n = neigh_lookup(nd_table(net), &nhc->nhc_gw.ipv6, nhc->nhc_dev);
|
||||
else
|
||||
n = NULL;
|
||||
|
||||
|
|
|
|||
|
|
@ -817,7 +817,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);
|
||||
|
|
|
|||
|
|
@ -376,6 +376,8 @@ static int snmp6_alloc_dev(struct inet6_dev *idev)
|
|||
|
||||
static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
|
||||
{
|
||||
struct net *net = dev_net(dev);
|
||||
struct neigh_table *tbl;
|
||||
struct inet6_dev *ndev;
|
||||
int err = -ENOMEM;
|
||||
|
||||
|
|
@ -393,14 +395,15 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
|
|||
ndev->dev = dev;
|
||||
INIT_LIST_HEAD(&ndev->addr_list);
|
||||
timer_setup(&ndev->rs_timer, addrconf_rs_timer, 0);
|
||||
memcpy(&ndev->cnf, dev_net(dev)->ipv6.devconf_dflt, sizeof(ndev->cnf));
|
||||
memcpy(&ndev->cnf, net->ipv6.devconf_dflt, sizeof(ndev->cnf));
|
||||
|
||||
if (ndev->cnf.stable_secret.initialized)
|
||||
ndev->cnf.addr_gen_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
|
||||
|
||||
tbl = nd_table(net);
|
||||
ndev->cnf.mtu6 = dev->mtu;
|
||||
ndev->ra_mtu = 0;
|
||||
ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl);
|
||||
ndev->nd_parms = neigh_parms_alloc(dev, tbl);
|
||||
if (!ndev->nd_parms) {
|
||||
kfree(ndev);
|
||||
return ERR_PTR(err);
|
||||
|
|
@ -413,7 +416,7 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
|
|||
if (snmp6_alloc_dev(ndev) < 0) {
|
||||
netdev_dbg(dev, "%s: cannot allocate memory for statistics\n",
|
||||
__func__);
|
||||
neigh_parms_release(&nd_tbl, ndev->nd_parms);
|
||||
neigh_parms_release(tbl, ndev->nd_parms);
|
||||
netdev_put(dev, &ndev->dev_tracker);
|
||||
kfree(ndev);
|
||||
return ERR_PTR(err);
|
||||
|
|
@ -481,7 +484,7 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
|
|||
return ndev;
|
||||
|
||||
err_release:
|
||||
neigh_parms_release(&nd_tbl, ndev->nd_parms);
|
||||
neigh_parms_release(tbl, ndev->nd_parms);
|
||||
ndev->dead = 1;
|
||||
in6_dev_finish_destroy(ndev);
|
||||
return ERR_PTR(err);
|
||||
|
|
@ -4039,9 +4042,11 @@ static int addrconf_ifdown(struct net_device *dev, bool unregister)
|
|||
|
||||
/* Last: Shot the device (if unregistered) */
|
||||
if (unregister) {
|
||||
struct neigh_table *tbl = nd_table(net);
|
||||
|
||||
addrconf_sysctl_unregister(idev);
|
||||
neigh_parms_release(&nd_tbl, idev->nd_parms);
|
||||
neigh_ifdown(&nd_tbl, dev);
|
||||
neigh_parms_release(tbl, idev->nd_parms);
|
||||
neigh_ifdown(tbl, dev);
|
||||
in6_dev_put(idev);
|
||||
}
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff *
|
|||
|
||||
if (IS_ERR_OR_NULL(neigh)) {
|
||||
if (unlikely(!neigh))
|
||||
neigh = __neigh_create(&nd_tbl, nexthop, dev, false);
|
||||
neigh = __neigh_create(nd_table(net), nexthop, dev, false);
|
||||
if (IS_ERR(neigh)) {
|
||||
IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTNOROUTES);
|
||||
kfree_skb_reason(skb, SKB_DROP_REASON_NEIGH_CREATEFAIL);
|
||||
|
|
@ -583,7 +583,7 @@ int ip6_forward(struct sk_buff *skb)
|
|||
|
||||
/* XXX: idev->cnf.proxy_ndp? */
|
||||
if (READ_ONCE(net->ipv6.devconf_all->proxy_ndp) &&
|
||||
pneigh_lookup(&nd_tbl, net, &hdr->daddr, skb->dev)) {
|
||||
pneigh_lookup(nd_table(net), &hdr->daddr, skb->dev)) {
|
||||
int proxied = ip6_forward_proxy_check(skb);
|
||||
|
||||
hdr = ipv6_hdr(skb);
|
||||
|
|
|
|||
148
net/ipv6/ndisc.c
148
net/ipv6/ndisc.c
|
|
@ -767,10 +767,11 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
|
|||
static int pndisc_is_router(const void *pkey,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct net *net = dev_net(dev);
|
||||
struct pneigh_entry *n;
|
||||
int ret = -1;
|
||||
|
||||
n = pneigh_lookup(&nd_tbl, dev_net(dev), pkey, dev);
|
||||
n = pneigh_lookup(nd_table(net), pkey, dev);
|
||||
if (n)
|
||||
ret = !!(READ_ONCE(n->flags) & NTF_ROUTER);
|
||||
|
||||
|
|
@ -788,19 +789,21 @@ void ndisc_update(const struct net_device *dev, struct neighbour *neigh,
|
|||
|
||||
static enum skb_drop_reason ndisc_recv_ns(struct sk_buff *skb)
|
||||
{
|
||||
u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
|
||||
offsetof(struct nd_msg, opt));
|
||||
struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
|
||||
const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
|
||||
const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
|
||||
u8 *lladdr = NULL;
|
||||
u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
|
||||
offsetof(struct nd_msg, opt));
|
||||
struct ndisc_options ndopts;
|
||||
struct net_device *dev = skb->dev;
|
||||
struct inet6_ifaddr *ifp;
|
||||
struct inet6_dev *idev = NULL;
|
||||
struct neighbour *neigh;
|
||||
struct net *net = dev_net(dev);
|
||||
int dad = ipv6_addr_any(saddr);
|
||||
struct inet6_dev *idev = NULL;
|
||||
struct ndisc_options ndopts;
|
||||
struct inet6_ifaddr *ifp;
|
||||
struct neigh_table *tbl;
|
||||
struct neighbour *neigh;
|
||||
int is_router = -1;
|
||||
u8 *lladdr = NULL;
|
||||
SKB_DR(reason);
|
||||
u64 nonce = 0;
|
||||
bool inc;
|
||||
|
|
@ -845,9 +848,10 @@ static enum skb_drop_reason ndisc_recv_ns(struct sk_buff *skb)
|
|||
if (ndopts.nd_opts_nonce && ndopts.nd_opts_nonce->nd_opt_len == 1)
|
||||
memcpy(&nonce, (u8 *)(ndopts.nd_opts_nonce + 1), 6);
|
||||
|
||||
inc = ipv6_addr_is_multicast(daddr);
|
||||
tbl = nd_table(net);
|
||||
|
||||
ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
|
||||
inc = ipv6_addr_is_multicast(daddr);
|
||||
ifp = ipv6_get_ifaddr(net, &msg->target, dev, 1);
|
||||
if (ifp) {
|
||||
have_ifp:
|
||||
if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) {
|
||||
|
|
@ -880,8 +884,6 @@ static enum skb_drop_reason ndisc_recv_ns(struct sk_buff *skb)
|
|||
|
||||
idev = ifp->idev;
|
||||
} else {
|
||||
struct net *net = dev_net(dev);
|
||||
|
||||
/* perhaps an address on the master device */
|
||||
if (netif_is_l3_slave(dev)) {
|
||||
struct net_device *mdev;
|
||||
|
|
@ -918,7 +920,7 @@ static enum skb_drop_reason ndisc_recv_ns(struct sk_buff *skb)
|
|||
*/
|
||||
struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);
|
||||
if (n)
|
||||
pneigh_enqueue(&nd_tbl, idev->nd_parms, n);
|
||||
pneigh_enqueue(tbl, idev->nd_parms, n);
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -937,15 +939,15 @@ static enum skb_drop_reason ndisc_recv_ns(struct sk_buff *skb)
|
|||
}
|
||||
|
||||
if (inc)
|
||||
NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_mcast);
|
||||
NEIGH_CACHE_STAT_INC(tbl, rcv_probes_mcast);
|
||||
else
|
||||
NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_ucast);
|
||||
NEIGH_CACHE_STAT_INC(tbl, rcv_probes_ucast);
|
||||
|
||||
/*
|
||||
* update / create cache entry
|
||||
* for the source address
|
||||
*/
|
||||
neigh = __neigh_lookup(&nd_tbl, saddr, dev,
|
||||
neigh = __neigh_lookup(tbl, saddr, dev,
|
||||
!inc || lladdr || !dev->addr_len);
|
||||
if (neigh)
|
||||
ndisc_update(dev, neigh, lladdr, NUD_STALE,
|
||||
|
|
@ -987,17 +989,19 @@ static int accept_untracked_na(struct inet6_dev *idev, struct in6_addr *saddr)
|
|||
|
||||
static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb)
|
||||
{
|
||||
struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
|
||||
struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
|
||||
const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
|
||||
u8 *lladdr = NULL;
|
||||
u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
|
||||
offsetof(struct nd_msg, opt));
|
||||
struct ndisc_options ndopts;
|
||||
struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
|
||||
const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
|
||||
struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
|
||||
struct net_device *dev = skb->dev;
|
||||
struct inet6_dev *idev = __in6_dev_get(dev);
|
||||
struct net *net = dev_net(dev);
|
||||
struct ndisc_options ndopts;
|
||||
struct inet6_ifaddr *ifp;
|
||||
struct neigh_table *tbl;
|
||||
struct neighbour *neigh;
|
||||
struct inet6_dev *idev;
|
||||
u8 *lladdr = NULL;
|
||||
SKB_DR(reason);
|
||||
u8 new_state;
|
||||
|
||||
|
|
@ -1020,6 +1024,7 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb)
|
|||
* and thus should not be accepted.
|
||||
* drop_unsolicited_na takes precedence over accept_untracked_na
|
||||
*/
|
||||
idev = __in6_dev_get(dev);
|
||||
if (!msg->icmph.icmp6_solicited && idev &&
|
||||
READ_ONCE(idev->cnf.drop_unsolicited_na))
|
||||
return reason;
|
||||
|
|
@ -1034,7 +1039,7 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb)
|
|||
return reason;
|
||||
}
|
||||
}
|
||||
ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
|
||||
ifp = ipv6_get_ifaddr(net, &msg->target, dev, 1);
|
||||
if (ifp) {
|
||||
if (skb->pkt_type != PACKET_LOOPBACK
|
||||
&& (ifp->flags & IFA_F_TENTATIVE)) {
|
||||
|
|
@ -1058,7 +1063,8 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb)
|
|||
return reason;
|
||||
}
|
||||
|
||||
neigh = neigh_lookup(&nd_tbl, &msg->target, dev);
|
||||
tbl = nd_table(net);
|
||||
neigh = neigh_lookup(tbl, &msg->target, dev);
|
||||
|
||||
/* RFC 9131 updates original Neighbour Discovery RFC 4861.
|
||||
* NAs with Target LL Address option without a corresponding
|
||||
|
|
@ -1078,14 +1084,13 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb)
|
|||
new_state = msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE;
|
||||
if (!neigh && lladdr && idev && READ_ONCE(idev->cnf.forwarding)) {
|
||||
if (accept_untracked_na(idev, saddr)) {
|
||||
neigh = neigh_create(&nd_tbl, &msg->target, dev);
|
||||
neigh = neigh_create(tbl, &msg->target, dev);
|
||||
new_state = NUD_STALE;
|
||||
}
|
||||
}
|
||||
|
||||
if (neigh && !IS_ERR(neigh)) {
|
||||
u8 old_flags = neigh->flags;
|
||||
struct net *net = dev_net(dev);
|
||||
|
||||
if (READ_ONCE(neigh->nud_state) & NUD_FAILED)
|
||||
goto out;
|
||||
|
|
@ -1098,7 +1103,7 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb)
|
|||
if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) &&
|
||||
READ_ONCE(net->ipv6.devconf_all->forwarding) &&
|
||||
READ_ONCE(net->ipv6.devconf_all->proxy_ndp) &&
|
||||
pneigh_lookup(&nd_tbl, net, &msg->target, dev)) {
|
||||
pneigh_lookup(tbl, &msg->target, dev)) {
|
||||
/* XXX: idev->cnf.proxy_ndp */
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -1127,18 +1132,20 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb)
|
|||
static enum skb_drop_reason ndisc_recv_rs(struct sk_buff *skb)
|
||||
{
|
||||
struct rs_msg *rs_msg = (struct rs_msg *)skb_transport_header(skb);
|
||||
const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
|
||||
unsigned long ndoptlen = skb->len - sizeof(*rs_msg);
|
||||
struct net_device *dev = skb->dev;
|
||||
struct ndisc_options ndopts;
|
||||
struct neigh_table *tbl;
|
||||
struct neighbour *neigh;
|
||||
struct inet6_dev *idev;
|
||||
const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
|
||||
struct ndisc_options ndopts;
|
||||
u8 *lladdr = NULL;
|
||||
SKB_DR(reason);
|
||||
|
||||
if (skb->len < sizeof(*rs_msg))
|
||||
return SKB_DROP_REASON_PKT_TOO_SMALL;
|
||||
|
||||
idev = __in6_dev_get(skb->dev);
|
||||
idev = __in6_dev_get(dev);
|
||||
if (!idev) {
|
||||
net_err_ratelimited("RS: can't find in6 device\n");
|
||||
return reason;
|
||||
|
|
@ -1156,19 +1163,19 @@ static enum skb_drop_reason ndisc_recv_rs(struct sk_buff *skb)
|
|||
goto out;
|
||||
|
||||
/* Parse ND options */
|
||||
if (!ndisc_parse_options(skb->dev, rs_msg->opt, ndoptlen, &ndopts))
|
||||
if (!ndisc_parse_options(dev, rs_msg->opt, ndoptlen, &ndopts))
|
||||
return SKB_DROP_REASON_IPV6_NDISC_BAD_OPTIONS;
|
||||
|
||||
if (ndopts.nd_opts_src_lladdr) {
|
||||
lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
|
||||
skb->dev);
|
||||
lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, dev);
|
||||
if (!lladdr)
|
||||
goto out;
|
||||
}
|
||||
|
||||
neigh = __neigh_lookup(&nd_tbl, saddr, skb->dev, 1);
|
||||
tbl = nd_table(dev_net(dev));
|
||||
neigh = __neigh_lookup(tbl, saddr, dev, 1);
|
||||
if (neigh) {
|
||||
ndisc_update(skb->dev, neigh, lladdr, NUD_STALE,
|
||||
ndisc_update(dev, neigh, lladdr, NUD_STALE,
|
||||
NEIGH_UPDATE_F_WEAK_OVERRIDE|
|
||||
NEIGH_UPDATE_F_OVERRIDE|
|
||||
NEIGH_UPDATE_F_OVERRIDE_ISROUTER,
|
||||
|
|
@ -1232,6 +1239,7 @@ static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
|
|||
static enum skb_drop_reason ndisc_router_discovery(struct sk_buff *skb)
|
||||
{
|
||||
struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb);
|
||||
struct net *net = dev_net(skb->dev);
|
||||
bool send_ifinfo_notify = false;
|
||||
struct neighbour *neigh = NULL;
|
||||
struct ndisc_options ndopts;
|
||||
|
|
@ -1241,7 +1249,6 @@ static enum skb_drop_reason ndisc_router_discovery(struct sk_buff *skb)
|
|||
u32 defrtr_usr_metric;
|
||||
unsigned int pref = 0;
|
||||
__u32 old_if_flags;
|
||||
struct net *net;
|
||||
SKB_DR(reason);
|
||||
int lifetime;
|
||||
int optlen;
|
||||
|
|
@ -1330,7 +1337,6 @@ static enum skb_drop_reason ndisc_router_discovery(struct sk_buff *skb)
|
|||
/* Do not accept RA with source-addr found on local machine unless
|
||||
* accept_ra_from_local is set to true.
|
||||
*/
|
||||
net = dev_net(in6_dev->dev);
|
||||
if (!READ_ONCE(in6_dev->cnf.accept_ra_from_local) &&
|
||||
ipv6_chk_addr(net, &ipv6_hdr(skb)->saddr, in6_dev->dev, 0)) {
|
||||
net_dbg_ratelimited("RA from local address detected on dev: %s: default router ignored\n",
|
||||
|
|
@ -1468,7 +1474,7 @@ static enum skb_drop_reason ndisc_router_discovery(struct sk_buff *skb)
|
|||
*/
|
||||
|
||||
if (!neigh)
|
||||
neigh = __neigh_lookup(&nd_tbl, &ipv6_hdr(skb)->saddr,
|
||||
neigh = __neigh_lookup(nd_table(net), &ipv6_hdr(skb)->saddr,
|
||||
skb->dev, 1);
|
||||
if (neigh) {
|
||||
u8 *lladdr = NULL;
|
||||
|
|
@ -1861,12 +1867,15 @@ static int ndisc_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 neigh_table *tbl;
|
||||
struct inet6_dev *idev;
|
||||
bool evict_nocarrier;
|
||||
|
||||
tbl = nd_table(net);
|
||||
|
||||
switch (event) {
|
||||
case NETDEV_CHANGEADDR:
|
||||
neigh_changeaddr(&nd_tbl, dev);
|
||||
neigh_changeaddr(tbl, dev);
|
||||
fib6_run_gc(0, net, false);
|
||||
fallthrough;
|
||||
case NETDEV_UP:
|
||||
|
|
@ -1890,12 +1899,12 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event,
|
|||
|
||||
change_info = ptr;
|
||||
if (change_info->flags_changed & IFF_NOARP)
|
||||
neigh_changeaddr(&nd_tbl, dev);
|
||||
neigh_changeaddr(tbl, dev);
|
||||
if (evict_nocarrier && !netif_carrier_ok(dev))
|
||||
neigh_carrier_down(&nd_tbl, dev);
|
||||
neigh_carrier_down(tbl, dev);
|
||||
break;
|
||||
case NETDEV_DOWN:
|
||||
neigh_ifdown(&nd_tbl, dev);
|
||||
neigh_ifdown(tbl, dev);
|
||||
fib6_run_gc(0, net, false);
|
||||
break;
|
||||
case NETDEV_NOTIFY_PEERS:
|
||||
|
|
@ -1974,12 +1983,23 @@ static int __net_init ndisc_net_init(struct net *net)
|
|||
struct sock *sk;
|
||||
int err;
|
||||
|
||||
err = neigh_table_register(net, &nd_tbl, NEIGH_ND_TABLE);
|
||||
if (err)
|
||||
goto err;
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
err = neigh_sysctl_register(NULL, &nd_table(net)->parms,
|
||||
ndisc_ifinfo_sysctl_change);
|
||||
if (err)
|
||||
goto err_sysctl;
|
||||
#endif
|
||||
|
||||
err = inet_ctl_sock_create(&sk, PF_INET6,
|
||||
SOCK_RAW, IPPROTO_ICMPV6, net);
|
||||
if (err < 0) {
|
||||
net_err_ratelimited("NDISC: Failed to initialize the control socket (err %d)\n",
|
||||
err);
|
||||
return err;
|
||||
goto err_sock_create;
|
||||
}
|
||||
|
||||
net->ipv6.ndisc_sk = sk;
|
||||
|
|
@ -1990,11 +2010,24 @@ static int __net_init ndisc_net_init(struct net *net)
|
|||
inet6_clear_bit(MC6_LOOP, sk);
|
||||
|
||||
return 0;
|
||||
|
||||
err_sock_create:
|
||||
#ifdef CONFIG_SYSCTL
|
||||
neigh_sysctl_unregister(&nd_table(net)->parms);
|
||||
err_sysctl:
|
||||
#endif
|
||||
neigh_table_unregister(net, NEIGH_ND_TABLE);
|
||||
err:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __net_exit ndisc_net_exit(struct net *net)
|
||||
{
|
||||
inet_ctl_sock_destroy(net->ipv6.ndisc_sk);
|
||||
#ifdef CONFIG_SYSCTL
|
||||
neigh_sysctl_unregister(&nd_table(net)->parms);
|
||||
#endif
|
||||
neigh_table_unregister(net, NEIGH_ND_TABLE);
|
||||
}
|
||||
|
||||
static struct pernet_operations ndisc_net_ops = {
|
||||
|
|
@ -2004,30 +2037,7 @@ static struct pernet_operations ndisc_net_ops = {
|
|||
|
||||
int __init ndisc_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = register_pernet_subsys(&ndisc_net_ops);
|
||||
if (err)
|
||||
return err;
|
||||
/*
|
||||
* Initialize the neighbour table
|
||||
*/
|
||||
neigh_table_init(NEIGH_ND_TABLE, &nd_tbl);
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
err = neigh_sysctl_register(NULL, &nd_tbl.parms,
|
||||
ndisc_ifinfo_sysctl_change);
|
||||
if (err)
|
||||
goto out_unregister_pernet;
|
||||
out:
|
||||
#endif
|
||||
return err;
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
out_unregister_pernet:
|
||||
unregister_pernet_subsys(&ndisc_net_ops);
|
||||
goto out;
|
||||
#endif
|
||||
return register_pernet_subsys(&ndisc_net_ops);
|
||||
}
|
||||
|
||||
int __init ndisc_late_init(void)
|
||||
|
|
@ -2042,9 +2052,5 @@ void ndisc_late_cleanup(void)
|
|||
|
||||
void ndisc_cleanup(void)
|
||||
{
|
||||
#ifdef CONFIG_SYSCTL
|
||||
neigh_sysctl_unregister(&nd_tbl.parms);
|
||||
#endif
|
||||
neigh_table_clear(NEIGH_ND_TABLE, &nd_tbl);
|
||||
unregister_pernet_subsys(&ndisc_net_ops);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ struct neighbour *ip6_neigh_lookup(const struct in6_addr *gw,
|
|||
if (n)
|
||||
return n;
|
||||
|
||||
n = neigh_create(&nd_tbl, daddr, dev);
|
||||
n = neigh_create(nd_table(dev_net(dev)), daddr, dev);
|
||||
return IS_ERR(n) ? NULL : n;
|
||||
}
|
||||
|
||||
|
|
@ -4241,6 +4241,7 @@ static int ip6_route_del(struct fib6_config *cfg,
|
|||
static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct netevent_redirect netevent;
|
||||
struct net_device *dev = skb->dev;
|
||||
struct rt6_info *rt, *nrt = NULL;
|
||||
struct fib6_result res = {};
|
||||
struct ndisc_options ndopts;
|
||||
|
|
@ -4274,7 +4275,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
|
|||
return;
|
||||
}
|
||||
|
||||
in6_dev = __in6_dev_get(skb->dev);
|
||||
in6_dev = __in6_dev_get(dev);
|
||||
if (!in6_dev)
|
||||
return;
|
||||
if (READ_ONCE(in6_dev->cnf.forwarding) ||
|
||||
|
|
@ -4286,15 +4287,14 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
|
|||
* first-hop router for the specified ICMP Destination Address.
|
||||
*/
|
||||
|
||||
if (!ndisc_parse_options(skb->dev, msg->opt, optlen, &ndopts)) {
|
||||
if (!ndisc_parse_options(dev, msg->opt, optlen, &ndopts)) {
|
||||
net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
|
||||
return;
|
||||
}
|
||||
|
||||
lladdr = NULL;
|
||||
if (ndopts.nd_opts_tgt_lladdr) {
|
||||
lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
|
||||
skb->dev);
|
||||
lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, dev);
|
||||
if (!lladdr) {
|
||||
net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n");
|
||||
return;
|
||||
|
|
@ -4313,7 +4313,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
|
|||
*/
|
||||
dst_confirm_neigh(&rt->dst, &ipv6_hdr(skb)->saddr);
|
||||
|
||||
neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
|
||||
neigh = __neigh_lookup(nd_table(dev_net(dev)), &msg->target, dev, 1);
|
||||
if (!neigh)
|
||||
return;
|
||||
|
||||
|
|
@ -4321,7 +4321,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
|
|||
* We have finally decided to accept it.
|
||||
*/
|
||||
|
||||
ndisc_update(skb->dev, neigh, lladdr, NUD_STALE,
|
||||
ndisc_update(dev, neigh, lladdr, NUD_STALE,
|
||||
NEIGH_UPDATE_F_WEAK_OVERRIDE|
|
||||
NEIGH_UPDATE_F_OVERRIDE|
|
||||
(on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
|
||||
|
|
@ -5042,9 +5042,11 @@ void rt6_sync_down_dev(struct net_device *dev, unsigned long event)
|
|||
|
||||
void rt6_disable_ip(struct net_device *dev, unsigned long event)
|
||||
{
|
||||
struct net *net = dev_net(dev);
|
||||
|
||||
rt6_sync_down_dev(dev, event);
|
||||
rt6_uncached_list_flush_dev(dev);
|
||||
neigh_ifdown(&nd_tbl, dev);
|
||||
neigh_ifdown(nd_table(net), dev);
|
||||
}
|
||||
|
||||
struct rt6_mtu_change_arg {
|
||||
|
|
|
|||
|
|
@ -63,6 +63,15 @@ exit_cleanup_all()
|
|||
exit "${EXIT_STATUS}"
|
||||
}
|
||||
|
||||
get_periodic_gc_runs()
|
||||
{
|
||||
local ns=$1
|
||||
local tbl_name=$2
|
||||
|
||||
ip -n "$ns" -j -s ntable show name "$tbl_name" | \
|
||||
jq '.[] | select(has("periodic_gc_runs")) | .["periodic_gc_runs"]'
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Tests
|
||||
|
||||
|
|
@ -231,9 +240,6 @@ extern_valid_common()
|
|||
# Check that an "extern_valid" entry survives a forced garbage
|
||||
# collection. Add an entry, wait 5 seconds and add more entries than
|
||||
# "thresh3" so that forced garbage collection will run.
|
||||
#
|
||||
# Note that the garbage collection thresholds are global resources and
|
||||
# that changes in the initial namespace affect all the namespaces.
|
||||
local forced_gc_runs_t0
|
||||
local forced_gc_runs_t1
|
||||
local orig_thresh1
|
||||
|
|
@ -241,18 +247,23 @@ extern_valid_common()
|
|||
local orig_thresh3
|
||||
|
||||
run_cmd "ip -n $ns1 neigh flush dev veth0"
|
||||
orig_thresh1=$(ip -j ntable show name "$tbl_name" | jq '.[] | select(has("thresh1")) | .["thresh1"]')
|
||||
orig_thresh2=$(ip -j ntable show name "$tbl_name" | jq '.[] | select(has("thresh2")) | .["thresh2"]')
|
||||
orig_thresh3=$(ip -j ntable show name "$tbl_name" | jq '.[] | select(has("thresh3")) | .["thresh3"]')
|
||||
run_cmd "ip ntable change name $tbl_name thresh3 10 thresh2 9 thresh1 8"
|
||||
orig_thresh1=$(ip -n "$ns1" -j ntable show name "$tbl_name" | \
|
||||
jq '.[] | select(has("thresh1")) | .["thresh1"]')
|
||||
orig_thresh2=$(ip -n "$ns1" -j ntable show name "$tbl_name" | \
|
||||
jq '.[] | select(has("thresh2")) | .["thresh2"]')
|
||||
orig_thresh3=$(ip -n "$ns1" -j ntable show name "$tbl_name" | \
|
||||
jq '.[] | select(has("thresh3")) | .["thresh3"]')
|
||||
run_cmd "ip -n $ns1 ntable change name $tbl_name thresh3 10 thresh2 9 thresh1 8"
|
||||
run_cmd "ip -n $ns1 neigh add $ip_addr lladdr $mac nud stale dev veth0 extern_valid"
|
||||
run_cmd "ip -n $ns1 neigh add ${subnet}3 lladdr $mac nud stale dev veth0"
|
||||
run_cmd "sleep 5"
|
||||
forced_gc_runs_t0=$(ip -j -s ntable show name "$tbl_name" | jq '.[] | select(has("forced_gc_runs")) | .["forced_gc_runs"]')
|
||||
forced_gc_runs_t0=$(ip -n "$ns1" -j -s ntable show name "$tbl_name" | \
|
||||
jq '.[] | select(has("forced_gc_runs")) | .["forced_gc_runs"]')
|
||||
for i in {1..20}; do
|
||||
run_cmd "ip -n $ns1 neigh add ${subnet}$((i + 4)) nud none dev veth0"
|
||||
done
|
||||
forced_gc_runs_t1=$(ip -j -s ntable show name "$tbl_name" | jq '.[] | select(has("forced_gc_runs")) | .["forced_gc_runs"]')
|
||||
forced_gc_runs_t1=$(ip -n "$ns1" -j -s ntable show name "$tbl_name" | \
|
||||
jq '.[] | select(has("forced_gc_runs")) | .["forced_gc_runs"]')
|
||||
if [[ $forced_gc_runs_t1 -eq $forced_gc_runs_t0 ]]; then
|
||||
check_err 1 "Forced garbage collection did not run"
|
||||
fi
|
||||
|
|
@ -263,7 +274,8 @@ extern_valid_common()
|
|||
|
||||
log_test "$af_str \"extern_valid\" flag: Forced garbage collection"
|
||||
|
||||
run_cmd "ip ntable change name $tbl_name thresh3 $orig_thresh3 thresh2 $orig_thresh2 thresh1 $orig_thresh1"
|
||||
run_cmd "ip -n $ns1 ntable change name $tbl_name \
|
||||
thresh3 $orig_thresh3 thresh2 $orig_thresh2 thresh1 $orig_thresh1"
|
||||
|
||||
RET=0
|
||||
|
||||
|
|
@ -275,31 +287,36 @@ extern_valid_common()
|
|||
# collection. Add an "extern_valid" entry, add more than "thresh1"
|
||||
# regular entries, wait "base_reachable" (longer than "gc_stale")
|
||||
# seconds and check that the "extern_valid" entry was not deleted.
|
||||
#
|
||||
# Note that the garbage collection thresholds and "base_reachable" are
|
||||
# global resources and that changes in the initial namespace affect all
|
||||
# the namespaces.
|
||||
local periodic_gc_runs_t0
|
||||
local periodic_gc_runs_t1
|
||||
local orig_base_reachable
|
||||
local base_reachable=10000
|
||||
local orig_gc_stale
|
||||
local timeout
|
||||
|
||||
run_cmd "ip -n $ns1 neigh flush dev veth0"
|
||||
orig_thresh1=$(ip -j ntable show name "$tbl_name" | jq '.[] | select(has("thresh1")) | .["thresh1"]')
|
||||
orig_base_reachable=$(ip -j ntable show name "$tbl_name" | jq '.[] | select(has("thresh1")) | .["base_reachable"]')
|
||||
run_cmd "ip ntable change name $tbl_name thresh1 10 base_reachable 10000"
|
||||
orig_gc_stale=$(ip -n "$ns1" -j ntable show name "$tbl_name" dev veth0 | jq '.[]["gc_stale"]')
|
||||
orig_thresh1=$(ip -n "$ns1" -j ntable show name "$tbl_name" | \
|
||||
jq '.[] | select(has("thresh1")) | .["thresh1"]')
|
||||
orig_base_reachable=$(ip -n "$ns1" -j ntable show name "$tbl_name" | \
|
||||
jq '.[] | select(has("thresh1")) | .["base_reachable"]')
|
||||
run_cmd "ip -n $ns1 ntable change name $tbl_name thresh1 10 base_reachable $base_reachable"
|
||||
orig_gc_stale=$(ip -n "$ns1" -j ntable show name "$tbl_name" dev veth0 | \
|
||||
jq '.[]["gc_stale"]')
|
||||
run_cmd "ip -n $ns1 ntable change name $tbl_name dev veth0 gc_stale 1000"
|
||||
run_cmd "ip -n $ns1 neigh add $ip_addr lladdr $mac nud stale dev veth0 extern_valid"
|
||||
run_cmd "ip -n $ns1 neigh add ${subnet}3 lladdr $mac nud stale dev veth0"
|
||||
# Wait orig_base_reachable/2 for the new interval to take effect.
|
||||
run_cmd "sleep $(((orig_base_reachable / 1000) / 2 + 2))"
|
||||
# Wait up to neigh_set_reach_time(BASE_REACHABLE_TIME) (~45s) + 5s
|
||||
# for the new interval to take effect, see neigh_table_init().
|
||||
timeout=$(((orig_base_reachable / 1000) * 3 / 2 + 5))
|
||||
slowwait_for_counter "$timeout" 1 get_periodic_gc_runs "$ns1" "$tbl_name" >/dev/null
|
||||
for i in {1..20}; do
|
||||
run_cmd "ip -n $ns1 neigh add ${subnet}$((i + 4)) nud none dev veth0"
|
||||
done
|
||||
periodic_gc_runs_t0=$(ip -j -s ntable show name "$tbl_name" | jq '.[] | select(has("periodic_gc_runs")) | .["periodic_gc_runs"]')
|
||||
run_cmd "sleep 10"
|
||||
periodic_gc_runs_t1=$(ip -j -s ntable show name "$tbl_name" | jq '.[] | select(has("periodic_gc_runs")) | .["periodic_gc_runs"]')
|
||||
periodic_gc_runs_t0=$(get_periodic_gc_runs "$ns1" "$tbl_name")
|
||||
# Wait up to BASE_REACHABLE_TIME / 2 + 5s, see neigh_periodic_work().
|
||||
timeout=$(((base_reachable / 1000) / 2 + 5))
|
||||
slowwait_for_counter "$timeout" 1 get_periodic_gc_runs "$ns1" "$tbl_name" >/dev/null
|
||||
periodic_gc_runs_t1=$(get_periodic_gc_runs "$ns1" "$tbl_name")
|
||||
[[ $periodic_gc_runs_t1 -ne $periodic_gc_runs_t0 ]]
|
||||
check_err $? "Periodic garbage collection did not run"
|
||||
run_cmd "ip -n $ns1 neigh get $ip_addr dev veth0 | grep \"extern_valid\""
|
||||
|
|
@ -310,7 +327,8 @@ extern_valid_common()
|
|||
log_test "$af_str \"extern_valid\" flag: Periodic garbage collection"
|
||||
|
||||
run_cmd "ip -n $ns1 ntable change name $tbl_name dev veth0 gc_stale $orig_gc_stale"
|
||||
run_cmd "ip ntable change name $tbl_name thresh1 $orig_thresh1 base_reachable $orig_base_reachable"
|
||||
run_cmd "ip -n $ns1 ntable change name $tbl_name \
|
||||
thresh1 $orig_thresh1 base_reachable $orig_base_reachable"
|
||||
}
|
||||
|
||||
extern_valid_ipv4()
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user