From 0c28d91d4144979f06ad61bd1fe5a406c18aadea Mon Sep 17 00:00:00 2001 From: Louis Scalbert Date: Wed, 10 Jan 2024 16:47:03 +0100 Subject: [PATCH] lib: take into account the IFF_LOWER_UP flag In Linux, a network driver can set the interface flags IFF_UP and IFF_RUNNING although the IFF_LOWER_UP flag is down, which means the interface is ready but the carrier is down: > These values contain interface state: > > ifinfomsg::if_flags & IFF_UP: > Interface is admin up > ifinfomsg::if_flags & IFF_RUNNING: > Interface is in RFC2863 operational state UP or UNKNOWN. This is for > backward compatibility, routing daemons, dhcp clients can use this > flag to determine whether they should use the interface. > ifinfomsg::if_flags & IFF_LOWER_UP: > Driver has signaled netif_carrier_on() However, FRR considers an interface is operational as soon it is up (IFF_UP) and running (IFF_RUNNING), disregarding the IFF_LOWER_UP flag. This can lead to a scenario where FRR starts adding routes through an interface that is technically down at the carrier level, resulting in kernel errors. > Jan 02 18:07:18 dut-vm zebra[283731]: [WVJCK-PPMGD][EC 4043309093] netlink-dp (NS 0) error: Network is down, type=RTM_NEWNEXTHOP(104), seq=243, pid=3112881162 > Jan 02 18:07:18 dut-vm zebra[283731]: [X5XE1-RS0SW][EC 4043309074] Failed to install Nexthop (318[if 164]) into the kernel > Jan 02 18:07:18 dut-vm zebra[283731]: [HSYZM-HV7HF] Extended Error: Carrier for nexthop device is down > Jan 02 18:07:18 dut-vm zebra[283731]: [WVJCK-PPMGD][EC 4043309093] netlink-dp (NS 0) error: Network is down, type=RTM_NEWNEXTHOP(104), seq=245, pid=3112881162 > Jan 02 18:07:18 dut-vm zebra[283731]: [HSYZM-HV7HF] Extended Error: Nexthop id does not exist > Jan 02 18:07:18 dut-vm zebra[283731]: [WVJCK-PPMGD][EC 4043309093] netlink-dp (NS 0) error: Invalid argument, type=RTM_NEWROUTE(24), seq=246, pid=3112881162 > Jan 02 18:07:18 dut-vm zebra[283731]: [X5XE1-RS0SW][EC 4043309074] Failed to install Nexthop (320[10.125.0.2 if 164]) into the kernel > Jan 02 18:07:18 dut-vm zebra[283731]: [VYKYC-709DP] default(0:254):0.0.0.0/0: Route install failed Consider an interface is operational when it has the IFF_UP, IFF_RUNNING and IFF_LOWER_UP flags. Link: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/networking/operstates.rst?h=v6.7-rc8#n29 Link: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/ipv4/nexthop.c?h=v6.7-rc8#n2886 Link: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/linux/netdevice.h?h=v6.7-rc8#n4198 Signed-off-by: Louis Scalbert --- lib/if.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/lib/if.c b/lib/if.c index a68f7f21e1cf..f1d1b362b715 100644 --- a/lib/if.c +++ b/lib/if.c @@ -654,7 +654,11 @@ static void if_set_name(struct interface *ifp, const char *name) /* Does interface up ? */ int if_is_up(const struct interface *ifp) { - return ifp->flags & IFF_UP; + return ((ifp->flags & IFF_UP) +#ifdef IFF_LOWER_UP + && (ifp->flags & IFF_LOWER_UP) +#endif /* IFF_LOWER_UP */ + ); } /* Is interface running? */ @@ -668,11 +672,14 @@ int if_is_running(const struct interface *ifp) if ptm checking is enabled, then ptm check has passed */ int if_is_operative(const struct interface *ifp) { - return ((ifp->flags & IFF_UP) - && (((ifp->flags & IFF_RUNNING) - && (ifp->ptm_status || !ifp->ptm_enable)) - || !CHECK_FLAG(ifp->status, - ZEBRA_INTERFACE_LINKDETECTION))); + return (((ifp->flags & IFF_UP) +#ifdef IFF_LOWER_UP + && (ifp->flags & IFF_LOWER_UP) +#endif /* IFF_LOWER_UP */ + ) && + (((ifp->flags & IFF_RUNNING) && + (ifp->ptm_status || !ifp->ptm_enable)) || + !CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION))); } /* Is the interface operative, eg. either UP & RUNNING @@ -680,9 +687,11 @@ int if_is_operative(const struct interface *ifp) int if_is_no_ptm_operative(const struct interface *ifp) { return ((ifp->flags & IFF_UP) - && ((ifp->flags & IFF_RUNNING) - || !CHECK_FLAG(ifp->status, - ZEBRA_INTERFACE_LINKDETECTION))); +#ifdef IFF_LOWER_UP + && (ifp->flags & IFF_LOWER_UP) +#endif /* IFF_LOWER_UP */ + && ((ifp->flags & IFF_RUNNING) || + !CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION))); } /* Is this loopback interface ? */ @@ -744,6 +753,9 @@ const char *if_flag_dump(unsigned long flag) strlcpy(logbuf, "<", BUFSIZ); IFF_OUT_LOG(IFF_UP, "UP"); +#ifdef IFF_LOWER_UP + IFF_OUT_LOG(IFF_LOWER_UP, "LOWER_UP"); +#endif /* IFF_LOWER_UP */ IFF_OUT_LOG(IFF_BROADCAST, "BROADCAST"); IFF_OUT_LOG(IFF_DEBUG, "DEBUG"); IFF_OUT_LOG(IFF_LOOPBACK, "LOOPBACK");