Skip to content

Commit

Permalink
ipv4: Add fib_nh_common to fib_result
Browse files Browse the repository at this point in the history
Most of the ipv4 code only needs data from fib_nh_common. Add
fib_nh_common selection to fib_result and update users to use it.

Right now, fib_nh_common in fib_result will point to a fib_nh struct
that is embedded within a fib_info:

        fib_info  --> fib_nh
                      fib_nh
                      ...
                      fib_nh
                        ^
    fib_result->nhc ----+

Later, nhc can point to a fib_nh within a nexthop struct:

        fib_info --> nexthop --> fib_nh
                                   ^
    fib_result->nhc ---------------+

or for a nexthop group:

        fib_info --> nexthop --> nexthop --> fib_nh
                                 nexthop --> fib_nh
                                 ...
                                 nexthop --> fib_nh
                                               ^
    fib_result->nhc ---------------------------+

In all cases nhsel within fib_result will point to which leg in the
multipath route is used.

Signed-off-by: David Ahern <dsahern@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David Ahern authored and David S. Miller committed Apr 4, 2019
1 parent 0af7e7c commit eba618a
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 65 deletions.
47 changes: 21 additions & 26 deletions include/net/ip_fib.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,15 +156,16 @@ struct fib_rule;

struct fib_table;
struct fib_result {
__be32 prefix;
unsigned char prefixlen;
unsigned char nh_sel;
unsigned char type;
unsigned char scope;
u32 tclassid;
struct fib_info *fi;
struct fib_table *table;
struct hlist_head *fa_head;
__be32 prefix;
unsigned char prefixlen;
unsigned char nh_sel;
unsigned char type;
unsigned char scope;
u32 tclassid;
struct fib_nh_common *nhc;
struct fib_info *fi;
struct fib_table *table;
struct hlist_head *fa_head;
};

struct fib_result_nl {
Expand All @@ -182,11 +183,10 @@ struct fib_result_nl {
int err;
};

#ifdef CONFIG_IP_ROUTE_MULTIPATH
#define FIB_RES_NH(res) ((res).fi->fib_nh[(res).nh_sel])
#else /* CONFIG_IP_ROUTE_MULTIPATH */
#define FIB_RES_NH(res) ((res).fi->fib_nh[0])
#endif /* CONFIG_IP_ROUTE_MULTIPATH */
static inline struct fib_nh_common *fib_info_nhc(struct fib_info *fi, int nhsel)
{
return &fi->fib_nh[nhsel].nh_common;
}

#ifdef CONFIG_IP_MULTIPLE_TABLES
#define FIB_TABLE_HASHSZ 256
Expand All @@ -195,18 +195,11 @@ struct fib_result_nl {
#endif

__be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh);
__be32 fib_result_prefsrc(struct net *net, struct fib_result *res);

#define FIB_RES_SADDR(net, res) \
((FIB_RES_NH(res).nh_saddr_genid == \
atomic_read(&(net)->ipv4.dev_addr_genid)) ? \
FIB_RES_NH(res).nh_saddr : \
fib_info_update_nh_saddr((net), &FIB_RES_NH(res)))
#define FIB_RES_GW(res) (FIB_RES_NH(res).fib_nh_gw4)
#define FIB_RES_DEV(res) (FIB_RES_NH(res).fib_nh_dev)
#define FIB_RES_OIF(res) (FIB_RES_NH(res).fib_nh_oif)

#define FIB_RES_PREFSRC(net, res) ((res).fi->fib_prefsrc ? : \
FIB_RES_SADDR(net, res))
#define FIB_RES_NHC(res) ((res).nhc)
#define FIB_RES_DEV(res) (FIB_RES_NHC(res)->nhc_dev)
#define FIB_RES_OIF(res) (FIB_RES_NHC(res)->nhc_oif)

