Commit cea29a70 authored by David S. Miller's avatar David S. Miller

Merge branch 'ipv6-Use-fib6_result-for-fib_lookups'

David Ahern says:

====================
ipv6: Use fib6_result for fib_lookups

Add fib6_result as a single data structure to hold results from a fib
lookup. IPv6 currently has everything in 1 data structure - a fib6_info,
but with nexthop objects the fib6_nh can be in a nexthop or a nexthop
can be a blackhole which affects the fib6_type and flags (REJECT).

v2
- fixed 2 bugs in patch12:
  i. checking return from fib6_table_lookup in fib6_lookup
  ii. call to fib6_rule_saddr in fib6_rule_action_alt should use res->nh
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 6b0a7f84 7d21fec9
...@@ -190,6 +190,13 @@ struct rt6_info { ...@@ -190,6 +190,13 @@ struct rt6_info {
unsigned short rt6i_nfheader_len; unsigned short rt6i_nfheader_len;
}; };
struct fib6_result {
struct fib6_nh *nh;
struct fib6_info *f6i;
u32 fib6_flags;
u8 fib6_type;
};
#define for_each_fib6_node_rt_rcu(fn) \ #define for_each_fib6_node_rt_rcu(fn) \
for (rt = rcu_dereference((fn)->leaf); rt; \ for (rt = rcu_dereference((fn)->leaf); rt; \
rt = rcu_dereference(rt->fib6_next)) rt = rcu_dereference(rt->fib6_next))
...@@ -384,18 +391,17 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6, ...@@ -384,18 +391,17 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6,
/* called with rcu lock held; can return error pointer /* called with rcu lock held; can return error pointer
* caller needs to select path * caller needs to select path
*/ */
struct fib6_info *fib6_lookup(struct net *net, int oif, struct flowi6 *fl6, int fib6_lookup(struct net *net, int oif, struct flowi6 *fl6,
int flags); struct fib6_result *res, int flags);
/* called with rcu lock held; caller needs to select path */ /* called with rcu lock held; caller needs to select path */
struct fib6_info *fib6_table_lookup(struct net *net, struct fib6_table *table, int fib6_table_lookup(struct net *net, struct fib6_table *table,
int oif, struct flowi6 *fl6, int strict); int oif, struct flowi6 *fl6, struct fib6_result *res,
int strict);
struct fib6_info *fib6_multipath_select(const struct net *net, void fib6_select_path(const struct net *net, struct fib6_result *res,
struct fib6_info *match, struct flowi6 *fl6, int oif, bool have_oif_match,
struct flowi6 *fl6, int oif,
const struct sk_buff *skb, int strict); const struct sk_buff *skb, int strict);
struct fib6_node *fib6_node_lookup(struct fib6_node *root, struct fib6_node *fib6_node_lookup(struct fib6_node *root,
const struct in6_addr *daddr, const struct in6_addr *daddr,
const struct in6_addr *saddr); const struct in6_addr *saddr);
......
...@@ -302,8 +302,9 @@ static inline unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst) ...@@ -302,8 +302,9 @@ static inline unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst)
return mtu; return mtu;
} }
u32 ip6_mtu_from_fib6(struct fib6_info *f6i, struct in6_addr *daddr, u32 ip6_mtu_from_fib6(const struct fib6_result *res,
struct in6_addr *saddr); const struct in6_addr *daddr,
const struct in6_addr *saddr);
struct neighbour *ip6_neigh_lookup(const struct in6_addr *gw, struct neighbour *ip6_neigh_lookup(const struct in6_addr *gw,
struct net_device *dev, struct sk_buff *skb, struct net_device *dev, struct sk_buff *skb,
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
struct fib6_info; struct fib6_info;
struct fib6_nh; struct fib6_nh;
struct fib6_config; struct fib6_config;
struct fib6_result;
/* This is ugly, ideally these symbols should be built /* This is ugly, ideally these symbols should be built
* into the core kernel. * into the core kernel.
...@@ -28,19 +29,17 @@ struct ipv6_stub { ...@@ -28,19 +29,17 @@ struct ipv6_stub {
int (*ipv6_route_input)(struct sk_buff *skb); int (*ipv6_route_input)(struct sk_buff *skb);
struct fib6_table *(*fib6_get_table)(struct net *net, u32 id); struct fib6_table *(*fib6_get_table)(struct net *net, u32 id);
struct fib6_info *(*fib6_lookup)(struct net *net, int oif, int (*fib6_lookup)(struct net *net, int oif, struct flowi6 *fl6,
struct flowi6 *fl6, int flags); struct fib6_result *res, int flags);
struct fib6_info *(*fib6_table_lookup)(struct net *net, int (*fib6_table_lookup)(struct net *net, struct fib6_table *table,
struct fib6_table *table,
int oif, struct flowi6 *fl6, int oif, struct flowi6 *fl6,
int flags); struct fib6_result *res, int flags);
struct fib6_info *(*fib6_multipath_select)(const struct net *net, void (*fib6_select_path)(const struct net *net, struct fib6_result *res,
struct fib6_info *f6i, struct flowi6 *fl6, int oif, bool oif_match,
struct flowi6 *fl6, int oif, const struct sk_buff *skb, int strict);
const struct sk_buff *skb, u32 (*ip6_mtu_from_fib6)(const struct fib6_result *res,
int strict); const struct in6_addr *daddr,
u32 (*ip6_mtu_from_fib6)(struct fib6_info *f6i, struct in6_addr *daddr, const struct in6_addr *saddr);
struct in6_addr *saddr);
int (*fib6_nh_init)(struct net *net, struct fib6_nh *fib6_nh, int (*fib6_nh_init)(struct net *net, struct fib6_nh *fib6_nh,
struct fib6_config *cfg, gfp_t gfp_flags, struct fib6_config *cfg, gfp_t gfp_flags,
......
...@@ -12,10 +12,10 @@ ...@@ -12,10 +12,10 @@
TRACE_EVENT(fib6_table_lookup, TRACE_EVENT(fib6_table_lookup,
TP_PROTO(const struct net *net, const struct fib6_info *f6i, TP_PROTO(const struct net *net, const struct fib6_result *res,
struct fib6_table *table, const struct flowi6 *flp), struct fib6_table *table, const struct flowi6 *flp),
TP_ARGS(net, f6i, table, flp), TP_ARGS(net, res, table, flp),
TP_STRUCT__entry( TP_STRUCT__entry(
__field( u32, tb_id ) __field( u32, tb_id )
...@@ -39,7 +39,7 @@ TRACE_EVENT(fib6_table_lookup, ...@@ -39,7 +39,7 @@ TRACE_EVENT(fib6_table_lookup,
struct in6_addr *in6; struct in6_addr *in6;
__entry->tb_id = table->tb6_id; __entry->tb_id = table->tb6_id;
__entry->err = ip6_rt_type_to_error(f6i->fib6_type); __entry->err = ip6_rt_type_to_error(res->fib6_type);
__entry->oif = flp->flowi6_oif; __entry->oif = flp->flowi6_oif;
__entry->iif = flp->flowi6_iif; __entry->iif = flp->flowi6_iif;
__entry->tos = ip6_tclass(flp->flowlabel); __entry->tos = ip6_tclass(flp->flowlabel);
...@@ -62,20 +62,20 @@ TRACE_EVENT(fib6_table_lookup, ...@@ -62,20 +62,20 @@ TRACE_EVENT(fib6_table_lookup,
__entry->dport = 0; __entry->dport = 0;
} }
if (f6i->fib6_nh.fib_nh_dev) { if (res->nh && res->nh->fib_nh_dev) {
__assign_str(name, f6i->fib6_nh.fib_nh_dev); __assign_str(name, res->nh->fib_nh_dev);
} else { } else {
__assign_str(name, "-"); __assign_str(name, "-");
} }
if (f6i == net->ipv6.fib6_null_entry) { if (res->f6i == net->ipv6.fib6_null_entry) {
struct in6_addr in6_zero = {}; struct in6_addr in6_zero = {};
in6 = (struct in6_addr *)__entry->gw; in6 = (struct in6_addr *)__entry->gw;
*in6 = in6_zero; *in6 = in6_zero;
} else if (f6i) { } else if (res->nh) {
in6 = (struct in6_addr *)__entry->gw; in6 = (struct in6_addr *)__entry->gw;
*in6 = f6i->fib6_nh.fib_nh_gw6; *in6 = res->nh->fib_nh_gw6;
} }
), ),
......
...@@ -4679,12 +4679,12 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params, ...@@ -4679,12 +4679,12 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
struct in6_addr *src = (struct in6_addr *) params->ipv6_src; struct in6_addr *src = (struct in6_addr *) params->ipv6_src;
struct in6_addr *dst = (struct in6_addr *) params->ipv6_dst; struct in6_addr *dst = (struct in6_addr *) params->ipv6_dst;
struct neighbour *neigh; struct neighbour *neigh;
struct fib6_result res;
struct net_device *dev; struct net_device *dev;
struct inet6_dev *idev; struct inet6_dev *idev;
struct fib6_info *f6i;
struct flowi6 fl6; struct flowi6 fl6;
int strict = 0; int strict = 0;
int oif; int oif, err;
u32 mtu; u32 mtu;
/* link local addresses are never forwarded */ /* link local addresses are never forwarded */
...@@ -4726,21 +4726,25 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params, ...@@ -4726,21 +4726,25 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
if (unlikely(!tb)) if (unlikely(!tb))
return BPF_FIB_LKUP_RET_NOT_FWDED; return BPF_FIB_LKUP_RET_NOT_FWDED;
f6i = ipv6_stub->fib6_table_lookup(net, tb, oif, &fl6, strict); err = ipv6_stub->fib6_table_lookup(net, tb, oif, &fl6, &res,
strict);
} else { } else {
fl6.flowi6_mark = 0; fl6.flowi6_mark = 0;
fl6.flowi6_secid = 0; fl6.flowi6_secid = 0;
fl6.flowi6_tun_key.tun_id = 0; fl6.flowi6_tun_key.tun_id = 0;
fl6.flowi6_uid = sock_net_uid(net, NULL); fl6.flowi6_uid = sock_net_uid(net, NULL);
f6i = ipv6_stub->fib6_lookup(net, oif, &fl6, strict); err = ipv6_stub->fib6_lookup(net, oif, &fl6, &res, strict);
} }
if (unlikely(IS_ERR_OR_NULL(f6i) || f6i == net->ipv6.fib6_null_entry)) if (unlikely(err || IS_ERR_OR_NULL(res.f6i) ||
res.f6i == net->ipv6.fib6_null_entry))
return BPF_FIB_LKUP_RET_NOT_FWDED; return BPF_FIB_LKUP_RET_NOT_FWDED;
if (unlikely(f6i->fib6_flags & RTF_REJECT)) { switch (res.fib6_type) {
switch (f6i->fib6_type) { /* only unicast is forwarded */
case RTN_UNICAST:
break;
case RTN_BLACKHOLE: case RTN_BLACKHOLE:
return BPF_FIB_LKUP_RET_BLACKHOLE; return BPF_FIB_LKUP_RET_BLACKHOLE;
case RTN_UNREACHABLE: case RTN_UNREACHABLE:
...@@ -4750,30 +4754,24 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params, ...@@ -4750,30 +4754,24 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
default: default:
return BPF_FIB_LKUP_RET_NOT_FWDED; return BPF_FIB_LKUP_RET_NOT_FWDED;
} }
}
if (f6i->fib6_type != RTN_UNICAST) ipv6_stub->fib6_select_path(net, &res, &fl6, fl6.flowi6_oif,
return BPF_FIB_LKUP_RET_NOT_FWDED; fl6.flowi6_oif != 0, NULL, strict);
if (f6i->fib6_nsiblings && fl6.flowi6_oif == 0)
f6i = ipv6_stub->fib6_multipath_select(net, f6i, &fl6,
fl6.flowi6_oif, NULL,
strict);
if (check_mtu) { if (check_mtu) {
mtu = ipv6_stub->ip6_mtu_from_fib6(f6i, dst, src); mtu = ipv6_stub->ip6_mtu_from_fib6(&res, dst, src);
if (params->tot_len > mtu) if (params->tot_len > mtu)
return BPF_FIB_LKUP_RET_FRAG_NEEDED; return BPF_FIB_LKUP_RET_FRAG_NEEDED;
} }
if (f6i->fib6_nh.fib_nh_lws) if (res.nh->fib_nh_lws)
return BPF_FIB_LKUP_RET_UNSUPP_LWT; return BPF_FIB_LKUP_RET_UNSUPP_LWT;
if (f6i->fib6_nh.fib_nh_gw_family) if (res.nh->fib_nh_gw_family)
*dst = f6i->fib6_nh.fib_nh_gw6; *dst = res.nh->fib_nh_gw6;
dev = f6i->fib6_nh.fib_nh_dev; dev = res.nh->fib_nh_dev;
params->rt_metric = f6i->fib6_metric; params->rt_metric = res.f6i->fib6_metric;
/* xdp and cls_bpf programs are run in RCU-bh so rcu_read_lock_bh is /* xdp and cls_bpf programs are run in RCU-bh so rcu_read_lock_bh is
* not needed here. * not needed here.
......
...@@ -144,31 +144,32 @@ static struct fib6_table *eafnosupport_fib6_get_table(struct net *net, u32 id) ...@@ -144,31 +144,32 @@ static struct fib6_table *eafnosupport_fib6_get_table(struct net *net, u32 id)
return NULL; return NULL;
} }
static struct fib6_info * static int
eafnosupport_fib6_table_lookup(struct net *net, struct fib6_table *table, eafnosupport_fib6_table_lookup(struct net *net, struct fib6_table *table,
int oif, struct flowi6 *fl6, int flags) int oif, struct flowi6 *fl6,
struct fib6_result *res, int flags)
{ {
return NULL; return -EAFNOSUPPORT;
} }
static struct fib6_info * static int
eafnosupport_fib6_lookup(struct net *net, int oif, struct flowi6 *fl6, eafnosupport_fib6_lookup(struct net *net, int oif, struct flowi6 *fl6,
int flags) struct fib6_result *res, int flags)
{ {
return NULL; return -EAFNOSUPPORT;
} }
static struct fib6_info * static void
eafnosupport_fib6_multipath_select(const struct net *net, struct fib6_info *f6i, eafnosupport_fib6_select_path(const struct net *net, struct fib6_result *res,
struct flowi6 *fl6, int oif, struct flowi6 *fl6, int oif, bool have_oif_match,
const struct sk_buff *skb, int strict) const struct sk_buff *skb, int strict)
{ {
return f6i;
} }
static u32 static u32
eafnosupport_ip6_mtu_from_fib6(struct fib6_info *f6i, struct in6_addr *daddr, eafnosupport_ip6_mtu_from_fib6(const struct fib6_result *res,
struct in6_addr *saddr) const struct in6_addr *daddr,
const struct in6_addr *saddr)
{ {
return 0; return 0;
} }
...@@ -187,7 +188,7 @@ const struct ipv6_stub *ipv6_stub __read_mostly = &(struct ipv6_stub) { ...@@ -187,7 +188,7 @@ const struct ipv6_stub *ipv6_stub __read_mostly = &(struct ipv6_stub) {
.fib6_get_table = eafnosupport_fib6_get_table, .fib6_get_table = eafnosupport_fib6_get_table,
.fib6_table_lookup = eafnosupport_fib6_table_lookup, .fib6_table_lookup = eafnosupport_fib6_table_lookup,
.fib6_lookup = eafnosupport_fib6_lookup, .fib6_lookup = eafnosupport_fib6_lookup,
.fib6_multipath_select = eafnosupport_fib6_multipath_select, .fib6_select_path = eafnosupport_fib6_select_path,
.ip6_mtu_from_fib6 = eafnosupport_ip6_mtu_from_fib6, .ip6_mtu_from_fib6 = eafnosupport_ip6_mtu_from_fib6,
.fib6_nh_init = eafnosupport_fib6_nh_init, .fib6_nh_init = eafnosupport_fib6_nh_init,
}; };
......
...@@ -917,7 +917,7 @@ static const struct ipv6_stub ipv6_stub_impl = { ...@@ -917,7 +917,7 @@ static const struct ipv6_stub ipv6_stub_impl = {
.fib6_get_table = fib6_get_table, .fib6_get_table = fib6_get_table,
.fib6_table_lookup = fib6_table_lookup, .fib6_table_lookup = fib6_table_lookup,
.fib6_lookup = fib6_lookup, .fib6_lookup = fib6_lookup,
.fib6_multipath_select = fib6_multipath_select, .fib6_select_path = fib6_select_path,
.ip6_mtu_from_fib6 = ip6_mtu_from_fib6, .ip6_mtu_from_fib6 = ip6_mtu_from_fib6,
.fib6_nh_init = fib6_nh_init, .fib6_nh_init = fib6_nh_init,
.fib6_nh_release = fib6_nh_release, .fib6_nh_release = fib6_nh_release,
......
...@@ -61,16 +61,16 @@ unsigned int fib6_rules_seq_read(struct net *net) ...@@ -61,16 +61,16 @@ unsigned int fib6_rules_seq_read(struct net *net)
} }
/* called with rcu lock held; no reference taken on fib6_info */ /* called with rcu lock held; no reference taken on fib6_info */
struct fib6_info *fib6_lookup(struct net *net, int oif, struct flowi6 *fl6, int fib6_lookup(struct net *net, int oif, struct flowi6 *fl6,
int flags) struct fib6_result *res, int flags)
{ {
struct fib6_info *f6i;
int err; int err;
if (net->ipv6.fib6_has_custom_rules) { if (net->ipv6.fib6_has_custom_rules) {
struct fib_lookup_arg arg = { struct fib_lookup_arg arg = {
.lookup_ptr = fib6_table_lookup, .lookup_ptr = fib6_table_lookup,
.lookup_data = &oif, .lookup_data = &oif,
.result = res,
.flags = FIB_LOOKUP_NOREF, .flags = FIB_LOOKUP_NOREF,
}; };
...@@ -78,19 +78,15 @@ struct fib6_info *fib6_lookup(struct net *net, int oif, struct flowi6 *fl6, ...@@ -78,19 +78,15 @@ struct fib6_info *fib6_lookup(struct net *net, int oif, struct flowi6 *fl6,
err = fib_rules_lookup(net->ipv6.fib6_rules_ops, err = fib_rules_lookup(net->ipv6.fib6_rules_ops,
flowi6_to_flowi(fl6), flags, &arg); flowi6_to_flowi(fl6), flags, &arg);
if (err)
return ERR_PTR(err);
f6i = arg.result ? : net->ipv6.fib6_null_entry;
} else { } else {
f6i = fib6_table_lookup(net, net->ipv6.fib6_local_tbl, err = fib6_table_lookup(net, net->ipv6.fib6_local_tbl, oif,
oif, fl6, flags); fl6, res, flags);
if (!f6i || f6i == net->ipv6.fib6_null_entry) if (err || res->f6i == net->ipv6.fib6_null_entry)
f6i = fib6_table_lookup(net, net->ipv6.fib6_main_tbl, err = fib6_table_lookup(net, net->ipv6.fib6_main_tbl,
oif, fl6, flags); oif, fl6, res, flags);
} }
return f6i; return err;
} }
struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6, struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6,
...@@ -157,10 +153,10 @@ static int fib6_rule_saddr(struct net *net, struct fib_rule *rule, int flags, ...@@ -157,10 +153,10 @@ static int fib6_rule_saddr(struct net *net, struct fib_rule *rule, int flags,
static int fib6_rule_action_alt(struct fib_rule *rule, struct flowi *flp, static int fib6_rule_action_alt(struct fib_rule *rule, struct flowi *flp,
int flags, struct fib_lookup_arg *arg) int flags, struct fib_lookup_arg *arg)
{ {
struct fib6_result *res = arg->result;
struct flowi6 *flp6 = &flp->u.ip6; struct flowi6 *flp6 = &flp->u.ip6;
struct net *net = rule->fr_net; struct net *net = rule->fr_net;
struct fib6_table *table; struct fib6_table *table;
struct fib6_info *f6i;
int err = -EAGAIN, *oif; int err = -EAGAIN, *oif;
u32 tb_id; u32 tb_id;
...@@ -182,14 +178,10 @@ static int fib6_rule_action_alt(struct fib_rule *rule, struct flowi *flp, ...@@ -182,14 +178,10 @@ static int fib6_rule_action_alt(struct fib_rule *rule, struct flowi *flp,
return -EAGAIN; return -EAGAIN;
oif = (int *)arg->lookup_data; oif = (int *)arg->lookup_data;
f6i = fib6_table_lookup(net, table, *oif, flp6, flags); err = fib6_table_lookup(net, table, *oif, flp6, res, flags);
if (f6i != net->ipv6.fib6_null_entry) { if (!err && res->f6i != net->ipv6.fib6_null_entry)
err = fib6_rule_saddr(net, rule, flags, flp6, err = fib6_rule_saddr(net, rule, flags, flp6,
fib6_info_nh_dev(f6i)); res->nh->fib_nh_dev);
if (likely(!err))
arg->result = f6i;
}
return err; return err;
} }
......
...@@ -354,10 +354,11 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6, ...@@ -354,10 +354,11 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6,
} }
/* called with rcu lock held; no reference taken on fib6_info */ /* called with rcu lock held; no reference taken on fib6_info */
struct fib6_info *fib6_lookup(struct net *net, int oif, struct flowi6 *fl6, int fib6_lookup(struct net *net, int oif, struct flowi6 *fl6,
int flags) struct fib6_result *res, int flags)
{ {
return fib6_table_lookup(net, net->ipv6.fib6_main_tbl, oif, fl6, flags); return fib6_table_lookup(net, net->ipv6.fib6_main_tbl, oif, fl6,
res, flags);
} }
static void __net_init fib6_tables_init(struct net *net) static void __net_init fib6_tables_init(struct net *net)
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment