Re: git: d05d1f256082 - main - routing: Subscribe nhops to ifnet link events
Date: Mon, 13 Jul 2026 14:58:00 UTC
On Sat, 11 Jul 2026, Pouria Mousavizadeh Tehrani wrote:
> The branch main has been updated by pouria:
>
> URL: https://cgit.FreeBSD.org/src/commit/?id=d05d1f25608230edd300d59b96da6521b409d4f3
>
> commit d05d1f25608230edd300d59b96da6521b409d4f3
> Author: Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org>
> AuthorDate: 2026-07-08 19:55:46 +0000
> Commit: Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org>
> CommitDate: 2026-07-11 18:23:05 +0000
>
> routing: Subscribe nhops to ifnet link events
>
> Update nexthop flags with interface link status events and
> instead of checking link status of interface for every packet
> only check the reachability flag of the final nexthop.
>
> Reviewed by: glebius
> Discussed with: markj
> Differential Revision: https://reviews.freebsd.org/D57375
> ---
> sys/net/route.h | 4 +--
> sys/net/route/nhop.h | 8 +-----
> sys/net/route/nhop_ctl.c | 68 +++++++++++++++++++++++++++++++++++++++++++++--
> sys/net/route/route_ctl.h | 1 +
> sys/netinet/in_fib.c | 6 ++---
> sys/netinet6/in6_fib.c | 6 ++---
> 6 files changed, 75 insertions(+), 18 deletions(-)
>
> diff --git a/sys/net/route.h b/sys/net/route.h
> index d8cc12a39c61..b4440de19d96 100644
> --- a/sys/net/route.h
> +++ b/sys/net/route.h
> @@ -205,6 +205,7 @@ EVENTHANDLER_DECLARE(rtnumfibs_change, rtnumfibs_change_t);
> #define NHF_BROADCAST 0x0100 /* RTF_BROADCAST */
> #define NHF_GATEWAY 0x0200 /* RTF_GATEWAY */
> #define NHF_HOST 0x0400 /* RTF_HOST */
> +#define NHF_INVALID 0x0800 /* Nexthop is unreachable */
>
> /* Nexthop request flags */
> #define NHR_NONE 0x00 /* empty flags field */
> @@ -368,9 +369,6 @@ struct rt_addrinfo {
>
> #ifdef _KERNEL
>
> -#define RT_LINK_IS_UP(ifp) (!((ifp)->if_capabilities & IFCAP_LINKSTATE) \
> - || (ifp)->if_link_state == LINK_STATE_UP)
> -
> #define RO_NHFREE(_ro) do { \
> if ((_ro)->ro_nh) { \
> NH_FREE((_ro)->ro_nh); \
> diff --git a/sys/net/route/nhop.h b/sys/net/route/nhop.h
> index 6c62ae2f2f5f..0ae41cbf8292 100644
> --- a/sys/net/route/nhop.h
> +++ b/sys/net/route/nhop.h
> @@ -145,14 +145,8 @@ struct nhop_object {
>
> /*
> * Nhop validness.
> - *
> - * Currently we verify whether link is up or not on every packet, which can be
> - * quite costy.
> - * TODO: subscribe for the interface notifications and update the nexthops
> - * with NHF_INVALID flag.
> */
> -
> -#define NH_IS_VALID(_nh) RT_LINK_IS_UP((_nh)->nh_ifp)
> +#define NH_IS_VALID(_nh) (!((_nh)->nh_flags & NHF_INVALID))
> #define NH_IS_NHGRP(_nh) ((_nh)->nh_flags & NHF_MULTIPATH)
>
> #define NH_FREE(_nh) do { \
> diff --git a/sys/net/route/nhop_ctl.c b/sys/net/route/nhop_ctl.c
> index 9ef5bbc74a92..4f013908b338 100644
> --- a/sys/net/route/nhop_ctl.c
> +++ b/sys/net/route/nhop_ctl.c
You need to include eventhandler.h or what it is (as it's currently only leaked in through vnet code):
24 /sys/net/route/nhop_ctl.c:114:2: error: call to undeclared function 'EVENTHANDLER_REGISTER'; ISO C99 and later do not support implicit function declarations [-Werror,-Wimplicit-function-declaration]
25 114 | EVENTHANDLER_REGISTER(ifnet_event, nhops_ifnet_event, NULL,
26 | ^
27 /sys/net/route/nhop_ctl.c:114:24: error: use of undeclared identifier 'ifnet_event'
28 114 | EVENTHANDLER_REGISTER(ifnet_event, nhops_ifnet_event, NULL,
29 | ^~~~~~~~~~~
30 /sys/net/route/nhop_ctl.c:115:6: error: use of undeclared identifier 'EVENTHANDLER_PRI_ANY'
31 115 | EVENTHANDLER_PRI_ANY);
32 | ^~~~~~~~~~~~~~~~~~~~
33 /sys/net/route/nhop_ctl.c:116:24: error: use of undeclared identifier 'ifnet_link_event'
34 116 | EVENTHANDLER_REGISTER(ifnet_link_event, nhops_ifnet_link_event, NULL,
35 | ^~~~~~~~~~~~~~~~
36 /sys/net/route/nhop_ctl.c:117:6: error: use of undeclared identifier 'EVENTHANDLER_PRI_ANY'
37 117 | EVENTHANDLER_PRI_ANY);
38 | ^~~~~~~~~~~~~~~~~~~~
39 5 errors generated.
40 --- nhop_ctl.o ---
41 *** [nhop_ctl.o] Error code 1
> @@ -90,6 +90,8 @@ static void fill_sdl_from_ifp(struct sockaddr_dl_short *sdl, const struct ifnet
>
> static void destroy_nhop_epoch(epoch_context_t ctx);
> static void destroy_nhop(struct nhop_object *nh);
> +static void nhops_ifnet_event(void *arg, struct ifnet *ifp, int state);
> +static void nhops_ifnet_link_event(void *arg, struct ifnet *ifp, int state);
>
> _Static_assert(__offsetof(struct nhop_object, nh_ifp) == 32,
> "nhop_object: wrong nh_ifp offset");
> @@ -109,6 +111,10 @@ nhops_init(void)
> nhops_zone = uma_zcreate("routing nhops",
> NHOP_OBJECT_ALIGNED_SIZE + NHOP_PRIV_ALIGNED_SIZE,
> NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
> + EVENTHANDLER_REGISTER(ifnet_event, nhops_ifnet_event, NULL,
> + EVENTHANDLER_PRI_ANY);
> + EVENTHANDLER_REGISTER(ifnet_link_event, nhops_ifnet_link_event, NULL,
> + EVENTHANDLER_PRI_ANY);
> }
>
> /*
> @@ -1109,7 +1115,10 @@ nhops_iter_start(struct nhop_iter *iter)
> if (iter->rh != NULL) {
> struct nh_control *ctl = iter->rh->nh_control;
>
> - NHOPS_RLOCK(ctl);
> + if (iter->wlock)
> + NHOPS_WLOCK(ctl);
> + else
> + NHOPS_RLOCK(ctl);
>
> iter->_i = 0;
> iter->_next = CHT_FIRST(&ctl->nh_head, iter->_i);
> @@ -1147,7 +1156,10 @@ nhops_iter_stop(struct nhop_iter *iter)
> if (iter->rh != NULL) {
> struct nh_control *ctl = iter->rh->nh_control;
>
> - NHOPS_RUNLOCK(ctl);
> + if (iter->wlock)
> + NHOPS_WUNLOCK(ctl);
> + else
> + NHOPS_RUNLOCK(ctl);
> }
> }
>
> @@ -1317,3 +1329,55 @@ nhops_dump_sysctl(struct rib_head *rh, struct sysctl_req *w)
>
> return (0);
> }
> +
> +static void
> +nhops_ifnet_state_changed(struct ifnet *ifp, bool status)
> +{
> + struct nhop_object *nh;
> + struct nhop_iter iter = { .fibnum = ifp->if_fib, .wlock = true };
> +
> + for (iter.family = 1; iter.family <= AF_MAX; iter.family++) {
> + iter.rh = rt_tables_get_rnh_safe(iter.fibnum, iter.family);
> + for (nh = nhops_iter_start(&iter); nh != NULL;
> + nh = nhops_iter_next(&iter)) {
> + if (nh->nh_ifp != ifp)
> + continue;
> +
> + if (status)
> + nh->nh_flags &= ~NHF_INVALID;
> + else
> + nh->nh_flags |= NHF_INVALID;
> + }
> + nhops_iter_stop(&iter);
> + }
> +}
> +
> +static void
> +nhops_ifnet_event(void *arg __unused, struct ifnet *ifp, int state)
> +{
> +
> + if ((ifp->if_flags & IFF_DYING) != 0 ||
> + (state != IFNET_EVENT_UP && state != IFNET_EVENT_DOWN))
> + return;
> +
> + nhops_ifnet_state_changed(ifp, state == IFNET_EVENT_UP);
> +}
> +
> +static void
> +nhops_ifnet_link_event(void *arg __unused, struct ifnet *ifp, int state)
> +{
> +#ifdef VIMAGE
> + /*
> + * rib_head will be calculated from V_tables in rt_tables_get_rnh
> + * and the VNET is destroyed.
> + */
> + if (VNET_IS_SHUTTING_DOWN(ifp->if_vnet))
> + return;
> +#endif
> +
> + if ((ifp->if_flags & IFF_DYING) != 0 ||
> + (state != LINK_STATE_UP && state != LINK_STATE_DOWN))
> + return;
> +
> + nhops_ifnet_state_changed(ifp, state == LINK_STATE_UP);
> +}
> diff --git a/sys/net/route/route_ctl.h b/sys/net/route/route_ctl.h
> index 845df8ce1fbe..2e34b2a35c25 100644
> --- a/sys/net/route/route_ctl.h
> +++ b/sys/net/route/route_ctl.h
> @@ -164,6 +164,7 @@ struct nhop_iter {
> struct rib_head *rh;
> int _i;
> struct nhop_priv *_next;
> + const bool wlock;
> };
>
> struct nhop_object *nhops_iter_start(struct nhop_iter *iter);
> diff --git a/sys/netinet/in_fib.c b/sys/netinet/in_fib.c
> index d8e373bf3dc2..d864bce07315 100644
> --- a/sys/netinet/in_fib.c
> +++ b/sys/netinet/in_fib.c
> @@ -117,7 +117,7 @@ fib4_lookup(uint32_t fibnum, struct in_addr dst, uint32_t scopeid,
> if (nh != NULL) {
> nh = nhop_select(nh, flowid);
> /* Ensure route & ifp is UP */
> - if (RT_LINK_IS_UP(nh->nh_ifp)) {
> + if (NH_IS_VALID(nh)) {
> if (flags & NHR_REF)
> nhop_ref_object(nh);
> return (nh);
> @@ -154,7 +154,7 @@ fib4_lookup(uint32_t fibnum, struct in_addr dst, uint32_t scopeid,
> if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) {
> nh = nhop_select((RNTORT(rn))->rt_nhop, flowid);
> /* Ensure route & ifp is UP */
> - if (RT_LINK_IS_UP(nh->nh_ifp)) {
> + if (NH_IS_VALID(nh)) {
> if (flags & NHR_REF)
> nhop_ref_object(nh);
> RIB_RUNLOCK(rh);
> @@ -320,7 +320,7 @@ fib4_lookup_debugnet(uint32_t fibnum, struct in_addr dst, uint32_t scopeid,
> if (rt != NULL) {
> struct nhop_object *nh = nhop_select(rnd.rnd_nhop, 0);
> /* Ensure route & ifp is UP */
> - if (RT_LINK_IS_UP(nh->nh_ifp))
> + if (NH_IS_VALID(nh))
> return (nh);
> }
>
> diff --git a/sys/netinet6/in6_fib.c b/sys/netinet6/in6_fib.c
> index c851a5bd14c5..594a9dc0a24e 100644
> --- a/sys/netinet6/in6_fib.c
> +++ b/sys/netinet6/in6_fib.c
> @@ -125,7 +125,7 @@ fib6_lookup(uint32_t fibnum, const struct in6_addr *dst6,
> if (nh != NULL) {
> nh = nhop_select(nh, flowid);
> /* Ensure route & ifp is UP */
> - if (RT_LINK_IS_UP(nh->nh_ifp)) {
> + if (NH_IS_VALID(nh)) {
> if (flags & NHR_REF)
> nhop_ref_object(nh);
> return (nh);
> @@ -163,7 +163,7 @@ fib6_lookup(uint32_t fibnum, const struct in6_addr *dst6,
> if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) {
> nh = nhop_select((RNTORT(rn))->rt_nhop, flowid);
> /* Ensure route & ifp is UP */
> - if (RT_LINK_IS_UP(nh->nh_ifp)) {
> + if (NH_IS_VALID(nh)) {
> if (flags & NHR_REF)
> nhop_ref_object(nh);
> RIB_RUNLOCK(rh);
> @@ -335,7 +335,7 @@ fib6_lookup_debugnet(uint32_t fibnum, const struct in6_addr *dst6,
> if (rt != NULL) {
> struct nhop_object *nh = nhop_select(rnd.rnd_nhop, 0);
> /* Ensure route & ifp is UP */
> - if (RT_LINK_IS_UP(nh->nh_ifp))
> + if (NH_IS_VALID(nh))
> return (nh);
> }
>
>
>
--
Bjoern A. Zeeb r15:7