struct fib_entry_notifier_info {
struct fib_notifier_info info; /* must be first */
Expand Down Expand Up @@ -453,10 +446,12 @@ struct fib_table *fib_trie_table(u32 id, struct fib_table *alias);
static inline void fib_combine_itag(u32 *itag, const struct fib_result *res)
{
#ifdef CONFIG_IP_ROUTE_CLASSID
struct fib_nh_common *nhc = res->nhc;
struct fib_nh *nh = container_of(nhc, struct fib_nh, nh_common);
#ifdef CONFIG_IP_MULTIPLE_TABLES
u32 rtag;
#endif
*itag = FIB_RES_NH(*res).nh_tclassid<<16;
*itag = nh->nh_tclassid << 16;
#ifdef CONFIG_IP_MULTIPLE_TABLES
rtag = res->tclassid;
if (*itag == 0)
Expand Down
12 changes: 6 additions & 6 deletions net/core/filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -4555,11 +4555,11 @@ static int bpf_fib_set_fwd_params(struct bpf_fib_lookup *params,
static int bpf_ipv4_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
u32 flags, bool check_mtu)
{
struct fib_nh_common *nhc;
struct in_device *in_dev;
struct neighbour *neigh;
struct net_device *dev;
struct fib_result res;
struct fib_nh *nh;
struct flowi4 fl4;
int err;
u32 mtu;
Expand Down Expand Up @@ -4632,15 +4632,15 @@ static int bpf_ipv4_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
return BPF_FIB_LKUP_RET_FRAG_NEEDED;
}

nh = &res.fi->fib_nh[res.nh_sel];
nhc = res.nhc;

/* do not handle lwt encaps right now */
if (nh->fib_nh_lws)
if (nhc->nhc_lwtstate)
return BPF_FIB_LKUP_RET_UNSUPP_LWT;

dev = nh->fib_nh_dev;
if (nh->fib_nh_gw4)
params->ipv4_dst = nh->fib_nh_gw4;
dev = nhc->nhc_dev;
if (nhc->nhc_has_gw)
params->ipv4_dst = nhc->nhc_gw.ipv4;

params->rt_metric = res.fi->fib_priority;

Expand Down
6 changes: 3 additions & 3 deletions net/ipv4/fib_frontend.c
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ __be32 fib_compute_spec_dst(struct sk_buff *skb)
.flowi4_mark = vmark ? skb->mark : 0,
};
if (!fib_lookup(net, &fl4, &res, 0))
return FIB_RES_PREFSRC(net, res);
return fib_result_prefsrc(net, &res);
} else {
scope = RT_SCOPE_LINK;
}
Expand Down Expand Up @@ -390,7 +390,7 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,

dev_match = fib_info_nh_uses_dev(res.fi, dev);
if (dev_match) {
ret = FIB_RES_NH(res).fib_nh_scope >= RT_SCOPE_HOST;
ret = FIB_RES_NHC(res)->nhc_scope >= RT_SCOPE_HOST;
return ret;
}
if (no_addr)
Expand All @@ -402,7 +402,7 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
ret = 0;
if (fib_lookup(net, &fl4, &res, FIB_LOOKUP_IGNORE_LINKSTATE) == 0) {
if (res.type == RTN_UNICAST)
ret = FIB_RES_NH(res).fib_nh_scope >= RT_SCOPE_HOST;
ret = FIB_RES_NHC(res)->nhc_scope >= RT_SCOPE_HOST;
}
return ret;

Expand Down
1 change: 1 addition & 0 deletions net/ipv4/fib_lookup.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ static inline void fib_result_assign(struct fib_result *res,
{
/* we used to play games with refcounts, but we now use RCU */
res->fi = fi;
res->nhc = fib_info_nhc(fi, 0);
}

struct fib_prop {
Expand Down
25 changes: 21 additions & 4 deletions net/ipv4/fib_semantics.c
Original file line number Diff line number Diff line change
Expand Up @@ -1075,6 +1075,21 @@ __be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh)
return nh->nh_saddr;
}

