1 // SPDX-License-Identifier: GPL-2.0
2 /* Original from tools/testing/selftests/net/ipsec.c */
3 #include <linux/netlink.h>
4 #include <linux/random.h>
5 #include <linux/rtnetlink.h>
6 #include <linux/veth.h>
7 #include <net/if.h>
8 #include <stdint.h>
9 #include <string.h>
10 #include <sys/socket.h>
11
12 #include "aolib.h"
13
14 #define MAX_PAYLOAD 2048
15
netlink_sock(int * sock,uint32_t * seq_nr,int proto)16 static int netlink_sock(int *sock, uint32_t *seq_nr, int proto)
17 {
18 if (*sock > 0) {
19 seq_nr++;
20 return 0;
21 }
22
23 *sock = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, proto);
24 if (*sock < 0) {
25 test_print("socket(AF_NETLINK)");
26 return -1;
27 }
28
29 randomize_buffer(seq_nr, sizeof(*seq_nr));
30
31 return 0;
32 }
33
netlink_check_answer(int sock,bool quite)34 static int netlink_check_answer(int sock, bool quite)
35 {
36 struct nlmsgerror {
37 struct nlmsghdr hdr;
38 int error;
39 struct nlmsghdr orig_msg;
40 } answer;
41
42 if (recv(sock, &answer, sizeof(answer), 0) < 0) {
43 test_print("recv()");
44 return -1;
45 } else if (answer.hdr.nlmsg_type != NLMSG_ERROR) {
46 test_print("expected NLMSG_ERROR, got %d",
47 (int)answer.hdr.nlmsg_type);
48 return -1;
49 } else if (answer.error) {
50 if (!quite) {
51 test_print("NLMSG_ERROR: %d: %s",
52 answer.error, strerror(-answer.error));
53 }
54 return answer.error;
55 }
56
57 return 0;
58 }
59
rtattr_hdr(struct nlmsghdr * nh)60 static inline struct rtattr *rtattr_hdr(struct nlmsghdr *nh)
61 {
62 return (struct rtattr *)((char *)(nh) + RTA_ALIGN((nh)->nlmsg_len));
63 }
64
rtattr_pack(struct nlmsghdr * nh,size_t req_sz,unsigned short rta_type,const void * payload,size_t size)65 static int rtattr_pack(struct nlmsghdr *nh, size_t req_sz,
66 unsigned short rta_type, const void *payload, size_t size)
67 {
68 /* NLMSG_ALIGNTO == RTA_ALIGNTO, nlmsg_len already aligned */
69 struct rtattr *attr = rtattr_hdr(nh);
70 size_t nl_size = RTA_ALIGN(nh->nlmsg_len) + RTA_LENGTH(size);
71
72 if (req_sz < nl_size) {
73 test_print("req buf is too small: %zu < %zu", req_sz, nl_size);
74 return -1;
75 }
76 nh->nlmsg_len = nl_size;
77
78 attr->rta_len = RTA_LENGTH(size);
79 attr->rta_type = rta_type;
80 memcpy(RTA_DATA(attr), payload, size);
81
82 return 0;
83 }
84
_rtattr_begin(struct nlmsghdr * nh,size_t req_sz,unsigned short rta_type,const void * payload,size_t size)85 static struct rtattr *_rtattr_begin(struct nlmsghdr *nh, size_t req_sz,
86 unsigned short rta_type, const void *payload, size_t size)
87 {
88 struct rtattr *ret = rtattr_hdr(nh);
89
90 if (rtattr_pack(nh, req_sz, rta_type, payload, size))
91 return 0;
92
93 return ret;
94 }
95
rtattr_begin(struct nlmsghdr * nh,size_t req_sz,unsigned short rta_type)96 static inline struct rtattr *rtattr_begin(struct nlmsghdr *nh, size_t req_sz,
97 unsigned short rta_type)
98 {
99 return _rtattr_begin(nh, req_sz, rta_type, 0, 0);
100 }
101
rtattr_end(struct nlmsghdr * nh,struct rtattr * attr)102 static inline void rtattr_end(struct nlmsghdr *nh, struct rtattr *attr)
103 {
104 char *nlmsg_end = (char *)nh + nh->nlmsg_len;
105
106 attr->rta_len = nlmsg_end - (char *)attr;
107 }
108
veth_pack_peerb(struct nlmsghdr * nh,size_t req_sz,const char * peer,int ns)109 static int veth_pack_peerb(struct nlmsghdr *nh, size_t req_sz,
110 const char *peer, int ns)
111 {
112 struct ifinfomsg pi;
113 struct rtattr *peer_attr;
114
115 memset(&pi, 0, sizeof(pi));
116 pi.ifi_family = AF_UNSPEC;
117 pi.ifi_change = 0xFFFFFFFF;
118
119 peer_attr = _rtattr_begin(nh, req_sz, VETH_INFO_PEER, &pi, sizeof(pi));
120 if (!peer_attr)
121 return -1;
122
123 if (rtattr_pack(nh, req_sz, IFLA_IFNAME, peer, strlen(peer)))
124 return -1;
125
126 if (rtattr_pack(nh, req_sz, IFLA_NET_NS_FD, &ns, sizeof(ns)))
127 return -1;
128
129 rtattr_end(nh, peer_attr);
130
131 return 0;
132 }
133
__add_veth(int sock,uint32_t seq,const char * name,int ns_a,int ns_b)134 static int __add_veth(int sock, uint32_t seq, const char *name,
135 int ns_a, int ns_b)
136 {
137 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE;
138 struct {
139 struct nlmsghdr nh;
140 struct ifinfomsg info;
141 char attrbuf[MAX_PAYLOAD];
142 } req;
143 static const char veth_type[] = "veth";
144 struct rtattr *link_info, *info_data;
145
146 memset(&req, 0, sizeof(req));
147 req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.info));
148 req.nh.nlmsg_type = RTM_NEWLINK;
149 req.nh.nlmsg_flags = flags;
150 req.nh.nlmsg_seq = seq;
151 req.info.ifi_family = AF_UNSPEC;
152 req.info.ifi_change = 0xFFFFFFFF;
153
154 if (rtattr_pack(&req.nh, sizeof(req), IFLA_IFNAME, name, strlen(name)))
155 return -1;
156
157 if (rtattr_pack(&req.nh, sizeof(req), IFLA_NET_NS_FD, &ns_a, sizeof(ns_a)))
158 return -1;
159
160 link_info = rtattr_begin(&req.nh, sizeof(req), IFLA_LINKINFO);
161 if (!link_info)
162 return -1;
163
164 if (rtattr_pack(&req.nh, sizeof(req), IFLA_INFO_KIND, veth_type, sizeof(veth_type)))
165 return -1;
166
167 info_data = rtattr_begin(&req.nh, sizeof(req), IFLA_INFO_DATA);
168 if (!info_data)
169 return -1;
170
171 if (veth_pack_peerb(&req.nh, sizeof(req), name, ns_b))
172 return -1;
173
174 rtattr_end(&req.nh, info_data);
175 rtattr_end(&req.nh, link_info);
176
177 if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
178 test_print("send()");
179 return -1;
180 }
181 return netlink_check_answer(sock, false);
182 }
183
add_veth(const char * name,int nsfda,int nsfdb)184 int add_veth(const char *name, int nsfda, int nsfdb)
185 {
186 int route_sock = -1, ret;
187 uint32_t route_seq;
188
189 if (netlink_sock(&route_sock, &route_seq, NETLINK_ROUTE))
190 test_error("Failed to open netlink route socket\n");
191
192 ret = __add_veth(route_sock, route_seq++, name, nsfda, nsfdb);
193 close(route_sock);
194 return ret;
195 }
196
__ip_addr_add(int sock,uint32_t seq,const char * intf,int family,union tcp_addr addr,uint8_t prefix)197 static int __ip_addr_add(int sock, uint32_t seq, const char *intf,
198 int family, union tcp_addr addr, uint8_t prefix)
199 {
200 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE;
201 struct {
202 struct nlmsghdr nh;
203 struct ifaddrmsg info;
204 char attrbuf[MAX_PAYLOAD];
205 } req;
206 size_t addr_len = (family == AF_INET) ? sizeof(struct in_addr) :
207 sizeof(struct in6_addr);
208
209 memset(&req, 0, sizeof(req));
210 req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.info));
211 req.nh.nlmsg_type = RTM_NEWADDR;
212 req.nh.nlmsg_flags = flags;
213 req.nh.nlmsg_seq = seq;
214 req.info.ifa_family = family;
215 req.info.ifa_prefixlen = prefix;
216 req.info.ifa_index = if_nametoindex(intf);
217 req.info.ifa_flags = IFA_F_NODAD;
218
219 if (rtattr_pack(&req.nh, sizeof(req), IFA_LOCAL, &addr, addr_len))
220 return -1;
221
222 if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
223 test_print("send()");
224 return -1;
225 }
226 return netlink_check_answer(sock, true);
227 }
228
ip_addr_add(const char * intf,int family,union tcp_addr addr,uint8_t prefix)229 int ip_addr_add(const char *intf, int family,
230 union tcp_addr addr, uint8_t prefix)
231 {
232 int route_sock = -1, ret;
233 uint32_t route_seq;
234
235 if (netlink_sock(&route_sock, &route_seq, NETLINK_ROUTE))
236 test_error("Failed to open netlink route socket\n");
237
238 ret = __ip_addr_add(route_sock, route_seq++, intf,
239 family, addr, prefix);
240
241 close(route_sock);
242 return ret;
243 }
244
__ip_route_add(int sock,uint32_t seq,const char * intf,int family,union tcp_addr src,union tcp_addr dst,uint8_t vrf)245 static int __ip_route_add(int sock, uint32_t seq, const char *intf, int family,
246 union tcp_addr src, union tcp_addr dst, uint8_t vrf)
247 {
248 struct {
249 struct nlmsghdr nh;
250 struct rtmsg rt;
251 char attrbuf[MAX_PAYLOAD];
252 } req;
253 unsigned int index = if_nametoindex(intf);
254 size_t addr_len = (family == AF_INET) ? sizeof(struct in_addr) :
255 sizeof(struct in6_addr);
256
257 memset(&req, 0, sizeof(req));
258 req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.rt));
259 req.nh.nlmsg_type = RTM_NEWROUTE;
260 req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE;
261 req.nh.nlmsg_seq = seq;
262 req.rt.rtm_family = family;
263 req.rt.rtm_dst_len = (family == AF_INET) ? 32 : 128;
264 req.rt.rtm_table = vrf;
265 req.rt.rtm_protocol = RTPROT_BOOT;
266 req.rt.rtm_scope = RT_SCOPE_UNIVERSE;
267 req.rt.rtm_type = RTN_UNICAST;
268
269 if (rtattr_pack(&req.nh, sizeof(req), RTA_DST, &dst, addr_len))
270 return -1;
271
272 if (rtattr_pack(&req.nh, sizeof(req), RTA_PREFSRC, &src, addr_len))
273 return -1;
274
275 if (rtattr_pack(&req.nh, sizeof(req), RTA_OIF, &index, sizeof(index)))
276 return -1;
277
278 if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
279 test_print("send()");
280 return -1;
281 }
282
283 return netlink_check_answer(sock, true);
284 }
285
ip_route_add_vrf(const char * intf,int family,union tcp_addr src,union tcp_addr dst,uint8_t vrf)286 int ip_route_add_vrf(const char *intf, int family,
287 union tcp_addr src, union tcp_addr dst, uint8_t vrf)
288 {
289 int route_sock = -1, ret;
290 uint32_t route_seq;
291
292 if (netlink_sock(&route_sock, &route_seq, NETLINK_ROUTE))
293 test_error("Failed to open netlink route socket\n");
294
295 ret = __ip_route_add(route_sock, route_seq++, intf,
296 family, src, dst, vrf);
297
298 close(route_sock);
299 return ret;
300 }
301
ip_route_add(const char * intf,int family,union tcp_addr src,union tcp_addr dst)302 int ip_route_add(const char *intf, int family,
303 union tcp_addr src, union tcp_addr dst)
304 {
305 return ip_route_add_vrf(intf, family, src, dst, RT_TABLE_MAIN);
306 }
307
__link_set_up(int sock,uint32_t seq,const char * intf)308 static int __link_set_up(int sock, uint32_t seq, const char *intf)
309 {
310 struct {
311 struct nlmsghdr nh;
312 struct ifinfomsg info;
313 char attrbuf[MAX_PAYLOAD];
314 } req;
315
316 memset(&req, 0, sizeof(req));
317 req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.info));
318 req.nh.nlmsg_type = RTM_NEWLINK;
319 req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
320 req.nh.nlmsg_seq = seq;
321 req.info.ifi_family = AF_UNSPEC;
322 req.info.ifi_change = 0xFFFFFFFF;
323 req.info.ifi_index = if_nametoindex(intf);
324 req.info.ifi_flags = IFF_UP;
325 req.info.ifi_change = IFF_UP;
326
327 if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
328 test_print("send()");
329 return -1;
330 }
331 return netlink_check_answer(sock, false);
332 }
333
link_set_up(const char * intf)334 int link_set_up(const char *intf)
335 {
336 int route_sock = -1, ret;
337 uint32_t route_seq;
338
339 if (netlink_sock(&route_sock, &route_seq, NETLINK_ROUTE))
340 test_error("Failed to open netlink route socket\n");
341
342 ret = __link_set_up(route_sock, route_seq++, intf);
343
344 close(route_sock);
345 return ret;
346 }
347
__add_vrf(int sock,uint32_t seq,const char * name,uint32_t tabid,int ifindex,int nsfd)348 static int __add_vrf(int sock, uint32_t seq, const char *name,
349 uint32_t tabid, int ifindex, int nsfd)
350 {
351 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE;
352 struct {
353 struct nlmsghdr nh;
354 struct ifinfomsg info;
355 char attrbuf[MAX_PAYLOAD];
356 } req;
357 static const char vrf_type[] = "vrf";
358 struct rtattr *link_info, *info_data;
359
360 memset(&req, 0, sizeof(req));
361 req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.info));
362 req.nh.nlmsg_type = RTM_NEWLINK;
363 req.nh.nlmsg_flags = flags;
364 req.nh.nlmsg_seq = seq;
365 req.info.ifi_family = AF_UNSPEC;
366 req.info.ifi_change = 0xFFFFFFFF;
367 req.info.ifi_index = ifindex;
368
369 if (rtattr_pack(&req.nh, sizeof(req), IFLA_IFNAME, name, strlen(name)))
370 return -1;
371
372 if (nsfd >= 0)
373 if (rtattr_pack(&req.nh, sizeof(req), IFLA_NET_NS_FD,
374 &nsfd, sizeof(nsfd)))
375 return -1;
376
377 link_info = rtattr_begin(&req.nh, sizeof(req), IFLA_LINKINFO);
378 if (!link_info)
379 return -1;
380
381 if (rtattr_pack(&req.nh, sizeof(req), IFLA_INFO_KIND, vrf_type, sizeof(vrf_type)))
382 return -1;
383
384 info_data = rtattr_begin(&req.nh, sizeof(req), IFLA_INFO_DATA);
385 if (!info_data)
386 return -1;
387
388 if (rtattr_pack(&req.nh, sizeof(req), IFLA_VRF_TABLE,
389 &tabid, sizeof(tabid)))
390 return -1;
391
392 rtattr_end(&req.nh, info_data);
393 rtattr_end(&req.nh, link_info);
394
395 if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
396 test_print("send()");
397 return -1;
398 }
399 return netlink_check_answer(sock, true);
400 }
401
add_vrf(const char * name,uint32_t tabid,int ifindex,int nsfd)402 int add_vrf(const char *name, uint32_t tabid, int ifindex, int nsfd)
403 {
404 int route_sock = -1, ret;
405 uint32_t route_seq;
406
407 if (netlink_sock(&route_sock, &route_seq, NETLINK_ROUTE))
408 test_error("Failed to open netlink route socket\n");
409
410 ret = __add_vrf(route_sock, route_seq++, name, tabid, ifindex, nsfd);
411 close(route_sock);
412 return ret;
413 }
414