Skip to content

Commit e2450d0

Browse files
committed
issue: 4219010 XLIO support for kernel 6.10
Kernel 6.10 netlink has breaked XLIO functionality. Transitioned to libnl - an abstraction that wraps netlink. This both solves the issue and makes us more robust. Signed-off-by: Tomer Cabouly <[email protected]>
1 parent 5c0e7a3 commit e2450d0

6 files changed

+186
-286
lines changed

src/core/proto/netlink_socket_mgr.cpp

+36-137
Original file line numberDiff line numberDiff line change
@@ -32,173 +32,72 @@
3232
* SOFTWARE.
3333
*/
3434

35-
#include "core/sock/sock-redirect.h"
3635
#include "core/util/utils.h"
3736
#include "vlogger/vlogger.h"
3837
#include "utils/bullseye.h"
3938
#include "netlink_socket_mgr.h"
4039

4140
#include <linux/rtnetlink.h>
4241
#include <linux/netlink.h>
43-
#include <stdlib.h>
4442
#include <unistd.h> // getpid()
4543

44+
#include <netlink/route/route.h>
45+
#include <netlink/route/rule.h>
46+
#include <netlink/route/link.h>
47+
4648
#ifndef MODULE_NAME
4749
#define MODULE_NAME "netlink_socket_mgr:"
4850
#endif
4951