__be32 fib_result_prefsrc(struct net *net, struct fib_result *res)
{
struct fib_nh_common *nhc = res->nhc;
struct fib_nh *nh;

if (res->fi->fib_prefsrc)
return res->fi->fib_prefsrc;

nh = container_of(nhc, struct fib_nh, nh_common);
if (nh->nh_saddr_genid == atomic_read(&net->ipv4.dev_addr_genid))
return nh->nh_saddr;

return fib_info_update_nh_saddr(net, nh);
}

static bool fib_valid_prefsrc(struct fib_config *cfg, __be32 fib_prefsrc)
{
if (cfg->fc_type != RTN_LOCAL || !cfg->fc_dst ||
Expand Down Expand Up @@ -1762,20 +1777,22 @@ void fib_select_multipath(struct fib_result *res, int hash)
struct net *net = fi->fib_net;
bool first = false;

for_nexthops(fi) {
change_nexthops(fi) {
if (net->ipv4.sysctl_fib_multipath_use_neigh) {
if (!fib_good_nh(nh))
if (!fib_good_nh(nexthop_nh))
continue;
if (!first) {
res->nh_sel = nhsel;
res->nhc = &nexthop_nh->nh_common;
first = true;
}
}

if (hash > atomic_read(&nh->fib_nh_upper_bound))
if (hash > atomic_read(&nexthop_nh->fib_nh_upper_bound))
continue;

res->nh_sel = nhsel;
res->nhc = &nexthop_nh->nh_common;
return;
} endfor_nexthops(fi);
}
Expand All @@ -1802,5 +1819,5 @@ void fib_select_path(struct net *net, struct fib_result *res,

check_saddr:
if (!fl4->saddr)
fl4->saddr = FIB_RES_PREFSRC(net, *res);
fl4->saddr = fib_result_prefsrc(net, res);
}
13 changes: 7 additions & 6 deletions net/ipv4/fib_trie.c
Original file line number Diff line number Diff line change
Expand Up @@ -1470,17 +1470,17 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
if (fi->fib_flags & RTNH_F_DEAD)
continue;
for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) {
const struct fib_nh *nh = &fi->fib_nh[nhsel];
struct fib_nh_common *nhc = fib_info_nhc(fi, nhsel);

if (nh->fib_nh_flags & RTNH_F_DEAD)
if (nhc->nhc_flags & RTNH_F_DEAD)
continue;
if (ip_ignore_linkdown(nh->fib_nh_dev) &&
nh->fib_nh_flags & RTNH_F_LINKDOWN &&
if (ip_ignore_linkdown(nhc->nhc_dev) &&
nhc->nhc_flags & RTNH_F_LINKDOWN &&
!(fib_flags & FIB_LOOKUP_IGNORE_LINKSTATE))
continue;
if (!(flp->flowi4_flags & FLOWI_FLAG_SKIP_NH_OIF)) {
if (flp->flowi4_oif &&
flp->flowi4_oif != nh->fib_nh_oif)
flp->flowi4_oif != nhc->nhc_oif)
continue;
}

Expand All @@ -1490,6 +1490,7 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
res->prefix = htonl(n->key);
res->prefixlen = KEYLENGTH - fa->fa_slen;
res->nh_sel = nhsel;
res->nhc = nhc;
res->type = fa->fa_type;
res->scope = fi->fib_scope;
res->fi = fi;
Expand All @@ -1498,7 +1499,7 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
#ifdef CONFIG_IP_FIB_TRIE_STATS
this_cpu_inc(stats->semantic_match_passed);
#endif
trace_fib_table_lookup(tb->tb_id, flp, &nh->nh_common, err);
trace_fib_table_lookup(tb->tb_id, flp, nhc, err);

return err;
}
Expand Down
Loading

0 comments on commit eba618a

Please sign in to comment.