[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20180901004954.7145-13-dsahern@kernel.org>
Date: Fri, 31 Aug 2018 17:49:47 -0700
From: dsahern@...nel.org
To: netdev@...r.kernel.org
Cc: roopa@...ulusnetworks.com, sharpd@...ulusnetworks.com,
idosch@...lanox.com, davem@...emloft.net,
David Ahern <dsahern@...il.com>
Subject: [PATCH RFC net-next 12/18] net/ipv4: Add nexthop helpers for ipv4 integration
From: David Ahern <dsahern@...il.com>
Add nexthop reference to fib_info along with a list_head for tracking
the association of nexthop back to the fib_info.
Add helpers to take a fib_info and return a fib_nh, a nexthop device
and nexthop gateway.
Add helper to validate a nexthop works with a fib_info.
Signed-off-by: David Ahern <dsahern@...il.com>
---
include/net/ip_fib.h | 4 ++++
include/net/nexthop.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++
net/ipv4/nexthop.c | 39 +++++++++++++++++++++++++++++++++++++++
3 files changed, 89 insertions(+)
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index 0b40c59b8a5f..e39f55f3c3d8 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -103,9 +103,12 @@ struct fib_nh {
* This structure contains data shared by many of routes.
*/
+struct nexthop;
+
struct fib_info {
struct hlist_node fib_hash;
struct hlist_node fib_lhash;
+ struct list_head nh_list;
struct net *fib_net;
int fib_treeref;
refcount_t fib_clntref;
@@ -122,6 +125,7 @@ struct fib_info {
#define fib_window fib_metrics->metrics[RTAX_WINDOW-1]
#define fib_rtt fib_metrics->metrics[RTAX_RTT-1]
#define fib_advmss fib_metrics->metrics[RTAX_ADVMSS-1]
+ struct nexthop *nh;
int fib_nhs;
struct rcu_head rcu;
struct fib_nh fib_nh[0];
diff --git a/include/net/nexthop.h b/include/net/nexthop.h
index 1c59d04d1da6..c149fe8394ab 100644
--- a/include/net/nexthop.h
+++ b/include/net/nexthop.h
@@ -118,4 +118,50 @@ static inline bool nexthop_is_blackhole(struct nexthop *nh)
nhi = rcu_dereference(nh->nh_info);
return !!nhi->reject_nh;
}
+
+static inline struct fib_nh *nexthop_fib_nh(struct nexthop *nh, int nhsel)
+{
+ struct nh_info *nhi;
+
+ nhi = rcu_dereference(nh->nh_info);
+ if (nhi->family == AF_INET ||
+ nhi->family == AF_UNSPEC) /* dev only re-uses IPv4 struct */
+ return &nhi->fib_nh;
+
+ return NULL;
+}
+
+static inline struct fib_nh *fib_info_nh(struct fib_info *fi, int nhsel)
+{
+ if (fi->nh)
+ return nexthop_fib_nh(fi->nh, 0);
+
+ WARN_ON(nhsel > fi->fib_nhs);
+ return &fi->fib_nh[nhsel];
+}
+
+/* return fib_nh for fib_info; for historical reasons
+ * returns first nexthop only
+ */
+static inline struct net_device *fib_info_nh_dev(struct fib_info *fi)
+{
+ struct fib_nh *fib_nh = fib_info_nh(fi, 0);
+
+ return fib_nh->nh_dev;
+}
+
+/* return gateway for fib_info; for historical reasons
+ * returns gateway for first nexthop if multipath
+ */
+static inline __be32 fib_info_nh_gw(struct fib_info *fi)
+{
+ struct fib_nh *fib_nh = fib_info_nh(fi, 0);
+
+ return fib_nh ? fib_nh->nh_gw : 0;
+}
+
+int fib_check_nexthop(struct fib_info *fi, struct fib_config *cfg,
+ struct netlink_ext_ack *extack);
+
+bool nexthop_uses_dev(const struct nexthop *nh, const struct net_device *dev);
#endif
diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c
index 24c4aa383c9d..d1fc3d21af86 100644
--- a/net/ipv4/nexthop.c
+++ b/net/ipv4/nexthop.c
@@ -315,6 +315,21 @@ static void nexthop_notify(int event, struct nexthop *nh, struct nl_info *info)
rtnl_set_sk_err(info->nl_net, RTNLGRP_IPV4_ROUTE, err);
}
+static void __remove_nexthop_fib(struct net *net, struct nexthop *nh)
+{
+ struct fib_info *fi;
+ bool do_flush;
+
+ do_flush = false;
+ list_for_each_entry(fi, &nh->fi_list, nh_list) {
+ fi->fib_flags |= RTNH_F_DEAD;
+ do_flush = true;
+ }
+
+ if (do_flush)
+ fib_flush(net);
+}
+
/* called on insert failure too */
static void __remove_nexthop(struct net *net, struct nexthop *nh,
bool skip_fib, struct nl_info *nlinfo)
@@ -326,6 +341,8 @@ static void __remove_nexthop(struct net *net, struct nexthop *nh,
dev = nh_info_dev(nhi);
if (dev)
hlist_del(&nhi->dev_hash);
+ if (!skip_fib)
+ __remove_nexthop_fib(net, nh);
}
static void remove_nexthop(struct net *net, struct nexthop *nh,
@@ -461,6 +478,28 @@ static void flush_all_nexthops(struct net *net)
}
}
+/* invoked by fib add code to verify nexthop by id is ok with
+ * config for prefix; parts of fib_check_nh not done when nexthop
+ * is created
+ */
+int fib_check_nexthop(struct fib_info *fi, struct fib_config *cfg,
+ struct netlink_ext_ack *extack)
+{
+ struct nexthop *nh = fi->nh;
+ struct nh_info *nhi;
+
+ nhi = rtnl_dereference(nh->nh_info);
+ if (nhi->family != AF_UNSPEC) {
+ if (nh->nh_flags & RTNH_F_ONLINK &&
+ cfg->fc_scope >= RT_SCOPE_LINK) {
+ NL_SET_ERR_MSG(extack, "Scope mismatch with nexthop");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static int nh_check_attr(struct nhmsg *nhm, struct nlattr *tb[],
struct net *net, struct netlink_ext_ack *extack)
{
--
2.11.0
Powered by blists - more mailing lists