From: David Ahern <dsah...@gmail.com> Move fib6_nh to the end of fib6_info and make an array of size 0. Pass a flag to fib6_info_alloc indicating if the allocation needs to add space for a fib6_nh.
The current code path always has a fib6_nh allocated; with nexthop objects they will not. Signed-off-by: David Ahern <dsah...@gmail.com> --- include/net/ip6_fib.h | 8 +-- include/net/ip6_route.h | 10 ++- include/trace/events/fib6.h | 15 ++-- net/core/filter.c | 6 +- net/ipv6/addrconf.c | 2 +- net/ipv6/ip6_fib.c | 15 ++-- net/ipv6/ndisc.c | 13 ++-- net/ipv6/route.c | 165 ++++++++++++++++++++++---------------------- 8 files changed, 124 insertions(+), 110 deletions(-) diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 2a1fae1247a9..9526eef711d5 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -170,8 +170,8 @@ struct fib6_info { dst_host:1, unused:3; - struct fib6_nh fib6_nh; struct rcu_head rcu; + struct fib6_nh fib6_nh[0]; }; struct rt6_info { @@ -274,7 +274,7 @@ static inline void ip6_rt_put(struct rt6_info *rt) dst_release(&rt->dst); } -struct fib6_info *fib6_info_alloc(gfp_t gfp_flags); +struct fib6_info *fib6_info_alloc(gfp_t gfp_flags, bool with_fib6_nh); void fib6_info_destroy_rcu(struct rcu_head *head); static inline void fib6_info_hold(struct fib6_info *f6i) @@ -426,13 +426,13 @@ static inline void fib6_nh_release(struct fib6_nh *fib6_nh) static inline struct net_device *fib6_info_nh_dev(const struct fib6_info *f6i) { - return f6i->fib6_nh.nh_dev; + return f6i->fib6_nh->nh_dev; } static inline struct lwtunnel_state *fib6_info_nh_lwt(const struct fib6_info *f6i) { - return f6i->fib6_nh.nh_lwtstate; + return f6i->fib6_nh->nh_lwtstate; } void inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info, diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 7b9c82de11cc..b1ca637acb2a 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -274,9 +274,13 @@ static inline struct in6_addr *rt6_nexthop(struct rt6_info *rt, 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 && - 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); +// TO-DO: + //if (a->nh || b->nh) + // return nexthop_cmp(a->nh, b->nh); + + return a->fib6_nh->nh_dev == b->fib6_nh->nh_dev && + 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); } static inline unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst) diff --git a/include/trace/events/fib6.h b/include/trace/events/fib6.h index b088b54d699c..037df3d2be0b 100644 --- a/include/trace/events/fib6.h +++ b/include/trace/events/fib6.h @@ -12,7 +12,7 @@ TRACE_EVENT(fib6_table_lookup, - TP_PROTO(const struct net *net, const struct fib6_info *f6i, + TP_PROTO(const struct net *net, struct fib6_info *f6i, struct fib6_table *table, const struct flowi6 *flp), TP_ARGS(net, f6i, table, flp), @@ -36,6 +36,7 @@ TRACE_EVENT(fib6_table_lookup, ), TP_fast_assign( + struct fib6_nh *fib6_nh = f6i->fib6_nh; struct in6_addr *in6; __entry->tb_id = table->tb6_id; @@ -62,20 +63,20 @@ TRACE_EVENT(fib6_table_lookup, __entry->dport = 0; } - if (f6i->fib6_nh.nh_dev) { - __assign_str(name, f6i->fib6_nh.nh_dev); + if (fib6_nh && fib6_nh->nh_dev) { + __assign_str(name, fib6_nh->nh_dev); } else { __assign_str(name, "-"); } - if (f6i == net->ipv6.fib6_null_entry) { + + if (!fib6_nh) { struct in6_addr in6_zero = {}; in6 = (struct in6_addr *)__entry->gw; *in6 = in6_zero; - - } else if (f6i) { + } else { in6 = (struct in6_addr *)__entry->gw; - *in6 = f6i->fib6_nh.nh_gw; + *in6 = fib6_nh->nh_gw; } ), diff --git a/net/core/filter.c b/net/core/filter.c index 0ba4c477415d..bc979edf06ca 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -4428,13 +4428,13 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params, return BPF_FIB_LKUP_RET_FRAG_NEEDED; } - if (f6i->fib6_nh.nh_lwtstate) + if (f6i->fib6_nh->nh_lwtstate) return BPF_FIB_LKUP_RET_UNSUPP_LWT; if (f6i->fib6_flags & RTF_GATEWAY) - *dst = f6i->fib6_nh.nh_gw; + *dst = f6i->fib6_nh->nh_gw; - dev = f6i->fib6_nh.nh_dev; + dev = f6i->fib6_nh->nh_dev; params->rt_metric = f6i->fib6_metric; /* xdp and cls_bpf programs are run in RCU-bh so rcu_read_lock_bh is diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index d51a8c0b3372..da5102bff2a9 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2366,7 +2366,7 @@ static struct fib6_info *addrconf_get_prefix_route(const struct in6_addr *pfx, goto out; for_each_fib6_node_rt_rcu(fn) { - if (rt->fib6_nh.nh_dev->ifindex != dev->ifindex) + if (rt->fib6_nh->nh_dev->ifindex != dev->ifindex) continue; if ((rt->fib6_flags & flags) != flags) continue; diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index c1c23427a81e..5b0ca5b3710d 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -145,11 +145,15 @@ static __be32 addr_bit_set(const void *token, int fn_bit) addr[fn_bit >> 5]; } -struct fib6_info *fib6_info_alloc(gfp_t gfp_flags) +struct fib6_info *fib6_info_alloc(gfp_t gfp_flags, bool with_fib6_nh) { struct fib6_info *f6i; + size_t sz = sizeof(*f6i); - f6i = kzalloc(sizeof(*f6i), gfp_flags); + if (with_fib6_nh) + sz += sizeof(struct fib6_nh); + + f6i = kzalloc(sz, gfp_flags); if (!f6i) return NULL; @@ -198,7 +202,7 @@ void fib6_info_destroy_rcu(struct rcu_head *head) } } - fib6_nh_release(&f6i->fib6_nh); + fib6_nh_release(f6i->fib6_nh); m = f6i->fib6_metrics; if (m != &dst_default_metrics && refcount_dec_and_test(&m->refcnt)) @@ -2247,6 +2251,7 @@ void fib6_gc_cleanup(void) static int ipv6_route_seq_show(struct seq_file *seq, void *v) { struct fib6_info *rt = v; + struct fib6_nh *fib6_nh = rt->fib6_nh; struct ipv6_route_iter *iter = seq->private; const struct net_device *dev; @@ -2258,11 +2263,11 @@ static int ipv6_route_seq_show(struct seq_file *seq, void *v) seq_puts(seq, "00000000000000000000000000000000 00 "); #endif if (rt->fib6_flags & RTF_GATEWAY) - seq_printf(seq, "%pi6", &rt->fib6_nh.nh_gw); + seq_printf(seq, "%pi6", &fib6_nh->nh_gw); else seq_puts(seq, "00000000000000000000000000000000"); - dev = rt->fib6_nh.nh_dev; + dev = fib6_nh->nh_dev; seq_printf(seq, " %08x %08x %08x %08x %8s\n", rt->fib6_metric, atomic_read(&rt->fib6_ref), 0, rt->fib6_flags, dev ? dev->name : ""); diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 0ec273997d1d..4bc47b9db35b 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1156,6 +1156,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) struct neighbour *neigh = NULL; struct inet6_dev *in6_dev; struct fib6_info *rt = NULL; + struct fib6_nh *fib6_nh; struct net *net; int lifetime; struct ndisc_options ndopts; @@ -1276,9 +1277,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 = ip6_neigh_lookup(&rt->fib6_nh.nh_gw, - rt->fib6_nh.nh_dev, NULL, - &ipv6_hdr(skb)->saddr); + fib6_nh = rt->fib6_nh; + neigh = ip6_neigh_lookup(&fib6_nh->nh_gw, fib6_nh->nh_dev, NULL, + &ipv6_hdr(skb)->saddr); if (!neigh) { ND_PRINTK(0, err, "RA: %s got default router without neighbour\n", @@ -1306,9 +1307,9 @@ static void ndisc_router_discovery(struct sk_buff *skb) return; } - neigh = ip6_neigh_lookup(&rt->fib6_nh.nh_gw, - rt->fib6_nh.nh_dev, NULL, - &ipv6_hdr(skb)->saddr); + fib6_nh = rt->fib6_nh; + neigh = ip6_neigh_lookup(&fib6_nh->nh_gw, fib6_nh->nh_dev, NULL, + &ipv6_hdr(skb)->saddr); if (!neigh) { ND_PRINTK(0, err, "RA: %s got default router without neighbour\n", diff --git a/net/ipv6/route.c b/net/ipv6/route.c index aa44cd5b3217..5792f57fdb91 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -439,14 +439,14 @@ struct fib6_info *fib6_multipath_select(const struct net *net, if (!fl6->mp_hash) fl6->mp_hash = rt6_multipath_hash(net, fl6, skb, NULL); - if (fl6->mp_hash <= atomic_read(&match->fib6_nh.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->fib6_siblings, fib6_siblings) { int nh_upper_bound; - nh_upper_bound = atomic_read(&sibling->fib6_nh.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) @@ -471,13 +471,13 @@ static inline struct fib6_info *rt6_device_match(struct net *net, struct fib6_info *sprt; if (!oif && ipv6_addr_any(saddr) && - !(rt->fib6_nh.nh_flags & RTNH_F_DEAD)) + !(rt->fib6_nh->nh_flags & RTNH_F_DEAD)) return rt; for (sprt = rt; sprt; sprt = rcu_dereference(sprt->fib6_next)) { - const struct net_device *dev = sprt->fib6_nh.nh_dev; + const struct net_device *dev = sprt->fib6_nh->nh_dev; - if (sprt->fib6_nh.nh_flags & RTNH_F_DEAD) + if (sprt->fib6_nh->nh_flags & RTNH_F_DEAD) continue; if (oif) { @@ -493,7 +493,7 @@ static inline struct fib6_info *rt6_device_match(struct net *net, if (oif && flags & RT6_LOOKUP_F_IFACE) return net->ipv6.fib6_null_entry; - return rt->fib6_nh.nh_flags & RTNH_F_DEAD ? net->ipv6.fib6_null_entry : rt; + return rt->fib6_nh->nh_flags & RTNH_F_DEAD ? net->ipv6.fib6_null_entry : rt; } #ifdef CONFIG_IPV6_ROUTER_PREF @@ -533,8 +533,8 @@ static void rt6_probe(struct fib6_info *rt) if (!rt || !(rt->fib6_flags & RTF_GATEWAY)) return; - nh_gw = &rt->fib6_nh.nh_gw; - dev = rt->fib6_nh.nh_dev; + nh_gw = &rt->fib6_nh->nh_gw; + dev = rt->fib6_nh->nh_dev; rcu_read_lock_bh(); neigh = __ipv6_neigh_lookup_noref(dev, nh_gw); if (neigh) { @@ -580,7 +580,7 @@ static inline void rt6_probe(struct fib6_info *rt) */ static inline int rt6_check_dev(struct fib6_info *rt, int oif) { - const struct net_device *dev = rt->fib6_nh.nh_dev; + const struct net_device *dev = rt->fib6_nh->nh_dev; if (!oif || dev->ifindex == oif) return 2; @@ -597,8 +597,8 @@ static inline enum rt6_nud_state rt6_check_neigh(struct fib6_info *rt) return RT6_NUD_SUCCEED; rcu_read_lock_bh(); - neigh = __ipv6_neigh_lookup_noref(rt->fib6_nh.nh_dev, - &rt->fib6_nh.nh_gw); + 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) @@ -638,6 +638,7 @@ static int rt6_score_route(struct fib6_info *rt, int oif, int strict) } /* called with rc_read_lock held */ +// TO-DO: if (!f6i->nh) static inline bool fib6_ignore_linkdown(const struct fib6_info *f6i) { const struct net_device *dev = fib6_info_nh_dev(f6i); @@ -659,11 +660,11 @@ static struct fib6_info *find_match(struct fib6_info *rt, int oif, int strict, int m; bool match_do_rr = false; - if (rt->fib6_nh.nh_flags & RTNH_F_DEAD) + if (rt->fib6_nh->nh_flags & RTNH_F_DEAD) goto out; if (fib6_ignore_linkdown(rt) && - rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN && + rt->fib6_nh->nh_flags & RTNH_F_LINKDOWN && !(strict & RT6_LOOKUP_F_IGNORE_LINKSTATE)) goto out; @@ -868,7 +869,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 fib6_info *rt) { - struct net_device *dev = rt->fib6_nh.nh_dev; + struct net_device *dev = rt->fib6_nh->nh_dev; if (rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) { /* for copies of local routes, dst->dev needs to be the @@ -964,8 +965,8 @@ static void ip6_rt_init_dst(struct rt6_info *rt, struct fib6_info *ort) rt->dst.input = ip6_forward; } - if (ort->fib6_nh.nh_lwtstate) { - rt->dst.lwtstate = lwtstate_get(ort->fib6_nh.nh_lwtstate); + if (ort->fib6_nh->nh_lwtstate) { + rt->dst.lwtstate = lwtstate_get(ort->fib6_nh->nh_lwtstate); lwtunnel_set_redirect(&rt->dst); } @@ -989,14 +990,14 @@ static void ip6_rt_copy_init(struct rt6_info *rt, struct fib6_info *ort) rt->rt6i_dst = ort->fib6_dst; rt->rt6i_idev = dev ? in6_dev_get(dev) : NULL; - rt->rt6i_gateway = ort->fib6_nh.nh_gw; + rt->rt6i_gateway = ort->fib6_nh->nh_gw; rt->rt6i_flags = ort->fib6_flags; rt6_set_from(rt, ort); #ifdef CONFIG_IPV6_SUBTREES rt->rt6i_src = ort->fib6_src; #endif rt->rt6i_prefsrc = ort->fib6_prefsrc; - rt->dst.lwtstate = lwtstate_get(ort->fib6_nh.nh_lwtstate); + rt->dst.lwtstate = lwtstate_get(ort->fib6_nh->nh_lwtstate); } static struct fib6_node* fib6_backtrack(struct fib6_node *fn, @@ -1038,7 +1039,7 @@ static bool ip6_hold_safe(struct net *net, struct rt6_info **prt, static struct rt6_info *ip6_create_rt_rcu(struct fib6_info *rt) { unsigned short flags = fib6_info_dst_flags(rt); - struct net_device *dev = rt->fib6_nh.nh_dev; + struct net_device *dev = rt->fib6_nh->nh_dev; struct rt6_info *nrt; if (!fib6_info_hold_safe(rt)) @@ -1409,7 +1410,7 @@ static unsigned int fib6_mtu(const struct fib6_info *rt) mtu = min_t(unsigned int, mtu, IP6_MAX_MTU); - return mtu - lwtunnel_headroom(rt->fib6_nh.nh_lwtstate, mtu); + return mtu - lwtunnel_headroom(rt->fib6_nh->nh_lwtstate, mtu); } static int rt6_insert_exception(struct rt6_info *nrt, @@ -2453,7 +2454,7 @@ static struct rt6_info *__ip6_route_redirect(struct net *net, fn = fib6_node_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr); restart: for_each_fib6_node_rt_rcu(fn) { - if (rt->fib6_nh.nh_flags & RTNH_F_DEAD) + if (rt->fib6_nh->nh_flags & RTNH_F_DEAD) continue; if (fib6_check_expired(rt)) continue; @@ -2461,14 +2462,14 @@ static struct rt6_info *__ip6_route_redirect(struct net *net, break; if (!(rt->fib6_flags & RTF_GATEWAY)) continue; - if (fl6->flowi6_oif != rt->fib6_nh.nh_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->fib6_nh.nh_gw)) { + if (!ipv6_addr_equal(&rdfl->gateway, &rt->fib6_nh->nh_gw)) { rt_cache = rt6_find_cached_rt(rt, &fl6->daddr, &fl6->saddr); @@ -3004,8 +3005,7 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh, } } cfg->fc_flags = RTF_REJECT | RTF_NONEXTHOP; - err = 0; - goto out; + goto set_dev; } if (cfg->fc_flags & RTF_GATEWAY) { @@ -3036,7 +3036,9 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh, !netif_carrier_ok(dev)) fib6_nh->nh_flags |= RTNH_F_LINKDOWN; +set_dev: fib6_nh->nh_dev = dev; + err = 0; out: if (idev) @@ -3108,7 +3110,7 @@ static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg, goto out; err = -ENOMEM; - rt = fib6_info_alloc(gfp_flags); + rt = fib6_info_alloc(gfp_flags, true); if (!rt) goto out; @@ -3142,7 +3144,7 @@ static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg, ipv6_addr_prefix(&rt->fib6_src.addr, &cfg->fc_src, cfg->fc_src_len); rt->fib6_src.plen = cfg->fc_src_len; #endif - err = fib6_nh_init(net, &rt->fib6_nh, cfg, extack); + err = fib6_nh_init(net, rt->fib6_nh, cfg, extack); if (err) goto out; @@ -3318,11 +3320,11 @@ static int ip6_route_del(struct fib6_config *cfg, continue; } if (cfg->fc_ifindex && - (!rt->fib6_nh.nh_dev || - rt->fib6_nh.nh_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->fib6_nh.nh_gw)) + !ipv6_addr_equal(&cfg->fc_gateway, &rt->fib6_nh->nh_gw)) continue; if (cfg->fc_metric && cfg->fc_metric != rt->fib6_metric) continue; @@ -3493,11 +3495,11 @@ static struct fib6_info *rt6_get_route_info(struct net *net, goto out; for_each_fib6_node_rt_rcu(fn) { - if (rt->fib6_nh.nh_dev->ifindex != ifindex) + if (rt->fib6_nh->nh_dev->ifindex != ifindex) continue; if ((rt->fib6_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY)) continue; - if (!ipv6_addr_equal(&rt->fib6_nh.nh_gw, gwaddr)) + if (!ipv6_addr_equal(&rt->fib6_nh->nh_gw, gwaddr)) continue; if (!fib6_info_hold_safe(rt)) continue; @@ -3555,9 +3557,9 @@ struct fib6_info *rt6_get_dflt_router(struct net *net, rcu_read_lock(); for_each_fib6_node_rt_rcu(&table->tb6_root) { - if (dev == rt->fib6_nh.nh_dev && + if (dev == rt->fib6_nh->nh_dev && ((rt->fib6_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) && - ipv6_addr_equal(&rt->fib6_nh.nh_gw, addr)) + ipv6_addr_equal(&rt->fib6_nh->nh_gw, addr)) break; } if (rt && !fib6_info_hold_safe(rt)) @@ -3763,7 +3765,7 @@ struct fib6_info *addrconf_f6i_alloc(struct net *net, struct net_device *dev = idev->dev; struct fib6_info *f6i; - f6i = fib6_info_alloc(gfp_flags); + f6i = fib6_info_alloc(gfp_flags, true); if (!f6i) return ERR_PTR(-ENOMEM); @@ -3779,9 +3781,9 @@ struct fib6_info *addrconf_f6i_alloc(struct net *net, f6i->fib6_flags |= RTF_LOCAL; } - f6i->fib6_nh.nh_gw = *addr; + f6i->fib6_nh->nh_gw = *addr; dev_hold(dev); - f6i->fib6_nh.nh_dev = dev; + f6i->fib6_nh->nh_dev = dev; f6i->fib6_dst.addr = *addr; f6i->fib6_dst.plen = 128; tb_id = l3mdev_fib_table(idev->dev) ? : RT6_TABLE_LOCAL; @@ -3803,7 +3805,7 @@ static int fib6_remove_prefsrc(struct fib6_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->fib6_nh.nh_dev == dev || !dev) && + if (((void *)rt->fib6_nh->nh_dev == dev || !dev) && rt != net->ipv6.fib6_null_entry && ipv6_addr_equal(addr, &rt->fib6_prefsrc.addr)) { spin_lock_bh(&rt6_exception_lock); @@ -3835,7 +3837,7 @@ static int fib6_clean_tohost(struct fib6_info *rt, void *arg) struct in6_addr *gateway = (struct in6_addr *)arg; if (((rt->fib6_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) && - ipv6_addr_equal(gateway, &rt->fib6_nh.nh_gw)) { + ipv6_addr_equal(gateway, &rt->fib6_nh->nh_gw)) { return -1; } @@ -3883,8 +3885,8 @@ static struct fib6_info *rt6_multipath_first_sibling(const struct fib6_info *rt) static bool rt6_is_dead(const struct fib6_info *rt) { - if (rt->fib6_nh.nh_flags & RTNH_F_DEAD || - (rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN && + if (rt->fib6_nh->nh_flags & RTNH_F_DEAD || + (rt->fib6_nh->nh_flags & RTNH_F_LINKDOWN && fib6_ignore_linkdown(rt))) return true; @@ -3897,11 +3899,11 @@ static int rt6_multipath_total_weight(const struct fib6_info *rt) int total = 0; if (!rt6_is_dead(rt)) - total += rt->fib6_nh.nh_weight; + total += rt->fib6_nh->nh_weight; list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) { if (!rt6_is_dead(iter)) - total += iter->fib6_nh.nh_weight; + total += iter->fib6_nh->nh_weight; } return total; @@ -3912,11 +3914,11 @@ static void rt6_upper_bound_set(struct fib6_info *rt, int *weight, int total) int upper_bound = -1; if (!rt6_is_dead(rt)) { - *weight += rt->fib6_nh.nh_weight; + *weight += rt->fib6_nh->nh_weight; upper_bound = DIV_ROUND_CLOSEST_ULL((u64) (*weight) << 31, total) - 1; } - atomic_set(&rt->fib6_nh.nh_upper_bound, upper_bound); + atomic_set(&rt->fib6_nh->nh_upper_bound, upper_bound); } static void rt6_multipath_upper_bound_set(struct fib6_info *rt, int total) @@ -3959,8 +3961,9 @@ static int fib6_ifup(struct fib6_info *rt, void *p_arg) const struct arg_netdev_event *arg = p_arg; struct net *net = dev_net(arg->dev); - if (rt != net->ipv6.fib6_null_entry && rt->fib6_nh.nh_dev == arg->dev) { - rt->fib6_nh.nh_flags &= ~arg->nh_flags; + if (rt != net->ipv6.fib6_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); } @@ -3988,10 +3991,10 @@ static bool rt6_multipath_uses_dev(const struct fib6_info *rt, { struct fib6_info *iter; - if (rt->fib6_nh.nh_dev == dev) + if (rt->fib6_nh->nh_dev == dev) return true; list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) - if (iter->fib6_nh.nh_dev == dev) + if (iter->fib6_nh->nh_dev == dev) return true; return false; @@ -4012,12 +4015,12 @@ static unsigned int rt6_multipath_dead_count(const struct fib6_info *rt, struct fib6_info *iter; unsigned int dead = 0; - if (rt->fib6_nh.nh_dev == down_dev || - rt->fib6_nh.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->fib6_siblings, fib6_siblings) - if (iter->fib6_nh.nh_dev == down_dev || - iter->fib6_nh.nh_flags & RTNH_F_DEAD) + if (iter->fib6_nh->nh_dev == down_dev || + iter->fib6_nh->nh_flags & RTNH_F_DEAD) dead++; return dead; @@ -4029,11 +4032,11 @@ static void rt6_multipath_nh_flags_set(struct fib6_info *rt, { struct fib6_info *iter; - if (rt->fib6_nh.nh_dev == dev) - rt->fib6_nh.nh_flags |= nh_flags; + if (rt->fib6_nh->nh_dev == dev) + rt->fib6_nh->nh_flags |= nh_flags; list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) - if (iter->fib6_nh.nh_dev == dev) - iter->fib6_nh.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 */ @@ -4048,12 +4051,12 @@ static int fib6_ifdown(struct fib6_info *rt, void *p_arg) switch (arg->event) { case NETDEV_UNREGISTER: - return rt->fib6_nh.nh_dev == dev ? -1 : 0; + return rt->fib6_nh->nh_dev == dev ? -1 : 0; case NETDEV_DOWN: if (rt->should_flush) return -1; if (!rt->fib6_nsiblings) - return rt->fib6_nh.nh_dev == dev ? -1 : 0; + return rt->fib6_nh->nh_dev == dev ? -1 : 0; if (rt6_multipath_uses_dev(rt, dev)) { unsigned int count; @@ -4069,10 +4072,10 @@ static int fib6_ifdown(struct fib6_info *rt, void *p_arg) } return -2; case NETDEV_CHANGE: - if (rt->fib6_nh.nh_dev != dev || + if (rt->fib6_nh->nh_dev != dev || rt->fib6_flags & (RTF_LOCAL | RTF_ANYCAST)) break; - rt->fib6_nh.nh_flags |= RTNH_F_LINKDOWN; + rt->fib6_nh->nh_flags |= RTNH_F_LINKDOWN; rt6_multipath_rebalance(rt); break; } @@ -4124,7 +4127,7 @@ static int rt6_mtu_change_route(struct fib6_info *rt, void *p_arg) Since RFC 1981 doesn't include administrative MTU increase update PMTU increase is a MUST. (i.e. jumbo frame) */ - if (rt->fib6_nh.nh_dev == arg->dev && + if (rt->fib6_nh->nh_dev == arg->dev && !fib6_metric_locked(rt, RTAX_MTU)) { u32 mtu = rt->fib6_pmtu; @@ -4426,7 +4429,7 @@ static int ip6_route_multipath_add(struct fib6_config *cfg, goto cleanup; } - rt->fib6_nh.nh_weight = rtnh->rtnh_hops + 1; + rt->fib6_nh->nh_weight = rtnh->rtnh_hops + 1; err = ip6_route_info_append(info->nl_net, &rt6_nh_list, rt, &r_cfg); @@ -4589,7 +4592,7 @@ static size_t rt6_nlmsg_size(struct fib6_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->fib6_nh.nh_lwtstate); + + lwtunnel_get_encap_size(rt->fib6_nh->nh_lwtstate); nexthop_len *= rt->fib6_nsiblings; } @@ -4607,17 +4610,17 @@ static size_t rt6_nlmsg_size(struct fib6_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->fib6_nh.nh_lwtstate) + + lwtunnel_get_encap_size(rt->fib6_nh->nh_lwtstate) + nexthop_len; } static int rt6_nexthop_info(struct sk_buff *skb, struct fib6_info *rt, unsigned int *flags, bool skip_oif) { - if (rt->fib6_nh.nh_flags & RTNH_F_DEAD) + if (rt->fib6_nh->nh_flags & RTNH_F_DEAD) *flags |= RTNH_F_DEAD; - if (rt->fib6_nh.nh_flags & RTNH_F_LINKDOWN) { + if (rt->fib6_nh->nh_flags & RTNH_F_LINKDOWN) { *flags |= RTNH_F_LINKDOWN; rcu_read_lock(); @@ -4627,21 +4630,21 @@ static int rt6_nexthop_info(struct sk_buff *skb, struct fib6_info *rt, } if (rt->fib6_flags & RTF_GATEWAY) { - if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->fib6_nh.nh_gw) < 0) + if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->fib6_nh->nh_gw) < 0) goto nla_put_failure; } - *flags |= (rt->fib6_nh.nh_flags & RTNH_F_ONLINK); - if (rt->fib6_nh.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->fib6_nh.nh_dev && - nla_put_u32(skb, RTA_OIF, rt->fib6_nh.nh_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->fib6_nh.nh_lwtstate && - lwtunnel_fill_encap(skb, rt->fib6_nh.nh_lwtstate) < 0) + if (rt->fib6_nh->nh_lwtstate && + lwtunnel_fill_encap(skb, rt->fib6_nh->nh_lwtstate) < 0) goto nla_put_failure; return 0; @@ -4653,7 +4656,7 @@ static int rt6_nexthop_info(struct sk_buff *skb, struct fib6_info *rt, /* add multipath next hop */ static int rt6_add_nexthop(struct sk_buff *skb, struct fib6_info *rt) { - const struct net_device *dev = rt->fib6_nh.nh_dev; + const struct net_device *dev = rt->fib6_nh->nh_dev; struct rtnexthop *rtnh; unsigned int flags = 0; @@ -4661,7 +4664,7 @@ static int rt6_add_nexthop(struct sk_buff *skb, struct fib6_info *rt) if (!rtnh) goto nla_put_failure; - rtnh->rtnh_hops = rt->fib6_nh.nh_weight - 1; + 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) @@ -5017,7 +5020,7 @@ static int ip6_route_dev_notify(struct notifier_block *this, return NOTIFY_OK; if (event == NETDEV_REGISTER) { - net->ipv6.fib6_null_entry->fib6_nh.nh_dev = dev; + net->ipv6.fib6_null_entry->fib6_nh->nh_dev = dev; net->ipv6.ip6_null_entry->dst.dev = dev; net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev); #ifdef CONFIG_IPV6_MULTIPLE_TABLES @@ -5194,11 +5197,11 @@ static int __net_init ip6_route_net_init(struct net *net) if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0) goto out_ip6_dst_ops; - net->ipv6.fib6_null_entry = kmemdup(&fib6_null_entry_template, - sizeof(*net->ipv6.fib6_null_entry), - GFP_KERNEL); + net->ipv6.fib6_null_entry = fib6_info_alloc(GFP_KERNEL, true); if (!net->ipv6.fib6_null_entry) goto out_ip6_dst_entries; + memcpy(net->ipv6.fib6_null_entry, &fib6_null_entry_template, + sizeof(*net->ipv6.fib6_null_entry)); net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template, sizeof(*net->ipv6.ip6_null_entry), @@ -5334,7 +5337,7 @@ void __init ip6_route_init_special_entries(void) /* Registering of the loopback is done before this portion of code, * the loopback reference in rt6_info will not be taken, do it * manually for init_net */ - init_net.ipv6.fib6_null_entry->fib6_nh.nh_dev = init_net.loopback_dev; + init_net.ipv6.fib6_null_entry->fib6_nh->nh_dev = init_net.loopback_dev; init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev; init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); #ifdef CONFIG_IPV6_MULTIPLE_TABLES -- 2.11.0