net: Convert neighbor tables to per-namespace
Subsystems (16)
[email protected]
maintainercover net: Convert neighbor tables to per-namespace
From: David Ahern <[email protected]>
Nikita Leshenko reported that neighbor entries in one namespace can evict neighbor entries in another. The problem is that the neighbor tables have entries across all namespaces without separate accounting and with global limits on when to scan for entries to evict.
Resolve by making the neighbor tables for ipv4, ipv6 and decnet per namespace and making the accounting and threshold limits per namespace.
David Ahern (17):
net/ipv4: rename ipv4_neigh_lookup to ipv4_dst_neigh_lookup net/neigh: export neigh_find_table
net/ipv4: wrappers for arp table references
net/ipv4: Remove open coded use of arp table net/ipv6: wrappers for neighbor table references net/ipv6: Remove open coded use of neighbor table drivers/net: remove open coding of neighbor tables
net: Remove nd_tbl from ipv6 stub
net: Remove arp_tbl and nd_tbl from headers
net: Add key_len to neighbor constructor
net: Change neigh_table_init and neigh_table_clear signature net/neigh: Change neigh_xmit to take an address family net/neighbor: Convert internal functions away from neigh_tables net/ipv4: Convert arp table to per namespace net/ipv6: Convert neighbor table to per-namespace net/decnet: Move neighbor table to per-namespace net/neighbor: Remove neigh_tables and NEIGH enum
drivers/infiniband/ulp/ipoib/ipoib_main.c | 14 +- drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 35 ++--- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 11 +- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 27 ++-- .../net/ethernet/mellanox/mlxsw/spectrum_span.c | 8 +- .../ethernet/netronome/nfp/flower/tunnel_conf.c | 2 +- drivers/net/ethernet/rocker/rocker_main.c | 4 +- drivers/net/ethernet/rocker/rocker_ofdpa.c | 2 +- drivers/net/vrf.c | 4 +- drivers/net/vxlan.c | 10 +- include/net/addrconf.h | 1 - include/net/arp.h | 25 +++- include/net/ndisc.h | 75 +++++++++- include/net/neighbour.h | 17 +-- include/net/net_namespace.h | 3 + include/net/netns/ipv4.h | 1 + include/net/netns/ipv6.h | 1 + net/atm/clip.c | 14 +- net/bridge/br_arp_nd_proxy.c | 4 +- net/core/filter.c | 3 +- net/core/neighbour.c | 115 +++++++++----- net/decnet/dn_neigh.c | 8 +- net/ieee802154/6lowpan/tx.c | 2 +- net/ipv4/arp.c | 130 +++++++++------- net/ipv4/devinet.c | 8 +- net/ipv4/fib_semantics.c | 2 +- net/ipv4/ip_output.c | 2 +- net/ipv4/route.c | 12 +- net/ipv6/addrconf.c | 16 +- net/ipv6/af_inet6.c | 1 - net/ipv6/ip6_output.c | 4 +- net/ipv6/ndisc.c | 165 +++++++++++---------- net/ipv6/route.c | 12 +- net/mpls/af_mpls.c | 33 ++--- net/mpls/mpls_iptunnel.c | 6 +- net/netfilter/nf_flow_table_ip.c | 4 +- net/netfilter/nft_fwd_netdev.c | 6 +- 37 files changed, 467 insertions(+), 320 deletions(-)
Signature · 1 line
2.11.0
[email protected]
maintainerPATCH 1/17 net/ipv4: rename ipv4_neigh_lookup to ipv4_dst_neigh_lookup
From: David Ahern <[email protected]>
Consistency with ipv6 name for similar function and allows ipv4_neigh_lookup to be reused for the wrapper to the arp table.
--- net/ipv4/route.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
net/ipv4/route.c +4 -4
@@ -153,7 +153,7 @@ static u32 *ipv4_cow_metrics(struct dst_entry *dst, unsigned long old)return NULL ; } -static struct neighbour *ipv4_neigh_lookup (const struct dst_entry *dst, +static struct neighbour *ipv4_dst_neigh_lookup (const struct dst_entry *dst,struct sk_buff *skb,const void *daddr);static void ipv4_confirm_neigh (const struct dst_entry *dst,const void *daddr);
@@ -170,7 +170,7 @@ static struct dst_ops ipv4_dst_ops = { .update_pmtu = ip_rt_update_pmtu, .redirect = ip_do_redirect, .local_out = __ip_local_out, - .neigh_lookup = ipv4_neigh_lookup, + .neigh_lookup = ipv4_dst_neigh_lookup, .confirm_neigh = ipv4_confirm_neigh, };
@@ -430,7 +430,7 @@ void rt_cache_flush(struct net *net)rt_genid_bump_ipv4 (net); } -static struct neighbour *ipv4_neigh_lookup (const struct dst_entry *dst, +static struct neighbour *ipv4_dst_neigh_lookup (const struct dst_entry *dst,struct sk_buff *skb,const void *daddr) {
@@ -2537,7 +2537,7 @@ static struct dst_ops ipv4_dst_blackhole_ops = { .update_pmtu = ipv4_rt_blackhole_update_pmtu, .redirect = ipv4_rt_blackhole_redirect, .cow_metrics = ipv4_rt_blackhole_cow_metrics, - .neigh_lookup = ipv4_neigh_lookup, + .neigh_lookup = ipv4_dst_neigh_lookup, };struct dst_entry *ipv4_blackhole_route (struct net *net,struct dst_entry *dst_orig)
Signature · 1 line
2.11.0
[email protected]
maintainerPATCH 2/17 net/neigh: export neigh_find_table
In reply to [email protected]From: David Ahern <[email protected]>
neighbor code already has an API for access to neighbor caches by address family. Export it for use by networking code. Add the namespace as an input arg and make family a u8 versus an int (all existing callers pass ndm_family which is a u8).
--- include/net/neighbour.h | 2 ++ net/core/neighbour.c | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-)
include/net/neighbour.h +2 -0
@@ -229,6 +229,8 @@ enum { NEIGH_LINK_TABLE = NEIGH_NR_TABLES /* Pseudo table for neigh_xmit */ }; +struct neigh_table *neigh_find_table (struct net *net,u8 family); +static inline int neigh_parms_family (struct neigh_parms *p) {return p->tbl->family;
net/core/neighbour.c +4 -3
@@ -1625,7 +1625,7 @@ int neigh_table_clear(int index, struct neigh_table *tbl) }EXPORT_SYMBOL (neigh_table_clear); -static struct neigh_table *neigh_find_table (int family) +struct neigh_table *neigh_find_table (struct net *net,u8 family) {struct neigh_table *tbl =NULL ;
@@ -1643,6 +1643,7 @@ static struct neigh_table *neigh_find_table(int family)return tbl; } +EXPORT_SYMBOL (neigh_find_table);static int neigh_delete (struct sk_buff *skb,struct nlmsghdr *nlh,struct netlink_ext_ack *extack)
@@ -1672,7 +1673,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 ;
@@ -1740,7 +1741,7 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, goto out; } - tbl =neigh_find_table (ndm->ndm_family); + tbl =neigh_find_table (net, ndm->ndm_family);if (tbl ==NULL )return -EAFNOSUPPORT ;
Signature · 1 line
2.11.0
[email protected]
maintainerPATCH 3/17 net/ipv4: wrappers for arp table references
In reply to [email protected]From: David Ahern <[email protected]>
Create a helper, ipv4_neigh_table, for retrieving a reference to the arp table. Add additional wrappers for commonly used neigh_* functions to avoid propagating the ipv4_neigh_table lookup all over the code.
--- include/net/arp.h | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-)
include/net/arp.h +25 -1
@@ -10,6 +10,29 @@extern struct neigh_table arp_tbl; +static inline struct neigh_table *ipv4_neigh_table (struct net *net) +{ +return neigh_find_table (net,AF_INET ); +} + +static inline struct neighbour *ipv4_neigh_create (struct net_device *dev, +const void *pkey) +{ +return neigh_create (ipv4_neigh_table (dev_net (dev)), pkey, dev); +} + +static inline struct neighbour *ipv4_neigh_create_noref (struct net_device *dev, +const void *pkey) +{ +return __neigh_create (ipv4_neigh_table (dev_net (dev)), pkey, dev, false); +} + +static inline struct neighbour *ipv4_neigh_lookup (struct net_device *dev, +void *key) +{ +return neigh_lookup (ipv4_neigh_table (dev_net (dev)), key, dev); +} +static inline u32 arp_hashfn (const void *pkey,const struct net_device *dev,u32 *hash_rnd) {u32 key = *(const u32 *)pkey;
@@ -23,7 +46,8 @@ static inline struct neighbour *__ipv4_neigh_lookup_noref(struct net_device *devif (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 (ipv4_neigh_table (dev_net (dev)), + neigh_key_eq32, arp_hashfn, &key, dev); }static inline struct neighbour *__ipv4_neigh_lookup (struct net_device *dev,u32 key)
Signature · 1 line
2.11.0
[email protected]
maintainerPATCH 4/17 net/ipv4: Remove open coded use of arp table
In reply to [email protected]From: David Ahern <[email protected]>
Convert existing uses for arp_tbl to the helpers introduced in the previous patch.
--- net/bridge/br_arp_nd_proxy.c | 2 +- net/ipv4/arp.c | 36 ++++++++++++++++++++---------------- net/ipv4/devinet.c | 8 ++++---- net/ipv4/fib_semantics.c | 2 +- net/ipv4/ip_output.c | 2 +- net/ipv4/route.c | 4 ++-- 6 files changed, 29 insertions(+), 25 deletions(-)
net/bridge/br_arp_nd_proxy.c +1 -1
@@ -183,7 +183,7 @@ void br_do_proxy_suppress_arp(struct sk_buff *skb, struct net_bridge *br,return ; } - n =neigh_lookup (&arp_tbl, &tip, vlandev); + n =ipv4_neigh_lookup (vlandev, &tip);if (n) {struct net_bridge_fdb_entry *f;
net/ipv4/arp.c +20 -16
@@ -678,6 +678,7 @@ static bool arp_is_garp(struct net *net, struct net_device *dev,static int arp_process (struct net *net,struct sock *sk,struct sk_buff *skb) { +struct neigh_table *tbl =ipv4_neigh_table (net);struct net_device *dev = skb->dev;struct in_device *in_dev =__in_dev_get_rcu (dev);struct arphdr *arp;
@@ -827,7 +828,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,
@@ -842,8 +843,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, 0)))) { - n = neigh_event_ns(&arp_tbl, sha, &sip, dev); + pneigh_lookup(tbl, net, &tip, dev, 0)))) { + n = neigh_event_ns(tbl, sha, &sip, dev);if (n)neigh_release (n);
@@ -855,7 +856,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; }
@@ -866,7 +867,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 ||IN_DEV_ARP_ACCEPT (in_dev)) {
@@ -887,7 +888,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) {
@@ -1011,7 +1012,7 @@ static int arp_req_set_public(struct net *net, struct arpreq *r,return -ENODEV ; }if (mask) { -if (!pneigh_lookup (&arp_tbl, net, &ip, dev,1 )) +if (!pneigh_lookup (ipv4_neigh_table (net), net, &ip, dev,1 ))return -ENOBUFS ;return 0 ; }
@@ -1063,7 +1064,7 @@ static int arp_req_set(struct net *net, struct arpreq *r,break ; } - neigh =__neigh_lookup_errno (&arp_tbl, &ip, dev); + neigh =__neigh_lookup_errno (ipv4_neigh_table (net), &ip, dev); err =PTR_ERR (neigh);if (!IS_ERR (neigh)) {unsigned int state =NUD_STALE ;
@@ -1098,7 +1099,7 @@ static int arp_req_get(struct arpreq *r, struct net_device *dev)struct neighbour *neigh;int err = -ENXIO ; - neigh =neigh_lookup (&arp_tbl, &ip, dev); + neigh =ipv4_neigh_lookup (dev, &ip);if (neigh) {if (!(neigh->nud_state &NUD_NOARP )) {read_lock_bh (&neigh->lock);
@@ -1116,9 +1117,9 @@ static int arp_req_get(struct arpreq *r, struct net_device *dev)static int arp_invalidate (struct net_device *dev,__be32 ip) { -struct neighbour *neigh =neigh_lookup (&arp_tbl, &ip, dev); +struct neigh_table *tbl =ipv4_neigh_table (dev_net (dev)); +struct neighbour *neigh =neigh_lookup (tbl, &ip, dev);int err = -ENXIO ; -struct neigh_table *tbl = &arp_tbl;if (neigh) {if (neigh->nud_state & ~NUD_NOARP )
@@ -1141,7 +1142,7 @@ static int arp_req_delete_public(struct net *net, struct arpreq *r,__be32 mask = ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr;if (mask ==htonl (0xFFFFFFFF )) -return pneigh_delete (&arp_tbl, net, &ip, dev); +return pneigh_delete (ipv4_neigh_table (net), net, &ip, dev);if (mask)return -EINVAL ;
@@ -1248,13 +1249,13 @@ static int arp_netdev_event(struct notifier_block *this, unsigned long event,switch (event) {case NETDEV_CHANGEADDR : -neigh_changeaddr (&arp_tbl, dev); +neigh_changeaddr (ipv4_neigh_table (dev_net (dev)), dev);rt_cache_flush (dev_net (dev));break ;case NETDEV_CHANGE : change_info = ptr;if (change_info->flags_changed &IFF_NOARP ) -neigh_changeaddr (&arp_tbl, dev); +neigh_changeaddr (ipv4_neigh_table (dev_net (dev)), dev);break ;default :break ;
@@ -1273,7 +1274,7 @@ static struct notifier_block arp_netdev_notifier = {*/ void arp_ifdown (struct net_device *dev) { -neigh_ifdown (&arp_tbl, dev); +neigh_ifdown (ipv4_neigh_table (dev_net (dev)), dev); }
@@ -1403,10 +1404,13 @@ static int arp_seq_show(struct seq_file *seq, void *v)static void *arp_seq_start (struct seq_file *seq,loff_t *pos) { +struct net *net =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,ipv4_neigh_table (net), +NEIGH_SEQ_SKIP_NOARP ); }/* ------------------------------------------------------------------------ */
net/ipv4/devinet.c +4 -4
@@ -239,6 +239,7 @@ 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;int err = -ENOMEM ;
@@ -247,11 +248,10 @@ static struct in_device *inetdev_init(struct net_device *dev) in_dev =kzalloc (sizeof (*in_dev),GFP_KERNEL );if (!in_dev) goto out; -memcpy (&in_dev->cnf,dev_net (dev)->ipv4.devconf_dflt, -sizeof (in_dev->cnf)); +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,ipv4_neigh_table (net));if (!in_dev->arp_parms) goto out_kfree;if (IPV4_DEVCONF (in_dev->cnf,FORWARDING ))
@@ -309,7 +309,7 @@ static void inetdev_destroy(struct in_device *in_dev)RCU_INIT_POINTER (dev->ip_ptr,NULL );devinet_sysctl_unregister (in_dev); -neigh_parms_release (&arp_tbl, in_dev->arp_parms); +neigh_parms_release (ipv4_neigh_table (dev_net (dev)), in_dev->arp_parms);arp_ifdown (dev);call_rcu (&in_dev->rcu_head, in_dev_rcu_put);
net/ipv4/fib_semantics.c +1 -1
@@ -440,7 +440,7 @@ static int fib_detect_death(struct fib_info *fi, int order,struct neighbour *n;int state =NUD_NONE ; - n =neigh_lookup (&arp_tbl, &fi->fib_nh[0 ].nh_gw, fi->fib_dev); + n =ipv4_neigh_lookup (fi->fib_dev, &fi->fib_nh[0 ].nh_gw);if (n) { state = n->nud_state;neigh_release (n);
net/ipv4/ip_output.c +1 -1
@@ -221,7 +221,7 @@ static int ip_finish_output2(struct net *net, struct sock *sk, struct sk_buff *s nexthop = (__force u32 )rt_nexthop (rt,ip_hdr (skb)->daddr); neigh =__ipv4_neigh_lookup_noref (dev, nexthop);if (unlikely (!neigh)) - neigh =__neigh_create (&arp_tbl, &nexthop, dev, false); + neigh =ipv4_neigh_create_noref (dev, &nexthop);if (!IS_ERR (neigh)) {int res;
net/ipv4/route.c +2 -2
@@ -448,7 +448,7 @@ static struct neighbour *ipv4_dst_neigh_lookup(const struct dst_entry *dst, n =__ipv4_neigh_lookup (dev, *(__force u32 *)pkey);if (n)return n; -return neigh_create (&arp_tbl, pkey, dev); +return ipv4_neigh_create (dev, pkey); }static void ipv4_confirm_neigh (const struct dst_entry *dst,const void *daddr)
@@ -770,7 +770,7 @@ static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flow n =__ipv4_neigh_lookup (rt->dst.dev, new_gw);if (!n) - n =neigh_create (&arp_tbl, &new_gw, rt->dst.dev); + n =ipv4_neigh_create (rt->dst.dev, &new_gw);if (!IS_ERR (n)) {if (!(n->nud_state &NUD_VALID )) {neigh_event_send (n,NULL );
Signature · 1 line
2.11.0
[email protected]
maintainerPATCH 5/17 net/ipv6: wrappers for neighbor table references
In reply to [email protected]From: David Ahern <[email protected]>
Create a helper, ipv6_neigh_table, for retrieving a reference to the ipv6 neighbor table. Add additional wrappers for commonly used neigh_* functions to avoid propagating the ipv6_neigh_table lookup all over the code.
For ipv6, the neighbor table may not exist (e.g., IPv6 not enabled at build time or the module is not loaded) so NULL checks are needed before use.
--- include/net/ndisc.h | 69 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 4 deletions(-)
include/net/ndisc.h +65 -4
@@ -374,17 +374,70 @@ static inline u32 ndisc_hashfn(const void *pkey, const struct net_device *dev, _ (p32[3] * hash_rnd[3])); } -static inline struct neighbour *__ipv6_neigh_lookup_noref (struct net_device *dev,const void *pkey) +static inline struct neigh_table *ipv6_neigh_table (struct net *net) { -return ___neigh_lookup_noref (&nd_tbl, neigh_key_eq128, ndisc_hashfn, pkey, dev); +return neigh_find_table (net,AF_INET6 ); } -static inline struct neighbour *__ipv6_neigh_lookup (struct net_device *dev,const void *pkey) +static inline struct neighbour *ipv6_neigh_create (struct net_device *dev, +const void *pkey, +bool want_ref) +{ +struct neigh_table *tbl =ipv6_neigh_table (dev_net (dev)); +struct neighbour *n =NULL ; + +if (tbl) + n =__neigh_create (tbl, pkey, dev, want_ref); + +return n; +} + +static inline struct neighbour *ipv6_neigh_lookup (struct net_device *dev, +const void *pkey) +{ +struct neigh_table *tbl =ipv6_neigh_table (dev_net (dev)); +struct neighbour *n =NULL ; + +if (tbl) + n =neigh_lookup (tbl, pkey, dev); + +return n; +} + +static inline struct neighbour *__ipv6_neigh_lookup (struct net_device *dev, +const void *pkey,int creat) +{ +struct neigh_table *tbl =ipv6_neigh_table (dev_net (dev)); +struct neighbour *n =NULL ; + +if (tbl) + n =__neigh_lookup (tbl, pkey, dev, creat); + +return n; +} + +static inline +struct neighbour *___ipv6_neigh_lookup_noref (struct net_device *dev, +const void *pkey) +{ +struct neigh_table *tbl =ipv6_neigh_table (dev_net (dev)); +struct neighbour *n =NULL ; + +if (tbl) + n =___neigh_lookup_noref (tbl, neigh_key_eq128, ndisc_hashfn, + pkey, dev); + +return n; +} + +static inline +struct neighbour *__ipv6_neigh_lookup_noref (struct net_device *dev, +const void *pkey) {struct neighbour *n;rcu_read_lock_bh (); - n =__ipv6_neigh_lookup_noref (dev, pkey); + n =___ipv6_neigh_lookup_noref (dev, pkey);if (n && !refcount_inc_not_zero (&n->refcnt)) n =NULL ;rcu_read_unlock_bh ();
@@ -409,6 +462,14 @@ static inline void __ipv6_confirm_neigh(struct net_device *dev,rcu_read_unlock_bh (); } +static inline struct pneigh_entry *ipv6_pneigh_lookup (struct net *net, +const void *key, +struct net_device *dev, +int creat) +{ +return pneigh_lookup (ipv6_neigh_table (net), net, key, dev, creat); +} +int ndisc_init (void );int ndisc_late_init (void );
Signature · 1 line
2.11.0
[email protected]
maintainerPATCH 6/17 net/ipv6: Remove open coded use of neighbor table
In reply to [email protected]From: David Ahern <[email protected]>
Convert existing uses for nd_tbl to the helpers introduced in the previous patch.
--- net/ipv6/addrconf.c | 16 ++++++++++------ net/ipv6/ip6_output.c | 4 ++-- net/ipv6/ndisc.c | 41 +++++++++++++++++++++++------------------ net/ipv6/route.c | 12 +++++++----- 4 files changed, 42 insertions(+), 31 deletions(-)
net/ipv6/addrconf.c +10 -6
@@ -365,6 +365,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 *neigh_tbl =ipv6_neigh_table (net);struct inet6_dev *ndev;int err = -ENOMEM ;
@@ -381,13 +383,13 @@ 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 ; ndev->cnf.mtu6 = dev->mtu; - ndev->nd_parms =neigh_parms_alloc (dev, &nd_tbl); + ndev->nd_parms =neigh_parms_alloc (dev, neigh_tbl);if (!ndev->nd_parms) {kfree (ndev);return ERR_PTR (err);
@@ -400,7 +402,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 (neigh_tbl, ndev->nd_parms);dev_put (dev);kfree (ndev);return ERR_PTR (err);
@@ -465,7 +467,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 (ipv6_neigh_table (net), ndev->nd_parms); ndev->dead =1 ;in6_dev_finish_destroy (ndev);return ERR_PTR (err);
@@ -3787,9 +3789,11 @@ static int addrconf_ifdown(struct net_device *dev, int how)/* Last: Shot the device (if unregistered) */ if (how) { +struct neigh_table *tbl =ipv6_neigh_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 ;
net/ipv6/ip6_output.c +2 -2
@@ -114,7 +114,7 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff * nexthop =rt6_nexthop ((struct 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 =ipv6_neigh_create (dst->dev, nexthop, false);if (!IS_ERR (neigh)) {sock_confirm_neigh (skb, neigh); ret =neigh_output (neigh, skb);
@@ -462,7 +462,7 @@ int ip6_forward(struct sk_buff *skb)/* XXX: idev->cnf.proxy_ndp? */ if (net->ipv6.devconf_all->proxy_ndp && -pneigh_lookup (&nd_tbl, net, &hdr->daddr, skb->dev,0 )) { +ipv6_pneigh_lookup (net, &hdr->daddr, skb->dev,0 )) {int proxied =ip6_forward_proxy_check (skb);if (proxied >0 )return ip6_input (skb);
net/ipv6/ndisc.c +23 -18
126 lines not on this page · raw message
net/ipv6/route.c +7 -5
@@ -207,10 +207,10 @@ struct neighbour *ip6_neigh_lookup(const struct in6_addr *gw,struct neighbour *n; daddr =choose_neigh_daddr (gw, skb, daddr); - n =__ipv6_neigh_lookup (dev, daddr); + n =__ipv6_neigh_lookup_noref (dev, daddr);if (n)return n; -return neigh_create (&nd_tbl, daddr, dev); +return ipv6_neigh_create (dev, daddr, true); } static struct neighbour *ip6_dst_neigh_lookup(const struct dst_entry *dst,
@@ -3392,7 +3392,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 =__ipv6_neigh_lookup (skb->dev, &msg->target,1 );if (!neigh)return ;
@@ -4064,9 +4064,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_net (dev), dev); -neigh_ifdown (&nd_tbl, dev); +rt6_uncached_list_flush_dev (net, dev); +neigh_ifdown (ipv6_neigh_table (net), dev); }struct rt6_mtu_change_arg {
Signature · 1 line
2.11.0
[email protected]
maintainerPATCH 7/17 drivers/net: remove open coding of neighbor tables
In reply to [email protected]From: David Ahern <[email protected]>
Remove open use of arp_tbl and nd_tbl in favor of the new ipv{4,6}_neigh_table helpers. Since the existence of the IPv6 table is managed by the core networking, the IS_ENABLED checks for IPv6 can be removed in favor of "is the table non-NULL".
--- drivers/infiniband/ulp/ipoib/ipoib_main.c | 14 ++++++--- drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 35 +++++++++++----------- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 11 ++----- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 27 ++++++++--------- .../net/ethernet/mellanox/mlxsw/spectrum_span.c | 8 +++-- .../ethernet/netronome/nfp/flower/tunnel_conf.c | 2 +- drivers/net/ethernet/rocker/rocker_main.c | 4 +-- drivers/net/ethernet/rocker/rocker_ofdpa.c | 2 +- drivers/net/vrf.c | 4 +-- drivers/net/vxlan.c | 10 +++---- net/atm/clip.c | 14 +++++---- net/ieee802154/6lowpan/tx.c | 2 +- 12 files changed, 70 insertions(+), 63 deletions(-)
drivers/infiniband/ulp/ipoib/ipoib_main.c +10 -4
@@ -1298,6 +1298,8 @@ struct ipoib_neigh *ipoib_neigh_get(struct net_device *dev, u8 *daddr)static void __ipoib_reap_neigh (struct ipoib_dev_priv *priv) { +struct net *net =dev_net (priv->dev); +struct neigh_table *arp_tbl =ipv4_neigh_table (net);struct ipoib_neigh_table *ntbl = &priv->ntbl;struct ipoib_neigh_hash *htbl;unsigned long neigh_obsolete;
@@ -1318,7 +1320,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 * arp_tbl->gc_interval; neigh_obsolete = jiffies - dt;/* handle possible race condition */ if (test_bit (IPOIB_STOP_NEIGH_GC , &priv->flags))
@@ -1357,12 +1359,14 @@ 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 *net =dev_net (priv->dev); +struct neigh_table *arp_tbl =ipv4_neigh_table (net);__ipoib_reap_neigh (priv);if (!test_bit (IPOIB_STOP_NEIGH_GC , &priv->flags))queue_delayed_work (priv->wq, &priv->neigh_reap_task, - arp_tbl.gc_interval); + arp_tbl->gc_interval); }
@@ -1514,6 +1518,8 @@ void ipoib_neigh_free(struct ipoib_neigh *neigh)static int ipoib_neigh_hash_init (struct ipoib_dev_priv *priv) { +struct net *net =dev_net (priv->dev); +struct neigh_table *arp_tbl =ipv4_neigh_table (net);struct ipoib_neigh_table *ntbl = &priv->ntbl;struct ipoib_neigh_hash *htbl;struct ipoib_neigh __rcu **buckets;
@@ -1525,7 +1531,7 @@ static int ipoib_neigh_hash_init(struct ipoib_dev_priv *priv)if (!htbl)return -ENOMEM ;set_bit (IPOIB_STOP_NEIGH_GC , &priv->flags); - size =roundup_pow_of_two (arp_tbl.gc_thresh3); + size =roundup_pow_of_two (arp_tbl->gc_thresh3); buckets =kcalloc (size,sizeof (*buckets),GFP_KERNEL );if (!buckets) {kfree (htbl);
@@ -1541,7 +1547,7 @@ static int ipoib_neigh_hash_init(struct ipoib_dev_priv *priv)/* start garbage collection */ clear_bit (IPOIB_STOP_NEIGH_GC , &priv->flags);queue_delayed_work (priv->wq, &priv->neigh_reap_task, - arp_tbl.gc_interval); + arp_tbl->gc_interval);return 0 ; }
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +18 -17
@@ -309,17 +309,19 @@ void mlx5e_remove_sqs_fwd_rules(struct mlx5e_priv *priv)static void mlx5e_rep_neigh_update_init_interval (struct mlx5e_rep_priv *rpriv) { -#if IS_ENABLED (CONFIG_IPV6 ) -unsigned long ipv6_interval =NEIGH_VAR (&nd_tbl.parms, +struct net_device *netdev = rpriv->netdev; +struct net *net =dev_net (netdev); +struct neigh_table *arp_table =ipv4_neigh_table (net); +struct neigh_table *nd_table =ipv6_neigh_table (net); + +unsigned long ipv4_interval =NEIGH_VAR (&arp_table->parms,DELAY_PROBE_TIME ); -#else unsigned long ipv6_interval = ~0UL ; -#endif -unsigned long ipv4_interval =NEIGH_VAR (&arp_tbl.parms, -DELAY_PROBE_TIME ); -struct net_device *netdev = rpriv->netdev;struct mlx5e_priv *priv =netdev_priv (netdev); +if (nd_table) + ipv6_interval =NEIGH_VAR (&nd_table->parms,DELAY_PROBE_TIME ); + rpriv->neigh_update.min_interval = min_t(unsigned long, ipv6_interval, ipv4_interval);mlx5_fc_update_sampling_interval (priv->mdev, rpriv->neigh_update.min_interval); }
@@ -437,19 +439,22 @@ static int mlx5e_rep_netevent_event(struct notifier_block *nb,struct net_device *netdev = rpriv->netdev;struct mlx5e_priv *priv =netdev_priv (netdev);struct mlx5e_neigh_hash_entry *nhe =NULL ; +struct net *net =dev_net (netdev);struct mlx5e_neigh m_neigh = {}; +struct neigh_table *arp_table; +struct neigh_table *nd_table;struct neigh_parms *p;struct neighbour *n;bool found = false; + arp_table =ipv4_neigh_table (net); + nd_table =ipv6_neigh_table (net); +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 + +if (n->tbl != nd_table && n->tbl != arp_table)return NOTIFY_DONE ; m_neigh.dev = n->dev;
@@ -493,11 +498,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 || (p->tbl != nd_table && p->tbl != arp_table))return NOTIFY_DONE ;/* We are in atomic context and can't take RTNL mutex,
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +3 -8
@@ -45,7 +45,7 @@#include <net/tc_act/tc_pedit.h> #include <net/tc_act/tc_csum.h> #include <net/vxlan.h> -#include <net/arp.h> +#include <net/neighbour.h> #include "en.h" #include "en_rep.h" #include "en_tc.h"
@@ -999,13 +999,8 @@ void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe)bool neigh_used = false;struct neighbour *n; -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 + tbl =neigh_find_table (dev_net (m_neigh->dev), m_neigh->family); +if (!tbl)return ;list_for_each_entry (e, &nhe->encap_list, encap_list) {
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +13 -14
@@ -2019,15 +2019,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) { -unsigned long interval; +/* mlxsw only works with init_net at the moment */ +struct neigh_table *arp_table =ipv4_neigh_table (&init_net); +struct neigh_table *nd_table =ipv6_neigh_table (&init_net); +unsigned long interval =NEIGH_VAR (&arp_table->parms,DELAY_PROBE_TIME ); + +if (nd_table) + interval = min_t(unsigned long, interval, +NEIGH_VAR (&nd_table->parms,DELAY_PROBE_TIME )); -#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 )); -#else - interval =NEIGH_VAR (&arp_tbl.parms,DELAY_PROBE_TIME ); -#endif mlxsw_sp->router->neighs_update.interval =jiffies_to_msecs (interval); }
@@ -2050,7 +2050,7 @@ static void mlxsw_sp_router_neigh_ent_ipv4_process(struct mlxsw_sp *mlxsw_sp, dipn =htonl (dip); dev = mlxsw_sp->router->rifs[rif]->dev; - n =neigh_lookup (&arp_tbl, &dipn, dev); + n =ipv4_neigh_lookup (dev, &dipn);if (!n)return ;
@@ -2064,6 +2064,7 @@ static void mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp *mlxsw_sp, char *rauhtd_pl, int rec_index) { +struct neigh_table *nd_table =ipv6_neigh_table (&init_net);struct net_device *dev;struct neighbour *n;struct in6_addr dip;
@@ -2078,7 +2079,7 @@ static void mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp *mlxsw_sp, } dev = mlxsw_sp->router->rifs[rif]->dev; - n =neigh_lookup (&nd_tbl, &dip, dev); + n =neigh_lookup (nd_table, &dip, dev);if (!n)return ;
@@ -3721,7 +3722,7 @@ mlxsw_sp_nexthop4_group_create(struct mlxsw_sp *mlxsw_sp, struct fib_info *fi)return ERR_PTR (-ENOMEM ); nh_grp->priv = fi;INIT_LIST_HEAD (&nh_grp->fib_list); - nh_grp->neigh_tbl = &arp_tbl; + nh_grp->neigh_tbl =ipv4_neigh_table (&init_net); nh_grp->gateway =mlxsw_sp_fi_is_gateway (mlxsw_sp, fi); nh_grp->count = fi->fib_nhs;
@@ -4919,9 +4920,7 @@ mlxsw_sp_nexthop6_group_create(struct mlxsw_sp *mlxsw_sp,if (!nh_grp)return ERR_PTR (-ENOMEM );INIT_LIST_HEAD (&nh_grp->fib_list); -#if IS_ENABLED (CONFIG_IPV6 ) - nh_grp->neigh_tbl = &nd_tbl; -#endif + nh_grp->neigh_tbl =ipv6_neigh_table (&init_net); mlxsw_sp_rt6 =list_first_entry (&fib6_entry->rt6_list, struct mlxsw_sp_rt6, list); nh_grp->gateway =mlxsw_sp_rt6_is_gateway (mlxsw_sp, mlxsw_sp_rt6->rt);
drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c +6 -2
@@ -365,6 +365,7 @@ mlxsw_sp_span_entry_gretap4_parms(const struct net_device *to_dev,bool inherit_ttl = !tparm.iph.ttl;union mlxsw_sp_l3addr gw = daddr;struct net_device *l3edev; +struct neigh_table *tbl; if (!(to_dev->flags & IFF_UP) ||/* Reject tunnels with GRE keys, checksums, etc. */
@@ -376,9 +377,10 @@ mlxsw_sp_span_entry_gretap4_parms(const struct net_device *to_dev,return mlxsw_sp_span_entry_unoffloadable (sparmsp); l3edev =mlxsw_sp_span_gretap4_route (to_dev, &saddr.addr4, &gw.addr4); + tbl =ipv4_neigh_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
@@ -466,6 +468,7 @@ mlxsw_sp_span_entry_gretap6_parms(const struct net_device *to_dev,bool inherit_ttl = !tparm.hop_limit;union mlxsw_sp_l3addr gw = daddr;struct net_device *l3edev; +struct neigh_table *tbl; if (!(to_dev->flags & IFF_UP) ||/* Reject tunnels with GRE keys, checksums, etc. */
@@ -477,9 +480,10 @@ mlxsw_sp_span_entry_gretap6_parms(const struct net_device *to_dev,return mlxsw_sp_span_entry_unoffloadable (sparmsp); l3edev =mlxsw_sp_span_gretap6_route (to_dev, &saddr.addr6, &gw.addr6); + tbl =ipv6_neigh_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
drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c +1 -1
@@ -201,7 +201,7 @@ void nfp_tunnel_keep_alive(struct nfp_app *app, struct sk_buff *skb)if (!netdev)continue ; - n =neigh_lookup (&arp_tbl, &ipv4_addr, netdev); + n =ipv4_neigh_lookup (netdev, &ipv4_addr);if (!n)continue ;
drivers/net/ethernet/rocker/rocker_main.c +2 -2
@@ -3098,9 +3098,9 @@ static int rocker_netevent_event(struct notifier_block *unused,switch (event) {case NETEVENT_NEIGH_UPDATE : -if (n->tbl != &arp_tbl) -return NOTIFY_DONE ; dev = n->dev; +if (n->tbl !=ipv4_neigh_table (dev_net (dev))) +return NOTIFY_DONE ;if (!rocker_port_dev_check (dev))return NOTIFY_DONE ; rocker_port =netdev_priv (dev);
drivers/net/ethernet/rocker/rocker_ofdpa.c +1 -1
@@ -1356,7 +1356,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 =ipv4_neigh_create (dev, &ip_addr);if (IS_ERR (n))return PTR_ERR (n); }
drivers/net/vrf.c +2 -2
@@ -367,7 +367,7 @@ static int vrf_finish_output6(struct net *net, struct sock *sk, nexthop =rt6_nexthop ((struct 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 =ipv6_neigh_create (dst->dev, nexthop, false);if (!IS_ERR (neigh)) {sock_confirm_neigh (skb, neigh); ret =neigh_output (neigh, skb);
@@ -575,7 +575,7 @@ static int vrf_finish_output(struct net *net, struct sock *sk, struct sk_buff *s nexthop = (__force u32 )rt_nexthop (rt,ip_hdr (skb)->daddr); neigh =__ipv4_neigh_lookup_noref (dev, nexthop);if (unlikely (!neigh)) - neigh =__neigh_create (&arp_tbl, &nexthop, dev, false); + neigh =ipv4_neigh_create_noref (dev, &nexthop);if (!IS_ERR (neigh)) {sock_confirm_neigh (skb, neigh); ret =neigh_output (neigh, skb);
drivers/net/vxlan.c +4 -6
@@ -1520,8 +1520,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 =ipv4_neigh_lookup (dev, &tip);if (n) {struct vxlan_fdb *f;struct sk_buff *reply;
@@ -1675,8 +1674,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 (ipv6_stub->nd_tbl, &msg->target, dev); - + n =ipv6_neigh_lookup (dev, &msg->target);if (n) {struct vxlan_fdb *f;struct sk_buff *reply;
@@ -1736,7 +1734,7 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)if (!pskb_may_pull (skb,sizeof (struct iphdr )))return false; pip =ip_hdr (skb); - n =neigh_lookup (&arp_tbl, &pip->daddr, dev); + n =ipv4_neigh_lookup (dev, &pip->daddr);if (!n && (vxlan->cfg.flags &VXLAN_F_L3MISS )) {union vxlan_addr ipa = { .sin.sin_addr.s_addr = pip->daddr,
@@ -1757,7 +1755,7 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)if (!pskb_may_pull (skb,sizeof (struct ipv6hdr )))return false; pip6 =ipv6_hdr (skb); - n =neigh_lookup (ipv6_stub->nd_tbl, &pip6->daddr, dev); + n =ipv6_neigh_lookup (dev, &pip6->daddr);if (!n && (vxlan->cfg.flags &VXLAN_F_L3MISS )) {union vxlan_addr ipa = { .sin6.sin6_addr = pip6->daddr,
net/atm/clip.c +9 -5
@@ -155,10 +155,12 @@ static int neigh_check_cb(struct neighbour *n)static void idle_timer_check (struct timer_list *unused) { -write_lock (&arp_tbl.lock); -__neigh_for_each_release (&arp_tbl, neigh_check_cb); +struct neigh_table *tbl =ipv4_neigh_table (&init_net); + +write_lock (&tbl->lock); +__neigh_for_each_release (tbl, neigh_check_cb);mod_timer (&idle_timer, jiffies +CLIP_CHECK_INTERVAL *HZ ); -write_unlock (&arp_tbl.lock); +write_unlock (&tbl->lock); }static int clip_arp_rcv (struct sk_buff *skb)
@@ -465,7 +467,8 @@ static int clip_setentry(struct atm_vcc *vcc, __be32 ip) rt =ip_route_output (&init_net, ip,0 ,1 ,0 );if (IS_ERR (rt))return PTR_ERR (rt); - neigh =__neigh_lookup (&arp_tbl, &ip, rt->dst.dev,1 ); + neigh =__neigh_lookup (ipv4_neigh_table (&init_net), &ip, + rt->dst.dev,1 );ip_rt_put (rt);if (!neigh)return -ENOMEM ;
@@ -836,7 +839,8 @@ static void *clip_seq_start(struct seq_file *seq, loff_t * pos) {struct clip_seq_state *state = seq->private; state->ns.neigh_sub_iter = clip_seq_sub_iter; -return neigh_seq_start (seq, pos, &arp_tbl,NEIGH_SEQ_NEIGH_ONLY ); +return neigh_seq_start (seq, pos,ipv4_neigh_table (&init_net), +NEIGH_SEQ_NEIGH_ONLY ); }static int clip_seq_show (struct seq_file *seq,void *v)
net/ieee802154/6lowpan/tx.c +1 -1
@@ -64,7 +64,7 @@ int lowpan_header_create(struct sk_buff *skb, struct net_device *ldev, }else {__le16 short_addr =cpu_to_le16 (IEEE802154_ADDR_SHORT_UNSPEC ); - n =neigh_lookup (&nd_tbl, &hdr->daddr, ldev); + n =ipv6_neigh_lookup (ldev, &hdr->daddr);if (n) { llneigh =lowpan_802154_neigh (neighbour_priv (n));read_lock_bh (&n->lock);
Signature · 1 line
2.11.0
[email protected]
maintainerPATCH 8/17 net: Remove nd_tbl from ipv6 stub
In reply to [email protected]From: David Ahern <[email protected]>
Fixup last 2 users to nd_tbl entry of the stub and remove it.
--- include/net/addrconf.h | 1 - net/bridge/br_arp_nd_proxy.c | 2 +- net/core/filter.c | 3 +-- net/ipv6/af_inet6.c | 1 - 4 files changed, 2 insertions(+), 5 deletions(-)
include/net/addrconf.h +0 -1
@@ -256,7 +256,6 @@ struct ipv6_stub {void (*ndisc_send_na)(struct net_device *dev,const struct in6_addr *daddr,const struct in6_addr *solicited_addr,bool router,bool solicited,bool override,bool inc_opt); -struct neigh_table *nd_tbl; };extern const struct ipv6_stub *ipv6_stub__read_mostly ;
net/bridge/br_arp_nd_proxy.c +1 -1
@@ -433,7 +433,7 @@ void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br,return ; } - n =neigh_lookup (ipv6_stub->nd_tbl, &msg->target, vlandev); + n =ipv6_neigh_lookup (vlandev, &msg->target);if (n) {struct net_bridge_fdb_entry *f;
net/core/filter.c +1 -2
@@ -4290,8 +4290,7 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,* not needed here. Can not use __ipv6_neigh_lookup_noref here * because we need to get nd_tbl via the stub */ - neigh =___neigh_lookup_noref (ipv6_stub->nd_tbl, neigh_key_eq128, - ndisc_hashfn, dst, dev); + neigh =___ipv6_neigh_lookup_noref (dev, dst);if (!neigh)return BPF_FIB_LKUP_RET_NO_NEIGH ;
net/ipv6/af_inet6.c +0 -1
@@ -898,7 +898,6 @@ static const struct ipv6_stub ipv6_stub_impl = { .ip6_mtu_from_fib6 = ip6_mtu_from_fib6, .udpv6_encap_enable = udpv6_encap_enable, .ndisc_send_na = ndisc_send_na, - .nd_tbl = &nd_tbl, };static const struct ipv6_bpf_stub ipv6_bpf_stub_impl = {
Signature · 1 line
2.11.0
[email protected]
maintainerPATCH 9/17 net: Remove arp_tbl and nd_tbl from headers
In reply to [email protected]From: David Ahern <[email protected]>
No more users at this point.
--- include/net/arp.h | 3 --- include/net/ndisc.h | 2 -- 2 files changed, 5 deletions(-)
include/net/arp.h +0 -3
@@ -7,9 +7,6 @@#include <linux/hash.h> #include <net/neighbour.h> - -extern struct neigh_table arp_tbl; -static inline struct neigh_table *ipv4_neigh_table (struct net *net) {return neigh_find_table (net,AF_INET );
include/net/ndisc.h +0 -2
@@ -72,8 +72,6 @@ struct net_proto_family;struct sk_buff ;struct prefix_info ; -extern struct neigh_table nd_tbl; -struct nd_msg {struct icmp6hdr icmph;struct in6_addr target;
Signature · 1 line
2.11.0
[email protected]
maintainerPATCH 10/17 net: Add key_len to neighbor constructor
In reply to [email protected]From: David Ahern <[email protected]>
Allows arp_constructor to not reference the arp_tbl directly. ndisc_constructor assumes key length. Could do the same with arp.
--- include/net/neighbour.h | 3 ++- net/core/neighbour.c | 3 ++- net/decnet/dn_neigh.c | 4 ++-- net/ipv4/arp.c | 6 +++--- net/ipv6/ndisc.c | 4 ++-- 5 files changed, 11 insertions(+), 9 deletions(-)
include/net/neighbour.h +2 -1
@@ -198,7 +198,8 @@ struct neigh_table {const struct net_device *dev, __u32 *hash_rnd);bool (*key_eq)(const struct neighbour *,const void *pkey); -int (*constructor)(struct neighbour *); +int (*constructor)(struct neighbour *, +unsigned int key_len);int (*pconstructor)(struct pneigh_entry *);void (*pdestructor)(struct pneigh_entry *);void (*proxy_redo)(struct sk_buff *skb);
net/core/neighbour.c +2 -1
@@ -505,7 +505,8 @@ struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,dev_hold (dev);/* Protocol specific setup. */ -if (tbl->constructor && (error = tbl->constructor (n)) <0 ) { +if (tbl->constructor && + (error = tbl->constructor (n, tbl->key_len)) <0 ) { rc =ERR_PTR (error); goto out_neigh_release; }
net/decnet/dn_neigh.c +2 -2
@@ -49,7 +49,7 @@#include <net/dn_neigh.h> #include <net/dn_route.h> -static int dn_neigh_construct (struct neighbour *); +static int dn_neigh_construct (struct neighbour *,unsigned int key_len);static void dn_neigh_error_report (struct neighbour *,struct sk_buff *);static int dn_neigh_output (struct neighbour *neigh,struct sk_buff *skb);
@@ -108,7 +108,7 @@ struct neigh_table dn_neigh_table = { .gc_thresh3 = 1024, }; -static int dn_neigh_construct (struct neighbour *neigh) +static int dn_neigh_construct (struct neighbour *neigh,unsigned int key_len) {struct net_device *dev = neigh->dev; struct dn_neigh *dn = container_of(neigh, struct dn_neigh, n);
net/ipv4/arp.c +3 -3
@@ -125,7 +125,7 @@*/ static u32 arp_hash (const void *pkey,const struct net_device *dev,__u32 *hash_rnd);static bool arp_key_eq (const struct neighbour *n,const void *pkey); -static int arp_constructor (struct neighbour *neigh); +static int arp_constructor (struct neighbour *neigh,unsigned int key_len);static void arp_solicit (struct neighbour *neigh,struct sk_buff *skb);static void arp_error_report (struct neighbour *neigh,struct sk_buff *skb);static void parp_redo (struct sk_buff *skb);
@@ -221,7 +221,7 @@ static bool arp_key_eq(const struct neighbour *neigh, const void *pkey)return neigh_key_eq32 (neigh, pkey); } -static int arp_constructor (struct neighbour *neigh) +static int arp_constructor (struct neighbour *neigh,unsigned int key_len) {__be32 addr;struct net_device *dev = neigh->dev;
@@ -230,7 +230,7 @@ static int arp_constructor(struct neighbour *neigh)u32 inaddr_any =INADDR_ANY ;if (dev->flags & (IFF_LOOPBACK |IFF_POINTOPOINT )) -memcpy (neigh->primary_key, &inaddr_any, arp_tbl.key_len); +memcpy (neigh->primary_key, &inaddr_any, key_len); addr = *(__be32 *)neigh->primary_key;rcu_read_lock ();
net/ipv6/ndisc.c +2 -2
@@ -77,7 +77,7 @@ static u32 ndisc_hash(const void *pkey,const struct net_device *dev, __u32 *hash_rnd);static bool ndisc_key_eq (const struct neighbour *neigh,const void *pkey); -static int ndisc_constructor (struct neighbour *neigh); +static int ndisc_constructor (struct neighbour *neigh,unsigned int key_len);static void ndisc_solicit (struct neighbour *neigh,struct sk_buff *skb);static void ndisc_error_report (struct neighbour *neigh,struct sk_buff *skb);static int pndisc_constructor (struct pneigh_entry *n);
@@ -319,7 +319,7 @@ static bool ndisc_key_eq(const struct neighbour *n, const void *pkey)return neigh_key_eq128 (n, pkey); } -static int ndisc_constructor (struct neighbour *neigh) +static int ndisc_constructor (struct neighbour *neigh,unsigned int key_len) {struct in6_addr *addr = (struct in6_addr *)&neigh->primary_key;struct net_device *dev = neigh->dev;
Signature · 1 line
2.11.0
[email protected]
maintainerPATCH 11/17 net: Change neigh_table_init and neigh_table_clear signature
In reply to [email protected]From: David Ahern <[email protected]>
Convert neigh_table_init and neigh_table_clear to use an address family instead of the NEIGH_*_TABLE macros which are effectively the same thing only setup as index into neigh_tables. The functions can do that mapping internally.
Further, add net to the arg list for both and remove the dependence on init_net.
--- include/net/neighbour.h | 4 ++-- net/core/neighbour.c | 40 ++++++++++++++++++++++++++++++++-------- net/decnet/dn_neigh.c | 4 ++-- net/ipv4/arp.c | 2 +- net/ipv6/ndisc.c | 4 ++-- 5 files changed, 39 insertions(+), 15 deletions(-)
include/net/neighbour.h +2 -2
@@ -304,8 +304,8 @@ static inline struct neighbour *__neigh_lookup_noref(struct neigh_table *tbl,return ___neigh_lookup_noref (tbl, tbl->key_eq, tbl->hash, pkey, dev); } -void neigh_table_init (int index,struct neigh_table *tbl); -int neigh_table_clear (int index,struct neigh_table *tbl); +void neigh_table_init (struct net *net,struct neigh_table *tbl); +int neigh_table_clear (struct net *net,struct neigh_table *tbl);struct neighbour *neigh_lookup (struct neigh_table *tbl,const void *pkey,struct net_device *dev); struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
net/core/neighbour.c +32 -8
@@ -1548,14 +1548,15 @@ static struct lock_class_key neigh_table_proxy_queue_class;static struct neigh_table *neigh_tables[NEIGH_NR_TABLES ]__read_mostly ; -void neigh_table_init (int index,struct neigh_table *tbl) +void neigh_table_init (struct net *net,struct neigh_table *tbl) {unsigned long now = jiffies; +u8 family = tbl->family;unsigned long phsize;INIT_LIST_HEAD (&tbl->parms_list);list_add (&tbl->parms.list, &tbl->parms_list); -write_pnet (&tbl->parms.net, &init_net); +write_pnet (&tbl->parms.net, net);refcount_set (&tbl->parms.refcnt,1 ); tbl->parms.reachable_time =neigh_rand_reach_time (NEIGH_VAR (&tbl->parms,BASE_REACHABLE_TIME ));
@@ -1565,8 +1566,8 @@ void neigh_table_init(int index, struct neigh_table *tbl)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)) +if (!proc_create_seq_data (tbl->id,0 , net->proc_net_stat, + &neigh_stat_seq_ops, tbl))panic ("cannot create neighbour proc dir entry" );#endif
@@ -1595,13 +1596,36 @@ void neigh_table_init(int index, struct neigh_table *tbl) tbl->last_flush = now; tbl->last_rand = now + tbl->parms.reachable_time *20 ; - neigh_tables[index] = tbl; +switch (family) { +case AF_INET : + neigh_tables[NEIGH_ARP_TABLE ] = tbl; +break ; +case AF_INET6 : + neigh_tables[NEIGH_ND_TABLE ] = tbl; +break ; +case AF_DECnet: + neigh_tables[NEIGH_DN_TABLE ] = tbl; +break ; + } }EXPORT_SYMBOL (neigh_table_init); -int neigh_table_clear (int index,struct neigh_table *tbl) +int neigh_table_clear (struct net *net,struct neigh_table *tbl) { - neigh_tables[index] =NULL ; +u8 family = tbl->family; + +switch (family) { +case AF_INET : + neigh_tables[NEIGH_ARP_TABLE ] =NULL ; +break ; +case AF_INET6 : + neigh_tables[NEIGH_ND_TABLE ] =NULL ; +break ; +case AF_DECnet: + neigh_tables[NEIGH_DN_TABLE ] =NULL ; +break ; + } +/* It is not clean... Fix it to unload IPv6 module safely */ cancel_delayed_work_sync (&tbl->gc_work);del_timer_sync (&tbl->proxy_timer);
@@ -1617,7 +1641,7 @@ int neigh_table_clear(int index, struct neigh_table *tbl)kfree (tbl->phash_buckets); tbl->phash_buckets =NULL ; -remove_proc_entry (tbl->id, init_net.proc_net_stat); +remove_proc_entry (tbl->id, net->proc_net_stat);free_percpu (tbl->stats); tbl->stats =NULL ;
net/decnet/dn_neigh.c +2 -2
@@ -593,7 +593,7 @@ static const struct seq_operations dn_neigh_seq_ops = {void __init dn_neigh_init (void ) { -neigh_table_init (NEIGH_DN_TABLE , &dn_neigh_table); +neigh_table_init (&init_net, &dn_neigh_table);proc_create_net ("decnet_neigh" ,0444 , init_net.proc_net, &dn_neigh_seq_ops,sizeof (struct neigh_seq_state )); }
@@ -601,5 +601,5 @@ void __init dn_neigh_init(void) void __exit dn_neigh_cleanup(void) {remove_proc_entry ("decnet_neigh" , init_net.proc_net); -neigh_table_clear (NEIGH_DN_TABLE , &dn_neigh_table); +neigh_table_clear (&init_net, &dn_neigh_table); }
net/ipv4/arp.c +1 -1
@@ -1291,7 +1291,7 @@ static int arp_proc_init(void);void __init arp_init (void ) { -neigh_table_init (NEIGH_ARP_TABLE , &arp_tbl); +neigh_table_init (&init_net, &arp_tbl);dev_add_pack (&arp_packet_type);arp_proc_init ();
net/ipv6/ndisc.c +2 -2
@@ -1908,7 +1908,7 @@ int __init ndisc_init(void)/* * Initialize the neighbour table */ -neigh_table_init (NEIGH_ND_TABLE , &nd_tbl); +neigh_table_init (&init_net, &nd_tbl);#ifdef CONFIG_SYSCTL err = neigh_sysctl_register(NULL, &nd_tbl.parms,
@@ -1941,6 +1941,6 @@ void ndisc_cleanup(void)#ifdef CONFIG_SYSCTL neigh_sysctl_unregister (&nd_tbl.parms);#endif -neigh_table_clear (NEIGH_ND_TABLE , &nd_tbl); +neigh_table_clear (&init_net, &nd_tbl);unregister_pernet_subsys (&ndisc_net_ops); }
Signature · 1 line
2.11.0
[email protected]
maintainerPATCH 12/17 net/neigh: Change neigh_xmit to take an address family
In reply to [email protected]From: David Ahern <[email protected]>
The NEIGH_*_TABLE enum is really related to *how* the tables are stored (in an array), a detail that does not need to leave the neighbor code. Change the neigh_xmit API to take a proper address family.
--- include/net/neighbour.h | 2 +- net/core/neighbour.c | 10 +++++----- net/mpls/af_mpls.c | 33 ++++++++++++--------------------- net/mpls/mpls_iptunnel.c | 6 ++---- net/netfilter/nf_flow_table_ip.c | 4 ++-- net/netfilter/nft_fwd_netdev.c | 6 +++--- 6 files changed, 25 insertions(+), 36 deletions(-)
include/net/neighbour.h +1 -1
@@ -365,7 +365,7 @@ 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 *); +int neigh_xmit (u8 fam,struct net_device *,const void *,struct sk_buff *);void pneigh_for_each (struct neigh_table *tbl,void (*cb)(struct pneigh_entry *));
net/core/neighbour.c +5 -5
@@ -2548,15 +2548,16 @@ void __neigh_for_each_release(struct neigh_table *tbl, }EXPORT_SYMBOL (__neigh_for_each_release); -int neigh_xmit (int index,struct net_device *dev, +int neigh_xmit (u8 family,struct net_device *dev,const void *addr,struct sk_buff *skb) {int err = -EAFNOSUPPORT ; -if (likely (index <NEIGH_NR_TABLES )) { + +if (likely (family !=AF_UNSPEC )) {struct neigh_table *tbl;struct neighbour *neigh; - tbl = neigh_tables[index]; + tbl =neigh_find_table (dev_net (dev), family);if (!tbl) goto out;rcu_read_lock_bh ();
@@ -2570,8 +2571,7 @@ int neigh_xmit(int index, struct net_device *dev, } err = neigh->output (neigh, skb);rcu_read_unlock_bh (); - } -else if (index ==NEIGH_LINK_TABLE ) { + }else { err =dev_hard_header (skb, dev,ntohs (skb->protocol), addr,NULL , skb->len);if (err <0 )
net/mpls/af_mpls.c +12 -21
@@ -34,7 +34,7 @@*/ #define MAX_MP_SELECT_LABELS 4 -#define MPLS_NEIGH_TABLE_UNSPEC (NEIGH_LINK_TABLE + 1) +#define MPLS_NEIGH_TABLE_UNSPEC AF_UNSPECstatic int zero =0 ;static int one =1 ;
@@ -453,7 +453,7 @@ static int mpls_forward(struct sk_buff *skb, struct net_device *dev,/* If via wasn't specified then send out using device address */ if (nh->nh_via_table ==MPLS_NEIGH_TABLE_UNSPEC ) - err =neigh_xmit (NEIGH_LINK_TABLE , out_dev, + err =neigh_xmit (AF_UNSPEC , out_dev, out_dev->dev_addr, skb);else err = neigh_xmit(nh->nh_via_table, out_dev,
@@ -651,14 +651,12 @@ static struct net_device *find_outdev(struct net *net,if (!oif) {switch (nh->nh_via_table) { -case NEIGH_ARP_TABLE : +case AF_INET : dev =inet_fib_lookup_dev (net,mpls_nh_via (rt, nh));break ; -case NEIGH_ND_TABLE : +case AF_INET6 : dev =inet6_fib_lookup_dev (net,mpls_nh_via (rt, nh));break ; -case NEIGH_LINK_TABLE : -break ; } }else { dev =dev_get_by_index (net, oif);
@@ -694,7 +692,7 @@ static int mpls_nh_assign_dev(struct net *net, struct mpls_route *rt,if (!mpls_dev_get (dev)) goto errout; -if ((nh->nh_via_table ==NEIGH_LINK_TABLE ) && +if ((nh->nh_via_table ==MPLS_NEIGH_TABLE_UNSPEC ) && (dev->addr_len != nh->nh_via_alen)) goto errout;
@@ -739,15 +737,15 @@ static int nla_get_via(const struct nlattr *nla, u8 *via_alen, u8 *via_table,/* Validate the address family */ switch (via->rtvia_family) {case AF_PACKET : - *via_table =NEIGH_LINK_TABLE ; + *via_table =MPLS_NEIGH_TABLE_UNSPEC ;break ;case AF_INET : - *via_table =NEIGH_ARP_TABLE ; + *via_table =AF_INET ;if (alen !=4 ) goto errout;break ;case AF_INET6 : - *via_table =NEIGH_ND_TABLE ; + *via_table =AF_INET6 ;if (alen !=16 ) goto errout;break ;
@@ -1596,23 +1594,16 @@ static struct notifier_block mpls_dev_notifier = { .notifier_call = mpls_dev_notify, }; -static int nla_put_via (struct sk_buff *skb, -u8 table,const void *addr,int alen) +static int nla_put_via (struct sk_buff *skb,u8 family, +const void *addr,int alen) { -static const int table_to_family[NEIGH_NR_TABLES +1 ] = { -AF_INET ,AF_INET6 , AF_DECnet,AF_PACKET , - };struct nlattr *nla;struct rtvia *via; -int family =AF_UNSPEC ; nla =nla_reserve (skb,RTA_VIA , alen +2 );if (!nla)return -EMSGSIZE ; -if (table <=NEIGH_NR_TABLES ) - family = table_to_family[table]; - via =nla_data (nla); via->rtvia_family = family;memcpy (via->rtvia_addr, addr, alen);
@@ -2295,7 +2286,7 @@ static int resize_platform_label_table(struct net *net, size_t limit) rt0->rt_protocol =RTPROT_KERNEL ; rt0->rt_payload_type =MPT_IPV4 ; rt0->rt_ttl_propagate =MPLS_TTL_PROP_DEFAULT ; - rt0->rt_nh->nh_via_table =NEIGH_LINK_TABLE ; + rt0->rt_nh->nh_via_table =MPLS_NEIGH_TABLE_UNSPEC ; rt0->rt_nh->nh_via_alen = lo->addr_len;memcpy (__mpls_nh_via (rt0, rt0->rt_nh), lo->dev_addr, lo->addr_len);
@@ -2309,7 +2300,7 @@ static int resize_platform_label_table(struct net *net, size_t limit) rt2->rt_protocol =RTPROT_KERNEL ; rt2->rt_payload_type =MPT_IPV6 ; rt2->rt_ttl_propagate =MPLS_TTL_PROP_DEFAULT ; - rt2->rt_nh->nh_via_table =NEIGH_LINK_TABLE ; + rt2->rt_nh->nh_via_table =MPLS_NEIGH_TABLE_UNSPEC ; rt2->rt_nh->nh_via_alen = lo->addr_len;memcpy (__mpls_nh_via (rt2, rt2->rt_nh), lo->dev_addr, lo->addr_len);
net/mpls/mpls_iptunnel.c +2 -4
@@ -138,11 +138,9 @@ static int mpls_xmit(struct sk_buff *skb)mpls_stats_inc_outucastpkts (out_dev, skb);if (rt) - err =neigh_xmit (NEIGH_ARP_TABLE , out_dev, &rt->rt_gateway, - skb); + err =neigh_xmit (AF_INET , out_dev, &rt->rt_gateway, skb);else if (rt6) - err =neigh_xmit (NEIGH_ND_TABLE , out_dev, &rt6->rt6i_gateway, - skb); + err =neigh_xmit (AF_INET6 , out_dev, &rt6->rt6i_gateway, skb);if (err)net_dbg_ratelimited ("%s: packet transmission failed: %d\n" , __func__, err);
net/netfilter/nf_flow_table_ip.c +2 -2
@@ -265,7 +265,7 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb, skb->dev = outdev; nexthop =rt_nexthop (rt, flow->tuplehash[!dir].tuple.src_v4.s_addr);skb_dst_set_noref (skb, &rt->dst); -neigh_xmit (NEIGH_ARP_TABLE , outdev, &nexthop, skb); +neigh_xmit (AF_INET , outdev, &nexthop, skb);return NF_STOLEN ; }
@@ -482,7 +482,7 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb, skb->dev = outdev; nexthop =rt6_nexthop (rt, &flow->tuplehash[!dir].tuple.src_v6);skb_dst_set_noref (skb, &rt->dst); -neigh_xmit (NEIGH_ND_TABLE , outdev, nexthop, skb); +neigh_xmit (AF_INET6 , outdev, nexthop, skb);return NF_STOLEN ; }
net/netfilter/nft_fwd_netdev.c +3 -3
@@ -84,7 +84,7 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr,unsigned int verdict =NF_STOLEN ;struct sk_buff *skb = pkt->skb;struct net_device *dev; -int neigh_table; +u8 neigh_table;switch (priv->nfproto) {case NFPROTO_IPV4 : {
@@ -100,7 +100,7 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr, } iph =ip_hdr (skb);ip_decrease_ttl (iph); - neigh_table =NEIGH_ARP_TABLE ; + neigh_table =AF_INET ;break ; }case NFPROTO_IPV6 : {
@@ -116,7 +116,7 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr, } ip6h =ipv6_hdr (skb); ip6h->hop_limit--; - neigh_table =NEIGH_ND_TABLE ; + neigh_table =AF_INET6 ;break ; }default :
Signature · 1 line
2.11.0
[email protected]
maintainerPATCH 13/17 net/neighbor: Convert internal functions away from neigh_tables
In reply to [email protected]From: David Ahern <[email protected]>
Convert uses of neigh_tables array to neigh_find_table. Maintain existing family order using a new table_families array. A later patch removes the neigh_tables array in favor of per-namespace accesses.
--- net/core/neighbour.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-)
net/core/neighbour.c +20 -7
@@ -62,6 +62,19 @@ static int pneigh_ifdown_and_unlock(struct neigh_table *tbl,static const struct seq_operations neigh_stat_seq_ops;#endif +/* used for table dumps to maintain the legacy order of +* ipv4, ipv6, decnet +*/ +static int table_families[] = { +AF_INET , +#if IS_ENABLED(CONFIG_IPV6) +AF_INET6 , +#endif +#if IS_ENABLED(CONFIG_DECNET) + AF_DECnet, +#endif +}; +/* Neighbour hash table buckets are protected with rwlock tbl->lock.
@@ -2046,8 +2059,8 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, ndtmsg =nlmsg_data (nlh); -for (tidx =0 ; tidx <NEIGH_NR_TABLES ; tidx++) { - tbl = neigh_tables[tidx]; +for (tidx =0 ; tidx <ARRAY_SIZE (table_families); tidx++) { + tbl =neigh_find_table (net, table_families[tidx]);if (!tbl)continue ;if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)
@@ -2195,10 +2208,10 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb) family = ((struct rtgenmsg *)nlmsg_data (cb->nlh))->rtgen_family; -for (tidx =0 ; tidx <NEIGH_NR_TABLES ; tidx++) { +for (tidx =0 ; tidx <ARRAY_SIZE (table_families); tidx++) {struct neigh_parms *p; - tbl = neigh_tables[tidx]; + tbl =neigh_find_table (net, table_families[tidx]);if (!tbl)continue ;
@@ -2453,6 +2466,7 @@ static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,static int neigh_dump_info (struct sk_buff *skb,struct netlink_callback *cb) { +struct net *net =sock_net (skb->sk);struct neigh_table *tbl;int t, family, s_t;int proxy =0 ;
@@ -2469,9 +2483,8 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb) s_t = cb->args[0 ]; -for (t =0 ; t <NEIGH_NR_TABLES ; t++) { - tbl = neigh_tables[t]; - +for (t =0 ; t <ARRAY_SIZE (table_families); t++) { + tbl =neigh_find_table (net, table_families[t]);if (!tbl)continue ;if (t < s_t || (family && tbl->family != family))
Signature · 1 line
2.11.0
[email protected]
maintainerPATCH 14/17 net/ipv4: Convert arp table to per namespace
In reply to [email protected]From: David Ahern <[email protected]>
Convert IPv4 neighbor table to per-namespace.
This patch is a transition patch for the core neighbor code, so update the init_net reference as needed for AF_INET. With the per-namespace table allow gc parameters to be changed per namespace.
--- include/net/arp.h | 2 +- include/net/netns/ipv4.h | 1 + net/core/neighbour.c | 22 +++++++----- net/ipv4/arp.c | 88 ++++++++++++++++++++++++++++-------------------- 4 files changed, 67 insertions(+), 46 deletions(-)
include/net/arp.h +1 -1
@@ -9,7 +9,7 @@static inline struct neigh_table *ipv4_neigh_table (struct net *net) { -return neigh_find_table (net,AF_INET ); +return net->ipv4.arp_tbl; } static inline struct neighbour *ipv4_neigh_create(struct net_device *dev,
include/net/netns/ipv4.h +1 -0
@@ -51,6 +51,7 @@ struct netns_ipv4 {struct ipv4_devconf *devconf_dflt;struct ip_ra_chain __rcu *ra_chain;struct mutex ra_mutex; +struct neigh_table *arp_tbl;#ifdef CONFIG_IP_MULTIPLE_TABLES struct fib_rules_ops *rules_ops;bool fib_has_custom_rules;
net/core/neighbour.c +14 -8
@@ -1485,11 +1485,15 @@ EXPORT_SYMBOL(pneigh_enqueue);static inline struct neigh_parms *lookup_neigh_parms (struct neigh_table *tbl,struct net *net,int ifindex) { +struct net *def_net = &init_net;struct neigh_parms *p; +if (tbl->family ==AF_INET ) + def_net =neigh_parms_net (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))) + (!p->dev && !ifindex &&net_eq (net, def_net)))return p; }
@@ -1611,7 +1615,7 @@ void neigh_table_init(struct net *net, struct neigh_table *tbl)switch (family) {case AF_INET : - neigh_tables[NEIGH_ARP_TABLE ] = tbl; + net->ipv4.arp_tbl = tbl;break ;case AF_INET6 : neigh_tables[NEIGH_ND_TABLE ] = tbl;
@@ -1629,7 +1633,7 @@ int neigh_table_clear(struct net *net, struct neigh_table *tbl)switch (family) {case AF_INET : - neigh_tables[NEIGH_ARP_TABLE ] =NULL ; + net->ipv4.arp_tbl =NULL ;break ;case AF_INET6 : neigh_tables[NEIGH_ND_TABLE ] =NULL ;
@@ -1669,7 +1673,7 @@ struct neigh_table *neigh_find_table(struct net *net, u8 family)switch (family) {case AF_INET : - tbl = neigh_tables[NEIGH_ARP_TABLE ]; + tbl = net->ipv4.arp_tbl;break ;case AF_INET6 : tbl = neigh_tables[NEIGH_ND_TABLE ];
@@ -2173,10 +2177,12 @@ 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 (tbl->family !=AF_INET ) { +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 ]) tbl->gc_thresh1 =nla_get_u32 (tb[NDTA_THRESH1 ]);
net/ipv4/arp.c +51 -37
117 lines not on this page · raw message
Signature · 1 line
2.11.0
[email protected]
maintainerPATCH 15/17 net/ipv6: Convert neighbor table to per-namespace
In reply to [email protected]From: David Ahern <[email protected]>
Convert IPv6 neighbor table to per-namespace.
This patch is a transition patch for the core neighbor code, so update the init_net reference as needed for AF_INET6. With the per-namespace table allow gc parameters to be changed per namespace.
--- include/net/ndisc.h | 6 ++- include/net/netns/ipv6.h | 1 + net/core/neighbour.c | 16 +++++-- net/ipv6/ndisc.c | 120 +++++++++++++++++++++++------------------------ 4 files changed, 76 insertions(+), 67 deletions(-)
include/net/ndisc.h +5 -1
@@ -374,7 +374,11 @@ static inline u32 ndisc_hashfn(const void *pkey, const struct net_device *dev, _static inline struct neigh_table *ipv6_neigh_table (struct net *net) { -return neigh_find_table (net,AF_INET6 ); +#if IS_ENABLED (CONFIG_IPV6 ) +return net->ipv6.nd_tbl; +#else +return NULL ; +#endif } static inline struct neighbour *ipv6_neigh_create(struct net_device *dev,
include/net/netns/ipv6.h +1 -0
@@ -66,6 +66,7 @@ struct netns_ipv6 {struct rt6_statistics *rt6_stats;struct timer_list ip6_fib_timer;struct hlist_head *fib_table_hash; +struct neigh_table *nd_tbl;struct fib6_table *fib6_main_tbl;struct list_head fib6_walkers;struct dst_ops ip6_dst_ops;
net/core/neighbour.c +11 -5
@@ -1488,7 +1488,7 @@ static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,struct net *def_net = &init_net;struct neigh_parms *p; -if (tbl->family ==AF_INET ) +if (tbl->family != AF_DECnet) def_net =neigh_parms_net (p);list_for_each_entry (p, &tbl->parms_list, list) {
@@ -1617,9 +1617,11 @@ void neigh_table_init(struct net *net, struct neigh_table *tbl)case AF_INET : net->ipv4.arp_tbl = tbl;break ; +#if IS_ENABLED (CONFIG_IPV6 )case AF_INET6 : - neigh_tables[NEIGH_ND_TABLE ] = tbl; + net->ipv6.nd_tbl = tbl;break ; +#endif case AF_DECnet: neigh_tables[NEIGH_DN_TABLE ] = tbl;break ;
@@ -1635,9 +1637,11 @@ int neigh_table_clear(struct net *net, struct neigh_table *tbl)case AF_INET : net->ipv4.arp_tbl =NULL ;break ; +#if IS_ENABLED (CONFIG_IPV6 )case AF_INET6 : - neigh_tables[NEIGH_ND_TABLE ] =NULL ; + net->ipv6.nd_tbl =NULL ;break ; +#endif case AF_DECnet: neigh_tables[NEIGH_DN_TABLE ] =NULL ;break ;
@@ -1675,9 +1679,11 @@ struct neigh_table *neigh_find_table(struct net *net, u8 family)case AF_INET : tbl = net->ipv4.arp_tbl;break ; +#if IS_ENABLED (CONFIG_IPV6 )case AF_INET6 : - tbl = neigh_tables[NEIGH_ND_TABLE ]; + tbl = net->ipv6.nd_tbl;break ; +#endif case AF_DECnet: tbl = neigh_tables[NEIGH_DN_TABLE ];break ;
@@ -2177,7 +2183,7 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, } err = -ENOENT ; -if (tbl->family !=AF_INET ) { +if (tbl->family == AF_DECnet) {if ((tb[NDTA_THRESH1 ] || tb[NDTA_THRESH2 ] || tb[NDTA_THRESH3 ] || tb[NDTA_GC_INTERVAL ]) && !net_eq (net, &init_net))
net/ipv6/ndisc.c +59 -61
165 lines not on this page · raw message
Signature · 1 line
2.11.0
[email protected]
maintainerPATCH 16/17 net/decnet: Move neighbor table to per-namespace
In reply to [email protected]From: David Ahern <[email protected]>
Convert decnet neighbor table to per-namespace. Since there are no other per-namespace parameters for decnet just add the reference to struct net directly.
--- include/net/net_namespace.h | 3 +++ net/core/neighbour.c | 26 ++++++++++---------------- 2 files changed, 13 insertions(+), 16 deletions(-)
include/net/net_namespace.h +3 -0
@@ -108,6 +108,9 @@ struct net {#if IS_ENABLED (CONFIG_IPV6 )struct netns_ipv6 ipv6;#endif +#if IS_ENABLED (CONFIG_DECNET ) +struct neigh_table *dn_tbl; +#endif #if IS_ENABLED (CONFIG_IEEE802154_6LOWPAN )struct netns_ieee802154_lowpan ieee802154_lowpan;#endif
net/core/neighbour.c +10 -16
@@ -1485,15 +1485,11 @@ EXPORT_SYMBOL(pneigh_enqueue);static inline struct neigh_parms *lookup_neigh_parms (struct neigh_table *tbl,struct net *net,int ifindex) { -struct net *def_net = &init_net;struct neigh_parms *p; -if (tbl->family != AF_DECnet) - def_net =neigh_parms_net (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, def_net))) + (!p->dev && !ifindex))return p; }
@@ -1622,9 +1618,11 @@ void neigh_table_init(struct net *net, struct neigh_table *tbl) net->ipv6.nd_tbl = tbl;break ;#endif +#if IS_ENABLED (CONFIG_DECNET )case AF_DECnet: - neigh_tables[NEIGH_DN_TABLE ] = tbl; + net->dn_tbl = tbl;break ; +#endif } }EXPORT_SYMBOL (neigh_table_init);
@@ -1642,9 +1640,11 @@ int neigh_table_clear(struct net *net, struct neigh_table *tbl) net->ipv6.nd_tbl =NULL ;break ;#endif +#if IS_ENABLED (CONFIG_DECNET )case AF_DECnet: - neigh_tables[NEIGH_DN_TABLE ] =NULL ; + net->dn_tbl =NULL ;break ; +#endif }/* It is not clean... Fix it to unload IPv6 module safely */
@@ -1684,9 +1684,11 @@ struct neigh_table *neigh_find_table(struct net *net, u8 family) tbl = net->ipv6.nd_tbl;break ;#endif +#if IS_ENABLED (CONFIG_DECNET )case AF_DECnet: - tbl = neigh_tables[NEIGH_DN_TABLE ]; + tbl = net->dn_tbl;break ; +#endif }return tbl;
@@ -2182,14 +2184,6 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, } } - err = -ENOENT ; -if (tbl->family == AF_DECnet) { -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 ]) tbl->gc_thresh1 =nla_get_u32 (tb[NDTA_THRESH1 ]);
Signature · 1 line
2.11.0
[email protected]
maintainerPATCH 17/17 net/neighbor: Remove neigh_tables and NEIGH enum
In reply to [email protected]From: David Ahern <[email protected]>
No longer used.
--- include/net/neighbour.h | 8 -------- net/core/neighbour.c | 2 -- 2 files changed, 10 deletions(-)
include/net/neighbour.h +0 -8
@@ -222,14 +222,6 @@ struct neigh_table {struct pneigh_entry **phash_buckets; }; -enum { -NEIGH_ARP_TABLE =0 , -NEIGH_ND_TABLE =1 , -NEIGH_DN_TABLE =2 , -NEIGH_NR_TABLES , -NEIGH_LINK_TABLE =NEIGH_NR_TABLES /* Pseudo table for neigh_xmit */ -}; -struct neigh_table *neigh_find_table (struct net *net,u8 family);static inline int neigh_parms_family (struct neigh_parms *p)
net/core/neighbour.c +0 -2
@@ -1559,8 +1559,6 @@ static void neigh_parms_destroy(struct neigh_parms *parms)static struct lock_class_key neigh_table_proxy_queue_class; -static struct neigh_table *neigh_tables[NEIGH_NR_TABLES ]__read_mostly ; -void neigh_table_init (struct net *net,struct neigh_table *tbl) {unsigned long now = jiffies;
Signature · 1 line
2.11.0
Quoted 7 lines · On Tue, Jul 17, 2018 at 5:11 AM <[email protected]> wrote:
From: David Ahern <[email protected]>
Nikita Leshenko reported that neighbor entries in one namespace can evict neighbor entries in another. The problem is that the neighbor tables have entries across all namespaces without separate accounting and with global limits on when to scan for entries to evict.
It is nothing new, people including me already noticed this before.
Quoted 3 lines
Resolve by making the neighbor tables for ipv4, ipv6 and decnet per namespace and making the accounting and threshold limits per namespace.
The last discussion about this a long time ago concluded that neigh table entries are controllable by remote, so after moving it to per netns, it would be easier to DOS the host.
Quoted 13 lines · Cong Wang
Quoted 7 lines · On Tue, Jul 17, 2018 at 5:11 AM <[email protected]> wrote:
From: David Ahern <[email protected]>
Nikita Leshenko reported that neighbor entries in one namespace can evict neighbor entries in another. The problem is that the neighbor tables have entries across all namespaces without separate accounting and with global limits on when to scan for entries to evict.
It is nothing new, people including me already noticed this before.
Quoted 1 line
Quoted 8 lines
Quoted 2 lines
Resolve by making the neighbor tables for ipv4, ipv6 and decnet per namespace and making the accounting and threshold limits per namespace.
The last discussion about this a long time ago concluded that neigh table entries are controllable by remote, so after moving it to per netns, it would be easier to DOS the host.
There are still limits on the total number of entries and with per-namespace limits an admin has better control.
Quoted 19 lines · David Ahern
Quoted 17 lines · Cong Wang
Quoted 7 lines · On Tue, Jul 17, 2018 at 5:11 AM <[email protected]> wrote:
From: David Ahern <[email protected]>
Nikita Leshenko reported that neighbor entries in one namespace can evict neighbor entries in another. The problem is that the neighbor tables have entries across all namespaces without separate accounting and with global limits on when to scan for entries to evict.
It is nothing new, people including me already noticed this before.
Quoted 3 lines
Resolve by making the neighbor tables for ipv4, ipv6 and decnet per namespace and making the accounting and threshold limits per namespace.
Quoted 7 lines
Quoted 4 lines
The last discussion about this a long time ago concluded that neigh table entries are controllable by remote, so after moving it to per netns, it would be easier to DOS the host.
There are still limits on the total number of entries and with per-namespace limits an admin has better control.
Per-netns limit is *exactly* the problem here.
Quote from David Miller:
"
From: [email protected] (Eric W. Biederman)
Date: Wed, 25 Jun 2014 18:17:08 -0700
Quoted 3 lines
I disagree that removing a global DOS prevention check is a benefit. Certainly large semantics changes like that should not happen without being discussed in the patch description.
Agreed, this is the most important core issue.
If we just make these things per netns, then as a result if you create N namespaces we will allow N times more neighbour entries to be sitting in the system at once.
Actually, I'm really surprised the limits get hit and this actually causes problems.
"
You can see the original discussion here:
https://marc.info/?l=linux-netdev&m=140356141019653&w=2
Quoted 3 lines · Cong Wang
You can see the original discussion here:
https://marc.info/?l=linux-netdev&m=140356141019653&w=2
Thanks for the reference.
I was surprised that the tables are still global. A number of objections raised in that thread were due to a large patch tackling multiple issues. This set is focused one thing - moving the tables to net - and does so in small incremental changes to make it easy to review.
One of DaveM's comments:
"Finally, another problem are permanent neigh entries as those cannot be reclaimed, that might be part of the main problem here.
One idea wrt. permanent entries is that we could decide that, since they are administratively added, they don't count against the thresholds and limits."
this is another we have hit and with same thinking ... permanent entries should not count in the gc numbers. We need to address this for EVPN.
As for the per-namespace tables, it is 4 years later and over that time Linux supports a number of features: EVPN which is very mac heavy, VRR which doubles mac entries (one against the VRR device and one against the lower device) and NOS level features such as mlxsw which has to ensure mac entries for nexthop gateaways stay active. In addition there are other features on the horizon - like the ability to use namespaces to create virtual switches (what Cisco calls a VDC) where you absolutely want isolation and not allowing entries from virtual switch to evict entries from another. And of course the continued proliferation of containerized workloads where isolation is desired.
I understand the concern about global resource and limits: as it stands you have to increase the limits in init_net to the max expected and hope for the best. With per namespace limits you can lower the limits of each namespace better control the total impact on the total memory used. Perhaps the defaults for namespaces after init_net could have really low defaults (e.g., 16 / 32 / 64 for gc_thresh 1/2/3) requiring admin intervention.
Quoted 10 lines · David Ahern
As for the per-namespace tables, it is 4 years later and over that time Linux supports a number of features: EVPN which is very mac heavy, VRR which doubles mac entries (one against the VRR device and one against the lower device) and NOS level features such as mlxsw which has to ensure mac entries for nexthop gateaways stay active. In addition there are other features on the horizon - like the ability to use namespaces to create virtual switches (what Cisco calls a VDC) where you absolutely want isolation and not allowing entries from virtual switch to evict entries from another. And of course the continued proliferation of containerized workloads where isolation is desired.
As long as no change in neigh table code base itself, these can't address the concern people raised before.
Quoted 5 lines
I understand the concern about global resource and limits: as it stands you have to increase the limits in
init_netto the max expected and hope for the best. With per namespace limits you can lower the limits of each namespace better control the total impact on the total memory used.
The problem is that the number of containers in a host is usually not predictable.
Of course, you can say containers limit kernel memory too, but memcg is not part of netns. I once told David Miller cpuset is the isolation for isolating per-CPU softnet_data, he didn't like it. Based on that I don't think you can convince him with memcg as a solution here.
David Miller
maintainerFrom: David Ahern <[email protected]>
Date: Tue, 17 Jul 2018 13:02:18 -0600
Quoted 7 lines
I understand the concern about global resource and limits: as it stands you have to increase the limits in
init_netto the max expected and hope for the best. With per namespace limits you can lower the limits of each namespace better control the total impact on the total memory used. Perhaps the defaults for namespaces afterinit_netcould have really low defaults (e.g., 16 / 32 / 64 forgc_thresh1/2/3) requiring admin intervention.
How does this work when a namespace creates another namespace?
Changing the defaults for non-init_net namespaces could work, but that could be a surprise to some people.
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
David Ahern <[email protected]> writes:
Quoted 7 lines · [email protected] wrote:
Nikita Leshenko reported that neighbor entries in one namespace can evict neighbor entries in another. The problem is that the neighbor tables have entries across all namespaces without separate accounting and with global limits on when to scan for entries to evict.
Resolve by making the neighbor tables for ipv4, ipv6 and decnet per namespace and making the accounting and threshold limits per namespace.
This is a good improvement, thank you.
We absolutely need to keep a DOS against a single netns from causing evictions in another netns.
Within a namespace there may be neighbours entries that are more sure/valid/useful than others. I would like an API to be able to mark them explicitely, but that could come leter.
In particular, in the 802.15.4 case, NE that arrive via encrypted channels should be preferred over entries that arrive over unencrypted channels. This is needed for IETF 6tisch secure join work, for instance.
I believe that we could use network namespaces to implement though.
I had not considered that before, and I think that it will work, but there might be something subtle that I've missed. (Alex?)
It appears that one can tune the amount of space on a per-namespace basis:
+ nd_tbl->gc_thresh1 = 128;
+ nd_tbl->gc_thresh2 = 512;
+ nd_tbl->gc_thresh3 = 1024;
Quoted 4 lines
Remove open use of
arp_tblandnd_tblin favor of the new ipv{4,6}_neigh_table helpers. Since the existence of the IPv6 table is managed by the core networking, theIS_ENABLEDchecks for IPv6 can be removed in favor of "is the table non-NULL".
What's the advantage of changing this check? (I am ignorant)
Quoted 7 lines · Michael Richardson
Quoted 4 lines
Remove open use of
arp_tblandnd_tblin favor of the new ipv{4,6}_neigh_table helpers. Since the existence of the IPv6 table is managed by the core networking, theIS_ENABLEDchecks for IPv6 can be removed in favor of "is the table non-NULL".What's the advantage of changing this check? (I am ignorant)
Just makes the code simpler.
The current nd_tbl is a global owned by the ipv6 code (net/ipv6/ndisc.c). If CONFIG_IPV6 is not enabled, then nd_tbl is not defined which leads code referencing it to use if checks like this:
#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
With the neigh_find_table approach the IS_ENABLED can be removed in favor of 'if (tbl)'. If tbl is set, then ipv6 is loaded and initialized.
Quoted 11 lines · David Miller
From: David Ahern <[email protected]>
Date: Tue, 17 Jul 2018 13:02:18 -0600Quoted 7 lines
I understand the concern about global resource and limits: as it stands you have to increase the limits in
init_netto the max expected and hope for the best. With per namespace limits you can lower the limits of each namespace better control the total impact on the total memory used. Perhaps the defaults for namespaces afterinit_netcould have really low defaults (e.g., 16 / 32 / 64 forgc_thresh1/2/3) requiring admin intervention.
Quoted 5 lines
How does this work when a namespace creates another namespace?
Changing the defaults for non-init_net namespaces could work, but that could be a surprise to some people.
Patches 14 (ipv4) and 15 (ipv6) currently use the existing hardcoded values - not based on current init_net or anything else. This could be changed to:
+ if (net_eq(net, &init_net)) {
+ arp_tbl->gc_thresh1 = 128;
+ arp_tbl->gc_thresh2 = 512;
+ arp_tbl->gc_thresh3 = 1024;
+ } else {
+ arp_tbl->gc_thresh1 = 16;
+ arp_tbl->gc_thresh2 = 32;
+ arp_tbl->gc_thresh3 = 64;
+ }
and update the documentation that any new network namespaces have lower defaults.
As for any change in behavior: today neighbor entries from one namespace can be removed due to actions in another so no obvious correlation. With lower settings then gc could kick in and remove entries that otherwise would not have been. The big hit would be to a new namespace where an app inserts a lot of PERMANENT entries.
Chatting with Nikolay about this and he brought up a good corollary - ip fragmentation. It really is a similar problem in that memory is consumed as a result of packets received from an external entity. The ipfrag sysctls are per namespace with a limit that non-init_net namespaces can not set high_thresh > the current value of init_net. Potential memory consumed by fragments scales with the number of namespaces which is the primary concern with making neighbor tables per namespace.
If we kept the current default settings (128/512/1024) per namespace we still have capped memory use, and the one user visible hit that comes to mind is the namespace with a lot of PERM entries.
Quoted 8 lines · David Ahern
Chatting with Nikolay about this and he brought up a good corollary - ip fragmentation. It really is a similar problem in that memory is consumed as a result of packets received from an external entity. The ipfrag sysctls are per namespace with a limit that non-init_net namespaces can not set
high_thresh> the current value ofinit_net. Potential memory consumed by fragments scales with the number of namespaces which is the primary concern with making neighbor tables per namespace.
Nothing new, already discussed:
https://marc.info/?l=linux-netdev&m=140391416215988&w=2
:)
Quoted 10 lines · Cong Wang
Quoted 8 lines · David Ahern
Chatting with Nikolay about this and he brought up a good corollary - ip fragmentation. It really is a similar problem in that memory is consumed as a result of packets received from an external entity. The ipfrag sysctls are per namespace with a limit that non-init_net namespaces can not set
high_thresh> the current value ofinit_net. Potential memory consumed by fragments scales with the number of namespaces which is the primary concern with making neighbor tables per namespace.
Quoted 5 lines
Nothing new, already discussed:
https://marc.info/?l=linux-netdev&m=140391416215988&w=2:)
Neighbor tables, bridge fdbs, vxlan fdbs and ip fragments all consume local memory resources due to received packets. bridge and vxlan fdb's are fairly straightforward analogs to neighbor entries; they are per device with no limits on the number of entries. Fragments have memory limits per namespace. So neighbor tables are the only ones with this strict limitation and concern on memory consumption.
I get the impression there is no longer a strong resistance against moving the tables to per namespace, but deciding what is the right approach to handle backwards compatibility. Correct? Changing the accounting is inevitably going to be noticeable to some use case(s), but with sysctl settings it is a simple runtime update once the user knows to make the change.
neighbor entries round up to 512 byte allocations, so with the current gc_thresh defaults (128/512/1024) 512k can be consumed. Using those limits per namespace seems high which is why I suggested a per-namespace default of (16/32/64) which amounts to 32k per namespace limit by default. Open to other suggestions as well.
David Miller
maintainerFrom: David Ahern <[email protected]>
Date: Tue, 24 Jul 2018 09:14:01 -0600
Quoted 7 lines
I get the impression there is no longer a strong resistance against moving the tables to per namespace, but deciding what is the right approach to handle backwards compatibility. Correct? Changing the accounting is inevitably going to be noticeable to some use case(s), but with sysctl settings it is a simple runtime update once the user knows to make the change.
Quoted 5 lines
neighbor entries round up to 512 byte allocations, so with the current
gc_threshdefaults (128/512/1024) 512k can be consumed. Using those limits per namespace seems high which is why I suggested a per-namespace default of (16/32/64) which amounts to 32k per namespace limit by default. Open to other suggestions as well.
No objection from me about going to per-ns neigh tables.
About the defaults, I wonder if we can scale them to the amount of memory given to the ns or something like that? I bet this will better match the intended use of the ns.
Quoted 25 lines · David Ahern
Quoted 10 lines · Cong Wang
Quoted 8 lines · David Ahern
Chatting with Nikolay about this and he brought up a good corollary - ip fragmentation. It really is a similar problem in that memory is consumed as a result of packets received from an external entity. The ipfrag sysctls are per namespace with a limit that non-init_net namespaces can not set
high_thresh> the current value ofinit_net. Potential memory consumed by fragments scales with the number of namespaces which is the primary concern with making neighbor tables per namespace.Quoted 5 lines
Nothing new, already discussed:
https://marc.info/?l=linux-netdev&m=140391416215988&w=2:)
Neighbor tables, bridge fdbs, vxlan fdbs and ip fragments all consume local memory resources due to received packets. bridge and vxlan fdb's are fairly straightforward analogs to neighbor entries; they are per device with no limits on the number of entries. Fragments have memory limits per namespace. So neighbor tables are the only ones with this strict limitation and concern on memory consumption.
Quoted 6 lines
I get the impression there is no longer a strong resistance against moving the tables to per namespace, but deciding what is the right approach to handle backwards compatibility. Correct? Changing the accounting is inevitably going to be noticeable to some use case(s), but with sysctl settings it is a simple runtime update once the user knows to make the change.
This question definitely should go to Eric Biederman who was against my proposal.
Let's add Eric into CC.
Quoted 33 lines · Cong Wang
Quoted 25 lines · David Ahern
Quoted 10 lines · Cong Wang
Quoted 8 lines · David Ahern
Chatting with Nikolay about this and he brought up a good corollary - ip fragmentation. It really is a similar problem in that memory is consumed as a result of packets received from an external entity. The ipfrag sysctls are per namespace with a limit that non-init_net namespaces can not set
high_thresh> the current value ofinit_net. Potential memory consumed by fragments scales with the number of namespaces which is the primary concern with making neighbor tables per namespace.Quoted 5 lines
Nothing new, already discussed:
https://marc.info/?l=linux-netdev&m=140391416215988&w=2:)
Neighbor tables, bridge fdbs, vxlan fdbs and ip fragments all consume local memory resources due to received packets. bridge and vxlan fdb's are fairly straightforward analogs to neighbor entries; they are per device with no limits on the number of entries. Fragments have memory limits per namespace. So neighbor tables are the only ones with this strict limitation and concern on memory consumption.
Quoted 6 lines
I get the impression there is no longer a strong resistance against moving the tables to per namespace, but deciding what is the right approach to handle backwards compatibility. Correct? Changing the accounting is inevitably going to be noticeable to some use case(s), but with sysctl settings it is a simple runtime update once the user knows to make the change.
Quoted 4 lines
This question definitely should go to Eric Biederman who was against my proposal.
Let's add Eric into CC.
Given that the entries are per device and the devices are per-namespace, semantically neighbours are already kept in a per-namespace manner. So this is all about making the code not honoring global resource limits. Making the code not honor gc_thresh3.
Skimming through the code today the default for gc_thresh3 is 1024. Which means that we limit the neighbour tables to 1024 entries per protocol type.
There are some pretty compelling reasons especially with ipv4 to keep the subnet size down. Arp storms are a real thing.
I don't know off the top of my head what the reasons for limiting the neighbour table sizes. I would be much more comfortable with a patchset like this if we did some research and figured out the reasons why we have a global limit. Then changed the code to remove those limits.
When the limits are gone. When the code can support large subnets without tuning. We we don't have to worry about someone scanning an all addresses in an ipv6 subnet and causing a DOS on working machines. I think it is completely appropriate to look to see if something per network namespace needs to happen.
So please let's address the limits, not the fact that some specific corner case ran into them.
If we are going to neuter gc_thresh3 let's go as far as removing it entirely. If we are going to make the neighbour table per something let's make it per network device. If we can afford the multiple hash
tables then a hash table per device is better. Perhaps we want to move
to rhash tables while we look at this, instead of an old hand grown version of resizable hash table.
Unless I misread something all your patchset did is reshuffle code and data structures so that gc_thresh3 does not apply accross namespaces. That does not feel like it really fixes anything. That just lies to people.
Further unless I misread something you are increasing the number of timers to 3 per namespace. If I create create a thousand network namespaces that feels like it will hurt system performance overall.
Eric
Quoted 66 lines · Eric W. Biederman
Quoted 33 lines · Cong Wang
Quoted 25 lines · David Ahern
Quoted 10 lines · Cong Wang
Quoted 8 lines · David Ahern
Chatting with Nikolay about this and he brought up a good corollary - ip fragmentation. It really is a similar problem in that memory is consumed as a result of packets received from an external entity. The ipfrag sysctls are per namespace with a limit that non-init_net namespaces can not set
high_thresh> the current value ofinit_net. Potential memory consumed by fragments scales with the number of namespaces which is the primary concern with making neighbor tables per namespace.Quoted 5 lines
Nothing new, already discussed:
https://marc.info/?l=linux-netdev&m=140391416215988&w=2:)
Neighbor tables, bridge fdbs, vxlan fdbs and ip fragments all consume local memory resources due to received packets. bridge and vxlan fdb's are fairly straightforward analogs to neighbor entries; they are per device with no limits on the number of entries. Fragments have memory limits per namespace. So neighbor tables are the only ones with this strict limitation and concern on memory consumption.
Quoted 6 lines
I get the impression there is no longer a strong resistance against moving the tables to per namespace, but deciding what is the right approach to handle backwards compatibility. Correct? Changing the accounting is inevitably going to be noticeable to some use case(s), but with sysctl settings it is a simple runtime update once the user knows to make the change.
Quoted 4 lines
This question definitely should go to Eric Biederman who was against my proposal.
Let's add Eric into CC.
Given that the entries are per device and the devices are per-namespace, semantically neighbours are already kept in a per-namespace manner. So this is all about making the code not honoring global resource limits. Making the code not honor
gc_thresh3.Skimming through the code today the default for
gc_thresh3is 1024. Which means that we limit the neighbour tables to 1024 entries per protocol type.There are some pretty compelling reasons especially with ipv4 to keep the subnet size down. Arp storms are a real thing.
I don't know off the top of my head what the reasons for limiting the neighbour table sizes. I would be much more comfortable with a patchset like this if we did some research and figured out the reasons why we have a global limit. Then changed the code to remove those limits.
When the limits are gone. When the code can support large subnets without tuning. We we don't have to worry about someone scanning an all addresses in an ipv6 subnet and causing a DOS on working machines. I think it is completely appropriate to look to see if something per network namespace needs to happen.
So please let's address the limits, not the fact that some specific corner case ran into them.
Quoted 6 lines
If we are going to neuter
gc_thresh3let's go as far as removing it entirely. If we are going to make the neighbour table per something let's make it per network device. If we can afford the multiple hash
tables then a hash table per device is better. Perhaps we want to move
to rhash tables while we look at this, instead of an old hand grown version of resizable hash table.
Given the uses cases with increasing number of devices (> 10,000), per-device tables will have more problems than per namespace - in reference to your concern in the last paragraph below.
Quoted 5 lines
Unless I misread something all your patchset did is reshuffle code and data structures so that
gc_thresh3does not apply accross namespaces. That does not feel like it really fixes anything. That just lies to people.
This patch set fixes the lie that network namespaces provide complete isolation when in fact one namespace can evict neighbor entries from another. An arp storm you are concerned about in one namespace impacts all containers.
It starts by removing the proliferation of open coded references to arp_tbl and nd_tbl, moving them behind the existing neigh_find_table.
Quoted 1 line
From there (patches 14-16) it makes the tables per-namespace and hence
makes the gc_thresh parameters which are per-table now per-table-per-namespace.
So it removes the global thresholds because the global ones are just wrong given the meaning of a network namespace and provides the more appropriate per-namespace limits.
Quoted 4 lines
Further unless I misread something you are increasing the number of timers to 3 per namespace. If I create create a thousand network namespaces that feels like it will hurt system performance overall.
It seems to me the timers are per neighbor entry not table. The per table ones are for proxies.
Quoted 84 lines · David Ahern
Quoted 66 lines · Eric W. Biederman
Quoted 33 lines · Cong Wang
Quoted 25 lines · David Ahern
Quoted 10 lines · Cong Wang
Quoted 8 lines · David Ahern
Chatting with Nikolay about this and he brought up a good corollary - ip fragmentation. It really is a similar problem in that memory is consumed as a result of packets received from an external entity. The ipfrag sysctls are per namespace with a limit that non-init_net namespaces can not set
high_thresh> the current value ofinit_net. Potential memory consumed by fragments scales with the number of namespaces which is the primary concern with making neighbor tables per namespace.Quoted 5 lines
Nothing new, already discussed:
https://marc.info/?l=linux-netdev&m=140391416215988&w=2:)
Neighbor tables, bridge fdbs, vxlan fdbs and ip fragments all consume local memory resources due to received packets. bridge and vxlan fdb's are fairly straightforward analogs to neighbor entries; they are per device with no limits on the number of entries. Fragments have memory limits per namespace. So neighbor tables are the only ones with this strict limitation and concern on memory consumption.
Quoted 6 lines
I get the impression there is no longer a strong resistance against moving the tables to per namespace, but deciding what is the right approach to handle backwards compatibility. Correct? Changing the accounting is inevitably going to be noticeable to some use case(s), but with sysctl settings it is a simple runtime update once the user knows to make the change.
Quoted 4 lines
This question definitely should go to Eric Biederman who was against my proposal.
Let's add Eric into CC.
Given that the entries are per device and the devices are per-namespace, semantically neighbours are already kept in a per-namespace manner. So this is all about making the code not honoring global resource limits. Making the code not honor
gc_thresh3.Skimming through the code today the default for
gc_thresh3is 1024. Which means that we limit the neighbour tables to 1024 entries per protocol type.There are some pretty compelling reasons especially with ipv4 to keep the subnet size down. Arp storms are a real thing.
I don't know off the top of my head what the reasons for limiting the neighbour table sizes. I would be much more comfortable with a patchset like this if we did some research and figured out the reasons why we have a global limit. Then changed the code to remove those limits.
When the limits are gone. When the code can support large subnets without tuning. We we don't have to worry about someone scanning an all addresses in an ipv6 subnet and causing a DOS on working machines. I think it is completely appropriate to look to see if something per network namespace needs to happen.
So please let's address the limits, not the fact that some specific corner case ran into them.
Quoted 6 lines
If we are going to neuter
gc_thresh3let's go as far as removing it entirely. If we are going to make the neighbour table per something let's make it per network device. If we can afford the multiple hash
tables then a hash table per device is better. Perhaps we want to move
to rhash tables while we look at this, instead of an old hand grown version of resizable hash table.Given the uses cases with increasing number of devices (> 10,000), per-device tables will have more problems than per namespace - in reference to your concern in the last paragraph below.
Quoted 5 lines
Unless I misread something all your patchset did is reshuffle code and data structures so that
gc_thresh3does not apply accross namespaces. That does not feel like it really fixes anything. That just lies to people.
Quoted 4 lines
This patch set fixes the lie that network namespaces provide complete isolation when in fact one namespace can evict neighbor entries from another. An arp storm you are concerned about in one namespace impacts all containers.
Network namespaces can not provide complete isolation. They share the same kernel and they do not dedicate resources to each other. Namespaces in general are about the names. They are about sharing a machine efficiently.
I humbly suggest that anyone who wants ``complete'' isolation to use vm at the very least.
I do think the limits on the neighbour table are quite likely too strict. We should be able to relax them and continue to have a networking stack that works for everyone.
Quoted 9 lines
It starts by removing the proliferation of open coded references to
arp_tblandnd_tbl, moving them behind the existingneigh_find_table. From there (patches 14-16) it makes the tables per-namespace and hence makes thegc_threshparameters which are per-table now per-table-per-namespace.So it removes the global thresholds because the global ones are just wrong given the meaning of a network namespace and provides the more appropriate per-namespace limits.
Absolutely NOT. Global thresholds are exactly correct given the fact you are running on a single kernel.
Memory is not free (Even though we are swimming in enough of it memory rarely matters). One of the few remaining challenges is for containers is finding was to limit resources in such a way that one application does not mess things up for another container during ordinary usage.
It looks like the neighbour tables absolutely are that kind of problem,
because the artificial limits are too strict. Completely giving up on
limits does not seem right approach either. We need to fix the limits we have (perhaps making them go away entirely), not just apply a band-aid. Let's get to the bottom of this and make the system better.
Quoted 6 lines
Quoted 3 lines
Further unless I misread something you are increasing the number of timers to 3 per namespace. If I create create a thousand network namespaces that feels like it will hurt system performance overall.
It seems to me the timers are per neighbor entry not table. The per table ones are for proxies.
It seems I misread that bit when I was refreshing my memory on what everything is doing. If we can already have 1024 timers that makes timers not a concern.
Eric
Quoted 9 lines · Eric W. Biederman
Absolutely NOT. Global thresholds are exactly correct given the fact you are running on a single kernel.
Memory is not free (Even though we are swimming in enough of it memory rarely matters). One of the few remaining challenges is for containers is finding was to limit resources in such a way that one application does not mess things up for another container during ordinary usage.
Quoted 5 lines
It looks like the neighbour tables absolutely are that kind of problem,
because the artificial limits are too strict. Completely giving up on
limits does not seem right approach either. We need to fix the limits we have (perhaps making them go away entirely), not just apply a band-aid. Let's get to the bottom of this and make the system better.
Eric: yes, they all share the global resource of memory and there should be limits on how many entries a remote entity can create.
Network namespaces can provide a separation such that one namespace does not disrupt networking in another. It is absolutely appropriate to do so. Your rigid stance is inconsistent given the basic meaning of a network namespace and the parallels to this same problem -- bridges, vxlans, and ip fragments. Only neighbor tables are not per-device or per namespace; your insistence on global limits is missing the mark and wrong.
Quoted 16 lines · David Miller
From: David Ahern <[email protected]>
Date: Tue, 24 Jul 2018 09:14:01 -0600Quoted 7 lines
I get the impression there is no longer a strong resistance against moving the tables to per namespace, but deciding what is the right approach to handle backwards compatibility. Correct? Changing the accounting is inevitably going to be noticeable to some use case(s), but with sysctl settings it is a simple runtime update once the user knows to make the change.
Quoted 5 lines
neighbor entries round up to 512 byte allocations, so with the current
gc_threshdefaults (128/512/1024) 512k can be consumed. Using those limits per namespace seems high which is why I suggested a per-namespace default of (16/32/64) which amounts to 32k per namespace limit by default. Open to other suggestions as well.
Quoted 6 lines
No objection from me about going to per-ns neigh tables.
About the defaults, I wonder if we can scale them to the amount of memory given to the ns or something like that? I bet this will better match the intended use of the ns.
Not sure how to do that. I am not aware of memory allocations to a network namespace. As I understand it containers use cgroups to control memory use, but I am not aware of any direct ties to namespace.
Quoted 19 lines · David Ahern
Quoted 9 lines · Eric W. Biederman
Absolutely NOT. Global thresholds are exactly correct given the fact you are running on a single kernel.
Memory is not free (Even though we are swimming in enough of it memory rarely matters). One of the few remaining challenges is for containers is finding was to limit resources in such a way that one application does not mess things up for another container during ordinary usage.
Quoted 5 lines
It looks like the neighbour tables absolutely are that kind of problem,
because the artificial limits are too strict. Completely giving up on
limits does not seem right approach either. We need to fix the limits we have (perhaps making them go away entirely), not just apply a band-aid. Let's get to the bottom of this and make the system better.Eric: yes, they all share the global resource of memory and there should be limits on how many entries a remote entity can create.
Quoted 6 lines
Network namespaces can provide a separation such that one namespace does not disrupt networking in another. It is absolutely appropriate to do so. Your rigid stance is inconsistent given the basic meaning of a network namespace and the parallels to this same problem -- bridges, vxlans, and ip fragments. Only neighbor tables are not per-device or per namespace; your insistence on global limits is missing the mark and wrong.
That is not what I said. Let me rephrase and see if you understand.
The problem appears to be of lots of devices. Fundamentally if you use lots of network devices today unless you adjust gc_thresh3 you will run out of neighbour table entries.
The problem has a bigger scope than what you are looking at.
If you fix the core problem you won't see the problem in the context of network namespaces either.
Default limits should be something that will never be hit unless something goes crazy. We are hitting them. Therefore by definition there is a bug in these limits.
And yes there is absolutely a place for global limits on things like inodes, file descriptors etc, that does not care about which part of the kernel you are in. However hitting those limits in normal operation is a bug.
We have ourselves a bug.
Eric
p.s. I wrote the definition of network namespaces and it absolutely does
have room for global limits. One of the things Linus has periodically
yelled at me about is that there are not enough of them.
From: Eric W. Biederman
Quoted 1 line
Sent: 25 July 2018 18:38
...
Quoted 10 lines
Quoted 6 lines
Quoted 3 lines
Further unless I misread something you are increasing the number of timers to 3 per namespace. If I create create a thousand network namespaces that feels like it will hurt system performance overall.
It seems to me the timers are per neighbor entry not table. The per table ones are for proxies.
It seems I misread that bit when I was refreshing my memory on what everything is doing. If we can already have 1024 timers that makes timers not a concern.
Surely it is enough to just have a timestamp in each entry. Deletion of expired items need not be done until insert (which has the table suitable locked) bumps into an expired item.
David
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales)
Quoted 10 lines · David Laight
From: Eric W. Biederman
Quoted 1 line
Sent: 25 July 2018 18:38
...
Quoted 7 lines
Quoted 6 lines
Quoted 3 lines
Further unless I misread something you are increasing the number of timers to 3 per namespace. If I create create a thousand network namespaces that feels like it will hurt system performance overall.
It seems to me the timers are per neighbor entry not table. The per table ones are for proxies.
Quoted 7 lines
Quoted 3 lines
It seems I misread that bit when I was refreshing my memory on what everything is doing. If we can already have 1024 timers that makes timers not a concern.
Surely it is enough to just have a timestamp in each entry. Deletion of expired items need not be done until insert (which has the table suitable locked) bumps into an expired item.
Part of the state machine the timer is used for is sending retransmits before we get out first response, so the state machine is not just about expiry and may not be simple enough to do without a timer.
I honestly don't remember the tradeoffs between the various kinds of timers. If we already can have up to 1000 timers without problems I suspect they are cheap enough optimizing for fewer times simply doesn't matter. Certainly we are not in regression territory if we don't.
As for bumping into expired items on insert it would be a bad hash table if we were bumping into any other entries frequently on insert.
Eric
Quoted 9 lines · On 07/17/2018 03:06 PM, [email protected] wrote:
From: David Ahern <[email protected]>
Nikita Leshenko reported that neighbor entries in one namespace can evict neighbor entries in another. The problem is that the neighbor tables have entries across all namespaces without separate accounting and with global limits on when to scan for entries to evict.
Resolve by making the neighbor tables for ipv4, ipv6 and decnet per namespace and making the accounting and threshold limits per namespace.
Dear David,
I prepared own patch set to fix this problem and found your one. It looks perfect for me, and I hope David Miller will merge it soon, however I have found a few drawbacks:
1) I know that if net_device exist it always have correct net reference, so dev_net(dev) will be always correct.
However I afraid that device reference itself is correct in some places. For example,
drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c +2 -1
@@ -376,9 +377,10 @@ mlxsw_sp_span_entry_gretap4_parms(const struct net_device *to_dev,return mlxsw_sp_span_entry_unoffloadable (sparmsp); l3edev =mlxsw_sp_span_gretap4_route (to_dev, &saddr.addr4, &gw.addr4); + tbl =ipv4_neigh_table (dev_net (l3edev));return mlxsw_sp_span_entry_tunnel_parms_common (l3edev, saddr, daddr, gw, tparm.iph.ttl, - &arp_tbl, sparmsp); + tbl, sparmsp); }
mlxsw_sp_span_entry_tunnel_parms_common() have "if (!edev)" check inside, so it seems l3edev can be set to NULL here and lead to crash inside dev_net(l3edev). There are few other suspicious places and I think they should be carefully re-checked.
2) modified arp_net_init() does not check return value neigh_sysctl_register() and lacks correct rollback. It was acceptable in arp_init, because it was called only once on boot, but now it will be called for each new net namespace, it can have real chances to fail lead to memory crash/memory corruption.
3) modified neigh_table_init() is called many times per netns but it can panic in case failed memory allocation. I think it should be reworked to return errors in such cases, its callers should check it and add correct rollbacks.
4) currently neigh_table_clear() always return 0, I think it makes sense to change it to return void.
Thank you,
Vasily Averin
Quoted 8 lines · Vasily Averin
Quoted 7 lines · On 07/17/2018 03:06 PM, [email protected] wrote:
From: David Ahern <[email protected]>
Nikita Leshenko reported that neighbor entries in one namespace can evict neighbor entries in another. The problem is that the neighbor tables have entries across all namespaces without separate accounting and with global limits on when to scan for entries to evict.
Quoted 8 lines
Quoted 2 lines
Resolve by making the neighbor tables for ipv4, ipv6 and decnet per namespace and making the accounting and threshold limits per namespace.
Dear David,
I prepared own patch set to fix this problem and found your one. It looks perfect for me, and I hope David Miller will merge it soon, however I have found a few drawbacks:
Hi:
I just returned from an extended vacation. I will revive this topic in the next few days.
Thanks for the comments. I will address in the next version.
Quoted 34 lines · Eric W. Biederman
Quoted 19 lines · David Ahern
Quoted 9 lines · Eric W. Biederman
Absolutely NOT. Global thresholds are exactly correct given the fact you are running on a single kernel.
Memory is not free (Even though we are swimming in enough of it memory rarely matters). One of the few remaining challenges is for containers is finding was to limit resources in such a way that one application does not mess things up for another container during ordinary usage.
Quoted 5 lines
It looks like the neighbour tables absolutely are that kind of problem,
because the artificial limits are too strict. Completely giving up on
limits does not seem right approach either. We need to fix the limits we have (perhaps making them go away entirely), not just apply a band-aid. Let's get to the bottom of this and make the system better.Eric: yes, they all share the global resource of memory and there should be limits on how many entries a remote entity can create.
Quoted 6 lines
Network namespaces can provide a separation such that one namespace does not disrupt networking in another. It is absolutely appropriate to do so. Your rigid stance is inconsistent given the basic meaning of a network namespace and the parallels to this same problem -- bridges, vxlans, and ip fragments. Only neighbor tables are not per-device or per namespace; your insistence on global limits is missing the mark and wrong.
That is not what I said. Let me rephrase and see if you understand.
The problem appears to be of lots of devices. Fundamentally if you use lots of network devices today unless you adjust
gc_thresh3you will run out of neighbour table entries.
Quoted 8 lines
The problem has a bigger scope than what you are looking at.
If you fix the core problem you won't see the problem in the context of network namespaces either.
Default limits should be something that will never be hit unless something goes crazy. We are hitting them. Therefore by definition there is a bug in these limits.
I disagree that the problem is a global limit. It is trivial for users to increase gc_thresh3. That does not solve the fundamental problem.
Quoted 8 lines
And yes there is absolutely a place for global limits on things like inodes, file descriptors etc, that does not care about which part of the kernel you are in. However hitting those limits in normal operation is a bug.
We have ourselves a bug.
I agree we have a bug; we disagree on what that bug is.
I am just back from vacation and re-read your responses. No where do you acknowledge the fundamental point of this patch set - that adding a new neighbor entry in one namespace can evict an entry in another namespace or worse networking in one namespace can fail due to table overflow because of entries from another. That is a real problem.
It is not a matter of increasing the default gc_thresh3 to some number N; it is ensuring that regardless of the value of gc_thresh3 one namespace is not affected by another.
You created network namespaces and it provides isolation -- separate tables essentially -- for devices, FIB entries, sockets, etc, but you argue against completing the task with separate neighbor tables which is very strange given the impact (completely broken networking).
Quoted 7 lines
Eric
p.s. I wrote the definition of network namespaces and it absolutely does
have room for global limits. One of the things Linus has periodically
yelled at me about is that there are not enough of them.
Quoted 64 lines · David Ahern
Quoted 34 lines · Eric W. Biederman
Quoted 19 lines · David Ahern
Quoted 9 lines · Eric W. Biederman
Absolutely NOT. Global thresholds are exactly correct given the fact you are running on a single kernel.
Memory is not free (Even though we are swimming in enough of it memory rarely matters). One of the few remaining challenges is for containers is finding was to limit resources in such a way that one application does not mess things up for another container during ordinary usage.
Quoted 5 lines
It looks like the neighbour tables absolutely are that kind of problem,
because the artificial limits are too strict. Completely giving up on
limits does not seem right approach either. We need to fix the limits we have (perhaps making them go away entirely), not just apply a band-aid. Let's get to the bottom of this and make the system better.Eric: yes, they all share the global resource of memory and there should be limits on how many entries a remote entity can create.
Quoted 6 lines
Network namespaces can provide a separation such that one namespace does not disrupt networking in another. It is absolutely appropriate to do so. Your rigid stance is inconsistent given the basic meaning of a network namespace and the parallels to this same problem -- bridges, vxlans, and ip fragments. Only neighbor tables are not per-device or per namespace; your insistence on global limits is missing the mark and wrong.
That is not what I said. Let me rephrase and see if you understand.
The problem appears to be of lots of devices. Fundamentally if you use lots of network devices today unless you adjust
gc_thresh3you will run out of neighbour table entries.Quoted 8 lines
The problem has a bigger scope than what you are looking at.
If you fix the core problem you won't see the problem in the context of network namespaces either.
Default limits should be something that will never be hit unless something goes crazy. We are hitting them. Therefore by definition there is a bug in these limits.
I disagree that the problem is a global limit. It is trivial for users to increase
gc_thresh3. That does not solve the fundamental problem.Quoted 8 lines
And yes there is absolutely a place for global limits on things like inodes, file descriptors etc, that does not care about which part of the kernel you are in. However hitting those limits in normal operation is a bug.
We have ourselves a bug.
I agree we have a bug; we disagree on what that bug is.
I am just back from vacation and re-read your responses. No where do you acknowledge the fundamental point of this patch set - that adding a new neighbor entry in one namespace can evict an entry in another namespace or worse networking in one namespace can fail due to table overflow because of entries from another. That is a real problem.
Quoted 3 lines
It is not a matter of increasing the default
gc_thresh3to some number N; it is ensuring that regardless of the value ofgc_thresh3one namespace is not affected by another.
My suggestion is to look at the problem and it's requirements and figure out how to safely remove gc_thresh3 entirely. We do have to ensure neighbour tables don't grow too large, I expect we can do it in a way that can scale from a small machine with few neighbours to a large machine with many neighbours.
Perhaps the code just needs to limit the number of neighbours who have never replied and the code is probing for an a per interface basis.
It still may make sense to have a global limit of perhaps a million entries just because that would be an indicator that something has truly gone weird.
Quoted 4 lines
You created network namespaces and it provides isolation -- separate tables essentially -- for devices, FIB entries, sockets, etc, but you argue against completing the task with separate neighbor tables which is very strange given the impact (completely broken networking).
Namespaces provide isolation at the level of names. The objects still share a kernel and compete for resources. Not competing for resources would require each namespace have it's own dedicated pool of resources which over the whole machine would be much less efficient.
That is the fundamental design difference between namespaces and VM's and it is why namespaces can be much cheaper and much more resource efficient. Reserving your worst case resource usage ahead of time tends to result in a lot of inefficiencies.
Eric