50-
#define MSG_BUFF_SIZE 81920
51-
52-
// This function builds Netlink request to retrieve data (Rule, Route) from kernel.
53-
// Parameters :
54-
// data_type : either RULE_DATA_TYPE or ROUTE_DATA_TYPE
55-
// pid : opaque pid for netlink request
56-
// seq : opaque seq for netlink request
57-
// buf : buffer for the request
58-
// nl_msg : [out] pointer to request
59-
void netlink_socket_mgr::build_request(nl_data_t data_type, uint32_t pid, uint32_t seq, char *buf,
60-
struct nlmsghdr **nl_msg)
61-
{
62-
struct rtmsg *rt_msg;
63-
64-
assert(MSG_BUFF_SIZE >= NLMSG_SPACE(sizeof(struct rtmsg)));
65-
memset(buf, 0, NLMSG_SPACE(sizeof(struct rtmsg)));
66-
67-
// point the header and the msg structure pointers into the buffer
68-
*nl_msg = (struct nlmsghdr *)buf;
69-
rt_msg = (struct rtmsg *)NLMSG_DATA(*nl_msg);
70-
71-
// Fill in the nlmsg header
72-
(*nl_msg)->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
73-
(*nl_msg)->nlmsg_seq = seq;
74-
(*nl_msg)->nlmsg_pid = pid;
75-
(*nl_msg)->nlmsg_type = data_type == RULE_DATA_TYPE ? RTM_GETRULE : RTM_GETROUTE;
76-
(*nl_msg)->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
77-
78-
rt_msg->rtm_family = AF_UNSPEC;
79-
}
80-
81-
// Query built request and receive requested data (Rule, Route)
82-
// Parameters:
83-
// nl_msg : request that is built previously.
84-
// buf : [out] buffer for the reply
85-
// len : [out] length of received data.
86-
bool netlink_socket_mgr::query(const struct nlmsghdr *nl_msg, char *buf, int &len)
52+
// Update data in a table
53+
void netlink_socket_mgr::update_tbl(nl_data_t data_type)
8754
{
88-
int sockfd;
89-
90-
// Opaque information in the request. To track expected reply.
91-
uint32_t nl_pid = nl_msg->nlmsg_pid;
92-
uint32_t nl_seq = nl_msg->nlmsg_seq;
55+
nl_sock *sockfd = nullptr;
9356

9457
BULLSEYE_EXCLUDE_BLOCK_START
95-
if ((sockfd = SYSCALL(socket, PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0) {
96-
__log_err("NL socket creation failed, errno = %d", errno);
97-
return false;
98-
}
99-
if (SYSCALL(fcntl, sockfd, F_SETFD, FD_CLOEXEC) != 0) {
100-
__log_warn("Fail in fcntl, errno = %d", errno);
101-
}
102-
if ((len = SYSCALL(send, sockfd, nl_msg, nl_msg->nlmsg_len, 0)) < 0) {
103-
__log_err("Write to NL socket failed, errno = %d", errno);
104-
}
105-
if (len > 0 && (len = recv_info(sockfd, nl_pid, nl_seq, buf)) < 0) {
106-
__log_err("Read from NL socket failed...");
107-
}
108-
BULLSEYE_EXCLUDE_BLOCK_END
10958

110-
close(sockfd);
111-
return len > 0;
112-
}
59+
sockfd = nl_socket_alloc();
60+
if (sockfd == nullptr) {
61+
__log_err("NL socket Creation: ");
62+
throw_xlio_exception("Failed nl_socket_alloc");
63+
}
11364

114-
// Receive requested data and save it to buffer.
115-
// Return length of received data.
116-
// Parameters:
117-
// sockfd : netlink socket
118-
// pid : expected opaque pid value
119-
// seq : expected opaque seq value
120-
// buf : [out] read reply
121-
int netlink_socket_mgr::recv_info(int sockfd, uint32_t pid, uint32_t seq, char *buf)
122-
{
123-
struct nlmsghdr *nlHdr;
124-
int readLen;
125-
int msgLen = 0;
126-
char *buf_ptr = buf;
127-
128-
do {
129-
// Receive response from the kernel
130-
BULLSEYE_EXCLUDE_BLOCK_START
131-
if ((readLen = SYSCALL(recv, sockfd, buf_ptr, MSG_BUFF_SIZE - msgLen, 0)) < 0) {
132-
__log_err("NL socket read failed, errno = %d", errno);
133-
return -1;
134-
}
135-
136-
nlHdr = (struct nlmsghdr *)buf_ptr;
137-
138-
// Check if the header is valid
139-
if ((NLMSG_OK(nlHdr, (u_int)readLen) == 0) || (nlHdr->nlmsg_type == NLMSG_ERROR)) {
140-
__log_err("Error in received packet, readLen = %d, msgLen = %d, type=%d, bufLen = %d",
141-
readLen, nlHdr->nlmsg_len, nlHdr->nlmsg_type, MSG_BUFF_SIZE);
142-
if ((int)nlHdr->nlmsg_len >= MSG_BUFF_SIZE - msgLen) {
143-
__log_err("The buffer we pass to netlink is too small for reading the whole table");
144-
}
145-
return -1;
146-
}
147-
BULLSEYE_EXCLUDE_BLOCK_END
148-
149-
if ((nlHdr->nlmsg_seq != seq) || (nlHdr->nlmsg_pid != pid)) {
150-
// Skip not expected messages
151-
continue;
152-
}
153-
154-
buf_ptr += readLen;
155-
msgLen += readLen;
156-
157-
// Loop until this is the last message of expected reply
158-
} while (nlHdr->nlmsg_type != NLMSG_DONE && (nlHdr->nlmsg_flags & NLM_F_MULTI));
159-
160-
return msgLen;
161-
}
65+
if (nl_connect(sockfd, NETLINK_ROUTE) < 0) {
66+
__log_err("NL socket Connection: ");
67+
nl_socket_free(sockfd);
68+
throw_xlio_exception("Failed nl_connect");
69+
}
16270

163-
// Update data in a table
164-
void netlink_socket_mgr::update_tbl(nl_data_t data_type)
165-
{
166-
struct nlmsghdr *nl_msg = nullptr;
167-
char *buf;
168-
int len = 0;
71+
struct nl_cache *cache_state = {0};
72+
int err = 0;
16973

170-
// Opaque netlink information
171-
uint32_t nl_pid = getpid();
172-
uint32_t nl_seq = static_cast<uint32_t>(data_type);
74+
// cache allocation fetches the latest existing rules/routes
75+
if (data_type == RULE_DATA_TYPE) {
17376

174-
__log_dbg("");
77+
err = rtnl_rule_alloc_cache(sockfd, AF_INET, &cache_state);
78+
} else if (data_type == ROUTE_DATA_TYPE) {
17579

176-
buf = new char[MSG_BUFF_SIZE];
177-
if (!buf) {
178-
__log_err("NL message buffer allocation failed");
179-
return;
80+
err = rtnl_route_alloc_cache(sockfd, AF_INET, 0, &cache_state);
18081
}
18182

182-
build_request(data_type, nl_pid, nl_seq, buf, &nl_msg);
183-
if (query(nl_msg, buf, len)) {
184-
parse_tbl(buf, len);
83+
if (err < 0) {
84+
throw_xlio_exception("Failed to allocate route cache");
18585
}
18686

187-
delete[] buf;
188-
__log_dbg("Done");
87+
parse_tbl(cache_state);
18988
}
19089

19190
// Parse received data in a table
192-
// Parameters:
193-
// buf : buffer with netlink reply.
194-
// len : length of received data.
195-
void netlink_socket_mgr::parse_tbl(char *buf, int len)
91+
void netlink_socket_mgr::parse_tbl(struct nl_cache *cache_state)
19692
{
197-
struct nlmsghdr *nl_header = (struct nlmsghdr *)buf;
198-
199-
for (; NLMSG_OK(nl_header, (u_int)len); nl_header = NLMSG_NEXT(nl_header, len)) {
200-
parse_entry(nl_header);
201-
}
93+
// a lambda can't be casted to a c-fptr with ref captures - so we provide context ourselves
94+
nl_cache_foreach(
95+
cache_state,
96+
[](struct nl_object *nl_obj, void *context) {
97+
netlink_socket_mgr *this_ptr = reinterpret_cast<netlink_socket_mgr *>(context);
98+
this_ptr->parse_entry(nl_obj);
99+
},
100+
this);
202101
}
203102

204103
#undef MODULE_NAME

src/core/proto/netlink_socket_mgr.h

+3-10
Original file line numberDiff line numberDiff line change
@@ -34,25 +34,18 @@
3434

3535
#ifndef NETLINK_SOCKET_MGR_H
3636
#define NETLINK_SOCKET_MGR_H
37-
38-
// Forward declarations
39-
struct nlmsghdr;
40-
37+
#include <netlink/netlink.h>
4138
// This enum specify the type of data to be retrieve using netlink socket.
4239
enum nl_data_t { RULE_DATA_TYPE, ROUTE_DATA_TYPE };
4340

4441
// This class manages retrieving data (Rule, Route) from kernel using netlink socket.
4542
class netlink_socket_mgr {
4643
protected:
47-
virtual void parse_entry(struct nlmsghdr *nl_header) = 0;
44+
virtual void parse_entry(struct nl_object *nl_obj) = 0;
4845
virtual void update_tbl(nl_data_t data_type);
4946

5047
private:
51-
void build_request(nl_data_t data_type, uint32_t pid, uint32_t seq, char *buf,
52-
struct nlmsghdr **nl_msg);
53-
bool query(const struct nlmsghdr *nl_msg, char *buf, int &len);
54-
int recv_info(int sockfd, uint32_t pid, uint32_t seq, char *buf);
55-
void parse_tbl(char *buf, int len);
48+
void parse_tbl(struct nl_cache *cache_state);
5649
};
5750

5851
#endif /* NETLINK_SOCKET_MGR_H */

0 commit comments

Comments
 (0)