net/ipv6: Separate data structures for FIB and data path
Subsystems (6)
v2 cover net/ipv6: Separate data structures for FIB and data path
IPv6 uses the same data struct for both control plane (FIB entries) and data path (dst entries). This struct has elements needed for both paths adding memory overhead and complexity (taking a dst hold in most places but an additional reference on rt6i_ref in a few). Furthermore, because of the dst_alloc tie, all FIB entries are allocated with GFP_ATOMIC.
This patch set separates FIB entries from dst entries, better aligning IPv6 code with IPv4, simplifying the reference counting and allowing FIB entries added by userspace (not autoconf) to use GFP_KERNEL. It is first step to a number of performance and scalability changes.
The end result of this patch set:
- FIB entries (fib6_info):
/* size: 208, cachelines: 4, members: 25 */
/* sum members: 207, holes: 1, sum holes: 1 */ - dst entries (rt6_info)
/* size: 240, cachelines: 4, members: 11 */
Versus the the single rt6_info struct today for both paths:
/* size: 320, cachelines: 5, members: 28 */
This amounts to a 35% reduction in memory use for FIB entries and a 25% reduction for dst entries.
With respect to locking FIB entries use RCU and a single atomic counter with fib6_info_hold and fib6_info_release helpers to manage the reference counting. dst entries use only the traditional dst refcounts with dst_hold and dst_release.
FIB entries for host routes are referenced by inet6_ifaddr and ifacaddr6. In both cases, additional holds are taken -- similar to what is done for devices.
This set is the first of many changes to improve the scalability of the IPv6 code. Follow on changes include:
- consolidating duplicate fib6_info references like IPv4 does with duplicate fib_info
- moving fib6_info into a slab cache to avoid allocation roundups to power of 2 (the 208 size becomes a 256 actual allocation)
- Allow FIB lookups without generating a dst (e.g., most rt6_lookup users just want to verify the egress device). Means moving dst allocation to the other side of fib6_rule_lookup which again aligns with IPv4 behavior
- using separate standalone nexthop objects which have performance benefits beyond fib_info consolidation
At this point I am not seeing any refcount leaks or underflows, no oops or bug_ons, or warnings from kasan, so I think it is ready for others to beat up on it finding errors in code paths I have missed.
RFC v2 changes
- improved commit messages
- move common metrics code from dst.c to net/ipv4/metrics.c (comment from DaveM)
- address comments from Wei Wang and Martin KaFai Lau (let me know if I missed something)
- fixes detected by kernel test robots
+ added fib6_metric_set to change metric on a FIB entry which could be pointing to read-only dst_default_metrics
+ 0day testing found a problem with an intermediate patch; added
dst_hold_safe on rt->from. Code is removed 3 patches later
- allow cacheinfo to handle NULL dst; means only expires is pushed to userspace
David Ahern (21):
net: Move fib_convert_metrics to metrics file
net: Handle null dst in rtnl_put_cacheinfo
vrf: Move fib6_table into net_vrf
net/ipv6: Pass net to fib6_update_sernum
net/ipv6: Pass net namespace to route functions net/ipv6: Move support functions up in route.c net/ipv6: Save route type in rt6_info
net/ipv6: Move nexthop data to fib6_nh
net/ipv6: Defer initialization of dst to data path net/ipv6: move metrics from dst to rt6_info
net/ipv6: move expires into rt6_info
net/ipv6: Add fib6_null_entry
net/ipv6: Add rt6_info create function for ip6_pol_route_lookup net/ipv6: Move dst flags to booleans in fib entries net/ipv6: Create a neigh_lookup for FIB entries net/ipv6: Add gfp_flags to route add functions net/ipv6: Cleanup exception and cache route handling net/ipv6: introduce fib6_info struct and helpers net/ipv6: separate handling of FIB entries from dst based routes net/ipv6: Flip FIB entries to fib6_info
net/ipv6: Remove unused code and variables for rt6_info
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 96 +- drivers/net/vrf.c | 25 +- include/net/if_inet6.h | 4 +- include/net/ip.h | 3 + include/net/ip6_fib.h | 151 ++- include/net/ip6_route.h | 45 +- include/net/netns/ipv6.h | 3 +- net/core/dst.c | 1 + net/core/rtnetlink.c | 8 +- net/ipv4/Makefile | 3 +- net/ipv4/fib_semantics.c | 43 +- net/ipv4/metrics.c | 53 + net/ipv6/addrconf.c | 118 +- net/ipv6/anycast.c | 21 +- net/ipv6/ip6_fib.c | 362 +++--- net/ipv6/ip6_output.c | 3 +- net/ipv6/ndisc.c | 40 +- net/ipv6/route.c | 1364 ++++++++++---------- net/ipv6/xfrm6_policy.c | 2 - 19 files changed, 1206 insertions(+), 1139 deletions(-) create mode 100644 net/ipv4/metrics.c
Signature · 1 line
2.11.0
RFC PATCH v2 1/21 net: Move fib_convert_metrics to metrics file
Move logic of fib_convert_metrics into ip_metrics_convert. This allows the code that converts netlink attributes into metrics struct to be re-used in a later patch by IPv6.
This is mostly a code move with the following changes to variable names:
- fi->fib_net becomes net
- fc_mx and fc_mx_len are passed as inputs pulled from fib_config
- metrics array is passed as an input from fi->fib_metrics->metrics
--- include/net/ip.h | 3 +++ net/ipv4/Makefile | 3 ++- net/ipv4/fib_semantics.c | 43 ++------------------------------------- net/ipv4/metrics.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 42 deletions(-) create mode 100644 net/ipv4/metrics.c
include/net/ip.h +3 -0
@@ -380,6 +380,9 @@ static inline unsigned int ip_skb_dst_mtu(struct sock *sk,return min (READ_ONCE (skb_dst (skb)->dev->mtu),IP_MAX_MTU ); } +int ip_metrics_convert (struct net *net,struct nlattr *fc_mx,int fc_mx_len, +u32 *metrics); +u32 ip_idents_reserve (u32 hash,int segs);void __ip_select_ident (struct net *net,struct iphdr *iph,int segs);
net/ipv4/Makefile +2 -1
@@ -13,7 +13,8 @@ obj-y := route.o inetpeer.o protocol.o \ tcp_offload.o datagram.o raw.o udp.o udplite.o \ udp_offload.o arp.o icmp.o devinet.o af_inet.o igmp.o \ fib_frontend.o fib_semantics.o fib_trie.o fib_notifier.o \ - inet_fragment.o ping.o ip_tunnel_core.o gre_offload.o + inet_fragment.o ping.o ip_tunnel_core.o gre_offload.o \ + metrics.o obj-$(CONFIG_NET_IP_TUNNEL) += ip_tunnel.o obj-$(CONFIG_SYSCTL) += sysctl_net_ipv4.o
net/ipv4/fib_semantics.c +2 -41
49 lines not on this page · raw message
net/ipv4/metrics.c new file +53 -0
53 lines not on this page · raw message
Signature · 1 line
2.11.0
RFC PATCH v2 2/21 net: Handle null dst in rtnl_put_cacheinfo
In reply to David AhernNeed to keep expires time for IPv6 routes in a dump of FIB entries. Update rtnl_put_cacheinfo to allow dst to be NULL in which case rta_cacheinfo will only contain non-dst data.
--- net/core/rtnetlink.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
net/core/rtnetlink.c +5 -3
@@ -780,13 +780,15 @@ int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst, u32 id, long expires, u32 error) {struct rta_cacheinfo ci = { - .rta_lastuse =jiffies_delta_to_clock_t (jiffies - dst->lastuse), - .rta_used = dst->__use, - .rta_clntref =atomic_read (&(dst->__refcnt)), .rta_error = error, .rta_id = id, }; +if (dst) { + ci.rta_lastuse =jiffies_delta_to_clock_t (jiffies - dst->lastuse); + ci.rta_used = dst->__use; + ci.rta_clntref =atomic_read (&dst->__refcnt); + }if (expires) {unsigned long clock;
Signature · 1 line
2.11.0
RFC PATCH v2 3/21 vrf: Move fib6_table into net_vrf
In reply to David AhernA later patch removes rt6i_table from rt6_info. Save the ipv6 table for a VRF in net_vrf. fib tables can not be deleted so no reference counting or locking is required.
--- drivers/net/vrf.c | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-)
drivers/net/vrf.c +6 -19
@@ -48,6 +48,9 @@ static unsigned int vrf_net_id;struct net_vrf {struct rtable __rcu *rth;struct rt6_info __rcu *rt6; +#if IS_ENABLED (CONFIG_IPV6 ) +struct fib6_table *fib6_table; +#endif u32 tb_id; };
@@ -496,7 +499,6 @@ static int vrf_rt6_create(struct net_device *dev)int flags =DST_HOST |DST_NOPOLICY |DST_NOXFRM ;struct net_vrf *vrf =netdev_priv (dev);struct net *net =dev_net (dev); -struct fib6_table *rt6i_table;struct rt6_info *rt6;int rc = -ENOMEM ;
@@ -504,8 +506,8 @@ static int vrf_rt6_create(struct net_device *dev)if (!ipv6_mod_enabled ())return 0 ; - rt6i_table =fib6_new_table (net, vrf->tb_id); -if (!rt6i_table) + vrf->fib6_table =fib6_new_table (net, vrf->tb_id); +if (!vrf->fib6_table) goto out;/* create a dst for routing packets out a VRF device */
@@ -513,7 +515,6 @@ static int vrf_rt6_create(struct net_device *dev)if (!rt6) goto out; - rt6->rt6i_table = rt6i_table; rt6->dst.output = vrf_output6;rcu_assign_pointer (vrf->rt6, rt6);
@@ -945,22 +946,8 @@ static struct rt6_info *vrf_ip6_route_lookup(struct net *net, int flags) {struct net_vrf *vrf =netdev_priv (dev); -struct fib6_table *table =NULL ; -struct rt6_info *rt6; - -rcu_read_lock (); - -/* fib6_table does not have a refcnt and can not be freed */ - rt6 =rcu_dereference (vrf->rt6); -if (likely (rt6)) - table = rt6->rt6i_table; - -rcu_read_unlock (); - -if (!table) -return NULL ; -return ip6_pol_route (net, table, ifindex, fl6, skb, flags); +return ip6_pol_route (net, vrf->fib6_table, ifindex, fl6, skb, flags); } static void vrf_ip6_input_dst(struct sk_buff *skb, struct net_device *vrf_dev,
Signature · 1 line
2.11.0
RFC PATCH v2 4/21 net/ipv6: Pass net to fib6_update_sernum
In reply to David AhernPass net namespace to fib6_update_sernum. It can not be marked const as fib6_new_sernum will change ipv6.fib6_sernum.
--- include/net/ip6_fib.h | 2 +- net/ipv6/ip6_fib.c | 3 +-- net/ipv6/route.c | 10 +++++----- 3 files changed, 7 insertions(+), 8 deletions(-)
include/net/ip6_fib.h +1 -1
@@ -408,7 +408,7 @@ void __net_exit fib6_notifier_exit(struct net *net);unsigned int fib6_tables_seq_read (struct net *net);int fib6_tables_dump (struct net *net,struct notifier_block *nb); -void fib6_update_sernum (struct rt6_info *rt); +void fib6_update_sernum (struct net *net,struct rt6_info *rt);void fib6_update_sernum_upto_root (struct net *net,struct rt6_info *rt);#ifdef CONFIG_IPV6_MULTIPLE_TABLES
net/ipv6/ip6_fib.c +1 -2
@@ -105,9 +105,8 @@ enum { FIB6_NO_SERNUM_CHANGE = 0, }; -void fib6_update_sernum (struct rt6_info *rt) +void fib6_update_sernum (struct net *net,struct rt6_info *rt) { -struct net *net =dev_net (rt->dst.dev);struct fib6_node *fn; fn = rcu_dereference_protected(rt->rt6i_node,
net/ipv6/route.c +5 -5
@@ -1349,7 +1349,7 @@ static int rt6_insert_exception(struct rt6_info *nrt,/* Update fn->fn_sernum to invalidate all cached dst */ if (!err) {spin_lock_bh (&ort->rt6i_table->tb6_lock); -fib6_update_sernum (ort); +fib6_update_sernum (net, ort);spin_unlock_bh (&ort->rt6i_table->tb6_lock);fib6_force_start_gc (net); }
@@ -3733,11 +3733,11 @@ void rt6_multipath_rebalance(struct rt6_info *rt)static int fib6_ifup (struct rt6_info *rt,void *p_arg) {const struct arg_netdev_event *arg = p_arg; -const struct net *net =dev_net (arg->dev); +struct net *net =dev_net (arg->dev);if (rt != net->ipv6.ip6_null_entry && rt->dst.dev == arg->dev) { rt->rt6i_nh_flags &= ~arg->nh_flags; -fib6_update_sernum_upto_root (dev_net (rt->dst.dev), rt); +fib6_update_sernum_upto_root (net, rt);rt6_multipath_rebalance (rt); }
@@ -3816,7 +3816,7 @@ static int fib6_ifdown(struct rt6_info *rt, void *p_arg) {const struct arg_netdev_event *arg = p_arg;const struct net_device *dev = arg->dev; -const struct net *net =dev_net (dev); +struct net *net =dev_net (dev);if (rt == net->ipv6.ip6_null_entry)return 0 ;
@@ -3839,7 +3839,7 @@ static int fib6_ifdown(struct rt6_info *rt, void *p_arg) }rt6_multipath_nh_flags_set (rt, dev,RTNH_F_DEAD |RTNH_F_LINKDOWN ); -fib6_update_sernum (rt); +fib6_update_sernum (net, rt);rt6_multipath_rebalance (rt); }return -2 ;
Signature · 1 line
2.11.0
RFC PATCH v2 5/21 net/ipv6: Pass net namespace to route functions
In reply to David AhernPass network namespace reference into route add, delete and get functions.
--- include/net/ip6_route.h | 12 ++++++----- net/ipv6/addrconf.c | 33 ++++++++++++++++-------------- net/ipv6/anycast.c | 10 +++++---- net/ipv6/ndisc.c | 12 ++++++----- net/ipv6/route.c | 54 +++++++++++++++++++++++++------------------------ 5 files changed, 66 insertions(+), 55 deletions(-)
include/net/ip6_route.h +7 -5
@@ -101,8 +101,8 @@ void ip6_route_cleanup(void);int ipv6_route_ioctl (struct net *net,unsigned int cmd,void __user *arg);int ip6_route_add (struct fib6_config *cfg,struct netlink_ext_ack *extack); -int ip6_ins_rt (struct rt6_info *); -int ip6_del_rt (struct rt6_info *); +int ip6_ins_rt (struct net *net,struct rt6_info *rt); +int ip6_del_rt (struct net *net,struct rt6_info *rt);void rt6_flush_exceptions (struct rt6_info *rt);int rt6_remove_exception_rt (struct rt6_info *rt);
@@ -137,7 +137,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, struct flowi6 *fl6);void fib6_force_start_gc (struct net *net); -struct rt6_info *addrconf_dst_alloc (struct inet6_dev *idev, +struct rt6_info *addrconf_dst_alloc (struct net *net,struct inet6_dev *idev,const struct in6_addr *addr,bool anycast); struct rt6_info *ip6_dst_alloc(struct net *net, struct net_device *dev,
@@ -147,9 +147,11 @@ struct rt6_info *ip6_dst_alloc(struct net *net, struct net_device *dev,* support functions for ND * */ -struct rt6_info *rt6_get_dflt_router (const struct in6_addr *addr, +struct rt6_info *rt6_get_dflt_router (struct net *net, +const struct in6_addr *addr,struct net_device *dev); -struct rt6_info *rt6_add_dflt_router (const struct in6_addr *gwaddr, +struct rt6_info *rt6_add_dflt_router (struct net *net, +const struct in6_addr *gwaddr,struct net_device *dev,unsigned int pref);void rt6_purge_dflt_routers (struct net *net);
net/ipv6/addrconf.c +18 -15
@@ -1049,7 +1049,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, goto out; } - rt =addrconf_dst_alloc (idev, addr, false); + rt =addrconf_dst_alloc (net, idev, addr, false);if (IS_ERR (rt)) { err =PTR_ERR (rt); rt =NULL ;
@@ -1199,7 +1199,7 @@ cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, bool del_r 0, RTF_GATEWAY | RTF_DEFAULT);if (rt) {if (del_rt) -ip6_del_rt (rt); +ip6_del_rt (dev_net (ifp->idev->dev), rt);else {if (!(rt->rt6i_flags &RTF_EXPIRES ))rt6_set_expires (rt, expires);
@@ -2679,7 +2679,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)if (rt) {/* Autoconf prefix route */ if (valid_lft ==0 ) { -ip6_del_rt (rt); +ip6_del_rt (net, rt); rt =NULL ; }else if (addrconf_finite_timeout (rt_expires)) {/* not infinity */
@@ -3341,7 +3341,8 @@ static void addrconf_gre_config(struct net_device *dev) }#endif -static int fixup_permanent_addr (struct inet6_dev *idev, +static int fixup_permanent_addr (struct net *net, +struct inet6_dev *idev,struct inet6_ifaddr *ifp) {/* !rt6i_node means the host route was removed from the
@@ -3351,7 +3352,7 @@ static int fixup_permanent_addr(struct inet6_dev *idev,if (!ifp->rt || !ifp->rt->rt6i_node) {struct rt6_info *rt, *prev; - rt =addrconf_dst_alloc (idev, &ifp->addr, false); + rt =addrconf_dst_alloc (net, idev, &ifp->addr, false);if (IS_ERR (rt))return PTR_ERR (rt);
@@ -3375,7 +3376,7 @@ static int fixup_permanent_addr(struct inet6_dev *idev,return 0 ; } -static void addrconf_permanent_addr (struct net_device *dev) +static void addrconf_permanent_addr (struct net *net,struct net_device *dev) {struct inet6_ifaddr *ifp, *tmp;struct inet6_dev *idev;
@@ -3388,7 +3389,7 @@ static void addrconf_permanent_addr(struct net_device *dev)list_for_each_entry_safe (ifp, tmp, &idev->addr_list, if_list) {if ((ifp->flags &IFA_F_PERMANENT ) && -fixup_permanent_addr (idev, ifp) <0 ) { +fixup_permanent_addr (net, idev, ifp) <0 ) {write_unlock_bh (&idev->lock);in6_ifa_hold (ifp);ipv6_del_addr (ifp);
@@ -3457,7 +3458,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,if (event ==NETDEV_UP ) {/* restore routes for permanent addresses */ -addrconf_permanent_addr (dev); +addrconf_permanent_addr (net, dev);if (!addrconf_link_ready (dev)) {/* device is not ready yet. */
@@ -3743,7 +3744,7 @@ static int addrconf_ifdown(struct net_device *dev, int how)spin_unlock_bh (&ifa->lock);if (rt) -ip6_del_rt (rt); +ip6_del_rt (net, rt);if (state !=INET6_IFADDR_STATE_DEAD ) {__ipv6_ifa_notify (RTM_DELADDR , ifa);
@@ -3861,6 +3862,7 @@ static void addrconf_dad_begin(struct inet6_ifaddr *ifp)struct inet6_dev *idev = ifp->idev;struct net_device *dev = idev->dev;bool bump_id, notify = false; +struct net *net;addrconf_join_solict (dev, &ifp->addr);
@@ -3871,8 +3873,9 @@ static void addrconf_dad_begin(struct inet6_ifaddr *ifp)if (ifp->state ==INET6_IFADDR_STATE_DEAD ) goto out; + net =dev_net (dev);if (dev->flags&(IFF_NOARP |IFF_LOOPBACK ) || - (dev_net (dev)->ipv6.devconf_all->accept_dad <1 && + (net->ipv6.devconf_all->accept_dad <1 && idev->cnf.accept_dad <1 ) || !(ifp->flags&IFA_F_TENTATIVE ) || ifp->flags &IFA_F_NODAD ) {
@@ -3908,8 +3911,8 @@ static void addrconf_dad_begin(struct inet6_ifaddr *ifp)* Frames right away */ if (ifp->flags &IFA_F_OPTIMISTIC ) { -ip6_ins_rt (ifp->rt); -if (ipv6_use_optimistic_addr (dev_net (dev), idev)) { +ip6_ins_rt (net, ifp->rt); +if (ipv6_use_optimistic_addr (net, idev)) {/* Because optimistic nodes can use this address, * notify listeners. If DAD fails, RTM_DELADDR is sent. */
@@ -5621,7 +5624,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)* to do it again */ if (!rcu_access_pointer (ifp->rt->rt6i_node)) -ip6_ins_rt (ifp->rt); +ip6_ins_rt (net, ifp->rt);if (ifp->idev->cnf.forwarding)addrconf_join_anycast (ifp);if (!ipv6_addr_any (&ifp->peer_addr))
@@ -5638,11 +5641,11 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) rt =addrconf_get_prefix_route (&ifp->peer_addr,128 , ifp->idev->dev,0 ,0 );if (rt) -ip6_del_rt (rt); +ip6_del_rt (net, rt); }if (ifp->rt) {if (dst_hold_safe (&ifp->rt->dst)) -ip6_del_rt (ifp->rt); +ip6_del_rt (net, ifp->rt); }rt_genid_bump_ipv6 (net);break ;
net/ipv6/anycast.c +6 -4
@@ -247,6 +247,7 @@ int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr) {struct ifacaddr6 *aca;struct rt6_info *rt; +struct net *net;int err;ASSERT_RTNL ();
@@ -265,7 +266,8 @@ int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr) } } - rt =addrconf_dst_alloc (idev, addr, true); + net =dev_net (idev->dev); + rt =addrconf_dst_alloc (net, idev, addr, true);if (IS_ERR (rt)) { err =PTR_ERR (rt); goto out;
@@ -286,7 +288,7 @@ int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr)aca_get (aca);write_unlock_bh (&idev->lock); -ip6_ins_rt (rt); +ip6_ins_rt (net, rt);addrconf_join_solict (idev->dev, &aca->aca_addr);
@@ -329,7 +331,7 @@ int __ipv6_dev_ac_dec(struct inet6_dev *idev, const struct in6_addr *addr)addrconf_leave_solict (idev, &aca->aca_addr);dst_hold (&aca->aca_rt->dst); -ip6_del_rt (aca->aca_rt); +ip6_del_rt (dev_net (idev->dev), aca->aca_rt);aca_put (aca);return 0 ;
@@ -357,7 +359,7 @@ void ipv6_ac_destroy_dev(struct inet6_dev *idev)addrconf_leave_solict (idev, &aca->aca_addr);dst_hold (&aca->aca_rt->dst); -ip6_del_rt (aca->aca_rt); +ip6_del_rt (dev_net (idev->dev), aca->aca_rt);aca_put (aca);
net/ipv6/ndisc.c +7 -5
@@ -1156,6 +1156,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)struct neighbour *neigh =NULL ;struct inet6_dev *in6_dev;struct rt6_info *rt =NULL ; +struct net *net;int lifetime;struct ndisc_options ndopts;int optlen;
@@ -1253,9 +1254,9 @@ static void ndisc_router_discovery(struct sk_buff *skb)/* Do not accept RA with source-addr found on local machine unless * accept_ra_from_local is set to true. */ + net =dev_net (in6_dev->dev);if (!in6_dev->cnf.accept_ra_from_local && -ipv6_chk_addr (dev_net (in6_dev->dev), &ipv6_hdr (skb)->saddr, - in6_dev->dev,0 )) { +ipv6_chk_addr (net, &ipv6_hdr (skb)->saddr, in6_dev->dev,0 )) {ND_PRINTK (2 , info,"RA from local address detected on dev: %s: default router ignored\n" , skb->dev->name);
@@ -1272,7 +1273,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) pref =ICMPV6_ROUTER_PREF_MEDIUM ;#endif - rt =rt6_get_dflt_router (&ipv6_hdr (skb)->saddr, skb->dev); + rt =rt6_get_dflt_router (net, &ipv6_hdr (skb)->saddr, skb->dev);if (rt) { neigh =dst_neigh_lookup (&rt->dst, &ipv6_hdr (skb)->saddr);
@@ -1285,7 +1286,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) } }if (rt && lifetime ==0 ) { -ip6_del_rt (rt); +ip6_del_rt (net, rt); rt =NULL ; }
@@ -1294,7 +1295,8 @@ static void ndisc_router_discovery(struct sk_buff *skb)if (!rt && lifetime) {ND_PRINTK (3 , info,"RA: adding default router\n" ); - rt =rt6_add_dflt_router (&ipv6_hdr (skb)->saddr, skb->dev, pref); + rt =rt6_add_dflt_router (net, &ipv6_hdr (skb)->saddr, + skb->dev, pref);if (!rt) { ND_PRINTK(0, err, "RA: %s failed to add default route\n",
net/ipv6/route.c +28 -26
168 lines not on this page · raw message
Signature · 1 line
2.11.0
RFC PATCH v2 6/21 net/ipv6: Move support functions up in route.c
In reply to David AhernCode move only.
--- net/ipv6/route.c | 119 +++++++++++++++++++++++++++---------------------------- 1 file changed, 59 insertions(+), 60 deletions(-)
net/ipv6/route.c +59 -60
@@ -78,7 +78,6 @@ enum rt6_nud_state { RT6_NUD_SUCCEED = 1 }; -static void ip6_rt_copy_init (struct rt6_info *rt,struct rt6_info *ort);static struct dst_entry *ip6_dst_check (struct dst_entry *dst,u32 cookie);static unsigned int ip6_default_advmss (const struct dst_entry *dst);static unsigned int ip6_mtu (const struct dst_entry *dst);
@@ -879,6 +878,65 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, }#endif +/* +* Misc support functions +*/ + +/* called with rcu_lock held */ +static struct net_device *ip6_rt_get_dev_rcu (struct rt6_info *rt) +{ +struct net_device *dev = rt->dst.dev; + +if (rt->rt6i_flags & (RTF_LOCAL |RTF_ANYCAST )) { +/* for copies of local routes, dst->dev needs to be the +* device if it is a master device, the master device if +* device is enslaved, and the loopback as the default +*/ +if (netif_is_l3_slave (dev) && + !rt6_need_strict (&rt->rt6i_dst.addr)) + dev =l3mdev_master_dev_rcu (dev); +else if (!netif_is_l3_master (dev)) + dev =dev_net (dev)->loopback_dev; +/* last case is netif_is_l3_master(dev) is true in which +* case we want dev returned to be dev +*/ + } + +return dev; +} + +static void rt6_set_from (struct rt6_info *rt,struct rt6_info *from) +{ +BUG_ON (from->from); + + rt->rt6i_flags &= ~RTF_EXPIRES ; +dst_hold (&from->dst); + rt->from = from; +dst_init_metrics (&rt->dst,dst_metrics_ptr (&from->dst), true); +} + +static void ip6_rt_copy_init (struct rt6_info *rt,struct rt6_info *ort) +{ + rt->dst.input = ort->dst.input; + rt->dst.output = ort->dst.output; + rt->rt6i_dst = ort->rt6i_dst; + rt->dst.error = ort->dst.error; + rt->rt6i_idev = ort->rt6i_idev; +if (rt->rt6i_idev) +in6_dev_hold (rt->rt6i_idev); + rt->dst.lastuse = jiffies; + rt->rt6i_gateway = ort->rt6i_gateway; + rt->rt6i_flags = ort->rt6i_flags; +rt6_set_from (rt, ort); + rt->rt6i_metric = ort->rt6i_metric; +#ifdef CONFIG_IPV6_SUBTREES + rt->rt6i_src = ort->rt6i_src; +#endif + rt->rt6i_prefsrc = ort->rt6i_prefsrc; + rt->rt6i_table = ort->rt6i_table; + rt->dst.lwtstate =lwtstate_get (ort->dst.lwtstate); +} +static struct fib6_node *fib6_backtrack (struct fib6_node *fn,struct in6_addr *saddr) {
@@ -1021,29 +1079,6 @@ int ip6_ins_rt(struct net *net, struct rt6_info *rt)return __ip6_ins_rt (rt, &info, &mxc,NULL ); } -/* called with rcu_lock held */ -static struct net_device *ip6_rt_get_dev_rcu (struct rt6_info *rt) -{ -struct net_device *dev = rt->dst.dev; - -if (rt->rt6i_flags & (RTF_LOCAL |RTF_ANYCAST )) { -/* for copies of local routes, dst->dev needs to be the -* device if it is a master device, the master device if -* device is enslaved, and the loopback as the default -*/ -if (netif_is_l3_slave (dev) && - !rt6_need_strict (&rt->rt6i_dst.addr)) - dev =l3mdev_master_dev_rcu (dev); -else if (!netif_is_l3_master (dev)) - dev =dev_net (dev)->loopback_dev; -/* last case is netif_is_l3_master(dev) is true in which -* case we want dev returned to be dev -*/ - } - -return dev; -} -static struct rt6_info *ip6_rt_cache_alloc (struct rt6_info *ort,const struct in6_addr *daddr,const struct in6_addr *saddr)
@@ -3218,42 +3253,6 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buneigh_release (neigh); } -/* -* Misc support functions -*/ - -static void rt6_set_from (struct rt6_info *rt,struct rt6_info *from) -{ -BUG_ON (from->from); - - rt->rt6i_flags &= ~RTF_EXPIRES ; -dst_hold (&from->dst); - rt->from = from; -dst_init_metrics (&rt->dst,dst_metrics_ptr (&from->dst), true); -} - -static void ip6_rt_copy_init (struct rt6_info *rt,struct rt6_info *ort) -{ - rt->dst.input = ort->dst.input; - rt->dst.output = ort->dst.output; - rt->rt6i_dst = ort->rt6i_dst; - rt->dst.error = ort->dst.error; - rt->rt6i_idev = ort->rt6i_idev; -if (rt->rt6i_idev) -in6_dev_hold (rt->rt6i_idev); - rt->dst.lastuse = jiffies; - rt->rt6i_gateway = ort->rt6i_gateway; - rt->rt6i_flags = ort->rt6i_flags; -rt6_set_from (rt, ort); - rt->rt6i_metric = ort->rt6i_metric; -#ifdef CONFIG_IPV6_SUBTREES - rt->rt6i_src = ort->rt6i_src; -#endif - rt->rt6i_prefsrc = ort->rt6i_prefsrc; - rt->rt6i_table = ort->rt6i_table; - rt->dst.lwtstate =lwtstate_get (ort->dst.lwtstate); -} -#ifdef CONFIG_IPV6_ROUTE_INFO static struct rt6_info *rt6_get_route_info(struct net *net, const struct in6_addr *prefix, int prefixlen,
Signature · 1 line
2.11.0
RFC PATCH v2 7/21 net/ipv6: Save route type in rt6_info
In reply to David AhernThe RTN_ type for IPv6 FIB entries is currently embedded in rt6i_flags and dst.error. Since dst is going to be removed, it can no longer be relied on for FIB dumps so save the route type as fib6_type.
--- include/net/ip6_fib.h | 1 + net/ipv6/addrconf.c | 2 ++ net/ipv6/route.c | 46 ++++++++++++++++++++-------------------------- 3 files changed, 23 insertions(+), 26 deletions(-)
include/net/ip6_fib.h +1 -0
@@ -174,6 +174,7 @@ struct rt6_info {int rt6i_nh_weight;unsigned short rt6i_nfheader_len;u8 rt6i_protocol; +u8 fib6_type; u8 exception_bucket_flushed:1, should_flush:1, unused:6;
net/ipv6/addrconf.c +2 -0
@@ -2343,6 +2343,7 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev, .fc_flags = RTF_UP | flags, .fc_nlinfo.nl_net = dev_net(dev), .fc_protocol = RTPROT_KERNEL, + .fc_type = RTN_UNICAST, }; cfg.fc_dst = *pfx;
@@ -2406,6 +2407,7 @@ static void addrconf_add_mroute(struct net_device *dev) .fc_ifindex = dev->ifindex, .fc_dst_len = 8, .fc_flags = RTF_UP, + .fc_type = RTN_UNICAST, .fc_nlinfo.nl_net = dev_net(dev), };
net/ipv6/route.c +20 -26
108 lines not on this page · raw message
Signature · 1 line
2.11.0
RFC PATCH v2 8/21 net/ipv6: Move nexthop data to fib6_nh
In reply to David AhernIntroduce fib6_nh structure and move nexthop related data from rt6_info and rt6_info.dst to fib6_nh. References to dev, gateway or lwtstate from a FIB lookup perspective are converted to use fib6_nh; datapath references to dst version are left as is.
--- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 32 ++-- include/net/ip6_fib.h | 16 +- include/net/ip6_route.h | 6 +- net/ipv6/addrconf.c | 2 +- net/ipv6/ip6_fib.c | 6 +- net/ipv6/route.c | 162 +++++++++++---------- 6 files changed, 125 insertions(+), 99 deletions(-)
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +16 -16
@@ -2704,9 +2704,9 @@ mlxsw_sp_nexthop6_group_cmp(const struct mlxsw_sp_nexthop_group *nh_grp,struct in6_addr *gw;int ifindex, weight; - ifindex = mlxsw_sp_rt6->rt->dst.dev->ifindex; - weight = mlxsw_sp_rt6->rt->rt6i_nh_weight; - gw = &mlxsw_sp_rt6->rt->rt6i_gateway; + ifindex = mlxsw_sp_rt6->rt->fib6_nh.nh_dev->ifindex; + weight = mlxsw_sp_rt6->rt->fib6_nh.nh_weight; + gw = &mlxsw_sp_rt6->rt->fib6_nh.nh_gw;if (!mlxsw_sp_nexthop6_group_has_nexthop (nh_grp, gw, ifindex, weight))return false;
@@ -2772,7 +2772,7 @@ mlxsw_sp_nexthop6_group_hash(struct mlxsw_sp_fib6_entry *fib6_entry, u32 seed)struct net_device *dev;list_for_each_entry (mlxsw_sp_rt6, &fib6_entry->rt6_list, list) { - dev = mlxsw_sp_rt6->rt->dst.dev; + dev = mlxsw_sp_rt6->rt->fib6_nh.nh_dev; val ^= dev->ifindex; }
@@ -3770,9 +3770,9 @@ mlxsw_sp_rt6_nexthop(struct mlxsw_sp_nexthop_group *nh_grp,struct mlxsw_sp_nexthop *nh = &nh_grp->nexthops[i];struct rt6_info *rt = mlxsw_sp_rt6->rt; -if (nh->rif && nh->rif->dev == rt->dst.dev && +if (nh->rif && nh->rif->dev == rt->fib6_nh.nh_dev &&ipv6_addr_equal ((const struct in6_addr *) &nh->gw_addr, - &rt->rt6i_gateway)) + &rt->fib6_nh.nh_gw))return nh;continue ; }
@@ -3829,7 +3829,7 @@ mlxsw_sp_fib6_entry_offload_set(struct mlxsw_sp_fib_entry *fib_entry)if (fib_entry->type ==MLXSW_SP_FIB_ENTRY_TYPE_LOCAL ) { list_first_entry(&fib6_entry->rt6_list, struct mlxsw_sp_rt6, - list)->rt->rt6i_nh_flags |=RTNH_F_OFFLOAD ; + list)->rt->fib6_nh.nh_flags |=RTNH_F_OFFLOAD ;return ; }
@@ -3839,9 +3839,9 @@ mlxsw_sp_fib6_entry_offload_set(struct mlxsw_sp_fib_entry *fib_entry) nh =mlxsw_sp_rt6_nexthop (nh_grp, mlxsw_sp_rt6);if (nh && nh->offloaded) - mlxsw_sp_rt6->rt->rt6i_nh_flags |=RTNH_F_OFFLOAD ; + mlxsw_sp_rt6->rt->fib6_nh.nh_flags |=RTNH_F_OFFLOAD ;else - mlxsw_sp_rt6->rt->rt6i_nh_flags &= ~RTNH_F_OFFLOAD ; + mlxsw_sp_rt6->rt->fib6_nh.nh_flags &= ~RTNH_F_OFFLOAD ; } }
@@ -3856,7 +3856,7 @@ mlxsw_sp_fib6_entry_offload_unset(struct mlxsw_sp_fib_entry *fib_entry)list_for_each_entry (mlxsw_sp_rt6, &fib6_entry->rt6_list, list) {struct rt6_info *rt = mlxsw_sp_rt6->rt; - rt->rt6i_nh_flags &= ~RTNH_F_OFFLOAD ; + rt->fib6_nh.nh_flags &= ~RTNH_F_OFFLOAD ; } }
@@ -4752,8 +4752,8 @@ static bool mlxsw_sp_nexthop6_ipip_type(const struct mlxsw_sp *mlxsw_sp,const struct rt6_info *rt, enum mlxsw_sp_ipip_type *ret) { - return rt->dst.dev && - mlxsw_sp_netdev_ipip_type(mlxsw_sp, rt->dst.dev, ret); + return rt->fib6_nh.nh_dev && + mlxsw_sp_netdev_ipip_type(mlxsw_sp, rt->fib6_nh.nh_dev, ret); } static int mlxsw_sp_nexthop6_type_init(struct mlxsw_sp *mlxsw_sp,
@@ -4763,7 +4763,7 @@ static int mlxsw_sp_nexthop6_type_init(struct mlxsw_sp *mlxsw_sp, {const struct mlxsw_sp_ipip_ops *ipip_ops;struct mlxsw_sp_ipip_entry *ipip_entry; -struct net_device *dev = rt->dst.dev; +struct net_device *dev = rt->fib6_nh.nh_dev;struct mlxsw_sp_rif *rif;int err;
@@ -4806,11 +4806,11 @@ static int mlxsw_sp_nexthop6_init(struct mlxsw_sp *mlxsw_sp,struct mlxsw_sp_nexthop *nh, const struct rt6_info *rt) { - struct net_device *dev = rt->dst.dev; + struct net_device *dev = rt->fib6_nh.nh_dev; nh->nh_grp = nh_grp; - nh->nh_weight = rt->rt6i_nh_weight; -memcpy (&nh->gw_addr, &rt->rt6i_gateway,sizeof (nh->gw_addr)); + nh->nh_weight = rt->fib6_nh.nh_weight; +memcpy (&nh->gw_addr, &rt->fib6_nh.nh_gw,sizeof (nh->gw_addr));mlxsw_sp_nexthop_counter_alloc (mlxsw_sp, nh);list_add_tail (&nh->router_list_node, &mlxsw_sp->router->nexthop_list);
include/net/ip6_fib.h +12 -4
@@ -127,6 +127,16 @@ struct rt6_exception {#define FIB6_EXCEPTION_BUCKET_SIZE (1 << FIB6_EXCEPTION_BUCKET_SIZE_SHIFT)#define FIB6_MAX_DEPTH 5 +struct fib6_nh { +struct in6_addr nh_gw; +struct net_device *nh_dev; +struct lwtunnel_state *nh_lwtstate; + +unsigned int nh_flags; +atomic_t nh_upper_bound; +int nh_weight; +}; +struct rt6_info {struct dst_entry dst;struct rt6_info __rcu *rt6_next;
@@ -149,12 +159,9 @@ struct rt6_info {*/ struct list_head rt6i_siblings;unsigned int rt6i_nsiblings; -atomic_t rt6i_nh_upper_bound;atomic_t rt6i_ref; -unsigned int rt6i_nh_flags; -/* These are in a separate cache line. */ struct rt6key rt6i_dst____cacheline_aligned_in_smp ;u32 rt6i_flags;
@@ -171,13 +178,14 @@ struct rt6_info {u32 rt6i_metric;u32 rt6i_pmtu;/* more non-fragment space at head required */ -int rt6i_nh_weight;unsigned short rt6i_nfheader_len;u8 rt6i_protocol;u8 fib6_type; u8 exception_bucket_flushed:1, should_flush:1, unused:6; + +struct fib6_nh fib6_nh; };#define for_each_fib6_node_rt_rcu (fn) \
include/net/ip6_route.h +3 -3
@@ -267,10 +267,10 @@ static inline struct in6_addr *rt6_nexthop(struct rt6_info *rt,static inline bool rt6_duplicate_nexthop (struct rt6_info *a,struct rt6_info *b) { -return a->dst.dev == b->dst.dev && +return a->fib6_nh.nh_dev == b->fib6_nh.nh_dev && a->rt6i_idev == b->rt6i_idev && -ipv6_addr_equal (&a->rt6i_gateway, &b->rt6i_gateway) && - !lwtunnel_cmp_encap (a->dst.lwtstate, b->dst.lwtstate); +ipv6_addr_equal (&a->fib6_nh.nh_gw, &b->fib6_nh.nh_gw) && + !lwtunnel_cmp_encap (a->fib6_nh.nh_lwtstate, b->fib6_nh.nh_lwtstate); }#endif
net/ipv6/addrconf.c +1 -1
@@ -2381,7 +2381,7 @@ static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx, goto out;for_each_fib6_node_rt_rcu (fn) { -if (rt->dst.dev->ifindex != dev->ifindex) +if (rt->fib6_nh.nh_dev->ifindex != dev->ifindex)continue ;if ((rt->rt6i_flags & flags) != flags)continue ;
net/ipv6/ip6_fib.c +4 -2
@@ -2214,6 +2214,7 @@ static int ipv6_route_seq_show(struct seq_file *seq, void *v) {struct rt6_info *rt = v;struct ipv6_route_iter *iter = seq->private; +const struct net_device *dev;seq_printf (seq,"%pi6 %02x " , &rt->rt6i_dst.addr, rt->rt6i_dst.plen);
@@ -2223,14 +2224,15 @@ static int ipv6_route_seq_show(struct seq_file *seq, void *v)seq_puts (seq,"00000000000000000000000000000000 00 " );#endif if (rt->rt6i_flags &RTF_GATEWAY ) -seq_printf (seq,"%pi6" , &rt->rt6i_gateway); +seq_printf (seq,"%pi6" , &rt->fib6_nh.nh_gw);else seq_puts (seq,"00000000000000000000000000000000" ); + dev = rt->fib6_nh.nh_dev;seq_printf (seq," %08x %08x %08x %08x %8s\n" , rt->rt6i_metric,atomic_read (&rt->dst.__refcnt), rt->dst.__use, rt->rt6i_flags, - rt->dst.dev ? rt->dst.dev->name :"" ); + dev ? dev->name :"" ); iter->w.leaf =NULL ;return 0 ; }
net/ipv6/route.c +89 -73
473 lines not on this page · raw message
Signature · 1 line
2.11.0
RFC PATCH v2 10/21 net/ipv6: move metrics from dst to rt6_info
In reply to David AhernSimilar to IPv4, add fib metrics to the fib struct, which at the moment is rt6_info. Will be moved to fib6_info in a later patch. Copy metrics into dst by reference using refcount.
To make the transition:
- add dst_metrics to rt6_info. Default to dst_default_metrics if no metrics are passed during route add. No need for a separate pmtu entry; it can reference the MTU slot in fib6_metrics
- ip6_convert_metrics allocates memory in the FIB entry and uses ip_metrics_convert to copy from netlink attribute to metrics entry
- the convert metrics call is done in ip6_route_info_create simplifying the route add path
+ fib6_commit_metrics and fib6_copy_metrics and the temporary mx6_config are no longer needed
- add fib6_metric_set helper to change the value of a metric in the fib entry since dst_metric_set can no longer be used
- cow_metrics for IPv6 can drop to dst_cow_metrics_generic
- rt6_dst_from_metrics_check is no longer needed
- rt6_fill_node needs the FIB entry and dst as separate arguments to keep compatibility with existing output. Current dst address is renamed to dest.
(to be consistent with IPv4 rt6_fill_node really should be split into 2 functions similar to fib_dump_info and rt_fill_info)
- rt6_fill_node no longer needs the temporary metrics variable
--- include/net/ip6_fib.h | 17 ++-- net/core/dst.c | 1 + net/ipv6/ip6_fib.c | 67 +++++-------- net/ipv6/ndisc.c | 10 +- net/ipv6/route.c | 262 +++++++++++++++++++------------------------------- 5 files changed, 134 insertions(+), 223 deletions(-)
include/net/ip6_fib.h +9 -8
@@ -94,11 +94,6 @@ struct fib6_gc_args {#define FIB6_SUBTREE (fn) (rcu_dereference_protected((fn)->subtree, 1))#endif -struct mx6_config { -const u32 *mx; - DECLARE_BITMAP(mx_valid, RTAX_MAX); -}; -/* * routing information *
@@ -176,7 +171,6 @@ struct rt6_info {struct rt6_exception_bucket __rcu *rt6i_exception_bucket;u32 rt6i_metric; -u32 rt6i_pmtu;/* more non-fragment space at head required */ unsigned short rt6i_nfheader_len;u8 rt6i_protocol;
@@ -185,6 +179,8 @@ struct rt6_info { should_flush:1 , unused:6; +struct dst_metrics *fib6_metrics; +#define fib6_pmtu fib6_metrics->metrics[RTAX_MTU-1]struct fib6_nh fib6_nh; };
@@ -390,8 +386,7 @@ void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *arg), void *arg);int fib6_add (struct fib6_node *root,struct rt6_info *rt, -struct nl_info *info,struct mx6_config *mxc, -struct netlink_ext_ack *extack); +struct nl_info *info,struct netlink_ext_ack *extack);int fib6_del (struct rt6_info *rt,struct nl_info *info); void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info,
@@ -420,6 +415,12 @@ int fib6_tables_dump(struct net *net, struct notifier_block *nb);void fib6_update_sernum (struct net *net,struct rt6_info *rt);void fib6_update_sernum_upto_root (struct net *net,struct rt6_info *rt); +void fib6_metric_set (struct rt6_info *f6i,int metric,u32 val); +static inline bool fib6_metric_locked (struct rt6_info *f6i,int metric) +{ +return !!(f6i->fib6_metrics->metrics[RTAX_LOCK -1 ] & (1 << metric)); +} +#ifdef CONFIG_IPV6_MULTIPLE_TABLES int fib6_rules_init (void );void fib6_rules_cleanup (void );
net/core/dst.c +1 -0
@@ -58,6 +58,7 @@ const struct dst_metrics dst_default_metrics = {*/ .refcnt = REFCOUNT_INIT(1), }; +EXPORT_SYMBOL (dst_default_metrics); void dst_init(struct dst_entry *dst, struct dst_ops *ops, struct net_device *dev, int initial_ref, int initial_obsolete,
net/ipv6/ip6_fib.c +22 -45
121 lines not on this page · raw message
net/ipv6/ndisc.c +3 -7
@@ -1323,9 +1323,8 @@ static void ndisc_router_discovery(struct sk_buff *skb) ra_msg->icmph.icmp6_hop_limit) {if (in6_dev->cnf.accept_ra_min_hop_limit <= ra_msg->icmph.icmp6_hop_limit) { in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit; -if (rt) -dst_metric_set (&rt->dst,RTAX_HOPLIMIT , - ra_msg->icmph.icmp6_hop_limit); +fib6_metric_set (rt,RTAX_HOPLIMIT , + ra_msg->icmph.icmp6_hop_limit); }else {ND_PRINTK (2 , warn,"RA: Got route advertisement with lower hop_limit than minimum\n" ); }
@@ -1477,10 +1476,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)ND_PRINTK (2 , warn,"RA: invalid mtu: %d\n" , mtu); }else if (in6_dev->cnf.mtu6 != mtu) { in6_dev->cnf.mtu6 = mtu; - -if (rt) -dst_metric_set (&rt->dst,RTAX_MTU , mtu); - +fib6_metric_set (rt,RTAX_MTU , mtu);rt6_mtu_change (skb->dev, mtu); } }
net/ipv6/route.c +99 -163
545 lines not on this page · raw message
Signature · 1 line
2.11.0
RFC PATCH v2 11/21 net/ipv6: move expires into rt6_info
In reply to David AhernAdd expires to rt6_info for FIB entries, and add fib6 helpers to manage it. Data path use of dst.expires remains.
The transition is fairly straightforward: when working with fib entries, rt->dst.expires is just rt->expires, rt6_clean_expires is replaced with fib6_clean_expires, rt6_set_expires becomes fib6_set_expires, and rt6_check_expired becomes fib6_check_expired, where the fib6 versions are added by this patch.
--- include/net/ip6_fib.h | 27 +++++++++++++++++++++++---- net/ipv6/addrconf.c | 6 +++--- net/ipv6/ip6_fib.c | 8 ++++---- net/ipv6/ndisc.c | 2 +- net/ipv6/route.c | 20 +++++++++++--------- 5 files changed, 42 insertions(+), 21 deletions(-)
include/net/ip6_fib.h +23 -4
@@ -179,6 +179,7 @@ struct rt6_info { should_flush:1 , unused:6; +unsigned long expires;struct dst_metrics *fib6_metrics;#define fib6_pmtu fib6_metrics->metrics[RTAX_MTU-1]struct fib6_nh fib6_nh;
@@ -197,6 +198,26 @@ static inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst)return ((struct rt6_info *)dst)->rt6i_idev; } +static inline void fib6_clean_expires (struct rt6_info *f6i) +{ + f6i->rt6i_flags &= ~RTF_EXPIRES ; + f6i->expires =0 ; +} + +static inline void fib6_set_expires (struct rt6_info *f6i, +unsigned long expires) +{ + f6i->expires = expires; + f6i->rt6i_flags |=RTF_EXPIRES ; +} + +static inline bool fib6_check_expired (const struct rt6_info *f6i) +{ +if (f6i->rt6i_flags &RTF_EXPIRES ) +return time_after (jiffies, f6i->expires); +return false; +} +static inline void rt6_clean_expires (struct rt6_info *rt) { rt->rt6i_flags &= ~RTF_EXPIRES ;
@@ -211,11 +232,9 @@ static inline void rt6_set_expires(struct rt6_info *rt, unsigned long expires)static inline void rt6_update_expires (struct rt6_info *rt0,int timeout) { -struct rt6_info *rt; +if (!(rt0->rt6i_flags &RTF_EXPIRES ) && rt0->from) + rt0->dst.expires = rt0->from->expires; -for (rt = rt0; rt && !(rt->rt6i_flags &RTF_EXPIRES ); rt = rt->from); -if (rt && rt != rt0) - rt0->dst.expires = rt->dst.expires;dst_set_expires (&rt0->dst, timeout); rt0->rt6i_flags |=RTF_EXPIRES ; }
net/ipv6/addrconf.c +3 -3
@@ -1202,7 +1202,7 @@ cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, bool del_rip6_del_rt (dev_net (ifp->idev->dev), rt); else {if (!(rt->rt6i_flags &RTF_EXPIRES )) -rt6_set_expires (rt, expires); +fib6_set_expires (rt, expires);ip6_rt_put (rt); } }
@@ -2685,9 +2685,9 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao) rt =NULL ; }else if (addrconf_finite_timeout (rt_expires)) {/* not infinity */ -rt6_set_expires (rt, jiffies + rt_expires); +fib6_set_expires (rt, jiffies + rt_expires); }else { -rt6_clean_expires (rt); +fib6_clean_expires (rt); } }else if (valid_lft) {clock_t expires =0 ;
net/ipv6/ip6_fib.c +4 -4
@@ -905,9 +905,9 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,if (!(iter->rt6i_flags &RTF_EXPIRES ))return -EEXIST ;if (!(rt->rt6i_flags &RTF_EXPIRES )) -rt6_clean_expires (iter); +fib6_clean_expires (iter);else -rt6_set_expires (iter, rt->dst.expires); +fib6_set_expires (iter, rt->expires);fib6_metric_set (iter,RTAX_MTU , rt->fib6_pmtu);return -EEXIST ; }
@@ -1994,8 +1994,8 @@ static int fib6_age(struct rt6_info *rt, void *arg)* Routes are expired even if they are in use. */ -if (rt->rt6i_flags &RTF_EXPIRES && rt->dst.expires) { -if (time_after (now, rt->dst.expires)) { +if (rt->rt6i_flags &RTF_EXPIRES && rt->expires) { +if (time_after (now, rt->expires)) {RT6_TRACE ("expiring %p\n" , rt);return -1 ; }
net/ipv6/ndisc.c +1 -1
@@ -1318,7 +1318,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) }if (rt) -rt6_set_expires (rt, jiffies + (HZ * lifetime)); +fib6_set_expires (rt, jiffies + (HZ * lifetime));if (in6_dev->cnf.accept_ra_min_hop_limit <256 && ra_msg->icmph.icmp6_hop_limit) {if (in6_dev->cnf.accept_ra_min_hop_limit <= ra_msg->icmph.icmp6_hop_limit) {
net/ipv6/route.c +11 -9
@@ -435,7 +435,7 @@ static bool rt6_check_expired(const struct rt6_info *rt)return true; }else if (rt->from) {return rt->dst.obsolete !=DST_OBSOLETE_FORCE_CHK || -rt6_check_expired (rt->from); +fib6_check_expired (rt->from); }return false; }
@@ -687,7 +687,7 @@ static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict, !(strict & RT6_LOOKUP_F_IGNORE_LINKSTATE)) goto out; -if (rt6_check_expired (rt)) +if (fib6_check_expired (rt)) goto out; m =rt6_score_route (rt, oif, strict);
@@ -871,9 +871,9 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,if (rt) {if (!addrconf_finite_timeout (lifetime)) -rt6_clean_expires (rt); +fib6_clean_expires (rt);else -rt6_set_expires (rt, jiffies +HZ * lifetime); +fib6_set_expires (rt, jiffies +HZ * lifetime);ip6_rt_put (rt); }
@@ -2339,7 +2339,7 @@ static struct rt6_info *__ip6_route_redirect(struct net *net,for_each_fib6_node_rt_rcu (fn) {if (rt->fib6_nh.nh_flags &RTNH_F_DEAD )continue ; -if (rt6_check_expired (rt)) +if (fib6_check_expired (rt))continue ;if (rt->rt6i_flags &RTF_REJECT )break ;
@@ -2865,10 +2865,10 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg, goto out;if (cfg->fc_flags &RTF_EXPIRES ) -rt6_set_expires (rt, jiffies + +fib6_set_expires (rt, jiffies +clock_t_to_jiffies (cfg->fc_expires));else -rt6_clean_expires (rt); +fib6_clean_expires (rt);if (cfg->fc_protocol ==RTPROT_UNSPEC ) cfg->fc_protocol =RTPROT_BOOT ;
@@ -4554,8 +4554,10 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, goto nla_put_failure; } -if (rt->rt6i_flags &RTF_EXPIRES && dst) - expires = dst->expires - jiffies; +if (rt->rt6i_flags &RTF_EXPIRES ) { + expires = dst ? dst->expires : rt->expires; + expires -= jiffies; + }if (rtnl_put_cacheinfo (skb, dst,0 , expires, dst ? dst->error :0 ) <0 ) goto nla_put_failure;
Signature · 1 line
2.11.0
RFC PATCH v2 9/21 net/ipv6: Defer initialization of dst to data path
In reply to David AhernDefer setting dst input, output and error until fib entry is copied.
The reject path from ip6_route_info_create is moved to a new function ip6_rt_init_dst_reject with a helper doing the conversion from fib6_type to dst error.
The remainder of the new ip6_rt_init_dst is an amalgamtion of dst code from addrconf_dst_alloc and the non-reject path of ip6_route_info_create. The dst output function is always ip6_output and the input function is either ip6_input (local routes), ip6_mc_input (multicast routes) or ip6_forward (anything else).
A couple of places using dst.error are updated to look at rt6i_flags.
--- net/ipv6/route.c | 115 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 74 insertions(+), 41 deletions(-)
net/ipv6/route.c +74 -41
@@ -920,6 +920,75 @@ static struct net_device *ip6_rt_get_dev_rcu(struct rt6_info *rt)return dev; } +static const int fib6_prop[RTN_MAX +1 ] = { + [RTN_UNSPEC ] =0 , + [RTN_UNICAST ] =0 , + [RTN_LOCAL ] =0 , + [RTN_BROADCAST ] =0 , + [RTN_ANYCAST ] =0 , + [RTN_MULTICAST ] =0 , + [RTN_BLACKHOLE ] = -EINVAL , + [RTN_UNREACHABLE ] = -EHOSTUNREACH , + [RTN_PROHIBIT ] = -EACCES , + [RTN_THROW ] = -EAGAIN , + [RTN_NAT ] = -EINVAL , + [RTN_XRESOLVE ] = -EINVAL , +}; + +static int ip6_rt_type_to_error (u8 fib6_type) +{ +return fib6_prop[fib6_type]; +} + +static void ip6_rt_init_dst_reject (struct rt6_info *rt,struct rt6_info *ort) +{ + rt->dst.error =ip6_rt_type_to_error (ort->fib6_type); + +switch (ort->fib6_type) { +case RTN_BLACKHOLE : + rt->dst.output = dst_discard_out; + rt->dst.input = dst_discard; +break ; +case RTN_PROHIBIT : + rt->dst.output = ip6_pkt_prohibit_out; + rt->dst.input = ip6_pkt_prohibit; +break ; +case RTN_THROW : +case RTN_UNREACHABLE : +default : + rt->dst.output = ip6_pkt_discard_out; + rt->dst.input = ip6_pkt_discard; +break ; + } +} + +static void ip6_rt_init_dst (struct rt6_info *rt,struct rt6_info *ort) +{ +if (ort->rt6i_flags &RTF_REJECT ) { +ip6_rt_init_dst_reject (rt, ort); +return ; + } + + rt->dst.error =0 ; + rt->dst.output = ip6_output; + +if (ort->fib6_type ==RTN_LOCAL ) { + rt->dst.flags |=DST_HOST ; + rt->dst.input = ip6_input; + }else if (ipv6_addr_type (&ort->rt6i_dst.addr) &IPV6_ADDR_MULTICAST ) { + rt->dst.input = ip6_mc_input; + }else { + rt->dst.input = ip6_forward; + } + +if (ort->fib6_nh.nh_lwtstate) { + rt->dst.lwtstate =lwtstate_get (ort->fib6_nh.nh_lwtstate); +lwtunnel_set_redirect (&rt->dst); + } + + rt->dst.lastuse = jiffies; +} +static void rt6_set_from (struct rt6_info *rt,struct rt6_info *from) {BUG_ON (from->from);
@@ -932,14 +1001,12 @@ static void rt6_set_from(struct rt6_info *rt, struct rt6_info *from)static void ip6_rt_copy_init (struct rt6_info *rt,struct rt6_info *ort) { - rt->dst.input = ort->dst.input; - rt->dst.output = ort->dst.output; +ip6_rt_init_dst (rt, ort); + rt->rt6i_dst = ort->rt6i_dst; - rt->dst.error = ort->dst.error; rt->rt6i_idev = ort->rt6i_idev;if (rt->rt6i_idev)in6_dev_hold (rt->rt6i_idev); - rt->dst.lastuse = jiffies; rt->rt6i_gateway = ort->fib6_nh.nh_gw; rt->rt6i_flags = ort->rt6i_flags;rt6_set_from (rt, ort);
@@ -2283,7 +2350,7 @@ static struct rt6_info *__ip6_route_redirect(struct net *net,continue ;if (rt6_check_expired (rt))continue ; -if (rt->dst.error) +if (rt->rt6i_flags &RTF_REJECT )break ;if (!(rt->rt6i_flags &RTF_GATEWAY ))continue ;
@@ -2311,7 +2378,7 @@ static struct rt6_info *__ip6_route_redirect(struct net *net,if (!rt) rt = net->ipv6.ip6_null_entry; -else if (rt->dst.error) { +else if (rt->rt6i_flags &RTF_REJECT ) { rt = net->ipv6.ip6_null_entry; goto out; }
@@ -2854,15 +2921,6 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg, addr_type =ipv6_addr_type (&cfg->fc_dst); -if (addr_type &IPV6_ADDR_MULTICAST ) - rt->dst.input = ip6_mc_input; -else if (cfg->fc_flags &RTF_LOCAL ) - rt->dst.input = ip6_input; -else - rt->dst.input = ip6_forward; - - rt->dst.output = ip6_output; -if (cfg->fc_encap) {struct lwtunnel_state *lwtstate;
@@ -2872,7 +2930,6 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg,if (err) goto out; rt->fib6_nh.nh_lwtstate =lwtstate_get (lwtstate); -lwtunnel_set_redirect (&rt->dst); }ipv6_addr_prefix (&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
@@ -2912,27 +2969,6 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg, } } rt->rt6i_flags =RTF_REJECT |RTF_NONEXTHOP ; -switch (cfg->fc_type) { -case RTN_BLACKHOLE : - rt->dst.error = -EINVAL ; - rt->dst.output = dst_discard_out; - rt->dst.input = dst_discard; -break ; -case RTN_PROHIBIT : - rt->dst.error = -EACCES ; - rt->dst.output = ip6_pkt_prohibit_out; - rt->dst.input = ip6_pkt_prohibit; -break ; -case RTN_THROW : -case RTN_UNREACHABLE : -default : - rt->dst.error = (cfg->fc_type ==RTN_THROW ) ? -EAGAIN - : (cfg->fc_type ==RTN_UNREACHABLE ) - ? -EHOSTUNREACH : -ENETUNREACH ; - rt->dst.output = ip6_pkt_discard_out; - rt->dst.input = ip6_pkt_discard; -break ; - } goto install_route; }
@@ -3570,12 +3606,9 @@ struct rt6_info *addrconf_dst_alloc(struct net *net,return ERR_PTR (-ENOMEM );in6_dev_hold (idev); - - rt->dst.flags |=DST_HOST ; - rt->dst.input = ip6_input; - rt->dst.output = ip6_output; rt->rt6i_idev = idev; + rt->dst.flags |=DST_HOST ; rt->rt6i_protocol =RTPROT_KERNEL ; rt->rt6i_flags =RTF_UP |RTF_NONEXTHOP ;if (anycast) {
Signature · 1 line
2.11.0
RFC PATCH v2 12/21 net/ipv6: Add fib6_null_entry
In reply to David Ahernip6_null_entry will stay a dst based return for lookups that fail to match an entry.
Add a new fib6_null_entry which constitutes the root node and leafs for fibs. Replace existing references to ip6_null_entry with the new fib6_null_entry when dealing with FIBs.
--- include/net/netns/ipv6.h | 3 ++- net/ipv6/ip6_fib.c | 26 ++++++++++---------- net/ipv6/route.c | 62 +++++++++++++++++++++++++++++++++--------------- 3 files changed, 58 insertions(+), 33 deletions(-)
include/net/netns/ipv6.h +2 -1
@@ -60,7 +60,8 @@ struct netns_ipv6 {#endif struct xt_table *ip6table_nat;#endif -struct rt6_info *ip6_null_entry; +struct rt6_info *fib6_null_entry; +struct rt6_info *ip6_null_entry;struct rt6_statistics *rt6_stats;struct timer_list ip6_fib_timer;struct hlist_head *fib_table_hash;
net/ipv6/ip6_fib.c +13 -13
@@ -231,7 +231,7 @@ static struct fib6_table *fib6_alloc_table(struct net *net, u32 id)if (table) { table->tb6_id = id;rcu_assign_pointer (table->tb6_root.leaf, - net->ipv6.ip6_null_entry); + net->ipv6.fib6_null_entry); table->tb6_root.fn_flags =RTN_ROOT |RTN_TL_ROOT |RTN_RTINFO ;inet_peer_base_init (&table->tb6_peers); }
@@ -369,7 +369,7 @@ struct fib6_dump_arg {static void fib6_rt_dump (struct rt6_info *rt,struct fib6_dump_arg *arg) { -if (rt == arg->net->ipv6.ip6_null_entry) +if (rt == arg->net->ipv6.fib6_null_entry)return ;call_fib6_entry_notifier (arg->nb, arg->net,FIB_EVENT_ENTRY_ADD , rt); }
@@ -658,7 +658,7 @@ static struct fib6_node *fib6_add_1(struct net *net,/* remove null_entry in the root node */ }else if (fn->fn_flags &RTN_TL_ROOT &&rcu_access_pointer (fn->leaf) == - net->ipv6.ip6_null_entry) { + net->ipv6.fib6_null_entry) {RCU_INIT_POINTER (fn->leaf,NULL ); }
@@ -1162,9 +1162,9 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,if (!sfn) goto failure; -atomic_inc (&info->nl_net->ipv6.ip6_null_entry->rt6i_ref); +atomic_inc (&info->nl_net->ipv6.fib6_null_entry->rt6i_ref);rcu_assign_pointer (sfn->leaf, - info->nl_net->ipv6.ip6_null_entry); + info->nl_net->ipv6.fib6_null_entry); sfn->fn_flags =RTN_ROOT ;/* Now add the first leaf node to new subtree */
@@ -1203,7 +1203,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,if (fn->fn_flags &RTN_TL_ROOT ) {/* put back null_entry for root node */ rcu_assign_pointer (fn->leaf, - info->nl_net->ipv6.ip6_null_entry); + info->nl_net->ipv6.fib6_null_entry); }else {atomic_inc (&rt->rt6i_ref);rcu_assign_pointer (fn->leaf, rt);
@@ -1242,7 +1242,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,if (!pn_leaf) {WARN_ON (!pn_leaf); pn_leaf = - info->nl_net->ipv6.ip6_null_entry; + info->nl_net->ipv6.fib6_null_entry; }#endif atomic_inc (&pn_leaf->rt6i_ref);
@@ -1485,7 +1485,7 @@ static struct rt6_info *fib6_find_prefix(struct net *net,struct fib6_node *child_left, *child_right;if (fn->fn_flags &RTN_ROOT ) -return net->ipv6.ip6_null_entry; +return net->ipv6.fib6_null_entry;while (fn) { child_left = rcu_dereference_protected(fn->left,
@@ -1522,7 +1522,7 @@ static struct fib6_node *fib6_repair_tree(struct net *net,/* Set fn->leaf to null_entry for root node. */ if (fn->fn_flags &RTN_TL_ROOT ) { -rcu_assign_pointer (fn->leaf, net->ipv6.ip6_null_entry); +rcu_assign_pointer (fn->leaf, net->ipv6.fib6_null_entry);return fn; }
@@ -1567,7 +1567,7 @@ static struct fib6_node *fib6_repair_tree(struct net *net,#if RT6_DEBUG >=2 if (!new_fn_leaf) {WARN_ON (!new_fn_leaf); - new_fn_leaf = net->ipv6.ip6_null_entry; + new_fn_leaf = net->ipv6.fib6_null_entry; }#endif atomic_inc (&new_fn_leaf->rt6i_ref);
@@ -1717,7 +1717,7 @@ int fib6_del(struct rt6_info *rt, struct nl_info *info) return -ENOENT; }#endif -if (!fn || rt == net->ipv6.ip6_null_entry) +if (!fn || rt == net->ipv6.fib6_null_entry)return -ENOENT ;WARN_ON (!(fn->fn_flags &RTN_RTINFO ));
@@ -2078,7 +2078,7 @@ static int __net_init fib6_net_init(struct net *net) net->ipv6.fib6_main_tbl->tb6_id =RT6_TABLE_MAIN ;rcu_assign_pointer (net->ipv6.fib6_main_tbl->tb6_root.leaf, - net->ipv6.ip6_null_entry); + net->ipv6.fib6_null_entry); net->ipv6.fib6_main_tbl->tb6_root.fn_flags =RTN_ROOT |RTN_TL_ROOT |RTN_RTINFO ;inet_peer_base_init (&net->ipv6.fib6_main_tbl->tb6_peers);
@@ -2090,7 +2090,7 @@ static int __net_init fib6_net_init(struct net *net) goto out_fib6_main_tbl; net->ipv6.fib6_local_tbl->tb6_id =RT6_TABLE_LOCAL ;rcu_assign_pointer (net->ipv6.fib6_local_tbl->tb6_root.leaf, - net->ipv6.ip6_null_entry); + net->ipv6.fib6_null_entry); net->ipv6.fib6_local_tbl->tb6_root.fn_flags =RTN_ROOT |RTN_TL_ROOT |RTN_RTINFO ;inet_peer_base_init (&net->ipv6.fib6_local_tbl->tb6_peers);
net/ipv6/route.c +43 -19
205 lines not on this page · raw message
Signature · 1 line
2.11.0
RFC PATCH v2 13/21 net/ipv6: Add rt6_info create function for ip6_pol_route_lookup
In reply to David Ahernip6_pol_route_lookup is the lookup function for ip6_route_lookup and rt6_lookup. At the moment it returns either a reference to a FIB entry or a cached exception. To move FIB entries to a separate struct, this lookup function needs to convert FIB entries to an rt6_info that is returned to the caller.
--- net/ipv6/route.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-)
net/ipv6/route.c +26 -4
@@ -1055,6 +1055,20 @@ static bool ip6_hold_safe(struct net *net, struct rt6_info **prt,return false; } +/* called with rcu_lock held */ +static struct rt6_info *ip6_create_rt_rcu (struct rt6_info *rt) +{ +struct net_device *dev; +struct rt6_info *nrt; + + dev =ip6_rt_get_dev_rcu (rt); + nrt =__ip6_dst_alloc (dev_net (dev), dev,0 ); +if (nrt) +ip6_rt_copy_init (nrt, rt); + +return nrt; +} + static struct rt6_info *ip6_pol_route_lookup(struct net *net, struct fib6_table *table, struct flowi6 *fl6,
@@ -1084,18 +1098,26 @@ static struct rt6_info *ip6_pol_route_lookup(struct net *net, }/* Search through exception table */ rt_cache =rt6_find_cached_rt (rt, &fl6->daddr, &fl6->saddr); -if (rt_cache) +if (rt_cache) { rt = rt_cache; +if (ip6_hold_safe (net, &rt, true)) +dst_use_noref (&rt->dst, jiffies); + }else if (dst_hold_safe (&rt->dst)) { +struct rt6_info *nrt; -if (ip6_hold_safe (net, &rt, true)) -dst_use_noref (&rt->dst, jiffies); + nrt =ip6_create_rt_rcu (rt); +dst_release (&rt->dst); + rt = nrt; + }else { + rt = net->ipv6.ip6_null_entry; +dst_hold (&rt->dst); + }rcu_read_unlock ();trace_fib6_table_lookup (net, rt, table, fl6);return rt; - } struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6,
Signature · 1 line
2.11.0
RFC PATCH v2 14/21 net/ipv6: Move dst flags to booleans in fib entries
In reply to David AhernContinuing to wean FIB paths off of dst_entry, use a bool to hold requests for certain dst settings. Add a helper to convert the flags to DST flags when a FIB entry is converted to a dst_entry.
--- include/net/ip6_fib.h | 5 ++++- net/ipv6/addrconf.c | 4 ++-- net/ipv6/route.c | 29 ++++++++++++++++++++++++----- 3 files changed, 30 insertions(+), 8 deletions(-)
include/net/ip6_fib.h +4 -1
@@ -177,7 +177,10 @@ struct rt6_info {u8 fib6_type; u8 exception_bucket_flushed:1, should_flush:1, - unused:6; + dst_nocount:1, + dst_nopolicy:1, + dst_host:1, + unused:3;unsigned long expires;struct dst_metrics *fib6_metrics;
net/ipv6/addrconf.c +2 -2
@@ -1058,7 +1058,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr,if (net->ipv6.devconf_all->disable_policy || idev->cnf.disable_policy) - rt->dst.flags |=DST_NOPOLICY ; + rt->dst_nopolicy = true;neigh_parms_data_state_setall (idev->nd_parms);
@@ -5998,7 +5998,7 @@ void addrconf_disable_policy_idev(struct inet6_dev *idev, int val)int cpu;rcu_read_lock (); -addrconf_set_nopolicy (ifa->rt, val); + ifa->rt->dst_nopolicy = val ? true : false;if (rt->rt6i_pcpu) {for_each_possible_cpu (cpu) {struct rt6_info **rtp;
net/ipv6/route.c +24 -5
@@ -937,6 +937,20 @@ static int ip6_rt_type_to_error(u8 fib6_type)return fib6_prop[fib6_type]; } +static unsigned short fib6_info_dst_flags (struct rt6_info *rt) +{ +unsigned short flags =0 ; + +if (rt->dst_nocount) + flags |=DST_NOCOUNT ; +if (rt->dst_nopolicy) + flags |=DST_NOPOLICY ; +if (rt->dst_host) + flags |=DST_HOST ; + +return flags; +} +static void ip6_rt_init_dst_reject (struct rt6_info *rt,struct rt6_info *ort) { rt->dst.error =ip6_rt_type_to_error (ort->fib6_type);
@@ -961,6 +975,8 @@ static void ip6_rt_init_dst_reject(struct rt6_info *rt, struct rt6_info *ort)static void ip6_rt_init_dst (struct rt6_info *rt,struct rt6_info *ort) { + rt->dst.flags |=fib6_info_dst_flags (ort); +if (ort->rt6i_flags &RTF_REJECT ) {ip6_rt_init_dst_reject (rt, ort);return ;
@@ -970,7 +986,6 @@ static void ip6_rt_init_dst(struct rt6_info *rt, struct rt6_info *ort) rt->dst.output = ip6_output;if (ort->fib6_type ==RTN_LOCAL ) { - rt->dst.flags |=DST_HOST ; rt->dst.input = ip6_input; }else if (ipv6_addr_type (&ort->rt6i_dst.addr) &IPV6_ADDR_MULTICAST ) { rt->dst.input = ip6_mc_input;
@@ -1058,11 +1073,12 @@ static bool ip6_hold_safe(struct net *net, struct rt6_info **prt,/* called with rcu_lock held */ static struct rt6_info *ip6_create_rt_rcu (struct rt6_info *rt) { +unsigned short flags =fib6_info_dst_flags (rt);struct net_device *dev;struct rt6_info *nrt; dev =ip6_rt_get_dev_rcu (rt); - nrt =__ip6_dst_alloc (dev_net (dev), dev,0 ); + nrt =__ip6_dst_alloc (dev_net (dev), dev, flags);if (nrt)ip6_rt_copy_init (nrt, rt);
@@ -1227,12 +1243,13 @@ static struct rt6_info *ip6_rt_cache_alloc(struct rt6_info *ort,static struct rt6_info *ip6_rt_pcpu_alloc (struct rt6_info *rt) { +unsigned short flags =fib6_info_dst_flags (rt);struct net_device *dev;struct rt6_info *pcpu_rt;rcu_read_lock (); dev =ip6_rt_get_dev_rcu (rt); - pcpu_rt =__ip6_dst_alloc (dev_net (dev), dev, rt->dst.flags); + pcpu_rt =__ip6_dst_alloc (dev_net (dev), dev, flags);rcu_read_unlock ();if (!pcpu_rt)return NULL ;
@@ -2922,7 +2939,7 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg,ipv6_addr_prefix (&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len); rt->rt6i_dst.plen = cfg->fc_dst_len;if (rt->rt6i_dst.plen ==128 ) - rt->dst.flags |=DST_HOST ; + rt->dst_host = true;#ifdef CONFIG_IPV6_SUBTREES ipv6_addr_prefix (&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len);
@@ -3576,10 +3593,12 @@ struct rt6_info *addrconf_dst_alloc(struct net *net,if (!rt)return ERR_PTR (-ENOMEM ); + rt->dst_nocount = true; +in6_dev_hold (idev); rt->rt6i_idev = idev; - rt->dst.flags |=DST_HOST ; + rt->dst_host = true; rt->rt6i_protocol =RTPROT_KERNEL ; rt->rt6i_flags =RTF_UP |RTF_NONEXTHOP ;if (anycast) {
Signature · 1 line
2.11.0
RFC PATCH v2 15/21 net/ipv6: Create a neigh_lookup for FIB entries
In reply to David AhernThe router discovery code has a FIB entry and wants to validate the gateway has a neighbor entry. Refactor the existing dst_neigh_lookup for IPv6 and create a new function that takes the gateway and device and returns a neighbor entry. Use the new function in ndisc_router_discovery to validate the gateway.
--- include/net/ip6_route.h | 3 +++ net/ipv6/ndisc.c | 8 ++++++-- net/ipv6/route.c | 33 ++++++++++++++++++++------------- 3 files changed, 29 insertions(+), 15 deletions(-)
include/net/ip6_route.h +3 -0
@@ -273,4 +273,7 @@ static inline bool rt6_duplicate_nexthop(struct rt6_info *a, struct rt6_info *b) !lwtunnel_cmp_encap(a->fib6_nh.nh_lwtstate, b->fib6_nh.nh_lwtstate); } +struct neighbour *ip6_neigh_lookup (const struct in6_addr *gw, +struct net_device *dev,struct sk_buff *skb, +const void *daddr);#endif
net/ipv6/ndisc.c +6 -2
@@ -1276,7 +1276,9 @@ static void ndisc_router_discovery(struct sk_buff *skb) rt =rt6_get_dflt_router (net, &ipv6_hdr (skb)->saddr, skb->dev);if (rt) { - neigh =dst_neigh_lookup (&rt->dst, &ipv6_hdr (skb)->saddr); + neigh =ip6_neigh_lookup (&rt->fib6_nh.nh_gw, + rt->fib6_nh.nh_dev,NULL , + &ipv6_hdr (skb)->saddr);if (!neigh) { ND_PRINTK(0, err, "RA: %s got default router without neighbour\n",
@@ -1304,7 +1306,9 @@ static void ndisc_router_discovery(struct sk_buff *skb)return ; } - neigh =dst_neigh_lookup (&rt->dst, &ipv6_hdr (skb)->saddr); + neigh =ip6_neigh_lookup (&rt->fib6_nh.nh_gw, + rt->fib6_nh.nh_dev,NULL , + &ipv6_hdr (skb)->saddr);if (!neigh) { ND_PRINTK(0, err, "RA: %s got default router without neighbour\n",
net/ipv6/route.c +20 -13
@@ -182,12 +182,10 @@ static void rt6_uncached_list_flush_dev(struct net *net, struct net_device *dev) } } -static inline const void *choose_neigh_daddr (struct rt6_info *rt, +static inline const void *choose_neigh_daddr (const struct in6_addr *p,struct sk_buff *skb,const void *daddr) { -struct in6_addr *p = &rt->rt6i_gateway; -if (!ipv6_addr_any (p))return (const void *) p;else if (skb)
@@ -195,18 +193,27 @@ static inline const void *choose_neigh_daddr(struct rt6_info *rt,return daddr; } -static struct neighbour *ip6_neigh_lookup (const struct dst_entry *dst, -struct sk_buff *skb, -const void *daddr) +struct neighbour *ip6_neigh_lookup (const struct in6_addr *gw, +struct net_device *dev, +struct sk_buff *skb, +const void *daddr) { -struct rt6_info *rt = (struct rt6_info *) dst;struct neighbour *n; - daddr =choose_neigh_daddr (rt, skb, daddr); - n =__ipv6_neigh_lookup (dst->dev, daddr); + daddr =choose_neigh_daddr (gw, skb, daddr); + n =__ipv6_neigh_lookup (dev, daddr);if (n)return n; -return neigh_create (&nd_tbl, daddr, dst->dev); +return neigh_create (&nd_tbl, daddr, dev); +} + +static struct neighbour *ip6_dst_neigh_lookup (const struct dst_entry *dst, +struct sk_buff *skb, +const void *daddr) +{ + const struct rt6_info *rt = container_of(dst, struct rt6_info, dst); + +return ip6_neigh_lookup (&rt->rt6i_gateway, dst->dev, skb, daddr); }static void ip6_confirm_neigh (const struct dst_entry *dst,const void *daddr)
@@ -214,7 +221,7 @@ static void ip6_confirm_neigh(const struct dst_entry *dst, const void *daddr)struct net_device *dev = dst->dev;struct rt6_info *rt = (struct rt6_info *)dst; - daddr =choose_neigh_daddr (rt,NULL , daddr); + daddr =choose_neigh_daddr (&rt->rt6i_gateway,NULL , daddr);if (!daddr)return ;if (dev->flags & (IFF_NOARP |IFF_LOOPBACK ))
@@ -239,7 +246,7 @@ static struct dst_ops ip6_dst_ops_template = { .update_pmtu = ip6_rt_update_pmtu, .redirect = rt6_do_redirect, .local_out = __ip6_local_out, - .neigh_lookup = ip6_neigh_lookup, + .neigh_lookup = ip6_dst_neigh_lookup, .confirm_neigh = ip6_confirm_neigh, };
@@ -269,7 +276,7 @@ static struct dst_ops ip6_dst_blackhole_ops = { .update_pmtu = ip6_rt_blackhole_update_pmtu, .redirect = ip6_rt_blackhole_redirect, .cow_metrics = dst_cow_metrics_generic, - .neigh_lookup = ip6_neigh_lookup, + .neigh_lookup = ip6_dst_neigh_lookup, };static const u32 ip6_template_metrics[RTAX_MAX ] = {
Signature · 1 line
2.11.0
RFC PATCH v2 16/21 net/ipv6: Add gfp_flags to route add functions
In reply to David AhernMost FIB entries can be added using memory allocated with GFP_KERNEL. Add gfp_flags to ip6_route_add and addrconf_dst_alloc. Code paths that can be reached from the packet path (e.g., ndisc and autoconfig) or atomic notifiers use GFP_ATOMIC; paths from user context (adding addresses and routes) use GFP_KERNEL.
--- include/net/ip6_route.h | 6 ++++-- net/ipv6/addrconf.c | 39 +++++++++++++++++++++++---------------- net/ipv6/anycast.c | 2 +- net/ipv6/route.c | 18 ++++++++++-------- 4 files changed, 38 insertions(+), 27 deletions(-)
include/net/ip6_route.h +4 -2
@@ -100,7 +100,8 @@ void ip6_route_cleanup(void);int ipv6_route_ioctl (struct net *net,unsigned int cmd,void __user *arg); -int ip6_route_add (struct fib6_config *cfg,struct netlink_ext_ack *extack); +int ip6_route_add (struct fib6_config *cfg,gfp_t gfp_flags, +struct netlink_ext_ack *extack);int ip6_ins_rt (struct net *net,struct rt6_info *rt);int ip6_del_rt (struct net *net,struct rt6_info *rt);
@@ -138,7 +139,8 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, struct flowi6 *fl6);void fib6_force_start_gc (struct net *net);struct rt6_info *addrconf_dst_alloc (struct net *net,struct inet6_dev *idev, -const struct in6_addr *addr,bool anycast); +const struct in6_addr *addr,bool anycast, +gfp_t gfp_flags);struct rt6_info *ip6_dst_alloc (struct net *net,struct net_device *dev,int flags);
net/ipv6/addrconf.c +23 -16
@@ -1049,7 +1049,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, goto out; } - rt =addrconf_dst_alloc (net, idev, addr, false); + rt =addrconf_dst_alloc (net, idev, addr, false, gfp_flags);if (IS_ERR (rt)) { err =PTR_ERR (rt); rt =NULL ;
@@ -2332,7 +2332,7 @@ static void ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpadstatic void addrconf_prefix_route (struct in6_addr *pfx,int plen,struct net_device *dev, -unsigned long expires,u32 flags) +unsigned long expires,u32 flags,gfp_t gfp_flags) {struct fib6_config cfg = { .fc_table =l3mdev_fib_table (dev) ? :RT6_TABLE_PREFIX ,
@@ -2357,7 +2357,7 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev, cfg.fc_flags |=RTF_NONEXTHOP ;#endif -ip6_route_add (&cfg,NULL ); +ip6_route_add (&cfg, gfp_flags,NULL ); }
@@ -2413,7 +2413,7 @@ static void addrconf_add_mroute(struct net_device *dev)ipv6_addr_set (&cfg.fc_dst,htonl (0xFF000000 ),0 ,0 ,0 ); -ip6_route_add (&cfg,NULL ); +ip6_route_add (&cfg,GFP_ATOMIC ,NULL ); }static struct inet6_dev *addrconf_add_dev (struct net_device *dev)
@@ -2698,7 +2698,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao) expires =jiffies_to_clock_t (rt_expires); }addrconf_prefix_route (&pinfo->prefix, pinfo->prefix_len, - dev, expires, flags); + dev, expires, flags,GFP_ATOMIC ); }ip6_rt_put (rt); }
@@ -2913,7 +2913,7 @@ static int inet6_addr_add(struct net *net, int ifindex,if (!IS_ERR (ifp)) {if (!(ifa_flags &IFA_F_NOPREFIXROUTE )) {addrconf_prefix_route (&ifp->addr, ifp->prefix_len, dev, - expires, flags); + expires, flags,GFP_KERNEL ); }/*
@@ -3061,7 +3061,8 @@ static void sit_add_v4_addrs(struct inet6_dev *idev)if (addr.s6_addr32[3 ]) {add_addr (idev, &addr, plen, scope); -addrconf_prefix_route (&addr, plen, idev->dev,0 , pflags); +addrconf_prefix_route (&addr, plen, idev->dev,0 , pflags, +GFP_ATOMIC );return ; }
@@ -3086,7 +3087,7 @@ static void sit_add_v4_addrs(struct inet6_dev *idev)add_addr (idev, &addr, plen, flag);addrconf_prefix_route (&addr, plen, idev->dev,0 , - pflags); + pflags,GFP_ATOMIC ); } } }
@@ -3126,7 +3127,8 @@ void addrconf_add_linklocal(struct inet6_dev *idev, ifp =ipv6_add_addr (idev, addr,NULL ,64 ,IFA_LINK , addr_flags,INFINITY_LIFE_TIME ,INFINITY_LIFE_TIME , true,NULL );if (!IS_ERR (ifp)) { -addrconf_prefix_route (&ifp->addr, ifp->prefix_len, idev->dev,0 ,0 ); +addrconf_prefix_route (&ifp->addr, ifp->prefix_len, idev->dev, +0 ,0 ,GFP_ATOMIC );addrconf_dad_start (ifp);in6_ifa_put (ifp); }
@@ -3241,7 +3243,8 @@ static void addrconf_addr_gen(struct inet6_dev *idev, bool prefix_route)addrconf_add_linklocal (idev, &addr,IFA_F_STABLE_PRIVACY ); else if (prefix_route) - addrconf_prefix_route(&addr, 64, idev->dev, 0, 0); + addrconf_prefix_route(&addr, 64, idev->dev, + 0, 0, GFP_KERNEL);break ;case IN6_ADDR_GEN_MODE_EUI64 :/* addrconf_add_linklocal also adds a prefix_route and we
@@ -3251,7 +3254,8 @@ static void addrconf_addr_gen(struct inet6_dev *idev, bool prefix_route)if (ipv6_generate_eui64 (addr.s6_addr +8 , idev->dev) ==0 )addrconf_add_linklocal (idev, &addr,0 );else if (prefix_route) -addrconf_prefix_route (&addr,64 , idev->dev,0 ,0 ); +addrconf_prefix_route (&addr,64 , idev->dev, +0 ,0 ,GFP_ATOMIC );break ;case IN6_ADDR_GEN_MODE_NONE :default :
@@ -3354,7 +3358,8 @@ static int fixup_permanent_addr(struct net *net,if (!ifp->rt || !ifp->rt->rt6i_node) {struct rt6_info *rt, *prev; - rt =addrconf_dst_alloc (net, idev, &ifp->addr, false); + rt =addrconf_dst_alloc (net, idev, &ifp->addr, false, +GFP_ATOMIC );if (IS_ERR (rt))return PTR_ERR (rt);
@@ -3369,7 +3374,7 @@ static int fixup_permanent_addr(struct net *net,if (!(ifp->flags &IFA_F_NOPREFIXROUTE )) {addrconf_prefix_route (&ifp->addr, ifp->prefix_len, - idev->dev,0 ,0 ); + idev->dev,0 ,0 ,GFP_ATOMIC ); }if (ifp->state ==INET6_IFADDR_STATE_PREDAD )
@@ -4581,8 +4586,9 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags,ipv6_ifa_notify (0 , ifp);if (!(ifa_flags &IFA_F_NOPREFIXROUTE )) { -addrconf_prefix_route (&ifp->addr, ifp->prefix_len, ifp->idev->dev, - expires, flags); +addrconf_prefix_route (&ifp->addr, ifp->prefix_len, + ifp->idev->dev, expires, flags, +GFP_KERNEL ); }else if (had_prefixroute) {enum cleanup_prefix_rt_t action;unsigned long rt_expires;
@@ -5631,7 +5637,8 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)addrconf_join_anycast (ifp);if (!ipv6_addr_any (&ifp->peer_addr))addrconf_prefix_route (&ifp->peer_addr,128 , - ifp->idev->dev,0 ,0 ); + ifp->idev->dev,0 ,0 , +GFP_KERNEL );break ;case RTM_DELADDR :if (ifp->idev->cnf.forwarding)
net/ipv6/anycast.c +1 -1
@@ -267,7 +267,7 @@ int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr) } net =dev_net (idev->dev); - rt =addrconf_dst_alloc (net, idev, addr, true); + rt =addrconf_dst_alloc (net, idev, addr, true,GFP_ATOMIC );if (IS_ERR (rt)) { err =PTR_ERR (rt); goto out;
net/ipv6/route.c +10 -8
@@ -2823,6 +2823,7 @@ static int ip6_validate_gw(struct net *net, struct fib6_config *cfg, }static struct rt6_info *ip6_route_info_create (struct fib6_config *cfg, +gfp_t gfp_flags,struct netlink_ext_ack *extack) {struct net *net = cfg->fc_nlinfo.nl_net;
@@ -3037,12 +3038,13 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg,return ERR_PTR (err); } -int ip6_route_add (struct fib6_config *cfg,struct netlink_ext_ack *extack) +int ip6_route_add (struct fib6_config *cfg,gfp_t gfp_flags, +struct netlink_ext_ack *extack) {struct rt6_info *rt;int err; - rt =ip6_route_info_create (cfg, extack); + rt =ip6_route_info_create (cfg, gfp_flags, extack);if (IS_ERR (rt))return PTR_ERR (rt);
@@ -3369,7 +3371,7 @@ static struct rt6_info *rt6_add_route_info(struct net *net,if (!prefixlen) cfg.fc_flags |=RTF_DEFAULT ; -ip6_route_add (&cfg,NULL ); +ip6_route_add (&cfg,GFP_ATOMIC ,NULL );return rt6_get_route_info (net, prefix, prefixlen, gwaddr, dev); }
@@ -3420,7 +3422,7 @@ struct rt6_info *rt6_add_dflt_router(struct net *net, cfg.fc_gateway = *gwaddr; -if (!ip6_route_add (&cfg,NULL )) { +if (!ip6_route_add (&cfg,GFP_ATOMIC ,NULL )) {struct fib6_table *table; table =fib6_get_table (dev_net (dev), cfg.fc_table);
@@ -3518,7 +3520,7 @@ int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)rtnl_lock ();switch (cmd) {case SIOCADDRT : - err =ip6_route_add (&cfg,NULL ); + err =ip6_route_add (&cfg,GFP_KERNEL ,NULL );break ;case SIOCDELRT : err =ip6_route_del (&cfg,NULL );
@@ -3590,7 +3592,7 @@ static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buffstruct rt6_info *addrconf_dst_alloc (struct net *net,struct inet6_dev *idev,const struct in6_addr *addr, -bool anycast) +bool anycast,gfp_t gfp_flags) {u32 tb_id;struct net_device *dev = idev->dev;
@@ -4251,7 +4253,7 @@ static int ip6_route_multipath_add(struct fib6_config *cfg, r_cfg.fc_encap_type =nla_get_u16 (nla); } - rt =ip6_route_info_create (&r_cfg, extack); + rt =ip6_route_info_create (&r_cfg,GFP_KERNEL , extack);if (IS_ERR (rt)) { err =PTR_ERR (rt); rt =NULL ;
@@ -4404,7 +4406,7 @@ static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,if (cfg.fc_mp)return ip6_route_multipath_add (&cfg, extack);else -return ip6_route_add (&cfg, extack); +return ip6_route_add (&cfg,GFP_KERNEL , extack); }static size_t rt6_nlmsg_size (struct rt6_info *rt)
Signature · 1 line
2.11.0
RFC PATCH v2 17/21 net/ipv6: Cleanup exception and cache route handling
In reply to David AhernIPv6 FIB will only contain FIB entries with exception routes added to the FIB entry. Once this transformation is complete, FIB lookups will return a fib6_info with the lookup functions still returning a dst based rt6_info. The current code uses rt6_info for both paths and overloads the rt6_info variable usually called 'rt'.
This patch introduces a new 'f6i' variable name for the result of the FIB lookup and keeps 'rt' as the dst based return variable. 'f6i' becomes a fib6_info in a later patch which is why it is introduced as f6i now; avoids the additional churn in the later patch.
In addition, remove RTF_CACHE and dst checks from fib6 add and delete since they can not happen now and will never happen after the data type flip.
--- include/net/ip6_route.h | 1 - net/ipv6/ip6_fib.c | 16 +----- net/ipv6/route.c | 137 ++++++++++++++++++++++++++---------------------- 3 files changed, 75 insertions(+), 79 deletions(-)
include/net/ip6_route.h +0 -1
@@ -106,7 +106,6 @@ int ip6_ins_rt(struct net *net, struct rt6_info *rt);int ip6_del_rt (struct net *net,struct rt6_info *rt);void rt6_flush_exceptions (struct rt6_info *rt); -int rt6_remove_exception_rt (struct rt6_info *rt);void rt6_age_exceptions (struct rt6_info *rt,struct fib6_gc_args *gc_args,unsigned long now);
net/ipv6/ip6_fib.c +1 -15
@@ -1065,7 +1065,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,static void fib6_start_gc (struct net *net,struct rt6_info *rt) {if (!timer_pending (&net->ipv6.ip6_fib_timer) && - (rt->rt6i_flags & (RTF_EXPIRES |RTF_CACHE ))) + (rt->rt6i_flags &RTF_EXPIRES ))mod_timer (&net->ipv6.ip6_fib_timer, jiffies + net->ipv6.sysctl.ip6_rt_gc_interval); }
@@ -1116,8 +1116,6 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,if (WARN_ON_ONCE (!atomic_read (&rt->dst.__refcnt)))return -EINVAL ; -if (WARN_ON_ONCE (rt->rt6i_flags &RTF_CACHE )) -return -EINVAL ;if (info->nlh) {if (!(info->nlh->nlmsg_flags &NLM_F_CREATE ))
@@ -1641,8 +1639,6 @@ static void fib6_del_route(struct fib6_table *table, struct fib6_node *fn,RT6_TRACE ("fib6_del_route\n" ); -WARN_ON_ONCE (rt->rt6i_flags &RTF_CACHE ); -/* Unlink it */ *rtp = rt->rt6_next; rt->rt6i_node =NULL ;
@@ -1711,21 +1707,11 @@ int fib6_del(struct rt6_info *rt, struct nl_info *info)struct rt6_info __rcu **rtp;struct rt6_info __rcu **rtp_next; -#if RT6_DEBUG >=2 -if (rt->dst.obsolete >0 ) { -WARN_ON (fn); -return -ENOENT ; - } -#endif if (!fn || rt == net->ipv6.fib6_null_entry)return -ENOENT ;WARN_ON (!(fn->fn_flags &RTN_RTINFO )); -/* remove cached dst from exception table */ -if (rt->rt6i_flags &RTF_CACHE ) -return rt6_remove_exception_rt (rt); -/* * Walk the leaf entries looking for ourself */
net/ipv6/route.c +74 -63
284 lines not on this page · raw message
Signature · 1 line
2.11.0
RFC PATCH v2 18/21 net/ipv6: introduce fib6_info struct and helpers
In reply to David AhernAdd fib6_info struct and alloc, destroy, hold and release helpers.
--- include/net/ip6_fib.h | 55 ++++++++++++++++++++++++++++++++++++++++++++++ net/ipv6/ip6_fib.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+)
include/net/ip6_fib.h +55 -0
@@ -38,6 +38,7 @@#endif struct rt6_info ; +struct fib6_info ;struct fib6_config {u32 fc_table;
@@ -132,6 +133,46 @@ struct fib6_nh {int nh_weight; }; +struct fib6_info { +struct fib6_table *rt6i_table; +struct fib6_info __rcu *rt6_next; +struct fib6_node __rcu *rt6i_node; + +/* Multipath routes: +* siblings is a list of fib6_info that have the the same metric/weight, +* destination, but not the same gateway. nsiblings is just a cache +* to speed up lookup. +*/ +struct list_head rt6i_siblings; +unsigned int rt6i_nsiblings; + +atomic_t rt6i_ref; +struct inet6_dev *rt6i_idev; +unsigned long expires; +struct dst_metrics *fib6_metrics; +#define fib6_pmtu fib6_metrics->metrics[RTAX_MTU-1] + +struct rt6key rt6i_dst; +u32 rt6i_flags; +struct rt6key rt6i_src; +struct rt6key rt6i_prefsrc; + +struct rt6_info *__percpu *rt6i_pcpu; +struct rt6_exception_bucket __rcu *rt6i_exception_bucket; + +u32 rt6i_metric; +u8 rt6i_protocol; +u8 fib6_type; +u8 exception_bucket_flushed:1 , + should_flush:1 , + dst_nocount:1 , + dst_nopolicy:1 , + dst_host:1 , + unused:3 ; + +struct fib6_nh fib6_nh; +}; +struct rt6_info {struct dst_entry dst;struct rt6_info __rcu *rt6_next;
@@ -291,6 +332,20 @@ static inline void ip6_rt_put(struct rt6_info *rt)void rt6_free_pcpu (struct rt6_info *non_pcpu_rt); +struct rt6_info *fib6_info_alloc (gfp_t gfp_flags); +void fib6_info_destroy (struct rt6_info *f6i); + +static inline void fib6_info_hold (struct rt6_info *f6i) +{ +atomic_inc (&f6i->rt6i_ref); +} + +static inline void fib6_info_release (struct rt6_info *f6i) +{ +if (f6i &&atomic_dec_and_test (&f6i->rt6i_ref)) +fib6_info_destroy (f6i); +} +static inline void rt6_hold (struct rt6_info *rt) {atomic_inc (&rt->rt6i_ref);
net/ipv6/ip6_fib.c +60 -0
66 lines not on this page · raw message
Signature · 1 line
2.11.0
RFC PATCH v2 19/21 net/ipv6: separate handling of FIB entries from dst based routes
In reply to David AhernLast step before flipping the data type for FIB entries:
- use fib6_info_alloc to create FIB entries in ip6_route_info_create and addrconf_dst_alloc
- use fib6_info_release in place of dst_release, ip6_rt_put and rt6_release
- remove the dst_hold before calling __ip6_ins_rt or ip6_del_rt
- when purging routes, drop per-cpu routes
- replace inc and dec of rt6i_ref with fib6_info_hold and fib6_info_release
- use rt->from since it points to the FIB entry
- drop references to exception bucket, fib6_metrics and per-cpu from dst entries (those are relevant for fib entries only)
--- include/net/ip6_fib.h | 4 +- include/net/ip6_route.h | 3 +- net/ipv6/addrconf.c | 18 +++-- net/ipv6/anycast.c | 7 +- net/ipv6/ip6_fib.c | 50 ++++++++------ net/ipv6/ip6_output.c | 3 +- net/ipv6/ndisc.c | 6 +- net/ipv6/route.c | 171 +++++++++++++++++------------------------------- 8 files changed, 110 insertions(+), 152 deletions(-)
include/net/ip6_fib.h +1 -3
@@ -314,9 +314,7 @@ static inline u32 rt6_get_cookie(const struct rt6_info *rt)if (rt->rt6i_flags &RTF_PCPU || (unlikely (!list_empty (&rt->rt6i_uncached)) && rt->from)) - rt = rt->from; - -rt6_get_cookie_safe (rt, &cookie); +rt6_get_cookie_safe (rt->from, &cookie);return cookie; }
include/net/ip6_route.h +1 -2
@@ -114,8 +114,7 @@ static inline int ip6_route_get_saddr(struct net *net, struct rt6_info *rt,unsigned int prefs, struct in6_addr *saddr) { - struct inet6_dev *idev = - rt ?ip6_dst_idev ((struct dst_entry *)rt) :NULL ; + struct inet6_dev *idev = rt ? rt->rt6i_idev : NULL;int err =0 ;if (rt && rt->rt6i_prefsrc.plen)
net/ipv6/addrconf.c +8 -10
@@ -927,7 +927,6 @@ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)pr_warn ("Freeing alive inet6 address %p\n" , ifp);return ; } -ip6_rt_put (ifp->rt);kfree_rcu (ifp, rcu); }
@@ -1114,8 +1113,8 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr,inet6addr_notifier_call_chain (NETDEV_UP , ifa); out:if (unlikely (err <0 )) { -if (rt) -ip6_rt_put (rt); +fib6_info_release (rt); +if (ifa) {if (ifa->idev)in6_dev_put (ifa->idev);
@@ -1203,7 +1202,7 @@ cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, bool del_relse {if (!(rt->rt6i_flags &RTF_EXPIRES ))fib6_set_expires (rt, expires); -ip6_rt_put (rt); +fib6_info_release (rt); } } }
@@ -2387,8 +2386,7 @@ static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx,continue ;if ((rt->rt6i_flags & noflags) !=0 )continue ; -if (!dst_hold_safe (&rt->dst)) - rt =NULL ; +fib6_info_hold (rt);break ; } out:
@@ -2700,7 +2698,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)addrconf_prefix_route (&pinfo->prefix, pinfo->prefix_len, dev, expires, flags,GFP_ATOMIC ); } -ip6_rt_put (rt); +fib6_info_release (rt); }/* Try to figure out our local address for this prefix */
@@ -3369,7 +3367,7 @@ static int fixup_permanent_addr(struct net *net, ifp->rt = rt;spin_unlock (&ifp->lock); -ip6_rt_put (prev); +fib6_info_release (prev); }if (!(ifp->flags &IFA_F_NOPREFIXROUTE )) {
@@ -5653,8 +5651,8 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)ip6_del_rt (net, rt); }if (ifp->rt) { -if (dst_hold_safe (&ifp->rt->dst)) -ip6_del_rt (net, ifp->rt); +ip6_del_rt (net, ifp->rt); + ifp->rt =NULL ; }rt_genid_bump_ipv6 (net);break ;
net/ipv6/anycast.c +3 -4
@@ -213,7 +213,7 @@ static void aca_put(struct ifacaddr6 *ac) {if (refcount_dec_and_test (&ac->aca_refcnt)) {in6_dev_put (ac->aca_idev); -dst_release (&ac->aca_rt->dst); +fib6_info_release (ac->aca_rt);kfree (ac); } }
@@ -231,6 +231,7 @@ static struct ifacaddr6 *aca_alloc(struct rt6_info *rt, aca->aca_addr = *addr;in6_dev_hold (idev); aca->aca_idev = idev; +fib6_info_hold (rt); aca->aca_rt = rt; aca->aca_users =1 ;/* aca_tstamp should be updated upon changes */
@@ -274,7 +275,7 @@ int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr) } aca =aca_alloc (rt, addr);if (!aca) { -ip6_rt_put (rt); +fib6_info_release (rt); err = -ENOMEM ; goto out; }
@@ -330,7 +331,6 @@ int __ipv6_dev_ac_dec(struct inet6_dev *idev, const struct in6_addr *addr)write_unlock_bh (&idev->lock);addrconf_leave_solict (idev, &aca->aca_addr); -dst_hold (&aca->aca_rt->dst);ip6_del_rt (dev_net (idev->dev), aca->aca_rt);aca_put (aca);
@@ -358,7 +358,6 @@ void ipv6_ac_destroy_dev(struct inet6_dev *idev)addrconf_leave_solict (idev, &aca->aca_addr); -dst_hold (&aca->aca_rt->dst);ip6_del_rt (dev_net (idev->dev), aca->aca_rt);aca_put (aca);
net/ipv6/ip6_fib.c +31 -19
127 lines not on this page · raw message
net/ipv6/ip6_output.c +2 -1
@@ -969,7 +969,8 @@ static int ip6_dst_lookup_tail(struct net *net, const struct sock *sk,if (!had_dst) *dst =ip6_route_output (net, sk, fl6); rt = (*dst)->error ?NULL : (struct rt6_info *)*dst; - err =ip6_route_get_saddr (net, rt, &fl6->daddr, + err =ip6_route_get_saddr (net, rt ? rt->from :NULL , + &fl6->daddr, sk ?inet6_sk (sk)->srcprefs :0 , &fl6->saddr);if (err)
net/ipv6/ndisc.c +3 -3
@@ -1283,7 +1283,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)ND_PRINTK (0 , err,"RA: %s got default router without neighbour\n" , __func__); -ip6_rt_put (rt); +fib6_info_release (rt);return ; } }
@@ -1313,7 +1313,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)ND_PRINTK (0 , err,"RA: %s got default router without neighbour\n" , __func__); -ip6_rt_put (rt); +fib6_info_release (rt);return ; } neigh->flags |=NTF_ROUTER ;
@@ -1499,7 +1499,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)ND_PRINTK (2 , warn,"RA: invalid RA options\n" ); } out: -ip6_rt_put (rt); +fib6_info_release (rt);if (neigh)neigh_release (neigh); }
net/ipv6/route.c +61 -110
403 lines not on this page · raw message
Signature · 1 line
2.11.0
RFC PATCH v2 20/21 net/ipv6: Flip FIB entries to fib6_info
In reply to David AhernConvert all code paths referencing a FIB entry from rt6_info to fib6_info.
--- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 64 ++--- include/net/if_inet6.h | 4 +- include/net/ip6_fib.h | 42 ++-- include/net/ip6_route.h | 28 +-- include/net/netns/ipv6.h | 2 +- net/ipv6/addrconf.c | 20 +- net/ipv6/anycast.c | 4 +- net/ipv6/ip6_fib.c | 116 ++++----- net/ipv6/ndisc.c | 2 +- net/ipv6/route.c | 259 +++++++++++---------- 10 files changed, 271 insertions(+), 270 deletions(-)
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +32 -32
@@ -442,7 +442,7 @@ struct mlxsw_sp_fib6_entry {struct mlxsw_sp_rt6 {struct list_head list; -struct rt6_info *rt; +struct fib6_info *rt; };struct mlxsw_sp_lpm_tree {
@@ -3768,7 +3768,7 @@ mlxsw_sp_rt6_nexthop(struct mlxsw_sp_nexthop_group *nh_grp, for (i = 0; i < nh_grp->count; i++) { struct mlxsw_sp_nexthop *nh = &nh_grp->nexthops[i]; - struct rt6_info *rt = mlxsw_sp_rt6->rt; + struct fib6_info *rt = mlxsw_sp_rt6->rt; if (nh->rif && nh->rif->dev == rt->fib6_nh.nh_dev && ipv6_addr_equal((const struct in6_addr *) &nh->gw_addr,
@@ -3854,7 +3854,7 @@ mlxsw_sp_fib6_entry_offload_unset(struct mlxsw_sp_fib_entry *fib_entry) fib6_entry = container_of(fib_entry, struct mlxsw_sp_fib6_entry, common);list_for_each_entry (mlxsw_sp_rt6, &fib6_entry->rt6_list, list) { -struct rt6_info *rt = mlxsw_sp_rt6->rt; +struct fib6_info *rt = mlxsw_sp_rt6->rt; rt->fib6_nh.nh_flags &= ~RTNH_F_OFFLOAD ; }
@@ -4633,7 +4633,7 @@ static void mlxsw_sp_router_fib4_del(struct mlxsw_sp *mlxsw_sp,mlxsw_sp_fib_node_put (mlxsw_sp, fib_node); } -static bool mlxsw_sp_fib6_rt_should_ignore (const struct rt6_info *rt) +static bool mlxsw_sp_fib6_rt_should_ignore (const struct fib6_info *rt) {/* Packets with link-local destination IP arriving to the router * are trapped to the CPU, so no need to program specific routes
@@ -4655,7 +4655,7 @@ static bool mlxsw_sp_fib6_rt_should_ignore(const struct rt6_info *rt)return false; } -static struct mlxsw_sp_rt6 *mlxsw_sp_rt6_create (struct rt6_info *rt) +static struct mlxsw_sp_rt6 *mlxsw_sp_rt6_create (struct fib6_info *rt) {struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
@@ -4668,18 +4668,18 @@ static struct mlxsw_sp_rt6 *mlxsw_sp_rt6_create(struct rt6_info *rt)* memory. */ mlxsw_sp_rt6->rt = rt; -rt6_hold (rt); +fib6_info_hold (rt);return mlxsw_sp_rt6; }#if IS_ENABLED (CONFIG_IPV6 ) -static void mlxsw_sp_rt6_release (struct rt6_info *rt) +static void mlxsw_sp_rt6_release (struct fib6_info *rt) { -rt6_release (rt); +fib6_info_release (rt); }#else -static void mlxsw_sp_rt6_release (struct rt6_info *rt) +static void mlxsw_sp_rt6_release (struct fib6_info *rt) { }#endif
@@ -4690,13 +4690,13 @@ static void mlxsw_sp_rt6_destroy(struct mlxsw_sp_rt6 *mlxsw_sp_rt6)kfree (mlxsw_sp_rt6); } -static bool mlxsw_sp_fib6_rt_can_mp (const struct rt6_info *rt) +static bool mlxsw_sp_fib6_rt_can_mp (const struct fib6_info *rt) {/* RTF_CACHE routes are ignored */ return (rt->rt6i_flags & (RTF_GATEWAY |RTF_ADDRCONF )) ==RTF_GATEWAY ; } -static struct rt6_info * +static struct fib6_info *mlxsw_sp_fib6_entry_rt (const struct mlxsw_sp_fib6_entry *fib6_entry) { return list_first_entry(&fib6_entry->rt6_list, struct mlxsw_sp_rt6,
@@ -4705,7 +4705,7 @@ mlxsw_sp_fib6_entry_rt(const struct mlxsw_sp_fib6_entry *fib6_entry)static struct mlxsw_sp_fib6_entry *mlxsw_sp_fib6_node_mp_entry_find (const struct mlxsw_sp_fib_node *fib_node, -const struct rt6_info *nrt,bool replace) +const struct fib6_info *nrt,bool replace) {struct mlxsw_sp_fib6_entry *fib6_entry;
@@ -4713,7 +4713,7 @@ mlxsw_sp_fib6_node_mp_entry_find(const struct mlxsw_sp_fib_node *fib_node,return NULL ;list_for_each_entry (fib6_entry, &fib_node->entry_list, common.list) { -struct rt6_info *rt =mlxsw_sp_fib6_entry_rt (fib6_entry); +struct fib6_info *rt =mlxsw_sp_fib6_entry_rt (fib6_entry);/* RT6_TABLE_LOCAL and RT6_TABLE_MAIN share the same * virtual router.
@@ -4736,7 +4736,7 @@ mlxsw_sp_fib6_node_mp_entry_find(const struct mlxsw_sp_fib_node *fib_node,static struct mlxsw_sp_rt6 *mlxsw_sp_fib6_entry_rt_find (const struct mlxsw_sp_fib6_entry *fib6_entry, -const struct rt6_info *rt) +const struct fib6_info *rt) {struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
@@ -4749,7 +4749,7 @@ mlxsw_sp_fib6_entry_rt_find(const struct mlxsw_sp_fib6_entry *fib6_entry, }static bool mlxsw_sp_nexthop6_ipip_type (const struct mlxsw_sp *mlxsw_sp, -const struct rt6_info *rt, +const struct fib6_info *rt,enum mlxsw_sp_ipip_type *ret) { return rt->fib6_nh.nh_dev &&
@@ -4759,7 +4759,7 @@ static bool mlxsw_sp_nexthop6_ipip_type(const struct mlxsw_sp *mlxsw_sp,static int mlxsw_sp_nexthop6_type_init (struct mlxsw_sp *mlxsw_sp,struct mlxsw_sp_nexthop_group *nh_grp,struct mlxsw_sp_nexthop *nh, -const struct rt6_info *rt) +const struct fib6_info *rt) {const struct mlxsw_sp_ipip_ops *ipip_ops;struct mlxsw_sp_ipip_entry *ipip_entry;
@@ -4804,7 +4804,7 @@ static void mlxsw_sp_nexthop6_type_fini(struct mlxsw_sp *mlxsw_sp,static int mlxsw_sp_nexthop6_init (struct mlxsw_sp *mlxsw_sp,struct mlxsw_sp_nexthop_group *nh_grp,struct mlxsw_sp_nexthop *nh, -const struct rt6_info *rt) +const struct fib6_info *rt) {struct net_device *dev = rt->fib6_nh.nh_dev;
@@ -4831,7 +4831,7 @@ static void mlxsw_sp_nexthop6_fini(struct mlxsw_sp *mlxsw_sp, }static bool mlxsw_sp_rt6_is_gateway (const struct mlxsw_sp *mlxsw_sp, -const struct rt6_info *rt) +const struct fib6_info *rt) {return rt->rt6i_flags &RTF_GATEWAY ||mlxsw_sp_nexthop6_ipip_type (mlxsw_sp, rt,NULL );
@@ -4862,7 +4862,7 @@ mlxsw_sp_nexthop6_group_create(struct mlxsw_sp *mlxsw_sp, nh_grp->gateway =mlxsw_sp_rt6_is_gateway (mlxsw_sp, mlxsw_sp_rt6->rt); nh_grp->count = fib6_entry->nrt6;for (i =0 ; i < nh_grp->count; i++) { -struct rt6_info *rt = mlxsw_sp_rt6->rt; +struct fib6_info *rt = mlxsw_sp_rt6->rt; nh = &nh_grp->nexthops[i]; err =mlxsw_sp_nexthop6_init (mlxsw_sp, nh_grp, nh, rt);
@@ -4974,7 +4974,7 @@ mlxsw_sp_nexthop6_group_update(struct mlxsw_sp *mlxsw_sp,static int mlxsw_sp_fib6_entry_nexthop_add (struct mlxsw_sp *mlxsw_sp,struct mlxsw_sp_fib6_entry *fib6_entry, -struct rt6_info *rt) +struct fib6_info *rt) {struct mlxsw_sp_rt6 *mlxsw_sp_rt6;int err;
@@ -5002,7 +5002,7 @@ mlxsw_sp_fib6_entry_nexthop_add(struct mlxsw_sp *mlxsw_sp,static void mlxsw_sp_fib6_entry_nexthop_del (struct mlxsw_sp *mlxsw_sp,struct mlxsw_sp_fib6_entry *fib6_entry, -struct rt6_info *rt) +struct fib6_info *rt) {struct mlxsw_sp_rt6 *mlxsw_sp_rt6;
@@ -5018,7 +5018,7 @@ mlxsw_sp_fib6_entry_nexthop_del(struct mlxsw_sp *mlxsw_sp,static void mlxsw_sp_fib6_entry_type_set (struct mlxsw_sp *mlxsw_sp,struct mlxsw_sp_fib_entry *fib_entry, -const struct rt6_info *rt) +const struct fib6_info *rt) {/* Packets hitting RTF_REJECT routes need to be discarded by the * stack. We can rely on their destination device not having a
@@ -5052,7 +5052,7 @@ mlxsw_sp_fib6_entry_rt_destroy_all(struct mlxsw_sp_fib6_entry *fib6_entry)static struct mlxsw_sp_fib6_entry *mlxsw_sp_fib6_entry_create (struct mlxsw_sp *mlxsw_sp,struct mlxsw_sp_fib_node *fib_node, -struct rt6_info *rt) +struct fib6_info *rt) {struct mlxsw_sp_fib6_entry *fib6_entry;struct mlxsw_sp_fib_entry *fib_entry;
@@ -5102,12 +5102,12 @@ static void mlxsw_sp_fib6_entry_destroy(struct mlxsw_sp *mlxsw_sp,static struct mlxsw_sp_fib6_entry *mlxsw_sp_fib6_node_entry_find (const struct mlxsw_sp_fib_node *fib_node, -const struct rt6_info *nrt,bool replace) +const struct fib6_info *nrt,bool replace) {struct mlxsw_sp_fib6_entry *fib6_entry, *fallback =NULL ;list_for_each_entry (fib6_entry, &fib_node->entry_list, common.list) { -struct rt6_info *rt =mlxsw_sp_fib6_entry_rt (fib6_entry); +struct fib6_info *rt =mlxsw_sp_fib6_entry_rt (fib6_entry);if (rt->rt6i_table->tb6_id > nrt->rt6i_table->tb6_id)continue ;
@@ -5132,7 +5132,7 @@ mlxsw_sp_fib6_node_list_insert(struct mlxsw_sp_fib6_entry *new6_entry, bool replace) {struct mlxsw_sp_fib_node *fib_node = new6_entry->common.fib_node; -struct rt6_info *nrt =mlxsw_sp_fib6_entry_rt (new6_entry); +struct fib6_info *nrt =mlxsw_sp_fib6_entry_rt (new6_entry);struct mlxsw_sp_fib6_entry *fib6_entry; fib6_entry =mlxsw_sp_fib6_node_entry_find (fib_node, nrt, replace);
@@ -5147,7 +5147,7 @@ mlxsw_sp_fib6_node_list_insert(struct mlxsw_sp_fib6_entry *new6_entry,struct mlxsw_sp_fib6_entry *last;list_for_each_entry (last, &fib_node->entry_list, common.list) { -struct rt6_info *rt =mlxsw_sp_fib6_entry_rt (last); +struct fib6_info *rt =mlxsw_sp_fib6_entry_rt (last);if (nrt->rt6i_table->tb6_id > rt->rt6i_table->tb6_id)break ;
@@ -5202,7 +5202,7 @@ mlxsw_sp_fib6_node_entry_unlink(struct mlxsw_sp *mlxsw_sp,static struct mlxsw_sp_fib6_entry *mlxsw_sp_fib6_entry_lookup (struct mlxsw_sp *mlxsw_sp, -const struct rt6_info *rt) +const struct fib6_info *rt) {struct mlxsw_sp_fib6_entry *fib6_entry;struct mlxsw_sp_fib_node *fib_node;
@@ -5221,7 +5221,7 @@ mlxsw_sp_fib6_entry_lookup(struct mlxsw_sp *mlxsw_sp,return NULL ;list_for_each_entry (fib6_entry, &fib_node->entry_list, common.list) { -struct rt6_info *iter_rt =mlxsw_sp_fib6_entry_rt (fib6_entry); +struct fib6_info *iter_rt =mlxsw_sp_fib6_entry_rt (fib6_entry); if (rt->rt6i_table->tb6_id == iter_rt->rt6i_table->tb6_id && rt->rt6i_metric == iter_rt->rt6i_metric &&
@@ -5250,7 +5250,7 @@ static void mlxsw_sp_fib6_entry_replace(struct mlxsw_sp *mlxsw_sp, }static int mlxsw_sp_router_fib6_add (struct mlxsw_sp *mlxsw_sp, -struct rt6_info *rt,bool replace) +struct fib6_info *rt,bool replace) {struct mlxsw_sp_fib6_entry *fib6_entry;struct mlxsw_sp_fib_node *fib_node;
@@ -5307,7 +5307,7 @@ static int mlxsw_sp_router_fib6_add(struct mlxsw_sp *mlxsw_sp, }static void mlxsw_sp_router_fib6_del (struct mlxsw_sp *mlxsw_sp, -struct rt6_info *rt) +struct fib6_info *rt) {struct mlxsw_sp_fib6_entry *fib6_entry;struct mlxsw_sp_fib_node *fib_node;
@@ -5752,7 +5752,7 @@ static void mlxsw_sp_router_fib6_event(struct mlxsw_sp_fib_event_work *fib_work, fen6_info = container_of(info, struct fib6_entry_notifier_info, info); fib_work->fen6_info = *fen6_info; -rt6_hold (fib_work->fen6_info.rt); +fib6_info_hold (fib_work->fen6_info.rt);break ; } }
include/net/if_inet6.h +2 -2
@@ -64,7 +64,7 @@ struct inet6_ifaddr {struct delayed_work dad_work;struct inet6_dev *idev; -struct rt6_info *rt; +struct fib6_info *rt;struct hlist_node addr_lst;struct list_head if_list;
@@ -144,7 +144,7 @@ struct ipv6_ac_socklist {struct ifacaddr6 {struct in6_addr aca_addr;struct inet6_dev *aca_idev; -struct rt6_info *aca_rt; +struct fib6_info *aca_rt;struct ifacaddr6 *aca_next;int aca_users;refcount_t aca_refcnt;
include/net/ip6_fib.h +21 -21
121 lines not on this page · raw message
include/net/ip6_route.h +14 -14
@@ -66,7 +66,7 @@ static inline bool rt6_need_strict(const struct in6_addr *daddr) (IPV6_ADDR_MULTICAST |IPV6_ADDR_LINKLOCAL |IPV6_ADDR_LOOPBACK ); } -static inline bool rt6_qualify_for_ecmp (const struct rt6_info *rt) +static inline bool rt6_qualify_for_ecmp (const struct fib6_info *rt) {return (rt->rt6i_flags & (RTF_GATEWAY |RTF_ADDRCONF |RTF_DYNAMIC )) ==RTF_GATEWAY ;
@@ -102,14 +102,14 @@ int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg);int ip6_route_add (struct fib6_config *cfg,gfp_t gfp_flags,struct netlink_ext_ack *extack); -int ip6_ins_rt (struct net *net,struct rt6_info *rt); -int ip6_del_rt (struct net *net,struct rt6_info *rt); +int ip6_ins_rt (struct net *net,struct fib6_info *rt); +int ip6_del_rt (struct net *net,struct fib6_info *rt); -void rt6_flush_exceptions (struct rt6_info *rt); -void rt6_age_exceptions (struct rt6_info *rt,struct fib6_gc_args *gc_args, +void rt6_flush_exceptions (struct fib6_info *rt); +void rt6_age_exceptions (struct fib6_info *rt,struct fib6_gc_args *gc_args,unsigned long now); -static inline int ip6_route_get_saddr (struct net *net,struct rt6_info *rt, +static inline int ip6_route_get_saddr (struct net *net,struct fib6_info *rt,const struct in6_addr *daddr,unsigned int prefs,struct in6_addr *saddr)
@@ -136,9 +136,9 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, struct flowi6 *fl6);void fib6_force_start_gc (struct net *net); -struct rt6_info *addrconf_dst_alloc (struct net *net,struct inet6_dev *idev, -const struct in6_addr *addr,bool anycast, -gfp_t gfp_flags); +struct fib6_info *addrconf_dst_alloc (struct net *net,struct inet6_dev *idev, +const struct in6_addr *addr,bool anycast, +gfp_t gfp_flags);struct rt6_info *ip6_dst_alloc (struct net *net,struct net_device *dev,int flags);
@@ -147,10 +147,10 @@ struct rt6_info *ip6_dst_alloc(struct net *net, struct net_device *dev,* support functions for ND * */ -struct rt6_info *rt6_get_dflt_router (struct net *net, +struct fib6_info *rt6_get_dflt_router (struct net *net,const struct in6_addr *addr,struct net_device *dev); -struct rt6_info *rt6_add_dflt_router (struct net *net, +struct fib6_info *rt6_add_dflt_router (struct net *net,const struct in6_addr *gwaddr,struct net_device *dev,unsigned int pref);
@@ -176,14 +176,14 @@ struct rt6_rtnl_dump_arg {struct net *net; }; -int rt6_dump_route (struct rt6_info *rt,void *p_arg); +int rt6_dump_route (struct fib6_info *rt,void *p_arg);void rt6_mtu_change (struct net_device *dev,unsigned int mtu);void rt6_remove_prefsrc (struct inet6_ifaddr *ifp);void rt6_clean_tohost (struct net *net,struct in6_addr *gateway);void rt6_sync_up (struct net_device *dev,unsigned int nh_flags);void rt6_disable_ip (struct net_device *dev,unsigned long event);void rt6_sync_down_dev (struct net_device *dev,unsigned long event); -void rt6_multipath_rebalance (struct rt6_info *rt); +void rt6_multipath_rebalance (struct fib6_info *rt);static inline const struct rt6_info *skb_rt6_info (const struct sk_buff *skb) {
@@ -265,7 +265,7 @@ static inline struct in6_addr *rt6_nexthop(struct rt6_info *rt,return daddr; } -static inline bool rt6_duplicate_nexthop (struct rt6_info *a,struct rt6_info *b) +static inline bool rt6_duplicate_nexthop (struct fib6_info *a,struct fib6_info *b) {return a->fib6_nh.nh_dev == b->fib6_nh.nh_dev && a->rt6i_idev == b->rt6i_idev &&
include/net/netns/ipv6.h +1 -1
@@ -60,7 +60,7 @@ struct netns_ipv6 {#endif struct xt_table *ip6table_nat;#endif -struct rt6_info *fib6_null_entry; +struct fib6_info *fib6_null_entry;struct rt6_info *ip6_null_entry;struct rt6_statistics *rt6_stats;struct timer_list ip6_fib_timer;
net/ipv6/addrconf.c +10 -10
@@ -179,7 +179,7 @@ static void addrconf_type_change(struct net_device *dev, unsigned long event);static int addrconf_ifdown (struct net_device *dev,int how); -static struct rt6_info *addrconf_get_prefix_route (const struct in6_addr *pfx, +static struct fib6_info *addrconf_get_prefix_route (const struct in6_addr *pfx,int plen,const struct net_device *dev,u32 flags,u32 noflags);
@@ -1005,7 +1005,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr,gfp_t gfp_flags = can_block ?GFP_KERNEL :GFP_ATOMIC ;struct net *net =dev_net (idev->dev);struct inet6_ifaddr *ifa =NULL ; -struct rt6_info *rt =NULL ; +struct fib6_info *rt =NULL ;int err =0 ;int addr_type =ipv6_addr_type (addr);
@@ -1190,7 +1190,7 @@ check_cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long *expires)static void cleanup_prefix_route (struct inet6_ifaddr *ifp,unsigned long expires,bool del_rt) { -struct rt6_info *rt; +struct fib6_info *rt; rt = addrconf_get_prefix_route(&ifp->addr, ifp->prefix_len,
@@ -2360,13 +2360,13 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev, } -static struct rt6_info *addrconf_get_prefix_route (const struct in6_addr *pfx, +static struct fib6_info *addrconf_get_prefix_route (const struct in6_addr *pfx,int plen,const struct net_device *dev,u32 flags,u32 noflags) {struct fib6_node *fn; -struct rt6_info *rt =NULL ; +struct fib6_info *rt =NULL ;struct fib6_table *table;u32 tb_id =l3mdev_fib_table (dev) ? :RT6_TABLE_PREFIX ;
@@ -2654,7 +2654,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)*/ if (pinfo->onlink) { -struct rt6_info *rt; +struct fib6_info *rt;unsigned long rt_expires;/* Avoid arithmetic overflow. Really, we could
@@ -3354,7 +3354,7 @@ static int fixup_permanent_addr(struct net *net,* case regenerate the host route. */ if (!ifp->rt || !ifp->rt->rt6i_node) { -struct rt6_info *rt, *prev; +struct fib6_info *rt, *prev; rt =addrconf_dst_alloc (net, idev, &ifp->addr, false,GFP_ATOMIC );
@@ -3721,7 +3721,7 @@ static int addrconf_ifdown(struct net_device *dev, int how) keep_addr = (!how && _keep_addr >0 && !idev->cnf.disable_ipv6);list_for_each_entry_safe (ifa, tmp, &idev->addr_list, if_list) { -struct rt6_info *rt =NULL ; +struct fib6_info *rt =NULL ;bool keep;addrconf_del_dad_work (ifa);
@@ -5643,7 +5643,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)addrconf_leave_anycast (ifp);addrconf_leave_solict (ifp->idev, &ifp->addr);if (!ipv6_addr_any (&ifp->peer_addr)) { -struct rt6_info *rt; +struct fib6_info *rt; rt =addrconf_get_prefix_route (&ifp->peer_addr,128 , ifp->idev->dev,0 ,0 );
@@ -5999,7 +5999,7 @@ void addrconf_disable_policy_idev(struct inet6_dev *idev, int val)list_for_each_entry (ifa, &idev->addr_list, if_list) {spin_lock (&ifa->lock);if (ifa->rt) { -struct rt6_info *rt = ifa->rt; +struct fib6_info *rt = ifa->rt;int cpu;rcu_read_lock ();
net/ipv6/anycast.c +2 -2
@@ -218,7 +218,7 @@ static void aca_put(struct ifacaddr6 *ac) } } -static struct ifacaddr6 *aca_alloc (struct rt6_info *rt, +static struct ifacaddr6 *aca_alloc (struct fib6_info *rt,const struct in6_addr *addr) {struct inet6_dev *idev = rt->rt6i_idev;
@@ -247,7 +247,7 @@ static struct ifacaddr6 *aca_alloc(struct rt6_info *rt,int __ipv6_dev_ac_inc (struct inet6_dev *idev,const struct in6_addr *addr) {struct ifacaddr6 *aca; -struct rt6_info *rt; +struct fib6_info *rt;struct net *net;int err;
net/ipv6/ip6_fib.c +58 -58
411 lines not on this page · raw message
net/ipv6/ndisc.c +1 -1
@@ -1155,7 +1155,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header (skb);struct neighbour *neigh =NULL ;struct inet6_dev *in6_dev; -struct rt6_info *rt =NULL ; +struct fib6_info *rt =NULL ;struct net *net;int lifetime;struct ndisc_options ndopts;
net/ipv6/route.c +130 -129
867 lines not on this page · raw message
Signature · 1 line
2.11.0
RFC PATCH v2 21/21 net/ipv6: Remove unused code and variables for rt6_info
In reply to David AhernDrop unneeded elements from rt6_info struct and rearrange layout to something more relevant for the data path.
--- include/net/ip6_fib.h | 60 +++---------------------------------------------- net/ipv6/ip6_fib.c | 22 ------------------ net/ipv6/route.c | 27 ++-------------------- net/ipv6/xfrm6_policy.c | 2 -- 4 files changed, 5 insertions(+), 106 deletions(-)
include/net/ip6_fib.h +3 -57
@@ -175,58 +175,20 @@ struct fib6_info {struct rt6_info {struct dst_entry dst; -struct rt6_info __rcu *rt6_next;struct fib6_info *from; -/* -* Tail elements of dst_entry (__refcnt etc.) -* and these elements (rarely used in hot path) are in -* the same cache line. -*/ -struct fib6_table *rt6i_table; -struct fib6_node __rcu *rt6i_node; - +struct rt6key rt6i_dst; +struct rt6key rt6i_src;struct in6_addr rt6i_gateway; - -/* Multipath routes: -* siblings is a list of rt6_info that have the the same metric/weight, -* destination, but not the same gateway. nsiblings is just a cache -* to speed up lookup. -*/ -struct list_head rt6i_siblings; -unsigned int rt6i_nsiblings; - -atomic_t rt6i_ref; - -/* These are in a separate cache line. */ -struct rt6key rt6i_dst____cacheline_aligned_in_smp ; +struct inet6_dev *rt6i_idev;u32 rt6i_flags; -struct rt6key rt6i_src;struct rt6key rt6i_prefsrc;struct list_head rt6i_uncached;struct uncached_list *rt6i_uncached_list; -struct inet6_dev *rt6i_idev; -struct rt6_info *__percpu *rt6i_pcpu; -struct rt6_exception_bucket __rcu *rt6i_exception_bucket; - -u32 rt6i_metric;/* more non-fragment space at head required */ unsigned short rt6i_nfheader_len; -u8 rt6i_protocol; -u8 fib6_type; -u8 exception_bucket_flushed:1 , - should_flush:1 , - dst_nocount:1 , - dst_nopolicy:1 , - dst_host:1 , - unused:3 ; - -unsigned long expires; -struct dst_metrics *fib6_metrics; -#define fib6_pmtu fib6_metrics->metrics[RTAX_MTU-1] -struct fib6_nh fib6_nh; };#define for_each_fib6_node_rt_rcu (fn) \
@@ -328,8 +290,6 @@ static inline void ip6_rt_put(struct rt6_info *rt)dst_release (&rt->dst); } -void rt6_free_pcpu (struct rt6_info *non_pcpu_rt); -struct fib6_info *fib6_info_alloc (gfp_t gfp_flags);void fib6_info_destroy (struct fib6_info *f6i);
@@ -344,20 +304,6 @@ static inline void fib6_info_release(struct fib6_info *f6i)fib6_info_destroy (f6i); } -static inline void rt6_hold (struct rt6_info *rt) -{ -atomic_inc (&rt->rt6i_ref); -} - -static inline void rt6_release (struct rt6_info *rt) -{ -if (atomic_dec_and_test (&rt->rt6i_ref)) { -rt6_free_pcpu (rt); -dst_dev_put (&rt->dst); -dst_release (&rt->dst); - } -} -enum fib6_walk_state {#ifdef CONFIG_IPV6_SUBTREES FWS_S ,
net/ipv6/ip6_fib.c +0 -22
@@ -235,28 +235,6 @@ static void node_free(struct net *net, struct fib6_node *fn) net->ipv6.rt6_stats->fib_nodes--; } -void rt6_free_pcpu (struct rt6_info *non_pcpu_rt) -{ -int cpu; - -if (!non_pcpu_rt->rt6i_pcpu) -return ; - -for_each_possible_cpu (cpu) { -struct rt6_info **ppcpu_rt; -struct rt6_info *pcpu_rt; - - ppcpu_rt =per_cpu_ptr (non_pcpu_rt->rt6i_pcpu, cpu); - pcpu_rt = *ppcpu_rt; -if (pcpu_rt) { -dst_dev_put (&pcpu_rt->dst); -dst_release (&pcpu_rt->dst); - *ppcpu_rt =NULL ; - } - } -} -EXPORT_SYMBOL_GPL (rt6_free_pcpu); -static void fib6_free_table (struct fib6_table *table) {inetpeer_invalidate_tree (&table->tb6_peers);
net/ipv6/route.c +2 -25
@@ -302,10 +302,6 @@ static const struct rt6_info ip6_null_entry_template = { .output = ip6_pkt_discard_out, }, .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), - .rt6i_protocol = RTPROT_KERNEL, - .rt6i_metric = ~(u32) 0, - .rt6i_ref = ATOMIC_INIT(1), - .fib6_type = RTN_UNREACHABLE, };#ifdef CONFIG_IPV6_MULTIPLE_TABLES
@@ -320,10 +316,6 @@ static const struct rt6_info ip6_prohibit_entry_template = { .output = ip6_pkt_prohibit_out, }, .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), - .rt6i_protocol = RTPROT_KERNEL, - .rt6i_metric = ~(u32) 0, - .rt6i_ref = ATOMIC_INIT(1), - .fib6_type = RTN_PROHIBIT, }; static const struct rt6_info ip6_blk_hole_entry_template = {
@@ -336,10 +328,6 @@ static const struct rt6_info ip6_blk_hole_entry_template = { .output = dst_discard_out, }, .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), - .rt6i_protocol = RTPROT_KERNEL, - .rt6i_metric = ~(u32) 0, - .rt6i_ref = ATOMIC_INIT(1), - .fib6_type = RTN_BLACKHOLE, };#endif
@@ -349,7 +337,6 @@ static void rt6_info_init(struct rt6_info *rt)struct dst_entry *dst = &rt->dst;memset (dst +1 ,0 ,sizeof (*rt) -sizeof (*dst)); -INIT_LIST_HEAD (&rt->rt6i_siblings);INIT_LIST_HEAD (&rt->rt6i_uncached); }
@@ -999,12 +986,10 @@ static void ip6_rt_copy_init(struct rt6_info *rt, struct fib6_info *ort) rt->rt6i_gateway = ort->fib6_nh.nh_gw; rt->rt6i_flags = ort->rt6i_flags;rt6_set_from (rt, ort); - rt->rt6i_metric = ort->rt6i_metric;#ifdef CONFIG_IPV6_SUBTREES rt->rt6i_src = ort->rt6i_src;#endif rt->rt6i_prefsrc = ort->rt6i_prefsrc; - rt->rt6i_table = ort->rt6i_table; rt->dst.lwtstate =lwtstate_get (ort->fib6_nh.nh_lwtstate); }
@@ -1183,7 +1168,6 @@ static struct rt6_info *ip6_rt_cache_alloc(struct fib6_info *ort,ip6_rt_copy_init (rt, ort); rt->rt6i_flags |=RTF_CACHE ; - rt->rt6i_metric =0 ; rt->dst.flags |=DST_HOST ; rt->rt6i_dst.addr = *daddr; rt->rt6i_dst.plen =128 ;
@@ -1216,7 +1200,6 @@ static struct rt6_info *ip6_rt_pcpu_alloc(struct fib6_info *rt)if (!pcpu_rt)return NULL ;ip6_rt_copy_init (pcpu_rt, rt); - pcpu_rt->rt6i_protocol = rt->rt6i_protocol; pcpu_rt->rt6i_flags |=RTF_PCPU ;return pcpu_rt; }
@@ -1270,9 +1253,8 @@ static void rt6_remove_exception(struct rt6_exception_bucket *bucket,return ; net =dev_net (rt6_ex->rt6i->dst.dev); - rt6_ex->rt6i->rt6i_node =NULL ;hlist_del_rcu (&rt6_ex->hlist); -ip6_rt_put (rt6_ex->rt6i); +dst_release (&rt6_ex->rt6i->dst);kfree_rcu (rt6_ex, rcu);WARN_ON_ONCE (!bucket->depth); bucket->depth--;
@@ -1454,8 +1436,6 @@ static int rt6_insert_exception(struct rt6_info *nrt, } rt6_ex->rt6i = nrt; rt6_ex->stamp = jiffies; -atomic_inc (&nrt->rt6i_ref); - nrt->rt6i_node = ort->rt6i_node;hlist_add_head_rcu (&rt6_ex->hlist, &bucket->chain); bucket->depth++; net->ipv6.rt6_stats->fib_rt_cache++;
@@ -2089,7 +2069,6 @@ struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_ori rt->rt6i_idev =in6_dev_get (loopback_dev); rt->rt6i_gateway = ort->rt6i_gateway; rt->rt6i_flags = ort->rt6i_flags & ~RTF_PCPU ; - rt->rt6i_metric =0 ;memcpy (&rt->rt6i_dst, &ort->rt6i_dst,sizeof (struct rt6key ));#ifdef CONFIG_IPV6_SUBTREES
@@ -2214,8 +2193,7 @@ static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu)static bool rt6_cache_allowed_for_pmtu (const struct rt6_info *rt) {return !(rt->rt6i_flags &RTF_CACHE ) && - (rt->rt6i_flags &RTF_PCPU || -rcu_access_pointer (rt->rt6i_node)); + (rt->rt6i_flags &RTF_PCPU || rt->from); } static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
@@ -3257,7 +3235,6 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buif (on_link) nrt->rt6i_flags &= ~RTF_GATEWAY ; - nrt->rt6i_protocol =RTPROT_REDIRECT ; nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;/* No need to remove rt from the exception table if rt is
net/ipv6/xfrm6_policy.c +0 -2
@@ -107,8 +107,6 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,* it was magically lost, so this code needs audit */ xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTF_ANYCAST |RTF_LOCAL ); - xdst->u.rt6.rt6i_metric = rt->rt6i_metric; - xdst->u.rt6.rt6i_node = rt->rt6i_node; xdst->route_cookie =rt6_get_cookie (rt); xdst->u.rt6.rt6i_gateway = rt->rt6i_gateway; xdst->u.rt6.rt6i_dst = rt->rt6i_dst;
Signature · 1 line
2.11.0
David Miller
maintainerFrom: David Ahern <[email protected]>
Date: Sun, 18 Mar 2018 20:36:01 -0700
Quoted 10 lines
RFC v2 changes
- improved commit messages
- move common metrics code fromdst.ctonet/ipv4/metrics.c(comment from DaveM)
- address comments from Wei Wang and Martin KaFai Lau (let me know if I missed something)
- fixes detected by kernel test robots
+ addedfib6_metric_setto change metric on a FIB entry which could be pointing to read-onlydst_default_metrics
+ 0day testing found a problem with an intermediate patch; added
Quoted 3 lines
dst_hold_safe on rt->from. Code is removed 3 patches later- allow cacheinfo to handle NULL dst; means only expires is pushed to userspace
Series looks great to me.
Nice work David.
Re: [PATCH RFC v2 net-next 19/21] net/ipv6: separate handling of FIB entries from dst based routes
In reply to David Ahernnet/ipv6/route.c static void ip6_dst_destroy(struct dst_entry *dst) · line 416
Quoted 13 lines · David Ahern
net/ipv6/route.c +0
-9@@ -405,18 +383,9 @@ static void ip6_dst_destroy(struct dst_entry *dst) rt->rt6i_idev =NULL ;in6_dev_put (idev); } - bucket =rcu_dereference_protected (rt->rt6i_exception_bucket,1 ); -if (bucket) { - rt->rt6i_exception_bucket =NULL ; -kfree (bucket); - } - - m = rt->fib6_metrics; -if (m != &dst_default_metrics &&refcount_dec_and_test (&m->refcnt)) -kfree (m);
You remove this...
net/ipv6/route.c static void ip6_dst_destroy(struct dst_entry *dst) · line 388
Quoted 4 lines
net/ipv6/route.c +1
-1rt->from =NULL ; -dst_release (&from->dst); +fib6_info_release (from);
Yet fib6_info_release() doesn't take care of it (unlike the IPv4 equivalent), which means you're leaking the metrics.
Quoted 1 line
(quoted diff) +0
-0}
Quoted 4 lines · David Ahern
This set is the first of many changes to improve the scalability of the IPv6 code. Follow on changes include:
- consolidating duplicatefib6_inforeferences like IPv4 does with duplicatefib_info
Before that you need to further break fib6_info into fib6_info and fib6_alias, or I misunderstood you?
Quoted 9 lines · Ido Schimmel
Quoted 4 lines · David Ahern
This set is the first of many changes to improve the scalability of the IPv6 code. Follow on changes include:
- consolidating duplicatefib6_inforeferences like IPv4 does with duplicatefib_infoBefore that you need to further break
fib6_infointofib6_infoandfib6_alias, or I misunderstood you?
I was only listing the high level intent - to consolidate duplication. I have not looked into that step yet, but I suspect that split can be done in the same patch set as consolidating duplicate fib6_info.
As you know, my preference is to move to nexthop objects (makes fib6_nh optional). I have IPv4 done; IPv6 requires this patch set. To get there the patch sequence is:
1. separate data structures for fib and dst paths (this set),
2. cleanup set on top of this one (separate set only because this one is at 21 patches), and
3. nexthop API.
Re: [PATCH RFC v2 net-next 19/21] net/ipv6: separate handling of FIB entries from dst based routes
In reply to Ido SchimmelQuoted 18 lines · Ido Schimmel
net/ipv6/route.c static void ip6_dst_destroy(struct dst_entry *dst) · line 416
Quoted 13 lines · David Ahern
net/ipv6/route.c +0
-9@@ -405,18 +383,9 @@ static void ip6_dst_destroy(struct dst_entry *dst) rt->rt6i_idev =NULL ;in6_dev_put (idev); } - bucket =rcu_dereference_protected (rt->rt6i_exception_bucket,1 ); -if (bucket) { - rt->rt6i_exception_bucket =NULL ; -kfree (bucket); - } - - m = rt->fib6_metrics; -if (m != &dst_default_metrics &&refcount_dec_and_test (&m->refcnt)) -kfree (m);You remove this...
Quoted 1 line
Quoted 8 lines
net/ipv6/route.c static void ip6_dst_destroy(struct dst_entry *dst) · line 388
Quoted 3 lines
net/ipv6/route.c +1
-1rt->from =NULL ; -dst_release (&from->dst); +fib6_info_release (from);Yet
fib6_info_release()doesn't take care of it (unlike the IPv4 equivalent), which means you're leaking the metrics.Quoted 1 line
}
ok, I'll take a look. I thought I verified both paths (fib6_info and dst) were freeing the metrics.
Quoted 7 lines · David Ahern
Quoted 6 lines · Ido Schimmel
Quoted 4 lines · David Ahern
This set is the first of many changes to improve the scalability of the IPv6 code. Follow on changes include:
- consolidating duplicatefib6_inforeferences like IPv4 does with duplicatefib_info
Quoted 7 lines
Quoted 3 lines
Before that you need to further break
fib6_infointofib6_infoandfib6_alias, or I misunderstood you?I was only listing the high level intent - to consolidate duplication. I have not looked into that step yet, but I suspect that split can be done in the same patch set as consolidating duplicate
fib6_info.
I don't think you can perform consolidation of fib6_info as long as it describes both the route and the nexthop info.
Quoted 2 lines
As you know, my preference is to move to nexthop objects (makes
fib6_nhoptional). I have IPv4 done; IPv6 requires this patch set.
After going over your presentation [1] I was under the impression that the fib6_info will be optional, not fib6_nh: "Idea is similar to adding id to fib_info that is exposed to userspace. Subsequent routes pass id to avoid fib_info overhead".
But I think misunderstood you. You want to introduce the nexthop API that will allow you to have multiple fib6_info pointing to the same fib6_nh?
1. http://vger.kernel.org/netconf2017_files/nexthop-objects.pdf
Re: [PATCH RFC v2 net-next 19/21] net/ipv6: separate handling of FIB entries from dst based routes
In reply to David AhernQuoted 26 lines · David Ahern
Quoted 25 lines · Ido Schimmel
net/ipv6/route.c static void ip6_dst_destroy(struct dst_entry *dst) · line 416
Quoted 13 lines · David Ahern
net/ipv6/route.c +0
-9@@ -405,18 +383,9 @@ static void ip6_dst_destroy(struct dst_entry *dst) rt->rt6i_idev =NULL ;in6_dev_put (idev); } - bucket =rcu_dereference_protected (rt->rt6i_exception_bucket,1 ); -if (bucket) { - rt->rt6i_exception_bucket =NULL ; -kfree (bucket); - } - - m = rt->fib6_metrics; -if (m != &dst_default_metrics &&refcount_dec_and_test (&m->refcnt)) -kfree (m);You remove this...
net/ipv6/route.c static void ip6_dst_destroy(struct dst_entry *dst) · line 388
Quoted 4 lines
net/ipv6/route.c +1
-1rt->from =NULL ; -dst_release (&from->dst); +fib6_info_release (from);Yet
fib6_info_release()doesn't take care of it (unlike the IPv4 equivalent), which means you're leaking the metrics.
Quoted 4 lines
Quoted 1 line
Review static void ip6_dst_destroy(struct dst_entry *dst) · line 388
Quoted 1 line
(quoted diff) +0
-0}ok, I'll take a look. I thought I verified both paths (
fib6_infoand dst) were freeing the metrics.
I get this from kmemleak (applied your patchset on top of fe2d55d295cf):
unreferenced object 0xffff88004e2c16c8 (size 96):
comm "systemd-network", pid 1255, jiffies 4295166424 (age 957.858s) hex dump (first 32 bytes):
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace:ip6_route_info_create (/net/ipv6/route.c:2849)ip6_route_add (/net/ipv6/route.c:2975)inet6_rtm_newroute (/net/ipv6/route.c:4357)rtnetlink_rcv_msg (/net/core/rtnetlink.c:4643)netlink_rcv_skb (/net/netlink/af_netlink.c:2445)netlink_unicast (/net/netlink/af_netlink.c:1309 /net/netlink/af_netlink.c:1334) netlink_sendmsg (/net/netlink/af_netlink.c:1897)sock_sendmsg (/net/socket.c:630 /net/socket.c:639)SYSC_sendto (/net/socket.c:1748)do_syscall_64 (/arch/x86/entry/common.c:287) entry_SYSCALL_64_after_hwframe (/arch/x86/entry/entry_64.S:239) 0xffffffffffffffff (/./include/asm-generic/sections.h:42)
Re: [PATCH RFC v2 net-next 19/21] net/ipv6: separate handling of FIB entries from dst based routes
Quoted 16 lines · Ido Schimmel
Quoted 3 lines
ok, I'll take a look. I thought I verified both paths (
fib6_infoand dst) were freeing the metrics.I get this from kmemleak (applied your patchset on top of
fe2d55d295cf):unreferenced object
0xffff88004e2c16c8(size 96):
comm "systemd-network", pid 1255, jiffies 4295166424 (age 957.858s) hex dump (first 32 bytes):
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace:ip6_route_info_create(/net/ipv6/route.c:2849)ip6_route_add(/net/ipv6/route.c:2975)inet6_rtm_newroute(/net/ipv6/route.c:4357)rtnetlink_rcv_msg(/net/core/rtnetlink.c:4643)
Quoted 9 lines
netlink_rcv_skb(/net/netlink/af_netlink.c:2445)netlink_unicast(/net/netlink/af_netlink.c:1309 /net/netlink/af_netlink.c:1334)netlink_sendmsg(/net/netlink/af_netlink.c:1897)sock_sendmsg(/net/socket.c:630 /net/socket.c:639)SYSC_sendto(/net/socket.c:1748)do_syscall_64(/arch/x86/entry/common.c:287)entry_SYSCALL_64_after_hwframe(/arch/x86/entry/entry_64.S:239)0xffffffffffffffff(/./include/asm-generic/sections.h:42)
Thanks for confirming. I'll take care of it.
Quoted 7 lines · Ido Schimmel
Quoted 2 lines
As you know, my preference is to move to nexthop objects (makes
fib6_nhoptional). I have IPv4 done; IPv6 requires this patch set.After going over your presentation [1] I was under the impression that the
fib6_infowill be optional, notfib6_nh: "Idea is similar to adding id tofib_infothat is exposed to userspace. Subsequent routes pass id to avoidfib_infooverhead".
Just using that as an analogy to explain the idea in terms of something that already exists.
Quoted 7 lines
But I think misunderstood you. You want to introduce the nexthop API that will allow you to have multiple
fib6_infopointing to the samefib6_nh?1. http://vger.kernel.org/netconf2017_files/nexthop-objects.pdf
I see nexthop specs as device, gateway, lwtunnel_state and flags. That's the basic building block. A nexthop group is multiple nexthops where each nexthop in the group as its own weight.
The fib_info struct has more than that -- data unrelated to a netxthop and is really a next level struct.