Message ID | 20180225194730.30063-8-dsahern@gmail.com |
---|---|
State | RFC, archived |
Delegated to: | David Miller |
Headers | show |
Series | net/ipv6: Separate data structures for FIB and data path | expand |
On Sun, Feb 25, 2018 at 11:47 AM, David Ahern <dsahern@gmail.com> wrote: > Introduce 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. > My understanding is that after your whole patch series, sibling routes will still have their own fib6_info. Does it make sense to make this fib6_nh as an array in fib6_info so that sibling routes will share fib6_info but will have their own fib6_nh as a future improvement? It matches ipv4 behavior. And I think it will make the sibling route handling code easier? > Signed-off-by: David Ahern <dsahern@gmail.com> > --- > .../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 | 164 ++++++++++++--------- > 6 files changed, 127 insertions(+), 99 deletions(-) > > diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c > index 05146970c19c..90d01df783b3 100644 > --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c > +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c > @@ -2700,9 +2700,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; > @@ -2768,7 +2768,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; > } > > @@ -3766,9 +3766,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; > } > @@ -3825,7 +3825,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; > } > > @@ -3835,9 +3835,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; > } > } > > @@ -3852,7 +3852,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; > } > } > > @@ -4748,8 +4748,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, > @@ -4759,7 +4759,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; > > @@ -4802,11 +4802,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); > diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h > index 4badcf105bd9..7678ae3de44a 100644 > --- a/include/net/ip6_fib.h > +++ b/include/net/ip6_fib.h > @@ -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) \ > diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h > index ef0d8977e2d0..bd82ec4a57e6 100644 > --- a/include/net/ip6_route.h > +++ b/include/net/ip6_route.h > @@ -263,9 +263,9 @@ 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 > diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c > index 82862d3f0295..eeecef2b83a4 100644 > --- a/net/ipv6/addrconf.c > +++ b/net/ipv6/addrconf.c > @@ -2344,7 +2344,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; > diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c > index 51d2d5a7ba89..134d86483f3c 100644 > --- a/net/ipv6/ip6_fib.c > +++ b/net/ipv6/ip6_fib.c > @@ -2213,6 +2213,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); > > @@ -2222,14 +2223,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; > } > diff --git a/net/ipv6/route.c b/net/ipv6/route.c > index 2de9af0bead1..ff809ee930c7 100644 > --- a/net/ipv6/route.c > +++ b/net/ipv6/route.c > @@ -464,12 +464,15 @@ static struct rt6_info *rt6_multipath_select(struct rt6_info *match, > if (!fl6->mp_hash) > fl6->mp_hash = rt6_multipath_hash(fl6, NULL); > > - if (fl6->mp_hash <= atomic_read(&match->rt6i_nh_upper_bound)) > + if (fl6->mp_hash <= atomic_read(&match->fib6_nh.nh_upper_bound)) > return match; > > list_for_each_entry_safe(sibling, next_sibling, &match->rt6i_siblings, > rt6i_siblings) { > - if (fl6->mp_hash > atomic_read(&sibling->rt6i_nh_upper_bound)) > + int nh_upper_bound; > + > + nh_upper_bound = atomic_read(&sibling->fib6_nh.nh_upper_bound); > + if (fl6->mp_hash > nh_upper_bound) > continue; > if (rt6_score_route(sibling, oif, strict) < 0) > break; > @@ -493,13 +496,14 @@ static inline struct rt6_info *rt6_device_match(struct net *net, > struct rt6_info *local = NULL; > struct rt6_info *sprt; > > - if (!oif && ipv6_addr_any(saddr) && !(rt->rt6i_nh_flags & RTNH_F_DEAD)) > + if (!oif && ipv6_addr_any(saddr) && > + !(rt->fib6_nh.nh_flags & RTNH_F_DEAD)) > return rt; > > for (sprt = rt; sprt; sprt = rcu_dereference(sprt->rt6_next)) { > - struct net_device *dev = sprt->dst.dev; > + const struct net_device *dev = sprt->fib6_nh.nh_dev; > > - if (sprt->rt6i_nh_flags & RTNH_F_DEAD) > + if (sprt->fib6_nh.nh_flags & RTNH_F_DEAD) > continue; > > if (oif) { > @@ -531,7 +535,7 @@ static inline struct rt6_info *rt6_device_match(struct net *net, > return net->ipv6.ip6_null_entry; > } > > - return rt->rt6i_nh_flags & RTNH_F_DEAD ? net->ipv6.ip6_null_entry : rt; > + return rt->fib6_nh.nh_flags & RTNH_F_DEAD ? net->ipv6.ip6_null_entry : rt; > } > > #ifdef CONFIG_IPV6_ROUTER_PREF > @@ -556,7 +560,10 @@ static void rt6_probe_deferred(struct work_struct *w) > static void rt6_probe(struct rt6_info *rt) > { > struct __rt6_probe_work *work; > + const struct in6_addr *nh_gw; > struct neighbour *neigh; > + struct net_device *dev; > + > /* > * Okay, this does not seem to be appropriate > * for now, however, we need to check if it > @@ -567,8 +574,11 @@ static void rt6_probe(struct rt6_info *rt) > */ > if (!rt || !(rt->rt6i_flags & RTF_GATEWAY)) > return; > + > + nh_gw = &rt->fib6_nh.nh_gw; > + dev = rt->fib6_nh.nh_dev; > rcu_read_lock_bh(); > - neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway); > + neigh = __ipv6_neigh_lookup_noref(dev, nh_gw); > if (neigh) { > if (neigh->nud_state & NUD_VALID) > goto out; > @@ -590,9 +600,9 @@ static void rt6_probe(struct rt6_info *rt) > > if (work) { > INIT_WORK(&work->work, rt6_probe_deferred); > - work->target = rt->rt6i_gateway; > - dev_hold(rt->dst.dev); > - work->dev = rt->dst.dev; > + work->target = *nh_gw; > + dev_hold(dev); > + work->dev = dev; > schedule_work(&work->work); > } > > @@ -610,7 +620,8 @@ static inline void rt6_probe(struct rt6_info *rt) > */ > static inline int rt6_check_dev(struct rt6_info *rt, int oif) > { > - struct net_device *dev = rt->dst.dev; > + const struct net_device *dev = rt->fib6_nh.nh_dev; > + > if (!oif || dev->ifindex == oif) > return 2; > if ((dev->flags & IFF_LOOPBACK) && > @@ -621,15 +632,16 @@ static inline int rt6_check_dev(struct rt6_info *rt, int oif) > > static inline enum rt6_nud_state rt6_check_neigh(struct rt6_info *rt) > { > - struct neighbour *neigh; > enum rt6_nud_state ret = RT6_NUD_FAIL_HARD; > + struct neighbour *neigh; > > if (rt->rt6i_flags & RTF_NONEXTHOP || > !(rt->rt6i_flags & RTF_GATEWAY)) > return RT6_NUD_SUCCEED; > > rcu_read_lock_bh(); > - neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway); > + neigh = __ipv6_neigh_lookup_noref(rt->fib6_nh.nh_dev, > + &rt->fib6_nh.nh_gw); > if (neigh) { > read_lock(&neigh->lock); > if (neigh->nud_state & NUD_VALID) > @@ -677,11 +689,11 @@ static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict, > bool match_do_rr = false; > struct inet6_dev *idev = rt->rt6i_idev; > > - if (rt->rt6i_nh_flags & RTNH_F_DEAD) > + if (rt->fib6_nh.nh_flags & RTNH_F_DEAD) > goto out; > > if (idev->cnf.ignore_routes_with_linkdown && > - rt->rt6i_nh_flags & RTNH_F_LINKDOWN && > + rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN && > !(strict & RT6_LOOKUP_F_IGNORE_LINKSTATE)) > goto out; > > @@ -886,7 +898,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, > /* 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; > + struct net_device *dev = rt->fib6_nh.nh_dev; > > if (rt->rt6i_flags & (RTF_LOCAL | RTF_ANYCAST)) { > /* for copies of local routes, dst->dev needs to be the > @@ -926,7 +938,7 @@ static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort) > if (rt->rt6i_idev) > in6_dev_hold(rt->rt6i_idev); > rt->dst.lastuse = jiffies; > - rt->rt6i_gateway = ort->rt6i_gateway; > + 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; > @@ -935,7 +947,7 @@ static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort) > #endif > rt->rt6i_prefsrc = ort->rt6i_prefsrc; > rt->rt6i_table = ort->rt6i_table; > - rt->dst.lwtstate = lwtstate_get(ort->dst.lwtstate); > + rt->dst.lwtstate = lwtstate_get(ort->fib6_nh.nh_lwtstate); > } > > static struct fib6_node* fib6_backtrack(struct fib6_node *fn, > @@ -1300,7 +1312,7 @@ __rt6_find_exception_rcu(struct rt6_exception_bucket **bucket, > static int rt6_insert_exception(struct rt6_info *nrt, > struct rt6_info *ort) > { > - struct net *net = dev_net(ort->dst.dev); > + struct net *net = dev_net(nrt->dst.dev); > struct rt6_exception_bucket *bucket; > struct in6_addr *src_key = NULL; > struct rt6_exception *rt6_ex; > @@ -2194,7 +2206,7 @@ static struct rt6_info *__ip6_route_redirect(struct net *net, > fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr); > restart: > for_each_fib6_node_rt_rcu(fn) { > - if (rt->rt6i_nh_flags & RTNH_F_DEAD) > + if (rt->fib6_nh.nh_flags & RTNH_F_DEAD) > continue; > if (rt6_check_expired(rt)) > continue; > @@ -2202,14 +2214,14 @@ static struct rt6_info *__ip6_route_redirect(struct net *net, > break; > if (!(rt->rt6i_flags & RTF_GATEWAY)) > continue; > - if (fl6->flowi6_oif != rt->dst.dev->ifindex) > + if (fl6->flowi6_oif != rt->fib6_nh.nh_dev->ifindex) > continue; > /* rt_cache's gateway might be different from its 'parent' > * in the case of an ip redirect. > * So we keep searching in the exception table if the gateway > * is different. > */ > - if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway)) { > + if (!ipv6_addr_equal(&rdfl->gateway, &rt->fib6_nh.nh_gw)) { > rt_cache = rt6_find_cached_rt(rt, > &fl6->daddr, > &fl6->saddr); > @@ -2712,7 +2724,7 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg, > &lwtstate, extack); > if (err) > goto out; > - rt->dst.lwtstate = lwtstate_get(lwtstate); > + rt->fib6_nh.nh_lwtstate = lwtstate_get(lwtstate); > lwtunnel_set_redirect(&rt->dst); > } > > @@ -2727,7 +2739,7 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg, > #endif > > rt->rt6i_metric = cfg->fc_metric; > - rt->rt6i_nh_weight = 1; > + rt->fib6_nh.nh_weight = 1; > > rt->fib6_type = cfg->fc_type; > > @@ -2796,7 +2808,9 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg, > NL_SET_ERR_MSG(extack, "Invalid gateway address"); > goto out; > } > - rt->rt6i_gateway = *gw_addr; > + rt->fib6_nh.nh_gw = *gw_addr; > + > + rt->rt6i_gateway = rt->fib6_nh.nh_gw; > > if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) { > /* IPv6 strictly inhibits using not link-local > @@ -2861,9 +2875,9 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg, > install_route: > if (!(rt->rt6i_flags & (RTF_LOCAL | RTF_ANYCAST)) && > !netif_carrier_ok(dev)) > - rt->rt6i_nh_flags |= RTNH_F_LINKDOWN; > - rt->rt6i_nh_flags |= (cfg->fc_flags & RTNH_F_ONLINK); > - rt->dst.dev = dev; > + rt->fib6_nh.nh_flags |= RTNH_F_LINKDOWN; > + rt->fib6_nh.nh_flags |= (cfg->fc_flags & RTNH_F_ONLINK); > + rt->fib6_nh.nh_dev = rt->dst.dev = dev; > rt->rt6i_idev = idev; > rt->rt6i_table = table; > > @@ -3022,11 +3036,11 @@ static int ip6_route_del(struct fib6_config *cfg, > rt = rt_cache; > } > if (cfg->fc_ifindex && > - (!rt->dst.dev || > - rt->dst.dev->ifindex != cfg->fc_ifindex)) > + (!rt->fib6_nh.nh_dev || > + rt->fib6_nh.nh_dev->ifindex != cfg->fc_ifindex)) > continue; > if (cfg->fc_flags & RTF_GATEWAY && > - !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway)) > + !ipv6_addr_equal(&cfg->fc_gateway, &rt->fib6_nh.nh_gw)) > continue; > if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric) > continue; > @@ -3188,11 +3202,11 @@ static struct rt6_info *rt6_get_route_info(struct net *net, > goto out; > > for_each_fib6_node_rt_rcu(fn) { > - if (rt->dst.dev->ifindex != ifindex) > + if (rt->fib6_nh.nh_dev->ifindex != ifindex) > continue; > if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY)) > continue; > - if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr)) > + if (!ipv6_addr_equal(&rt->fib6_nh.nh_gw, gwaddr)) > continue; > ip6_hold_safe(NULL, &rt, false); > break; > @@ -3249,9 +3263,9 @@ struct rt6_info *rt6_get_dflt_router(struct net *net, > > rcu_read_lock(); > for_each_fib6_node_rt_rcu(&table->tb6_root) { > - if (dev == rt->dst.dev && > + if (dev == rt->fib6_nh.nh_dev && > ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) && > - ipv6_addr_equal(&rt->rt6i_gateway, addr)) > + ipv6_addr_equal(&rt->fib6_nh.nh_gw, addr)) > break; > } > if (rt) > @@ -3477,6 +3491,8 @@ struct rt6_info *addrconf_dst_alloc(struct net *net, > rt->rt6i_flags |= RTF_LOCAL; > } > > + rt->fib6_nh.nh_gw = *addr; > + rt->fib6_nh.nh_dev = dev; > rt->rt6i_gateway = *addr; > rt->rt6i_dst.addr = *addr; > rt->rt6i_dst.plen = 128; > @@ -3499,7 +3515,7 @@ static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg) > struct net *net = ((struct arg_dev_net_ip *)arg)->net; > struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr; > > - if (((void *)rt->dst.dev == dev || !dev) && > + if (((void *)rt->fib6_nh.nh_dev == dev || !dev) && > rt != net->ipv6.ip6_null_entry && > ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) { > spin_lock_bh(&rt6_exception_lock); > @@ -3531,7 +3547,7 @@ static int fib6_clean_tohost(struct rt6_info *rt, void *arg) > struct in6_addr *gateway = (struct in6_addr *)arg; > > if (((rt->rt6i_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) && > - ipv6_addr_equal(gateway, &rt->rt6i_gateway)) { > + ipv6_addr_equal(gateway, &rt->fib6_nh.nh_gw)) { > return -1; > } > > @@ -3579,8 +3595,8 @@ static struct rt6_info *rt6_multipath_first_sibling(const struct rt6_info *rt) > > static bool rt6_is_dead(const struct rt6_info *rt) > { > - if (rt->rt6i_nh_flags & RTNH_F_DEAD || > - (rt->rt6i_nh_flags & RTNH_F_LINKDOWN && > + if (rt->fib6_nh.nh_flags & RTNH_F_DEAD || > + (rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN && > rt->rt6i_idev->cnf.ignore_routes_with_linkdown)) > return true; > > @@ -3593,11 +3609,11 @@ static int rt6_multipath_total_weight(const struct rt6_info *rt) > int total = 0; > > if (!rt6_is_dead(rt)) > - total += rt->rt6i_nh_weight; > + total += rt->fib6_nh.nh_weight; > > list_for_each_entry(iter, &rt->rt6i_siblings, rt6i_siblings) { > if (!rt6_is_dead(iter)) > - total += iter->rt6i_nh_weight; > + total += iter->fib6_nh.nh_weight; > } > > return total; > @@ -3608,11 +3624,11 @@ static void rt6_upper_bound_set(struct rt6_info *rt, int *weight, int total) > int upper_bound = -1; > > if (!rt6_is_dead(rt)) { > - *weight += rt->rt6i_nh_weight; > + *weight += rt->fib6_nh.nh_weight; > upper_bound = DIV_ROUND_CLOSEST_ULL((u64) (*weight) << 31, > total) - 1; > } > - atomic_set(&rt->rt6i_nh_upper_bound, upper_bound); > + atomic_set(&rt->fib6_nh.nh_upper_bound, upper_bound); > } > > static void rt6_multipath_upper_bound_set(struct rt6_info *rt, int total) > @@ -3655,8 +3671,8 @@ static int fib6_ifup(struct rt6_info *rt, void *p_arg) > const struct arg_netdev_event *arg = p_arg; > 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; > + if (rt != net->ipv6.ip6_null_entry && rt->fib6_nh.nh_dev == arg->dev) { > + rt->fib6_nh.nh_flags &= ~arg->nh_flags; > fib6_update_sernum_upto_root(net, rt); > rt6_multipath_rebalance(rt); > } > @@ -3684,10 +3700,10 @@ static bool rt6_multipath_uses_dev(const struct rt6_info *rt, > { > struct rt6_info *iter; > > - if (rt->dst.dev == dev) > + if (rt->fib6_nh.nh_dev == dev) > return true; > list_for_each_entry(iter, &rt->rt6i_siblings, rt6i_siblings) > - if (iter->dst.dev == dev) > + if (iter->fib6_nh.nh_dev == dev) > return true; > > return false; > @@ -3708,11 +3724,12 @@ static unsigned int rt6_multipath_dead_count(const struct rt6_info *rt, > struct rt6_info *iter; > unsigned int dead = 0; > > - if (rt->dst.dev == down_dev || rt->rt6i_nh_flags & RTNH_F_DEAD) > + if (rt->fib6_nh.nh_dev == down_dev || > + rt->fib6_nh.nh_flags & RTNH_F_DEAD) > dead++; > list_for_each_entry(iter, &rt->rt6i_siblings, rt6i_siblings) > - if (iter->dst.dev == down_dev || > - iter->rt6i_nh_flags & RTNH_F_DEAD) > + if (iter->fib6_nh.nh_dev == down_dev || > + iter->fib6_nh.nh_flags & RTNH_F_DEAD) > dead++; > > return dead; > @@ -3724,11 +3741,11 @@ static void rt6_multipath_nh_flags_set(struct rt6_info *rt, > { > struct rt6_info *iter; > > - if (rt->dst.dev == dev) > - rt->rt6i_nh_flags |= nh_flags; > + if (rt->fib6_nh.nh_dev == dev) > + rt->fib6_nh.nh_flags |= nh_flags; > list_for_each_entry(iter, &rt->rt6i_siblings, rt6i_siblings) > - if (iter->dst.dev == dev) > - iter->rt6i_nh_flags |= nh_flags; > + if (iter->fib6_nh.nh_dev == dev) > + iter->fib6_nh.nh_flags |= nh_flags; > } > > /* called with write lock held for table with rt */ > @@ -3743,12 +3760,12 @@ static int fib6_ifdown(struct rt6_info *rt, void *p_arg) > > switch (arg->event) { > case NETDEV_UNREGISTER: > - return rt->dst.dev == dev ? -1 : 0; > + return rt->fib6_nh.nh_dev == dev ? -1 : 0; > case NETDEV_DOWN: > if (rt->should_flush) > return -1; > if (!rt->rt6i_nsiblings) > - return rt->dst.dev == dev ? -1 : 0; > + return rt->fib6_nh.nh_dev == dev ? -1 : 0; > if (rt6_multipath_uses_dev(rt, dev)) { > unsigned int count; > > @@ -3764,10 +3781,10 @@ static int fib6_ifdown(struct rt6_info *rt, void *p_arg) > } > return -2; > case NETDEV_CHANGE: > - if (rt->dst.dev != dev || > + if (rt->fib6_nh.nh_dev != dev || > rt->rt6i_flags & (RTF_LOCAL | RTF_ANYCAST)) > break; > - rt->rt6i_nh_flags |= RTNH_F_LINKDOWN; > + rt->fib6_nh.nh_flags |= RTNH_F_LINKDOWN; > rt6_multipath_rebalance(rt); > break; > } > @@ -3828,7 +3845,7 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg) > also have the lowest MTU, TOO BIG MESSAGE will be lead to > PMTU discovery. > */ > - if (rt->dst.dev == arg->dev && > + if (rt->fib6_nh.nh_dev == arg->dev && > dst_metric_raw(&rt->dst, RTAX_MTU) && > !dst_metric_locked(&rt->dst, RTAX_MTU)) { > spin_lock_bh(&rt6_exception_lock); > @@ -4116,7 +4133,7 @@ static int ip6_route_multipath_add(struct fib6_config *cfg, > goto cleanup; > } > > - rt->rt6i_nh_weight = rtnh->rtnh_hops + 1; > + rt->fib6_nh.nh_weight = rtnh->rtnh_hops + 1; > > err = ip6_route_info_append(&rt6_nh_list, rt, &r_cfg); > if (err) { > @@ -4273,7 +4290,7 @@ static size_t rt6_nlmsg_size(struct rt6_info *rt) > nexthop_len = nla_total_size(0) /* RTA_MULTIPATH */ > + NLA_ALIGN(sizeof(struct rtnexthop)) > + nla_total_size(16) /* RTA_GATEWAY */ > - + lwtunnel_get_encap_size(rt->dst.lwtstate); > + + lwtunnel_get_encap_size(rt->fib6_nh.nh_lwtstate); > > nexthop_len *= rt->rt6i_nsiblings; > } > @@ -4291,38 +4308,38 @@ static size_t rt6_nlmsg_size(struct rt6_info *rt) > + nla_total_size(sizeof(struct rta_cacheinfo)) > + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */ > + nla_total_size(1) /* RTA_PREF */ > - + lwtunnel_get_encap_size(rt->dst.lwtstate) > + + lwtunnel_get_encap_size(rt->fib6_nh.nh_lwtstate) > + nexthop_len; > } > > static int rt6_nexthop_info(struct sk_buff *skb, struct rt6_info *rt, > unsigned int *flags, bool skip_oif) > { > - if (rt->rt6i_nh_flags & RTNH_F_DEAD) > + if (rt->fib6_nh.nh_flags & RTNH_F_DEAD) > *flags |= RTNH_F_DEAD; > > - if (rt->rt6i_nh_flags & RTNH_F_LINKDOWN) { > + if (rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN) { > *flags |= RTNH_F_LINKDOWN; > if (rt->rt6i_idev->cnf.ignore_routes_with_linkdown) > *flags |= RTNH_F_DEAD; > } > > if (rt->rt6i_flags & RTF_GATEWAY) { > - if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->rt6i_gateway) < 0) > + if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->fib6_nh.nh_gw) < 0) > goto nla_put_failure; > } > > - *flags |= (rt->rt6i_nh_flags & RTNH_F_ONLINK); > - if (rt->rt6i_nh_flags & RTNH_F_OFFLOAD) > + *flags |= (rt->fib6_nh.nh_flags & RTNH_F_ONLINK); > + if (rt->fib6_nh.nh_flags & RTNH_F_OFFLOAD) > *flags |= RTNH_F_OFFLOAD; > > /* not needed for multipath encoding b/c it has a rtnexthop struct */ > - if (!skip_oif && rt->dst.dev && > - nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex)) > + if (!skip_oif && rt->fib6_nh.nh_dev && > + nla_put_u32(skb, RTA_OIF, rt->fib6_nh.nh_dev->ifindex)) > goto nla_put_failure; > > - if (rt->dst.lwtstate && > - lwtunnel_fill_encap(skb, rt->dst.lwtstate) < 0) > + if (rt->fib6_nh.nh_lwtstate && > + lwtunnel_fill_encap(skb, rt->fib6_nh.nh_lwtstate) < 0) > goto nla_put_failure; > > return 0; > @@ -4334,6 +4351,7 @@ static int rt6_nexthop_info(struct sk_buff *skb, struct rt6_info *rt, > /* add multipath next hop */ > static int rt6_add_nexthop(struct sk_buff *skb, struct rt6_info *rt) > { > + const struct net_device *dev = rt->fib6_nh.nh_dev; > struct rtnexthop *rtnh; > unsigned int flags = 0; > > @@ -4341,8 +4359,8 @@ static int rt6_add_nexthop(struct sk_buff *skb, struct rt6_info *rt) > if (!rtnh) > goto nla_put_failure; > > - rtnh->rtnh_hops = rt->rt6i_nh_weight - 1; > - rtnh->rtnh_ifindex = rt->dst.dev ? rt->dst.dev->ifindex : 0; > + rtnh->rtnh_hops = rt->fib6_nh.nh_weight - 1; > + rtnh->rtnh_ifindex = dev ? dev->ifindex : 0; > > if (rt6_nexthop_info(skb, rt, &flags, true) < 0) > goto nla_put_failure; > -- > 2.11.0 >
On 2/26/18 3:28 PM, Wei Wang wrote: > On Sun, Feb 25, 2018 at 11:47 AM, David Ahern <dsahern@gmail.com> wrote: >> Introduce 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. >> > > My understanding is that after your whole patch series, sibling routes > will still have their own fib6_info. Does it make sense to make this > fib6_nh as an array in fib6_info so that sibling routes will share > fib6_info but will have their own fib6_nh as a future improvement? It > matches ipv4 behavior. And I think it will make the sibling route > handling code easier? I was not planning to. IPv6 allowing individual nexthops to be added and deleted is very convenient. I do agree the existing sibling route linkage makes the code much more complicated than it needs to be. After this set, I plan to send patches for nexthops as separate objects - which will have an impact on how multipath routes are done. With nexthop objects there will be 1 prefix route pointing to a nexthop object that is multipath (meaning it points in turn to a series of nexthop objects). This provides the simplification (no sibling linkage) without losing the individual nexhtop add / delete option.
On Mon, Feb 26, 2018 at 2:47 PM, David Ahern <dsahern@gmail.com> wrote: > On 2/26/18 3:28 PM, Wei Wang wrote: >> On Sun, Feb 25, 2018 at 11:47 AM, David Ahern <dsahern@gmail.com> wrote: >>> Introduce 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. >>> >> >> My understanding is that after your whole patch series, sibling routes >> will still have their own fib6_info. Does it make sense to make this >> fib6_nh as an array in fib6_info so that sibling routes will share >> fib6_info but will have their own fib6_nh as a future improvement? It >> matches ipv4 behavior. And I think it will make the sibling route >> handling code easier? > > I was not planning to. IPv6 allowing individual nexthops to be added and > deleted is very convenient. I do agree the existing sibling route > linkage makes the code much more complicated than it needs to be. > > After this set, I plan to send patches for nexthops as separate objects > - which will have an impact on how multipath routes are done. With > nexthop objects there will be 1 prefix route pointing to a nexthop > object that is multipath (meaning it points in turn to a series of > nexthop objects). This provides the simplification (no sibling linkage) > without losing the individual nexhtop add / delete option. Got it. Thanks for the explanation.
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 05146970c19c..90d01df783b3 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -2700,9 +2700,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; @@ -2768,7 +2768,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; } @@ -3766,9 +3766,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; } @@ -3825,7 +3825,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; } @@ -3835,9 +3835,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; } } @@ -3852,7 +3852,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; } } @@ -4748,8 +4748,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, @@ -4759,7 +4759,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; @@ -4802,11 +4802,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); diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 4badcf105bd9..7678ae3de44a 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -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) \ diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index ef0d8977e2d0..bd82ec4a57e6 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -263,9 +263,9 @@ 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 diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 82862d3f0295..eeecef2b83a4 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2344,7 +2344,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; diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 51d2d5a7ba89..134d86483f3c 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -2213,6 +2213,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); @@ -2222,14 +2223,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; } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 2de9af0bead1..ff809ee930c7 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -464,12 +464,15 @@ static struct rt6_info *rt6_multipath_select(struct rt6_info *match, if (!fl6->mp_hash) fl6->mp_hash = rt6_multipath_hash(fl6, NULL); - if (fl6->mp_hash <= atomic_read(&match->rt6i_nh_upper_bound)) + if (fl6->mp_hash <= atomic_read(&match->fib6_nh.nh_upper_bound)) return match; list_for_each_entry_safe(sibling, next_sibling, &match->rt6i_siblings, rt6i_siblings) { - if (fl6->mp_hash > atomic_read(&sibling->rt6i_nh_upper_bound)) + int nh_upper_bound; + + nh_upper_bound = atomic_read(&sibling->fib6_nh.nh_upper_bound); + if (fl6->mp_hash > nh_upper_bound) continue; if (rt6_score_route(sibling, oif, strict) < 0) break; @@ -493,13 +496,14 @@ static inline struct rt6_info *rt6_device_match(struct net *net, struct rt6_info *local = NULL; struct rt6_info *sprt; - if (!oif && ipv6_addr_any(saddr) && !(rt->rt6i_nh_flags & RTNH_F_DEAD)) + if (!oif && ipv6_addr_any(saddr) && + !(rt->fib6_nh.nh_flags & RTNH_F_DEAD)) return rt; for (sprt = rt; sprt; sprt = rcu_dereference(sprt->rt6_next)) { - struct net_device *dev = sprt->dst.dev; + const struct net_device *dev = sprt->fib6_nh.nh_dev; - if (sprt->rt6i_nh_flags & RTNH_F_DEAD) + if (sprt->fib6_nh.nh_flags & RTNH_F_DEAD) continue; if (oif) { @@ -531,7 +535,7 @@ static inline struct rt6_info *rt6_device_match(struct net *net, return net->ipv6.ip6_null_entry; } - return rt->rt6i_nh_flags & RTNH_F_DEAD ? net->ipv6.ip6_null_entry : rt; + return rt->fib6_nh.nh_flags & RTNH_F_DEAD ? net->ipv6.ip6_null_entry : rt; } #ifdef CONFIG_IPV6_ROUTER_PREF @@ -556,7 +560,10 @@ static void rt6_probe_deferred(struct work_struct *w) static void rt6_probe(struct rt6_info *rt) { struct __rt6_probe_work *work; + const struct in6_addr *nh_gw; struct neighbour *neigh; + struct net_device *dev; + /* * Okay, this does not seem to be appropriate * for now, however, we need to check if it @@ -567,8 +574,11 @@ static void rt6_probe(struct rt6_info *rt) */ if (!rt || !(rt->rt6i_flags & RTF_GATEWAY)) return; + + nh_gw = &rt->fib6_nh.nh_gw; + dev = rt->fib6_nh.nh_dev; rcu_read_lock_bh(); - neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway); + neigh = __ipv6_neigh_lookup_noref(dev, nh_gw); if (neigh) { if (neigh->nud_state & NUD_VALID) goto out; @@ -590,9 +600,9 @@ static void rt6_probe(struct rt6_info *rt) if (work) { INIT_WORK(&work->work, rt6_probe_deferred); - work->target = rt->rt6i_gateway; - dev_hold(rt->dst.dev); - work->dev = rt->dst.dev; + work->target = *nh_gw; + dev_hold(dev); + work->dev = dev; schedule_work(&work->work); } @@ -610,7 +620,8 @@ static inline void rt6_probe(struct rt6_info *rt) */ static inline int rt6_check_dev(struct rt6_info *rt, int oif) { - struct net_device *dev = rt->dst.dev; + const struct net_device *dev = rt->fib6_nh.nh_dev; + if (!oif || dev->ifindex == oif) return 2; if ((dev->flags & IFF_LOOPBACK) && @@ -621,15 +632,16 @@ static inline int rt6_check_dev(struct rt6_info *rt, int oif) static inline enum rt6_nud_state rt6_check_neigh(struct rt6_info *rt) { - struct neighbour *neigh; enum rt6_nud_state ret = RT6_NUD_FAIL_HARD; + struct neighbour *neigh; if (rt->rt6i_flags & RTF_NONEXTHOP || !(rt->rt6i_flags & RTF_GATEWAY)) return RT6_NUD_SUCCEED; rcu_read_lock_bh(); - neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway); + neigh = __ipv6_neigh_lookup_noref(rt->fib6_nh.nh_dev, + &rt->fib6_nh.nh_gw); if (neigh) { read_lock(&neigh->lock); if (neigh->nud_state & NUD_VALID) @@ -677,11 +689,11 @@ static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict, bool match_do_rr = false; struct inet6_dev *idev = rt->rt6i_idev; - if (rt->rt6i_nh_flags & RTNH_F_DEAD) + if (rt->fib6_nh.nh_flags & RTNH_F_DEAD) goto out; if (idev->cnf.ignore_routes_with_linkdown && - rt->rt6i_nh_flags & RTNH_F_LINKDOWN && + rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN && !(strict & RT6_LOOKUP_F_IGNORE_LINKSTATE)) goto out; @@ -886,7 +898,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, /* 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; + struct net_device *dev = rt->fib6_nh.nh_dev; if (rt->rt6i_flags & (RTF_LOCAL | RTF_ANYCAST)) { /* for copies of local routes, dst->dev needs to be the @@ -926,7 +938,7 @@ static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort) if (rt->rt6i_idev) in6_dev_hold(rt->rt6i_idev); rt->dst.lastuse = jiffies; - rt->rt6i_gateway = ort->rt6i_gateway; + 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; @@ -935,7 +947,7 @@ static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort) #endif rt->rt6i_prefsrc = ort->rt6i_prefsrc; rt->rt6i_table = ort->rt6i_table; - rt->dst.lwtstate = lwtstate_get(ort->dst.lwtstate); + rt->dst.lwtstate = lwtstate_get(ort->fib6_nh.nh_lwtstate); } static struct fib6_node* fib6_backtrack(struct fib6_node *fn, @@ -1300,7 +1312,7 @@ __rt6_find_exception_rcu(struct rt6_exception_bucket **bucket, static int rt6_insert_exception(struct rt6_info *nrt, struct rt6_info *ort) { - struct net *net = dev_net(ort->dst.dev); + struct net *net = dev_net(nrt->dst.dev); struct rt6_exception_bucket *bucket; struct in6_addr *src_key = NULL; struct rt6_exception *rt6_ex; @@ -2194,7 +2206,7 @@ static struct rt6_info *__ip6_route_redirect(struct net *net, fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr); restart: for_each_fib6_node_rt_rcu(fn) { - if (rt->rt6i_nh_flags & RTNH_F_DEAD) + if (rt->fib6_nh.nh_flags & RTNH_F_DEAD) continue; if (rt6_check_expired(rt)) continue; @@ -2202,14 +2214,14 @@ static struct rt6_info *__ip6_route_redirect(struct net *net, break; if (!(rt->rt6i_flags & RTF_GATEWAY)) continue; - if (fl6->flowi6_oif != rt->dst.dev->ifindex) + if (fl6->flowi6_oif != rt->fib6_nh.nh_dev->ifindex) continue; /* rt_cache's gateway might be different from its 'parent' * in the case of an ip redirect. * So we keep searching in the exception table if the gateway * is different. */ - if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway)) { + if (!ipv6_addr_equal(&rdfl->gateway, &rt->fib6_nh.nh_gw)) { rt_cache = rt6_find_cached_rt(rt, &fl6->daddr, &fl6->saddr); @@ -2712,7 +2724,7 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg, &lwtstate, extack); if (err) goto out; - rt->dst.lwtstate = lwtstate_get(lwtstate); + rt->fib6_nh.nh_lwtstate = lwtstate_get(lwtstate); lwtunnel_set_redirect(&rt->dst); } @@ -2727,7 +2739,7 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg, #endif rt->rt6i_metric = cfg->fc_metric; - rt->rt6i_nh_weight = 1; + rt->fib6_nh.nh_weight = 1; rt->fib6_type = cfg->fc_type; @@ -2796,7 +2808,9 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg, NL_SET_ERR_MSG(extack, "Invalid gateway address"); goto out; } - rt->rt6i_gateway = *gw_addr; + rt->fib6_nh.nh_gw = *gw_addr; + + rt->rt6i_gateway = rt->fib6_nh.nh_gw; if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) { /* IPv6 strictly inhibits using not link-local @@ -2861,9 +2875,9 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg, install_route: if (!(rt->rt6i_flags & (RTF_LOCAL | RTF_ANYCAST)) && !netif_carrier_ok(dev)) - rt->rt6i_nh_flags |= RTNH_F_LINKDOWN; - rt->rt6i_nh_flags |= (cfg->fc_flags & RTNH_F_ONLINK); - rt->dst.dev = dev; + rt->fib6_nh.nh_flags |= RTNH_F_LINKDOWN; + rt->fib6_nh.nh_flags |= (cfg->fc_flags & RTNH_F_ONLINK); + rt->fib6_nh.nh_dev = rt->dst.dev = dev; rt->rt6i_idev = idev; rt->rt6i_table = table; @@ -3022,11 +3036,11 @@ static int ip6_route_del(struct fib6_config *cfg, rt = rt_cache; } if (cfg->fc_ifindex && - (!rt->dst.dev || - rt->dst.dev->ifindex != cfg->fc_ifindex)) + (!rt->fib6_nh.nh_dev || + rt->fib6_nh.nh_dev->ifindex != cfg->fc_ifindex)) continue; if (cfg->fc_flags & RTF_GATEWAY && - !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway)) + !ipv6_addr_equal(&cfg->fc_gateway, &rt->fib6_nh.nh_gw)) continue; if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric) continue; @@ -3188,11 +3202,11 @@ static struct rt6_info *rt6_get_route_info(struct net *net, goto out; for_each_fib6_node_rt_rcu(fn) { - if (rt->dst.dev->ifindex != ifindex) + if (rt->fib6_nh.nh_dev->ifindex != ifindex) continue; if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY)) continue; - if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr)) + if (!ipv6_addr_equal(&rt->fib6_nh.nh_gw, gwaddr)) continue; ip6_hold_safe(NULL, &rt, false); break; @@ -3249,9 +3263,9 @@ struct rt6_info *rt6_get_dflt_router(struct net *net, rcu_read_lock(); for_each_fib6_node_rt_rcu(&table->tb6_root) { - if (dev == rt->dst.dev && + if (dev == rt->fib6_nh.nh_dev && ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) && - ipv6_addr_equal(&rt->rt6i_gateway, addr)) + ipv6_addr_equal(&rt->fib6_nh.nh_gw, addr)) break; } if (rt) @@ -3477,6 +3491,8 @@ struct rt6_info *addrconf_dst_alloc(struct net *net, rt->rt6i_flags |= RTF_LOCAL; } + rt->fib6_nh.nh_gw = *addr; + rt->fib6_nh.nh_dev = dev; rt->rt6i_gateway = *addr; rt->rt6i_dst.addr = *addr; rt->rt6i_dst.plen = 128; @@ -3499,7 +3515,7 @@ static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg) struct net *net = ((struct arg_dev_net_ip *)arg)->net; struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr; - if (((void *)rt->dst.dev == dev || !dev) && + if (((void *)rt->fib6_nh.nh_dev == dev || !dev) && rt != net->ipv6.ip6_null_entry && ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) { spin_lock_bh(&rt6_exception_lock); @@ -3531,7 +3547,7 @@ static int fib6_clean_tohost(struct rt6_info *rt, void *arg) struct in6_addr *gateway = (struct in6_addr *)arg; if (((rt->rt6i_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) && - ipv6_addr_equal(gateway, &rt->rt6i_gateway)) { + ipv6_addr_equal(gateway, &rt->fib6_nh.nh_gw)) { return -1; } @@ -3579,8 +3595,8 @@ static struct rt6_info *rt6_multipath_first_sibling(const struct rt6_info *rt) static bool rt6_is_dead(const struct rt6_info *rt) { - if (rt->rt6i_nh_flags & RTNH_F_DEAD || - (rt->rt6i_nh_flags & RTNH_F_LINKDOWN && + if (rt->fib6_nh.nh_flags & RTNH_F_DEAD || + (rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN && rt->rt6i_idev->cnf.ignore_routes_with_linkdown)) return true; @@ -3593,11 +3609,11 @@ static int rt6_multipath_total_weight(const struct rt6_info *rt) int total = 0; if (!rt6_is_dead(rt)) - total += rt->rt6i_nh_weight; + total += rt->fib6_nh.nh_weight; list_for_each_entry(iter, &rt->rt6i_siblings, rt6i_siblings) { if (!rt6_is_dead(iter)) - total += iter->rt6i_nh_weight; + total += iter->fib6_nh.nh_weight; } return total; @@ -3608,11 +3624,11 @@ static void rt6_upper_bound_set(struct rt6_info *rt, int *weight, int total) int upper_bound = -1; if (!rt6_is_dead(rt)) { - *weight += rt->rt6i_nh_weight; + *weight += rt->fib6_nh.nh_weight; upper_bound = DIV_ROUND_CLOSEST_ULL((u64) (*weight) << 31, total) - 1; } - atomic_set(&rt->rt6i_nh_upper_bound, upper_bound); + atomic_set(&rt->fib6_nh.nh_upper_bound, upper_bound); } static void rt6_multipath_upper_bound_set(struct rt6_info *rt, int total) @@ -3655,8 +3671,8 @@ static int fib6_ifup(struct rt6_info *rt, void *p_arg) const struct arg_netdev_event *arg = p_arg; 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; + if (rt != net->ipv6.ip6_null_entry && rt->fib6_nh.nh_dev == arg->dev) { + rt->fib6_nh.nh_flags &= ~arg->nh_flags; fib6_update_sernum_upto_root(net, rt); rt6_multipath_rebalance(rt); } @@ -3684,10 +3700,10 @@ static bool rt6_multipath_uses_dev(const struct rt6_info *rt, { struct rt6_info *iter; - if (rt->dst.dev == dev) + if (rt->fib6_nh.nh_dev == dev) return true; list_for_each_entry(iter, &rt->rt6i_siblings, rt6i_siblings) - if (iter->dst.dev == dev) + if (iter->fib6_nh.nh_dev == dev) return true; return false; @@ -3708,11 +3724,12 @@ static unsigned int rt6_multipath_dead_count(const struct rt6_info *rt, struct rt6_info *iter; unsigned int dead = 0; - if (rt->dst.dev == down_dev || rt->rt6i_nh_flags & RTNH_F_DEAD) + if (rt->fib6_nh.nh_dev == down_dev || + rt->fib6_nh.nh_flags & RTNH_F_DEAD) dead++; list_for_each_entry(iter, &rt->rt6i_siblings, rt6i_siblings) - if (iter->dst.dev == down_dev || - iter->rt6i_nh_flags & RTNH_F_DEAD) + if (iter->fib6_nh.nh_dev == down_dev || + iter->fib6_nh.nh_flags & RTNH_F_DEAD) dead++; return dead; @@ -3724,11 +3741,11 @@ static void rt6_multipath_nh_flags_set(struct rt6_info *rt, { struct rt6_info *iter; - if (rt->dst.dev == dev) - rt->rt6i_nh_flags |= nh_flags; + if (rt->fib6_nh.nh_dev == dev) + rt->fib6_nh.nh_flags |= nh_flags; list_for_each_entry(iter, &rt->rt6i_siblings, rt6i_siblings) - if (iter->dst.dev == dev) - iter->rt6i_nh_flags |= nh_flags; + if (iter->fib6_nh.nh_dev == dev) + iter->fib6_nh.nh_flags |= nh_flags; } /* called with write lock held for table with rt */ @@ -3743,12 +3760,12 @@ static int fib6_ifdown(struct rt6_info *rt, void *p_arg) switch (arg->event) { case NETDEV_UNREGISTER: - return rt->dst.dev == dev ? -1 : 0; + return rt->fib6_nh.nh_dev == dev ? -1 : 0; case NETDEV_DOWN: if (rt->should_flush) return -1; if (!rt->rt6i_nsiblings) - return rt->dst.dev == dev ? -1 : 0; + return rt->fib6_nh.nh_dev == dev ? -1 : 0; if (rt6_multipath_uses_dev(rt, dev)) { unsigned int count; @@ -3764,10 +3781,10 @@ static int fib6_ifdown(struct rt6_info *rt, void *p_arg) } return -2; case NETDEV_CHANGE: - if (rt->dst.dev != dev || + if (rt->fib6_nh.nh_dev != dev || rt->rt6i_flags & (RTF_LOCAL | RTF_ANYCAST)) break; - rt->rt6i_nh_flags |= RTNH_F_LINKDOWN; + rt->fib6_nh.nh_flags |= RTNH_F_LINKDOWN; rt6_multipath_rebalance(rt); break; } @@ -3828,7 +3845,7 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg) also have the lowest MTU, TOO BIG MESSAGE will be lead to PMTU discovery. */ - if (rt->dst.dev == arg->dev && + if (rt->fib6_nh.nh_dev == arg->dev && dst_metric_raw(&rt->dst, RTAX_MTU) && !dst_metric_locked(&rt->dst, RTAX_MTU)) { spin_lock_bh(&rt6_exception_lock); @@ -4116,7 +4133,7 @@ static int ip6_route_multipath_add(struct fib6_config *cfg, goto cleanup; } - rt->rt6i_nh_weight = rtnh->rtnh_hops + 1; + rt->fib6_nh.nh_weight = rtnh->rtnh_hops + 1; err = ip6_route_info_append(&rt6_nh_list, rt, &r_cfg); if (err) { @@ -4273,7 +4290,7 @@ static size_t rt6_nlmsg_size(struct rt6_info *rt) nexthop_len = nla_total_size(0) /* RTA_MULTIPATH */ + NLA_ALIGN(sizeof(struct rtnexthop)) + nla_total_size(16) /* RTA_GATEWAY */ - + lwtunnel_get_encap_size(rt->dst.lwtstate); + + lwtunnel_get_encap_size(rt->fib6_nh.nh_lwtstate); nexthop_len *= rt->rt6i_nsiblings; } @@ -4291,38 +4308,38 @@ static size_t rt6_nlmsg_size(struct rt6_info *rt) + nla_total_size(sizeof(struct rta_cacheinfo)) + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */ + nla_total_size(1) /* RTA_PREF */ - + lwtunnel_get_encap_size(rt->dst.lwtstate) + + lwtunnel_get_encap_size(rt->fib6_nh.nh_lwtstate) + nexthop_len; } static int rt6_nexthop_info(struct sk_buff *skb, struct rt6_info *rt, unsigned int *flags, bool skip_oif) { - if (rt->rt6i_nh_flags & RTNH_F_DEAD) + if (rt->fib6_nh.nh_flags & RTNH_F_DEAD) *flags |= RTNH_F_DEAD; - if (rt->rt6i_nh_flags & RTNH_F_LINKDOWN) { + if (rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN) { *flags |= RTNH_F_LINKDOWN; if (rt->rt6i_idev->cnf.ignore_routes_with_linkdown) *flags |= RTNH_F_DEAD; } if (rt->rt6i_flags & RTF_GATEWAY) { - if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->rt6i_gateway) < 0) + if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->fib6_nh.nh_gw) < 0) goto nla_put_failure; } - *flags |= (rt->rt6i_nh_flags & RTNH_F_ONLINK); - if (rt->rt6i_nh_flags & RTNH_F_OFFLOAD) + *flags |= (rt->fib6_nh.nh_flags & RTNH_F_ONLINK); + if (rt->fib6_nh.nh_flags & RTNH_F_OFFLOAD) *flags |= RTNH_F_OFFLOAD; /* not needed for multipath encoding b/c it has a rtnexthop struct */ - if (!skip_oif && rt->dst.dev && - nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex)) + if (!skip_oif && rt->fib6_nh.nh_dev && + nla_put_u32(skb, RTA_OIF, rt->fib6_nh.nh_dev->ifindex)) goto nla_put_failure; - if (rt->dst.lwtstate && - lwtunnel_fill_encap(skb, rt->dst.lwtstate) < 0) + if (rt->fib6_nh.nh_lwtstate && + lwtunnel_fill_encap(skb, rt->fib6_nh.nh_lwtstate) < 0) goto nla_put_failure; return 0; @@ -4334,6 +4351,7 @@ static int rt6_nexthop_info(struct sk_buff *skb, struct rt6_info *rt, /* add multipath next hop */ static int rt6_add_nexthop(struct sk_buff *skb, struct rt6_info *rt) { + const struct net_device *dev = rt->fib6_nh.nh_dev; struct rtnexthop *rtnh; unsigned int flags = 0; @@ -4341,8 +4359,8 @@ static int rt6_add_nexthop(struct sk_buff *skb, struct rt6_info *rt) if (!rtnh) goto nla_put_failure; - rtnh->rtnh_hops = rt->rt6i_nh_weight - 1; - rtnh->rtnh_ifindex = rt->dst.dev ? rt->dst.dev->ifindex : 0; + rtnh->rtnh_hops = rt->fib6_nh.nh_weight - 1; + rtnh->rtnh_ifindex = dev ? dev->ifindex : 0; if (rt6_nexthop_info(skb, rt, &flags, true) < 0) goto nla_put_failure;
Introduce 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. Signed-off-by: David Ahern <dsahern@gmail.com> --- .../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 | 164 ++++++++++++--------- 6 files changed, 127 insertions(+), 99 deletions(-)