We have our own copy of linux kernel headers, and we must never
directly include the corresponding versions from the system.
Avoid that, by only including the clones via "libnm-std-aux/nm-linux-compat.h"
and by including the compat wrapper header before other system headers.
`nm_platform_ip_address_sync()` likes to add IFA_F_NOPREFIXROUTE flag
for all addresses, regardless of `a_ifi_flags` property. By setting this
boolean, that automatism can be suppressed, and the noprefixroute flag
does not get added automatically.
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1307
Some compiler versions don't like this. Workaround.
src/libnm-platform/nm-linux-platform.c: In function event_seq_check:
src/libnm-platform/nm-linux-platform.c:7254:1: error: label at end of compound statement
out:
^~~
Fixes: 3d4906a3da ('platform: add genl socket support for events and genl family')
That seems common. It's also done by genl-ctrl-list and
iproute2's genl tool.
Also, use avoid the leading zeros (0x1c instead of 0x001c).
iproute2's genl tool does the former, libnl3's genl-ctrl-list
does the latter.
We now cache the family ID for generic netlink protocols. However,
when we for example create a wireguard interface, the kernel module
might just get autoloaded. At this point, we didn't know the family ID
yet.
We already made an effort, that if the family ID is unknown during
nm_platform_genl_get_family_id(), we would try to poll the genl socket
in the hope there is a relevant event there. However, polling the socket
also means to potentially emit all signals for any change that happen.
We don't want that, if we currently are already polling the socket.
Instead, fallback to synchronously get the family ID.
$ sudo rmmod wireguard \
./tools/run-nm-test.sh -m src/core/platform/tests/test-link-linux -p /link/software/detect/wireguard/1/external
Fixes: 3d4906a3da ('platform: add genl socket support for events and genl family')
An NMPObject is hashable, can be compared and printed. That is useful.
Make an NMPObject for MPTCP addresses. It will hold the content of
MPTCP_PM_ATTR_ADDR netlink attribute. But like other NMPObject types it
will also be used to represent the data as NetworkManager tracks it.
An object type that doesn't implement cmd_plobj_id_copy(), either:
- implements cmd_obj_copy(), but then we cannot copy the ID only
to a stack instance, because that cannot track ownership.
This is a bug in the caller. We cannot use stackinit for an
object of a type that is not a plain old data (in C++ terms).
- fallback to plain memcpy(). That is in line with nmp_object_clone().
and nmp_object_copy().
- use proper integer types. A netlink message cannot be as large as
size_t, because the length is tracked in an uint32_t. Use the
right types.
- fields like "nlmsg_type" or "nlmsg_flags" are uint16_t. Use the
right types.
- note that nlmsg_size() still returns and accepts "int". Maybe
the should be adjusted too, but we use macros from kernel headers,
which also use int. Even if that is not the type of the length on
the binary protocol. So some of these functions still use int, to
be closer and compatible with <linux/netlink.h>.
For generic netlink, the family-id is important. It changes when
loading/unloading a module, so we should not cache it indefinitely.
To get this right, takes some effort. For "nl80211", "nl802154"
and "wireguard", we only cache the family ID in relation to an
interface. If the module gets unloaded, the family ID also becomes
irrelevant and we need to re-fetch it the next time.
For generic families like "mptcp_pm" or "ethtool", they are commonly not
kernel modules and cannot be unloaded. So caching them would be
(probably) fine.
Still. Some generic netlink families emit notifications, and it will
be interesting to be able to handle them. Since that will be useful later,
start by doing something simple: let the generic netlink family also be
cached this way. Generic netlink will send notifications when a family gets
added/deleted, and we can use that to reliably cache the family ID.
We only care about a well-known set of generic families. Unlike libnl
(which has "struct genl_family" object to handle any family), we can hard
code the few we care about (NMPGenlFamilyType).
This adds the necessary infrastructure of NMLinuxPlatform to listen to
events on the generic netlink socket.
Currently there is no problem. However, DelayedActionType is a packed
enum, and if we add a few more enum values, it might happen that
DELAYED_ACTION_TYPE_MAX is 0x8000 and DelayedActionType effectively
uint16_t.
When that happens, the code would become an infinite loop, because
0x8000 is not larger than DELAYED_ACTION_TYPE_MAX, but `<<= 1`
shifts out the bit, making it zero.
Avoid that.
If nm_platform_get_cache_tc() is disabled, there is no need to refresh
it. Filter those flags out.
Also, don't duplicate the code and add a helper function
delayed_action_schedule_refresh_all().
Reorder fields in DelayedActionWaitForNlResponseData, so that
the struct size is optimal due to the alignment constraints.
Also, when we remember enum values and embed them somewhere, it's nice
if they only take the space actually needed. _nm_packed solves that.
The term "addr_family" is used very frequently, and it usually is an
auto variable or a function parameter.
It is interesting to search where this field is used. So rename to give
it a unique (and better fitting) name.
While at it, use gint8 to encode the addr_family. It's always
sufficient, and this reduces the size of RefreshAllInfo from 8 bytes
to two.
The genl types that we care about are well known. Add an enum
for them, so we can do a lookup by index.
To kernel, the corresponding names (like "wireguard") are also well
known. However, the family-id, that we need when using genl are
allocated dynamically. So we need to lookup the family-id, and by having
an enum for the genl type, we can do so generically.
In the past, nmp_lookup_init_object() could both lookup all object for a
certain ifindex, and lookup all objects of a type. That fallback path
already leads to an assertion failure fora while now, so nobody should
be using this function to lookup all objects of a certain type (for
what, we have nmp_lookup_init_obj_type()).
Now, remove the fallback path, and rename the function to what it really
does.
NMPObject is a union. It's not clear to me that C guarnatees that
designated initializers will meaningfully set all fields to zero. Use
memset() instead.
- replace "s_flags" field by explicit boolean fields.
- "s_msg_peek" now is simplified. Previously, we would default
to peek, unless the user caller nl_socket_disable_msg_peek()
or set nl_socket_set_msg_buf_size(). Simplify that. We now
default to peek, unless NL_SOCKET_FLAGS_DISABLE_MSG_PEEK is set.
We have no callers that call nl_socket_set_msg_buf_size(),
so we can simplify that logic and just enable peeking by default.
- keep "s_auto_ack" field, although it is always TRUE and there
is no API to toggle that. However, it is kept as a self-documenting
thing, so we would know the relevant places where auto-ack matters.
- drop nl_socket_disable_msg_peek(). We have no caller of this function
and we can set peeking in nl_socket_new(). We also don't need to
change it after creation of the socket.
The real purpose is that we set the socket options before bind().
For that, we need to be able to specify the flag during nl_socket_new().
Another reason is that these are common questions to ponder while
creating a netlink socket. There shouldn't be several setter functions,
just specify the flag right away. These parameters are not going to
change afterwards (at least, we don't need/use that and we don't have
API for that either).
We will need this, for getting nl_pktinfo control messages
that contain the extended destination group number.
Also, drop NL_SOCK_PASSCRED. It was only used to not iterate over the
control messages, but doing that should be cheap.
There really is no need for two(!) heap allocations while parsing
the netlink message. We already have it in the buffer. Just use it.
Note that netlink attributes need to be aligned to 4 bytes. But
nlmsg_next() already ensures that, so not even for alignment purpose we
need to clone the message.
Create a new "struct nl_msg_lite" that can hold pointers to everything
we need.
Whether we use a socket blockingly or non-blocking is usually determined
upfront and does not change. Make it a parameter of nl_socket_new().
Also, it saves an additional syscall.
- "priv->nlh" to "priv->sk_rtnl": as we also have an genl socket,
"nlh" is not a good name. The point is that this is rtnetlink.
Also, "h" sounds like a handle, that is, a file descriptor.
Make this clearer with a "sk_" prefix.
- "priv->genl" to "priv->sk_genl_sync": This socket is only used for synchronous
operations, that is, it is passed to various independent components, that use
it to send a request and wait for the response (while consuming all messages).
We will have a use for a second socket, hence the "_sync" part.
The "sk_" prefix is for consistency with "sk_rtnl".
- "priv->event_source" to "priv->rtnl_event_source". Just make it
clearer, that this is for the rtnetlink socket. In any case,
this field is hardly used at all, it can have a sturdy name.