Skip to content

Commit

Permalink
lib: take into account the IFF_LOWER_UP flag
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
louis-6wind committed Jan 3, 2024
1 parent 2aef695 commit a3aded7
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 9 deletions.
30 changes: 21 additions & 9 deletions lib/if.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 GNU_LINUX
&& (ifp->flags & IFF_LOWER_UP)
#endif /* GNU_LINUX */
);
}

/* Is interface running? */
Expand All @@ -668,21 +672,26 @@ 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 GNU_LINUX
&& (ifp->flags & IFF_LOWER_UP)
#endif /* GNU_LINUX */
) &&
(((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
or UP & !ZEBRA_INTERFACE_LINK_DETECTION, without PTM check */
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 GNU_LINUX
&& (ifp->flags & IFF_LOWER_UP)
#endif /* GNU_LINUX */
&& ((ifp->flags & IFF_RUNNING) ||
!CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION)));
}

/* Is this loopback interface ? */
Expand Down Expand Up @@ -744,6 +753,9 @@ const char *if_flag_dump(unsigned long flag)

strlcpy(logbuf, "<", BUFSIZ);
IFF_OUT_LOG(IFF_UP, "UP");
#ifdef GNU_LINUX
IFF_OUT_LOG(IFF_LOWER_UP, "LOWER_UP");
#endif /* GNU_LINUX */
IFF_OUT_LOG(IFF_BROADCAST, "BROADCAST");
IFF_OUT_LOG(IFF_DEBUG, "DEBUG");
IFF_OUT_LOG(IFF_LOOPBACK, "LOOPBACK");
Expand Down
3 changes: 3 additions & 0 deletions lib/if.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
#include "qobj.h"
#include "hook.h"
#include "admin_group.h"
#ifdef GNU_LINUX
#include <linux/if.h>
#endif /* GNU_LINUX */

#ifdef __cplusplus
extern "C" {
Expand Down

0 comments on commit a3aded7

Please sign in to comment.