Add netlink regression test and gVisor test

This commit is contained in:
jiangjianfeng 2025-03-27 03:24:35 +00:00 committed by Tate, Hongliang Tian
parent 7d24e63216
commit 5e9f537222
6 changed files with 245 additions and 2 deletions

View File

@ -70,6 +70,9 @@ $(INITRAMFS)/lib/x86_64-linux-gnu: | $(VDSO_LIB)
@cp -L /lib/x86_64-linux-gnu/libevent-2.1.so.7 $@
@# required for VDSO
@cp -L $(VDSO_LIB) $@
@# required for netlink test
@cp -L /lib/x86_64-linux-gnu/libnl-3.so.200 $@
@cp -L /lib/x86_64-linux-gnu/libnl-route-3.so.200 $@
$(VDSO_LIB): | $(VDSO_DIR) $(BINARY_CACHE_DIR)/vdso64.so
@# TODO: use a custom compiled vdso.so file in the future.

View File

@ -2,4 +2,4 @@
include ../test_common.mk
EXTRA_C_FLAGS :=
EXTRA_C_FLAGS := -I/usr/include/libnl3 -lnl-3 -lnl-route-3

View File

@ -0,0 +1,227 @@
// SPDX-License-Identifier: MPL-2.0
#include <netlink/netlink.h>
#include <netlink/route/link.h>
#include <netlink/route/addr.h>
#include <net/if.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "test.h"
#define ETHER_NAME "eth0"
#define LOOPBACK_NAME "lo"
#define SUCC(expr) ((expr), 0)
int find_lo_and_eth0_by_libc(struct if_nameindex *if_ni)
{
int found_links = 0;
for (struct if_nameindex *i = if_ni;
!(i->if_index == 0 && i->if_name == NULL); i++) {
if (strcmp(i->if_name, LOOPBACK_NAME) == 0) {
found_links++;
}
if (strcmp(i->if_name, ETHER_NAME) == 0) {
found_links++;
}
}
return found_links;
}
FN_TEST(if_nameindex)
{
struct if_nameindex *if_ni;
CHECK_WITH(SUCC(if_ni = if_nameindex()), if_ni != NULL);
TEST_RES(find_lo_and_eth0_by_libc(if_ni), _ret == 2);
if_freenameindex(if_ni);
}
END_TEST()
void find_lo_and_eth0_by_libnl(struct nl_object *obj, void *arg)
{
int *found_links = (int *)arg;
struct rtnl_link *link = (struct rtnl_link *)obj;
if (strcmp(rtnl_link_get_name(link), LOOPBACK_NAME) == 0) {
*found_links += 1;
}
if (strcmp(rtnl_link_get_name(link), ETHER_NAME) == 0) {
*found_links += 1;
}
}
FN_TEST(get_link_by_libnl)
{
struct nl_sock *sock;
struct nl_cache *link_cache;
// 1. Create netlink socket and connect
sock = nl_socket_alloc();
TEST_RES(nl_connect(sock, NETLINK_ROUTE), _ret >= 0);
// 2. Allocate and retrieve link cache
TEST_RES(rtnl_link_alloc_cache(sock, AF_UNSPEC, &link_cache),
_ret >= 0);
// 3. Iterate over all links to find lo and eth0
int found_links = 0;
TEST_RES(SUCC(nl_cache_foreach(link_cache, find_lo_and_eth0_by_libnl,
&found_links)),
found_links == 2);
// 4. Cleanup
nl_cache_free(link_cache);
nl_close(sock);
nl_socket_free(sock);
}
END_TEST()
void find_loopback_address(struct nl_object *obj, void *arg)
{
int *found_loopback = (int *)arg;
struct rtnl_addr *addr = (struct rtnl_addr *)obj;
struct nl_addr *local;
char buf[INET_ADDRSTRLEN];
int family = rtnl_addr_get_family(addr);
if (family != AF_INET) {
return;
}
local = rtnl_addr_get_local(addr);
if (local) {
nl_addr2str(local, buf, sizeof(buf));
if (strcmp(buf, "127.0.0.1/8") == 0) {
*found_loopback = 1;
}
}
}
FN_TEST(get_loopback_address)
{
struct nl_sock *sock;
struct nl_cache *addr_cache;
// 1. Create netlink socket and connect
sock = nl_socket_alloc();
TEST_RES(nl_connect(sock, NETLINK_ROUTE), _ret >= 0);
// 2. Allocate and retrieve address cache
TEST_RES(rtnl_addr_alloc_cache(sock, &addr_cache), _ret >= 0);
// 3. Iterate over all addresses to find loopback address
int found_loopback = 0;
TEST_RES(SUCC(nl_cache_foreach(addr_cache, find_loopback_address,
&found_loopback)),
found_loopback == 1);
// 4. Cleanup
nl_cache_free(addr_cache);
nl_close(sock);
nl_socket_free(sock);
}
END_TEST()
int find_new_addr_until_done(char *buffer, size_t len, int *found_new_addr)
{
struct nlmsghdr *nlh = (struct nlmsghdr *)buffer;
for (; NLMSG_OK(nlh, len); nlh = NLMSG_NEXT(nlh, len)) {
if (nlh->nlmsg_type == NLMSG_DONE) {
return *found_new_addr ? 1 : -1;
}
if (nlh->nlmsg_type == RTM_NEWADDR) {
*found_new_addr += 1;
} else {
return -1;
}
}
return 0;
}
FN_TEST(get_addr_error)
{
#define BUFFER_SIZE 8192
struct nl_req {
struct nlmsghdr hdr;
struct ifaddrmsg ifa;
};
int sock_fd;
struct sockaddr_nl sa;
char buffer[BUFFER_SIZE];
sock_fd = TEST_SUCC(socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE));
memset(&sa, 0, sizeof(sa));
sa.nl_family = AF_NETLINK;
TEST_SUCC(bind(sock_fd, (struct sockaddr *)&sa, sizeof(sa)));
// 1. Without NLM_F_DUMP flag
struct nl_req req;
memset(&req, 0, sizeof(req));
req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
req.hdr.nlmsg_type = RTM_GETADDR;
req.hdr.nlmsg_flags = NLM_F_REQUEST;
req.hdr.nlmsg_seq = 1;
req.ifa.ifa_family = AF_UNSPEC;
struct iovec iov = { &req, req.hdr.nlmsg_len };
struct msghdr msg = { &sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
TEST_SUCC(sendmsg(sock_fd, &msg, 0));
TEST_RES(recv(sock_fd, buffer, BUFFER_SIZE, 0),
((struct nlmsghdr *)buffer)->nlmsg_type == NLMSG_ERROR &&
((struct nlmsgerr *)NLMSG_DATA(buffer))->error ==
-EOPNOTSUPP);
// 2. Invalid required index
req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP | NLM_F_ACK;
req.ifa.ifa_index = 9999;
TEST_SUCC(sendmsg(sock_fd, &msg, 0));
int found_new_addr = 0;
while (1) {
size_t recv_len =
TEST_SUCC(recv(sock_fd, buffer, BUFFER_SIZE, 0));
int found_done = TEST_SUCC(find_new_addr_until_done(
buffer, recv_len, &found_new_addr));
if (found_done != 0) {
break;
}
}
// 3. Invalid required family
req.ifa.ifa_family = 255;
req.ifa.ifa_index = 0;
TEST_SUCC(sendmsg(sock_fd, &msg, 0));
found_new_addr = 0;
while (1) {
size_t recv_len =
TEST_SUCC(recv(sock_fd, buffer, BUFFER_SIZE, 0));
int found_done = TEST_SUCC(find_new_addr_until_done(
buffer, recv_len, &found_new_addr));
if (found_done != 0) {
break;
}
}
}
END_TEST()

View File

@ -22,7 +22,7 @@ $(OBJ_OUTPUT_DIR) $(DEP_OUTPUT_DIR):
@mkdir -p $@
$(OBJ_OUTPUT_DIR)/%: %.c | $(OBJ_OUTPUT_DIR) $(DEP_OUTPUT_DIR)
@$(CC) $(C_FLAGS) $(EXTRA_C_FLAGS) $< -o $@ \
@$(CC) $(C_FLAGS) $< -o $@ $(EXTRA_C_FLAGS) \
-MMD -MF $(DEP_OUTPUT_DIR)/$*.d
@echo "CC <= $@"

View File

@ -46,6 +46,7 @@ TESTS ?= \
sigaction_test \
sigaltstack_test \
signalfd_test \
socket_netlink_route_test \
stat_test \
stat_times_test \
statfs_test \

View File

@ -0,0 +1,12 @@
NetlinkRouteTest.MsgHdrMsgUnsuppType
NetlinkRouteTest.MsgHdrMsgTrunc
NetlinkRouteTest.MsgTruncMsgHdrMsgTrunc
NetlinkRouteTest.ControlMessageIgnored
NetlinkRouteTest.AddAddr
NetlinkRouteTest.GetRouteDump
NetlinkRouteTest.GetRouteRequest
NetlinkRouteTest.RecvmsgTrunc
NetlinkRouteTest.RecvmsgTruncPeek
NetlinkRouteTest.NoPasscredNoCreds
NetlinkRouteTest.PasscredCreds
NetlinkRouteTest/SockOptTest.GetSockOpt/*