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

