|
32 | 32 | * SOFTWARE.
|
33 | 33 | */
|
34 | 34 |
|
35 |
| -#include "core/sock/sock-redirect.h" |
36 | 35 | #include "core/util/utils.h"
|
37 | 36 | #include "vlogger/vlogger.h"
|
38 | 37 | #include "utils/bullseye.h"
|
39 | 38 | #include "netlink_socket_mgr.h"
|
40 | 39 |
|
41 | 40 | #include <linux/rtnetlink.h>
|
42 | 41 | #include <linux/netlink.h>
|
43 |
| -#include <stdlib.h> |
44 | 42 | #include <unistd.h> // getpid()
|
45 | 43 |
|
| 44 | +#include <netlink/route/route.h> |
| 45 | +#include <netlink/route/rule.h> |
| 46 | +#include <netlink/route/link.h> |
| 47 | + |
46 | 48 | #ifndef MODULE_NAME
|
47 | 49 | #define MODULE_NAME "netlink_socket_mgr:"
|
48 | 50 | #endif
|
49 | 51 |
|
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) |
87 | 54 | {
|
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; |
93 | 56 |
|
94 | 57 | 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 |
109 | 58 |
|
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 | + } |
113 | 64 |
|
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 | + } |
162 | 70 |
|
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; |
169 | 73 |
|
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) { |
173 | 76 |
|
174 |
| - __log_dbg(""); |
| 77 | + err = rtnl_rule_alloc_cache(sockfd, AF_INET, &cache_state); |
| 78 | + } else if (data_type == ROUTE_DATA_TYPE) { |
175 | 79 |
|
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); |
180 | 81 | }
|
181 | 82 |
|
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"); |
185 | 85 | }
|
186 | 86 |
|
187 |
| - delete[] buf; |
188 |
| - __log_dbg("Done"); |
| 87 | + parse_tbl(cache_state); |
189 | 88 | }
|
190 | 89 |
|
191 | 90 | // 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) |
196 | 92 | {
|
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); |
202 | 101 | }
|
203 | 102 |
|
204 | 103 | #undef MODULE_NAME
|
0 commit comments