Add RTA_DEL_REASON and enum rta_del_reason to the rtnetlink uAPI, and
add ip6_del_rt_reason(), which takes the reason a route is being
deleted. ip6_del_rt() becomes a wrapper that passes
RTA_DEL_REASON_UNSPEC, so its callers do not change.

The reason is unused for now. Subsequent patches propagate it to the
deletion path and report it on RTM_DELROUTE.

Signed-off-by: Yuyang Huang <[email protected]>
---
 include/net/ip6_route.h        |  9 +++++++++
 include/uapi/linux/rtnetlink.h | 17 +++++++++++++++++
 net/ipv6/route.c               |  8 +++++++-
 3 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index 09ffe0f13ce7..92ad5a0d03a2 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -128,12 +128,21 @@ int ip6_route_add(struct fib6_config *cfg, gfp_t 
gfp_flags,
 int ip6_ins_rt(struct net *net, struct fib6_info *f6i);
 #if IS_ENABLED(CONFIG_IPV6)
 int ip6_del_rt(struct net *net, struct fib6_info *f6i, bool skip_notify);
+int ip6_del_rt_reason(struct net *net, struct fib6_info *f6i, bool skip_notify,
+                     enum rta_del_reason del_reason);
 #else
 static inline int ip6_del_rt(struct net *net, struct fib6_info *f6i,
                             bool skip_notify)
 {
        return -EAFNOSUPPORT;
 }
+
+static inline int ip6_del_rt_reason(struct net *net, struct fib6_info *f6i,
+                                   bool skip_notify,
+                                   enum rta_del_reason del_reason)
+{
+       return -EAFNOSUPPORT;
+}
 #endif
 
 void rt6_flush_exceptions(struct fib6_info *f6i);
diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h
index 27265fd31e5f..fe00e624f3c3 100644
--- a/include/uapi/linux/rtnetlink.h
+++ b/include/uapi/linux/rtnetlink.h
@@ -399,6 +399,7 @@ enum rtattr_type_t {
        RTA_DPORT,
        RTA_NH_ID,
        RTA_FLOWLABEL,
+       RTA_DEL_REASON,
        __RTA_MAX
 };
 
@@ -407,6 +408,22 @@ enum rtattr_type_t {
 #define RTM_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct 
rtmsg))))
 #define RTM_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct rtmsg))
 
+/* RTA_DEL_REASON: why the kernel deleted the route. u32.
+ * Emitted only on RTM_DELROUTE notifications, and only when the deletion
+ * path records a cause. Absence means either an older kernel or a
+ * deletion path that does not (yet) record its cause - consumers must
+ * treat "absent" and "unspec" identically. New causes may be appended.
+ * Currently only IPv6 deletion paths record a cause.
+ */
+enum rta_del_reason {
+       RTA_DEL_REASON_UNSPEC,          /* cause not recorded */
+       RTA_DEL_REASON_EXPIRED,         /* RTF_EXPIRES lifetime ran out (GC) */
+       RTA_DEL_REASON_RA_WITHDRAWN,    /* zero-lifetime RA / PIO / RIO */
+       __RTA_DEL_REASON_MAX
+};
+
+#define RTA_DEL_REASON_MAX (__RTA_DEL_REASON_MAX - 1)
+
 /* RTM_MULTIPATH --- array of struct rtnexthop.
  *
  * "struct rtnexthop" describes all necessary nexthop information,
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index a1301334da48..9f82829923ab 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -3994,7 +3994,8 @@ static int __ip6_del_rt(struct fib6_info *rt, struct 
nl_info *info)
        return err;
 }
 
-int ip6_del_rt(struct net *net, struct fib6_info *rt, bool skip_notify)
+int ip6_del_rt_reason(struct net *net, struct fib6_info *rt, bool skip_notify,
+                     enum rta_del_reason del_reason)
 {
        struct nl_info info = {
                .nl_net = net,
@@ -4004,6 +4005,11 @@ int ip6_del_rt(struct net *net, struct fib6_info *rt, 
bool skip_notify)
        return __ip6_del_rt(rt, &info);
 }
 
+int ip6_del_rt(struct net *net, struct fib6_info *rt, bool skip_notify)
+{
+       return ip6_del_rt_reason(net, rt, skip_notify, RTA_DEL_REASON_UNSPEC);
+}
+
 static int __ip6_del_rt_siblings(struct fib6_info *rt, struct fib6_config *cfg)
 {
        struct nl_info *info = &cfg->fc_nlinfo;
-- 
2.43.0


Reply via email to