xref: /linux/tools/testing/selftests/net/tcp_ao/lib/netlink.c (revision 06d07429858317ded2db7986113a9e0129cd599b)
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