On Sun, Jul 19, 2026 at 3:53 PM Ido Schimmel <[email protected]> wrote: > Please expand more on the motivation: Which user space application is > going to consume this information and what is it going to do with it?
Thanks for the review, let me add more background information. My current use case comes from Android devices, but I think it is a general problem that any consumer device running Linux will face, especially on Wi-Fi networks (multicast delivery on Wi-Fi is not guaranteed, e.g. frames can be lost around DTIM for clients in power save mode). On Android, the userspace NetworkStack process listens on RTMGRP_IPV6_ROUTE and today treats any loss of the IPv6 default route as "router lost". To prevent the device from repeatedly gaining and losing IPv6 connectivity on a badly configured network (e.g. a misconfigured RA interval), when it detects the device is on a dual-stack network with working IPv4 connectivity, it defensively clears accept_ra_defrtr and restarts IPv6. The intention is to stop userspace apps from continuing to use broken global IPv6 connectivity (while keeping link-local IPv6 working). However, if the route was withdrawn by a zero-lifetime RA (some ISPs do this intentionally for various reconfiguration reasons), that reaction is wrong - with accept_ra_defrtr off, IPv6 never recovers when the router advertises again. If the route genuinely expired, the defensive reaction is right, since the router failed to refresh it in time. We tried to fix this in userspace but found we cannot get the needed information from the kernel. RTM_NEWROUTE carries the initial route lifetime (in rta_cacheinfo), but when a later RA refreshes the lifetime, the kernel does not resend RTM_NEWROUTE. So to distinguish the cause of an RTM_DELROUTE, userspace would have to open a raw socket, listen to RAs, and track lifetimes itself. That is not ideal: this logic already exists in the kernel, and userspace should not need to replicate it. I also considered sending RTM_NEWROUTE on every RA lifetime update, but that would be spammy and is technically wrong (a lifetime update does not add a new route, so it should not trigger RTM_NEWROUTE). I think RTA_DEL_REASON is the architecturally correct fix: it tells userspace why the route was deleted so it can react accordingly. In our use case, NetworkStack should defensively disable global IPv6 only on RTA_DEL_REASON_EXPIRED, and take no action on RTA_DEL_REASON_RA_WITHDRAWN since that is RFC-compliant behavior. Feel free to let me know if more background is needed. If this use case makes sense, I will summarize it in the v2 commit message. > Also, Sashiko has some valid comments. Please take a look. Here is the reply to the sashiko's feedback. >Does this new attribute violate the Netlink uAPI guidelines for integer >types? The guidelines state we should avoid integer types smaller than 32 >bits since they save no memory due to 4-byte attribute alignment padding, >unless the value is a fixed protocol header field. >Should this be defined as a u32? ... >Since this deletion reason is a software classification and not a compact >protocol field, it has no natural requirement to be 8-bit. Would it be >better to document and serialize this as a 32-bit integer to prevent >artificially limiting the enum space for future additions? ... >If the attribute type in the YAML spec is updated to u32, this call to >nla_put_u8() in rt6_fill_node() would also need to be updated to >nla_put_u32() to match the 32-bit width. Good point, given u8 saves nothing, will change it to u32 in v2. >Will this operation cause a TypeError crash during test execution? >In Python 3, using the subtraction operator between a set and a dict_keys >object raises an unsupported operand type error. Since the caller >ipv6_route_del_reason_ra_withdrawn() passes a set for the want parameter, >want - seen.keys() will crash the test. >Should this be converted to a set first, such as want - set(seen.keys())? I don't think this is a bug (dict_keys is a set-like view) and the test passes correctly in my local test. But the suggested form reads better, so I'll apply it in v2. Thanks, Yuyang

