Commit dcb1ecb5 authored by David Ahern's avatar David Ahern Committed by David S. Miller

ipv4: Prepare for fib6_nh from a nexthop object

Convert more IPv4 code to use fib_nh_common over fib_nh to enable routes
to use a fib6_nh based nexthop. In the end, only code not using a
nexthop object in a fib_info should directly access fib_nh in a fib_info
without checking the famiy and going through fib_nh_common. Those
functions will be marked when it is not directly evident.
Signed-off-by: default avatarDavid Ahern <dsahern@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5481d73f
...@@ -195,7 +195,7 @@ struct fib_result_nl { ...@@ -195,7 +195,7 @@ struct fib_result_nl {
#define FIB_TABLE_HASHSZ 2 #define FIB_TABLE_HASHSZ 2
#endif #endif
__be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh, __be32 fib_info_update_nhc_saddr(struct net *net, struct fib_nh_common *nhc,
unsigned char scope); unsigned char scope);
__be32 fib_result_prefsrc(struct net *net, struct fib_result *res); __be32 fib_result_prefsrc(struct net *net, struct fib_result *res);
...@@ -455,11 +455,18 @@ static inline void fib_combine_itag(u32 *itag, const struct fib_result *res) ...@@ -455,11 +455,18 @@ static inline void fib_combine_itag(u32 *itag, const struct fib_result *res)
{ {
#ifdef CONFIG_IP_ROUTE_CLASSID #ifdef CONFIG_IP_ROUTE_CLASSID
struct fib_nh_common *nhc = res->nhc; struct fib_nh_common *nhc = res->nhc;
struct fib_nh *nh = container_of(nhc, struct fib_nh, nh_common);
#ifdef CONFIG_IP_MULTIPLE_TABLES #ifdef CONFIG_IP_MULTIPLE_TABLES
u32 rtag; u32 rtag;
#endif #endif
if (nhc->nhc_family == AF_INET) {
struct fib_nh *nh;
nh = container_of(nhc, struct fib_nh, nh_common);
*itag = nh->nh_tclassid << 16; *itag = nh->nh_tclassid << 16;
} else {
*itag = 0;
}
#ifdef CONFIG_IP_MULTIPLE_TABLES #ifdef CONFIG_IP_MULTIPLE_TABLES
rtag = res->tclassid; rtag = res->tclassid;
if (*itag == 0) if (*itag == 0)
......
...@@ -235,9 +235,9 @@ static inline unsigned int __inet_dev_addr_type(struct net *net, ...@@ -235,9 +235,9 @@ static inline unsigned int __inet_dev_addr_type(struct net *net,
if (table) { if (table) {
ret = RTN_UNICAST; ret = RTN_UNICAST;
if (!fib_table_lookup(table, &fl4, &res, FIB_LOOKUP_NOREF)) { if (!fib_table_lookup(table, &fl4, &res, FIB_LOOKUP_NOREF)) {
struct fib_nh *nh = fib_info_nh(res.fi, 0); struct fib_nh_common *nhc = fib_info_nhc(res.fi, 0);
if (!dev || dev == nh->fib_nh_dev) if (!dev || dev == nhc->nhc_dev)
ret = res.type; ret = res.type;
} }
} }
...@@ -325,18 +325,18 @@ bool fib_info_nh_uses_dev(struct fib_info *fi, const struct net_device *dev) ...@@ -325,18 +325,18 @@ bool fib_info_nh_uses_dev(struct fib_info *fi, const struct net_device *dev)
int ret; int ret;
for (ret = 0; ret < fib_info_num_path(fi); ret++) { for (ret = 0; ret < fib_info_num_path(fi); ret++) {
const struct fib_nh *nh = fib_info_nh(fi, ret); const struct fib_nh_common *nhc = fib_info_nhc(fi, ret);
if (nh->fib_nh_dev == dev) { if (nhc->nhc_dev == dev) {
dev_match = true; dev_match = true;
break; break;
} else if (l3mdev_master_ifindex_rcu(nh->fib_nh_dev) == dev->ifindex) { } else if (l3mdev_master_ifindex_rcu(nhc->nhc_dev) == dev->ifindex) {
dev_match = true; dev_match = true;
break; break;
} }
} }
#else #else
if (fib_info_nh(fi, 0)->fib_nh_dev == dev) if (fib_info_nhc(fi, 0)->nhc_dev == dev)
dev_match = true; dev_match = true;
#endif #endif
......
...@@ -147,9 +147,9 @@ static bool fib4_rule_suppress(struct fib_rule *rule, struct fib_lookup_arg *arg ...@@ -147,9 +147,9 @@ static bool fib4_rule_suppress(struct fib_rule *rule, struct fib_lookup_arg *arg
struct net_device *dev = NULL; struct net_device *dev = NULL;
if (result->fi) { if (result->fi) {
struct fib_nh *nh = fib_info_nh(result->fi, 0); struct fib_nh_common *nhc = fib_info_nhc(result->fi, 0);
dev = nh->fib_nh_dev; dev = nhc->nhc_dev;
} }
/* do not accept result if the route does /* do not accept result if the route does
......
...@@ -61,6 +61,9 @@ static unsigned int fib_info_cnt; ...@@ -61,6 +61,9 @@ static unsigned int fib_info_cnt;
#define DEVINDEX_HASHSIZE (1U << DEVINDEX_HASHBITS) #define DEVINDEX_HASHSIZE (1U << DEVINDEX_HASHBITS)
static struct hlist_head fib_info_devhash[DEVINDEX_HASHSIZE]; static struct hlist_head fib_info_devhash[DEVINDEX_HASHSIZE];
/* for_nexthops and change_nexthops only used when nexthop object
* is not set in a fib_info. The logic within can reference fib_nh.
*/
#ifdef CONFIG_IP_ROUTE_MULTIPATH #ifdef CONFIG_IP_ROUTE_MULTIPATH
#define for_nexthops(fi) { \ #define for_nexthops(fi) { \
...@@ -402,20 +405,23 @@ static inline size_t fib_nlmsg_size(struct fib_info *fi) ...@@ -402,20 +405,23 @@ static inline size_t fib_nlmsg_size(struct fib_info *fi)
/* each nexthop is packed in an attribute */ /* each nexthop is packed in an attribute */
size_t nhsize = nla_total_size(sizeof(struct rtnexthop)); size_t nhsize = nla_total_size(sizeof(struct rtnexthop));
unsigned int i;
/* may contain flow and gateway attribute */ /* may contain flow and gateway attribute */
nhsize += 2 * nla_total_size(4); nhsize += 2 * nla_total_size(4);
/* grab encap info */ /* grab encap info */
for_nexthops(fi) { for (i = 0; i < fib_info_num_path(fi); i++) {
if (nh->fib_nh_lws) { struct fib_nh_common *nhc = fib_info_nhc(fi, i);
if (nhc->nhc_lwtstate) {
/* RTA_ENCAP_TYPE */ /* RTA_ENCAP_TYPE */
nh_encapsize += lwtunnel_get_encap_size( nh_encapsize += lwtunnel_get_encap_size(
nh->fib_nh_lws); nhc->nhc_lwtstate);
/* RTA_ENCAP */ /* RTA_ENCAP */
nh_encapsize += nla_total_size(2); nh_encapsize += nla_total_size(2);
} }
} endfor_nexthops(fi); }
/* all nexthops are packed in a nested attribute */ /* all nexthops are packed in a nested attribute */
payload += nla_total_size((nhs * nhsize) + nh_encapsize); payload += nla_total_size((nhs * nhsize) + nh_encapsize);
...@@ -1194,9 +1200,15 @@ static void fib_info_hash_move(struct hlist_head *new_info_hash, ...@@ -1194,9 +1200,15 @@ static void fib_info_hash_move(struct hlist_head *new_info_hash,
fib_info_hash_free(old_laddrhash, bytes); fib_info_hash_free(old_laddrhash, bytes);
} }
__be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh, __be32 fib_info_update_nhc_saddr(struct net *net, struct fib_nh_common *nhc,
unsigned char scope) unsigned char scope)
{ {
struct fib_nh *nh;
if (nhc->nhc_family != AF_INET)
return inet_select_addr(nhc->nhc_dev, 0, scope);
nh = container_of(nhc, struct fib_nh, nh_common);
nh->nh_saddr = inet_select_addr(nh->fib_nh_dev, nh->fib_nh_gw4, scope); nh->nh_saddr = inet_select_addr(nh->fib_nh_dev, nh->fib_nh_gw4, scope);
nh->nh_saddr_genid = atomic_read(&net->ipv4.dev_addr_genid); nh->nh_saddr_genid = atomic_read(&net->ipv4.dev_addr_genid);
...@@ -1206,16 +1218,19 @@ __be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh, ...@@ -1206,16 +1218,19 @@ __be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh,
__be32 fib_result_prefsrc(struct net *net, struct fib_result *res) __be32 fib_result_prefsrc(struct net *net, struct fib_result *res)
{ {
struct fib_nh_common *nhc = res->nhc; struct fib_nh_common *nhc = res->nhc;
struct fib_nh *nh;
if (res->fi->fib_prefsrc) if (res->fi->fib_prefsrc)
return res->fi->fib_prefsrc; return res->fi->fib_prefsrc;
if (nhc->nhc_family == AF_INET) {
struct fib_nh *nh;
nh = container_of(nhc, struct fib_nh, nh_common); nh = container_of(nhc, struct fib_nh, nh_common);
if (nh->nh_saddr_genid == atomic_read(&net->ipv4.dev_addr_genid)) if (nh->nh_saddr_genid == atomic_read(&net->ipv4.dev_addr_genid))
return nh->nh_saddr; return nh->nh_saddr;
}
return fib_info_update_nh_saddr(net, nh, res->fi->fib_scope); return fib_info_update_nhc_saddr(net, nhc, res->fi->fib_scope);
} }
static bool fib_valid_prefsrc(struct fib_config *cfg, __be32 fib_prefsrc) static bool fib_valid_prefsrc(struct fib_config *cfg, __be32 fib_prefsrc)
...@@ -1397,7 +1412,8 @@ struct fib_info *fib_create_info(struct fib_config *cfg, ...@@ -1397,7 +1412,8 @@ struct fib_info *fib_create_info(struct fib_config *cfg,
} }
change_nexthops(fi) { change_nexthops(fi) {
fib_info_update_nh_saddr(net, nexthop_nh, fi->fib_scope); fib_info_update_nhc_saddr(net, &nexthop_nh->nh_common,
fi->fib_scope);
if (nexthop_nh->fib_nh_gw_family == AF_INET6) if (nexthop_nh->fib_nh_gw_family == AF_INET6)
fi->fib_nh_is_v6 = true; fi->fib_nh_is_v6 = true;
} endfor_nexthops(fi) } endfor_nexthops(fi)
...@@ -1625,17 +1641,22 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event, ...@@ -1625,17 +1641,22 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
nla_put_in_addr(skb, RTA_PREFSRC, fi->fib_prefsrc)) nla_put_in_addr(skb, RTA_PREFSRC, fi->fib_prefsrc))
goto nla_put_failure; goto nla_put_failure;
if (nhs == 1) { if (nhs == 1) {
const struct fib_nh *nh = fib_info_nh(fi, 0); const struct fib_nh_common *nhc = fib_info_nhc(fi, 0);
unsigned char flags = 0; unsigned char flags = 0;
if (fib_nexthop_info(skb, &nh->nh_common, &flags, false) < 0) if (fib_nexthop_info(skb, nhc, &flags, false) < 0)
goto nla_put_failure; goto nla_put_failure;
rtm->rtm_flags = flags; rtm->rtm_flags = flags;
#ifdef CONFIG_IP_ROUTE_CLASSID #ifdef CONFIG_IP_ROUTE_CLASSID
if (nhc->nhc_family == AF_INET) {
struct fib_nh *nh;
nh = container_of(nhc, struct fib_nh, nh_common);
if (nh->nh_tclassid && if (nh->nh_tclassid &&
nla_put_u32(skb, RTA_FLOW, nh->nh_tclassid)) nla_put_u32(skb, RTA_FLOW, nh->nh_tclassid))
goto nla_put_failure; goto nla_put_failure;
}
#endif #endif
} else { } else {
if (fib_add_multipath(skb, fi) < 0) if (fib_add_multipath(skb, fi) < 0)
......
...@@ -2724,9 +2724,9 @@ static unsigned int fib_flag_trans(int type, __be32 mask, struct fib_info *fi) ...@@ -2724,9 +2724,9 @@ static unsigned int fib_flag_trans(int type, __be32 mask, struct fib_info *fi)
if (type == RTN_UNREACHABLE || type == RTN_PROHIBIT) if (type == RTN_UNREACHABLE || type == RTN_PROHIBIT)
flags = RTF_REJECT; flags = RTF_REJECT;
if (fi) { if (fi) {
const struct fib_nh *nh = fib_info_nh(fi, 0); const struct fib_nh_common *nhc = fib_info_nhc(fi, 0);
if (nh->fib_nh_gw4) if (nhc->nhc_gw.ipv4)
flags |= RTF_GATEWAY; flags |= RTF_GATEWAY;
} }
if (mask == htonl(0xFFFFFFFF)) if (mask == htonl(0xFFFFFFFF))
...@@ -2773,14 +2773,17 @@ static int fib_route_seq_show(struct seq_file *seq, void *v) ...@@ -2773,14 +2773,17 @@ static int fib_route_seq_show(struct seq_file *seq, void *v)
seq_setwidth(seq, 127); seq_setwidth(seq, 127);
if (fi) { if (fi) {
struct fib_nh *nh = fib_info_nh(fi, 0); struct fib_nh_common *nhc = fib_info_nhc(fi, 0);
__be32 gw = 0;
if (nhc->nhc_gw_family == AF_INET)
gw = nhc->nhc_gw.ipv4;
seq_printf(seq, seq_printf(seq,
"%s\t%08X\t%08X\t%04X\t%d\t%u\t" "%s\t%08X\t%08X\t%04X\t%d\t%u\t"
"%d\t%08X\t%d\t%u\t%u", "%d\t%08X\t%d\t%u\t%u",
nh->fib_nh_dev ? nh->fib_nh_dev->name : "*", nhc->nhc_dev ? nhc->nhc_dev->name : "*",
prefix, prefix, gw, flags, 0, 0,
nh->fib_nh_gw4, flags, 0, 0,
fi->fib_priority, fi->fib_priority,
mask, mask,
(fi->fib_advmss ? (fi->fib_advmss ?
......
...@@ -815,7 +815,8 @@ static int nh_create_ipv4(struct net *net, struct nexthop *nh, ...@@ -815,7 +815,8 @@ static int nh_create_ipv4(struct net *net, struct nexthop *nh,
err = fib_check_nh(net, fib_nh, tb_id, 0, extack); err = fib_check_nh(net, fib_nh, tb_id, 0, extack);
if (!err) { if (!err) {
nh->nh_flags = fib_nh->fib_nh_flags; nh->nh_flags = fib_nh->fib_nh_flags;
fib_info_update_nh_saddr(net, fib_nh, fib_nh->fib_nh_scope); fib_info_update_nhc_saddr(net, &fib_nh->nh_common,
fib_nh->fib_nh_scope);
} else { } else {
fib_nh_release(net, fib_nh); fib_nh_release(net, fib_nh);
} }
......
...@@ -1585,7 +1585,7 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr, ...@@ -1585,7 +1585,7 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr,
ip_dst_init_metrics(&rt->dst, fi->fib_metrics); ip_dst_init_metrics(&rt->dst, fi->fib_metrics);
#ifdef CONFIG_IP_ROUTE_CLASSID #ifdef CONFIG_IP_ROUTE_CLASSID
{ if (nhc->nhc_family == AF_INET) {
struct fib_nh *nh; struct fib_nh *nh;
nh = container_of(nhc, struct fib_nh, nh_common); nh = container_of(nhc, struct fib_nh, nh_common);
......
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