On Tue, Aug 04, 2026 at 10:47:05AM +0900, Yuyang Huang wrote:
> Add RTA_DEL_REASON and enum rt_del_reason to the rtnetlink uAPI, and
> add ip6_del_rt_reason(), which takes the reason a route is being
> deleted. It has no skip_notify argument: a caller that records a
> deletion reason wants the notification that carries it.
> 
> 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        |  2 ++
>  include/uapi/linux/rtnetlink.h | 22 ++++++++++++++++++++++
>  net/ipv6/route.c               |  8 ++++++++
>  3 files changed, 32 insertions(+)
> 
> diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
> index 09ffe0f13ce7..7bcf0e5bd887 100644
> --- a/include/net/ip6_route.h
> +++ b/include/net/ip6_route.h
> @@ -128,6 +128,8 @@ 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,
> +                   enum rt_del_reason del_reason);

Since the function is only invoked by IPv6 code there is no reason to
put it inside the guard and it would also suppress the comment from
Sashiko. You can place it near ip6_ins_rt().

>  #else
>  static inline int ip6_del_rt(struct net *net, struct fib6_info *f6i,
>                            bool skip_notify)
> diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h
> index 27265fd31e5f..66cfc17ede0e 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,27 @@ 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.

Please add a note that this attribute is rejected by the kernel in
requests, like you did in patch #9.

> + *
> + * The value space is family-agnostic: a value must never be
> + * reinterpreted per address family. A cause that only one family can
> + * produce still gets its own value rather than reusing another
> + * family's.
> + */
> +enum rt_del_reason {
> +     RT_DEL_REASON_UNSPEC,           /* cause not recorded */
> +     RT_DEL_REASON_EXPIRED,          /* RTF_EXPIRES lifetime ran out (GC) */
> +     RT_DEL_REASON_RA_WITHDRAWN,     /* zero-lifetime RA / PIO / RIO */
> +     __RT_DEL_REASON_MAX
> +};
> +
> +#define RT_DEL_REASON_MAX (__RT_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 fc42d67e5822..ca374b056f5a 100644
> --- a/net/ipv6/route.c
> +++ b/net/ipv6/route.c
> @@ -4004,6 +4004,14 @@ int ip6_del_rt(struct net *net, struct fib6_info *rt, 
> bool skip_notify)
>       return __ip6_del_rt(rt, &info);
>  }
>  
> +int ip6_del_rt_reason(struct net *net, struct fib6_info *rt,
> +                   enum rt_del_reason del_reason)
> +{
> +     struct nl_info info = { .nl_net = net };
> +
> +     return __ip6_del_rt(rt, &info);
> +}
> +
>  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