-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
lib: take into account the Linux IFF_LOWER_UP flag #15082
Conversation
a3aded7
to
03695fc
Compare
lib/if.h
Outdated
@@ -12,6 +12,10 @@ | |||
#include "qobj.h" | |||
#include "hook.h" | |||
#include "admin_group.h" | |||
#ifdef GNU_LINUX |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO, let's remove the zebra.h inclusion of net/if.h and move it into this file instead. It will require some small reworking of stuff in nhrpd/linux.c and zebra/if_netlink.c, but frankly it's worth it.
I'd also break up the commits into 2 -> The inclusion of the new header files and the small rearrangement and the second commit would be the actual changes in lib/if.c
Why do I want it this way? too much is in zebra.h -> It needs to be broken up. if.h should own interface header definitions not zebra.h. I've started breaking up zebra.h in other commits just haven't gotten to this part yet. Since you are in here I would just do it now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure we can remove "net/if.h", it is even set in Linux kernel sources #include.
I'd also break up the commits into 2 -> The inclusion of the new header files and the small rearrangement and the second commit would be the actual changes in lib/if.c
done
In lib/if.c, I am testing the definition IFF_LOWER_UP
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please reread what I stated. inclusion of net/if.h does not belong in zebra.h it belongs in lib/if.h.
03695fc
to
6ed8e8f
Compare
6ed8e8f
to
0c28d91
Compare
Why do we rely on our own copy of the linux headers instead of compiling with the headers of the local machine ? |
we rely on our own headers because the local machine may not have a new enough of a header. I can write a feature against the linux netlink stack that is available on 6.X but if I only have 5. locally then the compile will fail. This way FRR can compile against newer versions of the linux abi and when that abi is not available due to it being an older kernel the call will just fail. This also allows FRR to compile into a package and be deployed against a variety of kernels |
0c28d91
to
0a996ca
Compare
64c08d4
to
593dabb
Compare
593dabb
to
ab11d1f
Compare
@donaldsharp could you detail what you expect for the zebra/if_netlink.c rework I cannot get rid of net/if.h there Removal of if.h include
Re-add linux if.h
Force not including net/if.h
|
0c10659
to
84d40f2
Compare
84d40f2
to
d61cac2
Compare
48e0a77
to
7ade0f3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't check if the header inclusion was done correctly, not an expert in this. But I approve the actual code change.
7ade0f3
to
b5edf91
Compare
@idryzhov could you merge this please ? |
CI:rerun Rerun after fixing git access on CI infra |
1 similar comment
CI:rerun Rerun after fixing git access on CI infra |
@louis-6wind it looks like there are actual build errors right now. Please, take a look. |
b5edf91
to
6a5dcc3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
questions
return ((ifp->flags & IFF_UP) && | ||
(((ifp->flags & IFF_RUNNING) | ||
#ifdef IFF_LOWER_UP | ||
&& (ifp->flags & IFF_LOWER_UP) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1. this will break FRR completely on older kernels that do not send this flag (you are making a compile-time check, that does not mean the [different] kernel at run-time will support the flag)
- AFAIK
IFF_RUNNING
should never be set ifIFF_LOWER_UP
is not set? Can you elaborate when this is not the case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've crossed out the compatibility part, since the flag has been in the kernel since ≤2014. The other question remains.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2. AFAIK
IFF_RUNNING
should never be set ifIFF_LOWER_UP
is not set? Can you elaborate when this is not the case?
According to the kernel documentation: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/networking/operstates.rst?h=v6.7-rc8#n29
ifinfomsg::if_flags & IFF_RUNNING:
Interface is in RFC2863 operational state UP or UNKNOWN. [...]
ifinfomsg::if_flags & IFF_LOWER_UP:
Driver has signaled netif_carrier_on()
Therefore, it is consistent with the kernel specifications for an interface to have IFF_RUNNING
set without having IFF_LOWER_UP
set.
The tentative answer during the call on tuesday is that this was done to work around kernel bugs with specific interface drivers. If this is the reason, I'm opposed to this change. My reasoning is quite simple: The change is apparently being made because some buggy drivers set We should code to the API as designed, not to some specific driver bugs. Checking for |
Can we have a list (interface types) of bug'd kernel drivers ? Could it be limited to those interfaces until the kernel's ones will be fixed ? |
I only have the info in this PR… @louis-6wind can you provide the context/info here? |
On Tuesday, I mentioned a problem with a specific driver, not a kernel bug. The issue was identified with the tun/tap driver - I couldn't remember which one was having problems. At initialization, the module reports
According to the pull-request description, Zebra is unable to install the nexthop, as indicated by the logs
This "extended error" originates from the kernel, because Furthermore, the kernel itself sets It's important to note that this flag setting is handled by the kernel, not by the driver directly.
|
Seems to be related #10199 |
ci:rerun |
I don't see this behavior, what exactly do you need to do to get a tun/tap device in
Yeah, but I'd really like to see where in the kernel it is possible to get |
I am not able to extract the exact conditions, but here is what I observe with 'ip -d monitor link'
You are saying that IFF_RUNNING means IF_OPER_UP or IF_OPER_UNKNOWN. That is correct. That doesn't contradict what I'm saying. If the state is IF_OPER_UNKNOWN, the driver is not usable.
Logs are saying it is possible and it conforms with the specifications. |
Import our a copy of Linux if.h and its dependencies (compiler_types.h and libc-compat.h) from the above links. In "if.h", "#include <linux/compiler.h>" has been replaced by "#include <linux/compiler_types.h>". libc-compat.h is needed to avoid conflicts with glibc. Include "linux/if.h" in "zebra.h" when compiling on Linux. De-reference "net/if.h" in C files. Note that "net/if.h" is still needed. It is even included in many Linux kernel files. "linux/if.h" provides additional definitions. Link: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/if.h?h=v5.5 Link: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/libc-compat.h?h=v5.5 Link: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/linux/compiler_types.h?h=v5.5 Link: https://patchwork.ozlabs.org/project/glibc/patch/[email protected]/ Signed-off-by: Louis Scalbert <[email protected]>
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]>
Add lower_up to expected interface flags. Signed-off-by: Louis Scalbert <[email protected]>
I don't know why it appears only now. > ../sdist/zebra/fpm_listener.c:420:8: error: comparison of integers of different signs: 'int' and 'size_t' (aka 'unsigned long') [-Werror,-Wsign-compare] > if (!RTNH_OK(rtnh, len)) { > ^~~~~~~~~~~~~~~~~~ > ../sdist/include/linux/rtnetlink.h:437:31: note: expanded from macro 'RTNH_OK' > ((int)(rtnh)->rtnh_len) <= (len)) len is set with RTA_PAYLOAD and should be an integer. > len = RTA_PAYLOAD(mpath_rtattr); > #define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0)) Signed-off-by: Louis Scalbert <[email protected]>
6a5dcc3
to
bb46027
Compare
To summarize, nexthop objects can only be installed on interfaces marked as IFF_LOWER_UP. The IFF_LOWER_UP flag indicates that the operational state of the interface is "up." On the other hand, IFF_RUNNING indicates that the operational state is either "up" or "unknown." Zebra currently treats an interface as operational and allows the creation of nexthop objects as soon as the IFF_RUNNING flag is set, regardless of the IFF_LOWER_UP status. However, this approach can lead to issues if the interface's operational state is "unknown," causing nexthop creation to fail. It would be more appropriate for Zebra to initiate nexthop creation only when IFF_LOWER_UP is set. It is worth noting that the IFF_LOWER_UP flag is activated by the kernel itself when the driver invokes netif_carrier_on(), reliably indicating that the interface is operational. |
Ok, I think it should work. I hope we won't have the opposite problem with another driver though. If that happens we should just revert this. |
@eqvinox could you approve and merge this pull request? "verify source" is triggering errors on imported linux headers. They should not be modified. |
@eqvinox please approve and merge! |
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:
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.
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