xref: /aosp_15_r20/external/ltp/lib/tst_netdevice.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2021 Linux Test Project
4  */
5 
6 #include <asm/types.h>
7 #include <linux/veth.h>
8 #include <sys/socket.h>
9 #include <net/if.h>
10 #include <linux/pkt_sched.h>
11 #include "lapi/rtnetlink.h"
12 
13 #define TST_NO_DEFAULT_MAIN
14 #include "tst_test.h"
15 #include "tst_netlink.h"
16 #include "tst_netdevice.h"
17 
create_request(const char * file,const int lineno,unsigned int type,unsigned int flags,const void * payload,size_t psize)18 static struct tst_netlink_context *create_request(const char *file,
19 	const int lineno, unsigned int type, unsigned int flags,
20 	const void *payload, size_t psize)
21 {
22 	struct tst_netlink_context *ctx;
23 	struct nlmsghdr header = {
24 		.nlmsg_type = type,
25 		.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags,
26 	};
27 
28 	ctx = tst_netlink_create_context(file, lineno, NETLINK_ROUTE);
29 
30 	if (!ctx)
31 		return NULL;
32 
33 	if (!tst_netlink_add_message(file, lineno, ctx, &header, payload,
34 		psize)) {
35 		tst_netlink_destroy_context(file, lineno, ctx);
36 		return NULL;
37 	}
38 
39 	return ctx;
40 }
41 
tst_netdev_index_by_name(const char * file,const int lineno,const char * ifname)42 int tst_netdev_index_by_name(const char *file, const int lineno,
43 	const char *ifname)
44 {
45 	struct ifreq ifr;
46 	int sock, ret;
47 
48 	if (strlen(ifname) >= IFNAMSIZ) {
49 		tst_brk_(file, lineno, TBROK,
50 			"Network device name \"%s\" too long", ifname);
51 		return -1;
52 	}
53 
54 	sock = safe_socket(file, lineno, NULL, AF_INET, SOCK_DGRAM, 0);
55 
56 	if (sock < 0)
57 		return -1;
58 
59 	strcpy(ifr.ifr_name, ifname);
60 	ret = SAFE_IOCTL_(file, lineno, sock, SIOCGIFINDEX, &ifr);
61 	safe_close(file, lineno, NULL, sock);
62 
63 	return ret ? -1 : ifr.ifr_ifindex;
64 }
65 
tst_netdev_set_state(const char * file,const int lineno,const char * ifname,int up)66 int tst_netdev_set_state(const char *file, const int lineno,
67 	const char *ifname, int up)
68 {
69 	struct ifreq ifr;
70 	int sock, ret;
71 
72 	if (strlen(ifname) >= IFNAMSIZ) {
73 		tst_brk_(file, lineno, TBROK,
74 			"Network device name \"%s\" too long", ifname);
75 		return -1;
76 	}
77 
78 	sock = safe_socket(file, lineno, NULL, AF_INET, SOCK_DGRAM, 0);
79 
80 	if (sock < 0)
81 		return -1;
82 
83 	strcpy(ifr.ifr_name, ifname);
84 	ret = SAFE_IOCTL_(file, lineno, sock, SIOCGIFFLAGS, &ifr);
85 
86 	if (ret) {
87 		safe_close(file, lineno, NULL, sock);
88 		return ret;
89 	}
90 
91 	if (up)
92 		ifr.ifr_flags |= IFF_UP;
93 	else
94 		ifr.ifr_flags &= ~IFF_UP;
95 
96 	ret = SAFE_IOCTL_(file, lineno, sock, SIOCSIFFLAGS, &ifr);
97 	safe_close(file, lineno, NULL, sock);
98 
99 	return ret;
100 }
101 
tst_create_veth_pair(const char * file,const int lineno,int strict,const char * ifname1,const char * ifname2)102 int tst_create_veth_pair(const char *file, const int lineno, int strict,
103 	const char *ifname1, const char *ifname2)
104 {
105 	int ret;
106 	struct ifinfomsg info = { .ifi_family = AF_UNSPEC };
107 	struct tst_netlink_context *ctx;
108 	struct tst_netlink_attr_list peerinfo[] = {
109 		{IFLA_IFNAME, ifname2, strlen(ifname2) + 1, NULL},
110 		{0, NULL, -1, NULL}
111 	};
112 	struct tst_netlink_attr_list peerdata[] = {
113 		{VETH_INFO_PEER, &info, sizeof(info), peerinfo},
114 		{0, NULL, -1, NULL}
115 	};
116 	struct tst_netlink_attr_list attrs[] = {
117 		{IFLA_IFNAME, ifname1, strlen(ifname1) + 1, NULL},
118 		{IFLA_LINKINFO, NULL, 0, (const struct tst_netlink_attr_list[]){
119 			{IFLA_INFO_KIND, "veth", 4, NULL},
120 			{IFLA_INFO_DATA, NULL, 0, peerdata},
121 			{0, NULL, -1, NULL}
122 		}},
123 		{0, NULL, -1, NULL}
124 	};
125 
126 	if (strlen(ifname1) >= IFNAMSIZ) {
127 		tst_brk_(file, lineno, TBROK,
128 			"Network device name \"%s\" too long", ifname1);
129 		return 0;
130 	}
131 
132 	if (strlen(ifname2) >= IFNAMSIZ) {
133 		tst_brk_(file, lineno, TBROK,
134 			"Network device name \"%s\" too long", ifname2);
135 		return 0;
136 	}
137 
138 	ctx = create_request(file, lineno, RTM_NEWLINK,
139 		NLM_F_CREATE | NLM_F_EXCL, &info, sizeof(info));
140 
141 	if (!ctx)
142 		return 0;
143 
144 	if (tst_rtnl_add_attr_list(file, lineno, ctx, attrs) != 2) {
145 		tst_netlink_destroy_context(file, lineno, ctx);
146 		return 0;
147 	}
148 
149 	ret = tst_netlink_send_validate(file, lineno, ctx);
150 	tst_netlink_destroy_context(file, lineno, ctx);
151 
152 	if (strict && !ret) {
153 		tst_brk_(file, lineno, TBROK,
154 			"Failed to create veth interfaces %s+%s: %s", ifname1,
155 			ifname2, tst_strerrno(tst_netlink_errno));
156 	}
157 
158 	return ret;
159 }
160 
tst_netdev_add_device(const char * file,const int lineno,int strict,const char * ifname,const char * devtype)161 int tst_netdev_add_device(const char *file, const int lineno, int strict,
162 	const char *ifname, const char *devtype)
163 {
164 	int ret;
165 	struct ifinfomsg info = { .ifi_family = AF_UNSPEC };
166 	struct tst_netlink_context *ctx;
167 	struct tst_netlink_attr_list attrs[] = {
168 		{IFLA_IFNAME, ifname, strlen(ifname) + 1, NULL},
169 		{IFLA_LINKINFO, NULL, 0, (const struct tst_netlink_attr_list[]){
170 			{IFLA_INFO_KIND, devtype, strlen(devtype), NULL},
171 			{0, NULL, -1, NULL}
172 		}},
173 		{0, NULL, -1, NULL}
174 	};
175 
176 	if (strlen(ifname) >= IFNAMSIZ) {
177 		tst_brk_(file, lineno, TBROK,
178 			"Network device name \"%s\" too long", ifname);
179 		return 0;
180 	}
181 
182 	ctx = create_request(file, lineno, RTM_NEWLINK,
183 		NLM_F_CREATE | NLM_F_EXCL, &info, sizeof(info));
184 
185 	if (!ctx)
186 		return 0;
187 
188 	if (tst_rtnl_add_attr_list(file, lineno, ctx, attrs) != 2) {
189 		tst_netlink_destroy_context(file, lineno, ctx);
190 		return 0;
191 	}
192 
193 	ret = tst_netlink_send_validate(file, lineno, ctx);
194 	tst_netlink_destroy_context(file, lineno, ctx);
195 
196 	if (strict && !ret) {
197 		tst_brk_(file, lineno, TBROK,
198 			"Failed to create %s device %s: %s", devtype, ifname,
199 			tst_strerrno(tst_netlink_errno));
200 	}
201 
202 	return ret;
203 }
204 
tst_netdev_remove_device(const char * file,const int lineno,int strict,const char * ifname)205 int tst_netdev_remove_device(const char *file, const int lineno, int strict,
206 	const char *ifname)
207 {
208 	struct ifinfomsg info = { .ifi_family = AF_UNSPEC };
209 	struct tst_netlink_context *ctx;
210 	int ret;
211 
212 	if (strlen(ifname) >= IFNAMSIZ) {
213 		tst_brk_(file, lineno, TBROK,
214 			"Network device name \"%s\" too long", ifname);
215 		return 0;
216 	}
217 
218 	ctx = create_request(file, lineno, RTM_DELLINK, 0, &info, sizeof(info));
219 
220 	if (!ctx)
221 		return 0;
222 
223 	if (!tst_rtnl_add_attr_string(file, lineno, ctx, IFLA_IFNAME, ifname)) {
224 		tst_netlink_destroy_context(file, lineno, ctx);
225 		return 0;
226 	}
227 
228 	ret = tst_netlink_send_validate(file, lineno, ctx);
229 	tst_netlink_destroy_context(file, lineno, ctx);
230 
231 	if (strict && !ret) {
232 		tst_brk_(file, lineno, TBROK,
233 			"Failed to remove netdevice %s: %s", ifname,
234 			tst_strerrno(tst_netlink_errno));
235 	}
236 
237 	return ret;
238 }
239 
modify_address(const char * file,const int lineno,int strict,unsigned int action,unsigned int nl_flags,const char * ifname,unsigned int family,const void * address,unsigned int prefix,size_t addrlen,uint32_t addr_flags)240 static int modify_address(const char *file, const int lineno, int strict,
241 	unsigned int action, unsigned int nl_flags, const char *ifname,
242 	unsigned int family, const void *address, unsigned int prefix,
243 	size_t addrlen, uint32_t addr_flags)
244 {
245 	struct tst_netlink_context *ctx;
246 	int index, ret;
247 	struct ifaddrmsg info = {
248 		.ifa_family = family,
249 		.ifa_prefixlen = prefix
250 	};
251 
252 	index = tst_netdev_index_by_name(file, lineno, ifname);
253 
254 	if (index < 0) {
255 		tst_brk_(file, lineno, TBROK, "Interface %s not found", ifname);
256 		return 0;
257 	}
258 
259 	info.ifa_index = index;
260 	ctx = create_request(file, lineno, action, nl_flags, &info,
261 		sizeof(info));
262 
263 	if (!ctx)
264 		return 0;
265 
266 	if (!tst_rtnl_add_attr(file, lineno, ctx, IFA_FLAGS, &addr_flags,
267 		sizeof(uint32_t))) {
268 		tst_netlink_destroy_context(file, lineno, ctx);
269 		return 0;
270 	}
271 
272 	if (!tst_rtnl_add_attr(file, lineno, ctx, IFA_LOCAL, address,
273 		addrlen)) {
274 		tst_netlink_destroy_context(file, lineno, ctx);
275 		return 0;
276 	}
277 
278 	ret = tst_netlink_send_validate(file, lineno, ctx);
279 	tst_netlink_destroy_context(file, lineno, ctx);
280 
281 	if (strict && !ret) {
282 		tst_brk_(file, lineno, TBROK,
283 			"Failed to modify %s network address: %s", ifname,
284 			tst_strerrno(tst_netlink_errno));
285 	}
286 
287 	return ret;
288 }
289 
tst_netdev_add_address(const char * file,const int lineno,int strict,const char * ifname,unsigned int family,const void * address,unsigned int prefix,size_t addrlen,unsigned int flags)290 int tst_netdev_add_address(const char *file, const int lineno, int strict,
291 	const char *ifname, unsigned int family, const void *address,
292 	unsigned int prefix, size_t addrlen, unsigned int flags)
293 {
294 	return modify_address(file, lineno, strict, RTM_NEWADDR,
295 		NLM_F_CREATE | NLM_F_EXCL, ifname, family, address, prefix,
296 		addrlen, flags);
297 }
298 
tst_netdev_add_address_inet(const char * file,const int lineno,int strict,const char * ifname,in_addr_t address,unsigned int prefix,unsigned int flags)299 int tst_netdev_add_address_inet(const char *file, const int lineno, int strict,
300 	const char *ifname, in_addr_t address, unsigned int prefix,
301 	unsigned int flags)
302 {
303 	return tst_netdev_add_address(file, lineno, strict, ifname, AF_INET,
304 		&address, prefix, sizeof(address), flags);
305 }
306 
tst_netdev_remove_address(const char * file,const int lineno,int strict,const char * ifname,unsigned int family,const void * address,size_t addrlen)307 int tst_netdev_remove_address(const char *file, const int lineno, int strict,
308 	const char *ifname, unsigned int family, const void *address,
309 	size_t addrlen)
310 {
311 	return modify_address(file, lineno, strict, RTM_DELADDR, 0, ifname,
312 		family, address, 0, addrlen, 0);
313 }
314 
tst_netdev_remove_address_inet(const char * file,const int lineno,int strict,const char * ifname,in_addr_t address)315 int tst_netdev_remove_address_inet(const char *file, const int lineno,
316 	int strict, const char *ifname, in_addr_t address)
317 {
318 	return tst_netdev_remove_address(file, lineno, strict, ifname, AF_INET,
319 		&address, sizeof(address));
320 }
321 
change_ns(const char * file,const int lineno,int strict,const char * ifname,unsigned short attr,uint32_t value)322 static int change_ns(const char *file, const int lineno, int strict,
323 	const char *ifname, unsigned short attr, uint32_t value)
324 {
325 	struct ifinfomsg info = { .ifi_family = AF_UNSPEC };
326 	struct tst_netlink_context *ctx;
327 	int ret;
328 
329 	if (strlen(ifname) >= IFNAMSIZ) {
330 		tst_brk_(file, lineno, TBROK,
331 			"Network device name \"%s\" too long", ifname);
332 		return 0;
333 	}
334 
335 	ctx = create_request(file, lineno, RTM_NEWLINK, 0, &info, sizeof(info));
336 
337 	if (!ctx)
338 		return 0;
339 
340 	if (!tst_rtnl_add_attr_string(file, lineno, ctx, IFLA_IFNAME, ifname)) {
341 		tst_netlink_destroy_context(file, lineno, ctx);
342 		return 0;
343 	}
344 
345 	if (!tst_rtnl_add_attr(file, lineno, ctx, attr, &value,
346 		sizeof(uint32_t))) {
347 		tst_netlink_destroy_context(file, lineno, ctx);
348 		return 0;
349 	}
350 
351 	ret = tst_netlink_send_validate(file, lineno, ctx);
352 	tst_netlink_destroy_context(file, lineno, ctx);
353 
354 	if (strict && !ret) {
355 		tst_brk_(file, lineno, TBROK,
356 			"Failed to move %s to another namespace: %s", ifname,
357 			tst_strerrno(tst_netlink_errno));
358 	}
359 
360 	return ret;
361 }
362 
tst_netdev_change_ns_fd(const char * file,const int lineno,int strict,const char * ifname,int nsfd)363 int tst_netdev_change_ns_fd(const char *file, const int lineno, int strict,
364 	const char *ifname, int nsfd)
365 {
366 	return change_ns(file, lineno, strict, ifname, IFLA_NET_NS_FD, nsfd);
367 }
368 
tst_netdev_change_ns_pid(const char * file,const int lineno,int strict,const char * ifname,pid_t nspid)369 int tst_netdev_change_ns_pid(const char *file, const int lineno, int strict,
370 	const char *ifname, pid_t nspid)
371 {
372 	return change_ns(file, lineno, strict, ifname, IFLA_NET_NS_PID, nspid);
373 }
374 
modify_route(const char * file,const int lineno,int strict,unsigned int action,unsigned int flags,const char * ifname,unsigned int family,const void * srcaddr,unsigned int srcprefix,size_t srclen,const void * dstaddr,unsigned int dstprefix,size_t dstlen,const void * gateway,size_t gatewaylen)375 static int modify_route(const char *file, const int lineno, int strict,
376 	unsigned int action, unsigned int flags, const char *ifname,
377 	unsigned int family, const void *srcaddr, unsigned int srcprefix,
378 	size_t srclen, const void *dstaddr, unsigned int dstprefix,
379 	size_t dstlen, const void *gateway, size_t gatewaylen)
380 {
381 	struct tst_netlink_context *ctx;
382 	int ret;
383 	int32_t index;
384 	struct rtmsg info = {
385 		.rtm_family = family,
386 		.rtm_dst_len = dstprefix,
387 		.rtm_src_len = srcprefix,
388 		.rtm_table = RT_TABLE_MAIN,
389 		.rtm_protocol = RTPROT_STATIC,
390 		.rtm_type = RTN_UNICAST
391 	};
392 
393 	if (!ifname && !gateway) {
394 		tst_brk_(file, lineno, TBROK,
395 			"Interface name or gateway address required");
396 		return 0;
397 	}
398 
399 	if (ifname && strlen(ifname) >= IFNAMSIZ) {
400 		tst_brk_(file, lineno, TBROK,
401 			"Network device name \"%s\" too long", ifname);
402 		return 0;
403 	}
404 
405 	if (ifname) {
406 		index = tst_netdev_index_by_name(file, lineno, ifname);
407 
408 		if (index < 0)
409 			return 0;
410 	}
411 
412 	if (action == RTM_DELROUTE)
413 		info.rtm_scope = RT_SCOPE_NOWHERE;
414 	else
415 		info.rtm_scope = RT_SCOPE_UNIVERSE;
416 
417 	ctx = create_request(file, lineno, action, flags, &info, sizeof(info));
418 
419 	if (!ctx)
420 		return 0;
421 
422 	if (srcaddr && !tst_rtnl_add_attr(file, lineno, ctx, RTA_SRC, srcaddr,
423 		srclen)) {
424 		tst_netlink_destroy_context(file, lineno, ctx);
425 		return 0;
426 	}
427 
428 	if (dstaddr && !tst_rtnl_add_attr(file, lineno, ctx, RTA_DST, dstaddr,
429 		dstlen)) {
430 		tst_netlink_destroy_context(file, lineno, ctx);
431 		return 0;
432 	}
433 
434 	if (gateway && !tst_rtnl_add_attr(file, lineno, ctx, RTA_GATEWAY,
435 		gateway, gatewaylen)) {
436 		tst_netlink_destroy_context(file, lineno, ctx);
437 		return 0;
438 	}
439 
440 	if (ifname && !tst_rtnl_add_attr(file, lineno, ctx, RTA_OIF, &index,
441 		sizeof(index))) {
442 		tst_netlink_destroy_context(file, lineno, ctx);
443 		return 0;
444 	}
445 
446 	ret = tst_netlink_send_validate(file, lineno, ctx);
447 	tst_netlink_destroy_context(file, lineno, ctx);
448 
449 	if (strict && !ret) {
450 		tst_brk_(file, lineno, TBROK,
451 			"Failed to modify network route: %s",
452 			tst_strerrno(tst_netlink_errno));
453 	}
454 
455 	return ret;
456 }
457 
modify_route_inet(const char * file,const int lineno,int strict,unsigned int action,unsigned int flags,const char * ifname,in_addr_t srcaddr,unsigned int srcprefix,in_addr_t dstaddr,unsigned int dstprefix,in_addr_t gateway)458 static int modify_route_inet(const char *file, const int lineno, int strict,
459 	unsigned int action, unsigned int flags, const char *ifname,
460 	in_addr_t srcaddr, unsigned int srcprefix, in_addr_t dstaddr,
461 	unsigned int dstprefix, in_addr_t gateway)
462 {
463 	void *src = NULL, *dst = NULL, *gw = NULL;
464 	size_t srclen = 0, dstlen = 0, gwlen = 0;
465 
466 	if (srcprefix) {
467 		src = &srcaddr;
468 		srclen = sizeof(srcaddr);
469 	}
470 
471 	if (dstprefix) {
472 		dst = &dstaddr;
473 		dstlen = sizeof(dstaddr);
474 	}
475 
476 	if (gateway) {
477 		gw = &gateway;
478 		gwlen = sizeof(gateway);
479 	}
480 
481 	return modify_route(file, lineno, strict, action, flags, ifname,
482 		AF_INET, src, srcprefix, srclen, dst, dstprefix, dstlen, gw,
483 		gwlen);
484 }
485 
tst_netdev_add_route(const char * file,const int lineno,int strict,const char * ifname,unsigned int family,const void * srcaddr,unsigned int srcprefix,size_t srclen,const void * dstaddr,unsigned int dstprefix,size_t dstlen,const void * gateway,size_t gatewaylen)486 int tst_netdev_add_route(const char *file, const int lineno, int strict,
487 	const char *ifname, unsigned int family, const void *srcaddr,
488 	unsigned int srcprefix, size_t srclen, const void *dstaddr,
489 	unsigned int dstprefix, size_t dstlen, const void *gateway,
490 	size_t gatewaylen)
491 {
492 	return modify_route(file, lineno, strict, RTM_NEWROUTE,
493 		NLM_F_CREATE | NLM_F_EXCL, ifname, family, srcaddr, srcprefix,
494 		srclen, dstaddr, dstprefix, dstlen, gateway, gatewaylen);
495 }
496 
tst_netdev_add_route_inet(const char * file,const int lineno,int strict,const char * ifname,in_addr_t srcaddr,unsigned int srcprefix,in_addr_t dstaddr,unsigned int dstprefix,in_addr_t gateway)497 int tst_netdev_add_route_inet(const char *file, const int lineno, int strict,
498 	const char *ifname, in_addr_t srcaddr, unsigned int srcprefix,
499 	in_addr_t dstaddr, unsigned int dstprefix, in_addr_t gateway)
500 {
501 	return modify_route_inet(file, lineno, strict, RTM_NEWROUTE,
502 		NLM_F_CREATE | NLM_F_EXCL, ifname, srcaddr, srcprefix, dstaddr,
503 		dstprefix, gateway);
504 }
505 
tst_netdev_remove_route(const char * file,const int lineno,int strict,const char * ifname,unsigned int family,const void * srcaddr,unsigned int srcprefix,size_t srclen,const void * dstaddr,unsigned int dstprefix,size_t dstlen,const void * gateway,size_t gatewaylen)506 int tst_netdev_remove_route(const char *file, const int lineno, int strict,
507 	const char *ifname, unsigned int family, const void *srcaddr,
508 	unsigned int srcprefix, size_t srclen, const void *dstaddr,
509 	unsigned int dstprefix, size_t dstlen, const void *gateway,
510 	size_t gatewaylen)
511 {
512 	return modify_route(file, lineno, strict, RTM_DELROUTE, 0, ifname,
513 		family, srcaddr, srcprefix, srclen, dstaddr, dstprefix, dstlen,
514 		gateway, gatewaylen);
515 }
516 
tst_netdev_remove_route_inet(const char * file,const int lineno,int strict,const char * ifname,in_addr_t srcaddr,unsigned int srcprefix,in_addr_t dstaddr,unsigned int dstprefix,in_addr_t gateway)517 int tst_netdev_remove_route_inet(const char *file, const int lineno,
518 	int strict, const char *ifname, in_addr_t srcaddr,
519 	unsigned int srcprefix, in_addr_t dstaddr, unsigned int dstprefix,
520 	in_addr_t gateway)
521 {
522 	return modify_route_inet(file, lineno, strict, RTM_DELROUTE, 0, ifname,
523 		srcaddr, srcprefix, dstaddr, dstprefix, gateway);
524 }
525 
modify_qdisc(const char * file,const int lineno,int strict,const char * object,unsigned int action,unsigned int nl_flags,const char * ifname,unsigned int family,unsigned int parent,unsigned int handle,unsigned int info,const char * qd_kind,const struct tst_netlink_attr_list * config)526 static int modify_qdisc(const char *file, const int lineno, int strict,
527 	const char *object, unsigned int action, unsigned int nl_flags,
528 	const char *ifname, unsigned int family, unsigned int parent,
529 	unsigned int handle, unsigned int info, const char *qd_kind,
530 	const struct tst_netlink_attr_list *config)
531 {
532 	struct tst_netlink_context *ctx;
533 	int ret;
534 	struct tcmsg msg = {
535 		.tcm_family = family,
536 		.tcm_handle = handle,
537 		.tcm_parent = parent,
538 		.tcm_info = info
539 	};
540 
541 	if (!qd_kind) {
542 		tst_brk_(file, lineno, TBROK,
543 			"Queueing discipline name required");
544 		return 0;
545 	}
546 
547 	if (ifname) {
548 		msg.tcm_ifindex = tst_netdev_index_by_name(file, lineno,
549 			ifname);
550 
551 		if (msg.tcm_ifindex < 0) {
552 			tst_brk_(file, lineno, TBROK, "Interface %s not found",
553 				ifname);
554 			return 0;
555 		}
556 	}
557 
558 	ctx = create_request(file, lineno, action, nl_flags, &msg, sizeof(msg));
559 
560 	if (!ctx)
561 		return 0;
562 
563 	if (!tst_rtnl_add_attr_string(file, lineno, ctx, TCA_KIND, qd_kind)) {
564 		tst_netlink_destroy_context(file, lineno, ctx);
565 		return 0;
566 	}
567 
568 	if (config && !tst_rtnl_add_attr_list(file, lineno, ctx, config)) {
569 		tst_netlink_destroy_context(file, lineno, ctx);
570 		return 0;
571 	}
572 
573 	ret = tst_netlink_send_validate(file, lineno, ctx);
574 	tst_netlink_destroy_context(file, lineno, ctx);
575 
576 	if (strict && !ret) {
577 		tst_brk_(file, lineno, TBROK,
578 			"Failed to modify %s: %s", object,
579 			tst_strerrno(tst_netlink_errno));
580 	}
581 
582 	return ret;
583 }
584 
tst_netdev_add_qdisc(const char * file,const int lineno,int strict,const char * ifname,unsigned int family,unsigned int parent,unsigned int handle,const char * qd_kind,const struct tst_netlink_attr_list * config)585 int tst_netdev_add_qdisc(const char *file, const int lineno, int strict,
586 	const char *ifname, unsigned int family, unsigned int parent,
587 	unsigned int handle, const char *qd_kind,
588 	const struct tst_netlink_attr_list *config)
589 {
590 	return modify_qdisc(file, lineno, strict, "queueing discipline",
591 		RTM_NEWQDISC, NLM_F_CREATE | NLM_F_EXCL, ifname, family,
592 		parent, handle, 0, qd_kind, config);
593 }
594 
tst_netdev_remove_qdisc(const char * file,const int lineno,int strict,const char * ifname,unsigned int family,unsigned int parent,unsigned int handle,const char * qd_kind)595 int tst_netdev_remove_qdisc(const char *file, const int lineno, int strict,
596 	const char *ifname, unsigned int family, unsigned int parent,
597 	unsigned int handle, const char *qd_kind)
598 {
599 	return modify_qdisc(file, lineno, strict, "queueing discipline",
600 		RTM_DELQDISC, 0, ifname, family, parent, handle, 0, qd_kind,
601 		NULL);
602 }
603 
tst_netdev_add_traffic_class(const char * file,const int lineno,int strict,const char * ifname,unsigned int parent,unsigned int handle,const char * qd_kind,const struct tst_netlink_attr_list * config)604 int tst_netdev_add_traffic_class(const char *file, const int lineno,
605 	int strict, const char *ifname, unsigned int parent,
606 	unsigned int handle, const char *qd_kind,
607 	const struct tst_netlink_attr_list *config)
608 {
609 	return modify_qdisc(file, lineno, strict, "traffic class",
610 		RTM_NEWTCLASS, NLM_F_CREATE | NLM_F_EXCL, ifname, AF_UNSPEC,
611 		parent, handle, 0, qd_kind, config);
612 }
613 
tst_netdev_remove_traffic_class(const char * file,const int lineno,int strict,const char * ifname,unsigned int parent,unsigned int handle,const char * qd_kind)614 int tst_netdev_remove_traffic_class(const char *file, const int lineno,
615 	int strict, const char *ifname, unsigned int parent,
616 	unsigned int handle, const char *qd_kind)
617 {
618 	return modify_qdisc(file, lineno, strict, "traffic class",
619 		RTM_DELTCLASS, 0, ifname, AF_UNSPEC, parent, handle, 0,
620 		qd_kind, NULL);
621 }
622 
tst_netdev_add_traffic_filter(const char * file,const int lineno,int strict,const char * ifname,unsigned int parent,unsigned int handle,unsigned int protocol,unsigned int priority,const char * f_kind,const struct tst_netlink_attr_list * config)623 int tst_netdev_add_traffic_filter(const char *file, const int lineno,
624 	int strict, const char *ifname, unsigned int parent,
625 	unsigned int handle, unsigned int protocol, unsigned int priority,
626 	const char *f_kind, const struct tst_netlink_attr_list *config)
627 {
628 	return modify_qdisc(file, lineno, strict, "traffic filter",
629 		RTM_NEWTFILTER, NLM_F_CREATE | NLM_F_EXCL, ifname, AF_UNSPEC,
630 		parent, handle, TC_H_MAKE(priority << 16, htons(protocol)),
631 		f_kind, config);
632 }
633 
tst_netdev_remove_traffic_filter(const char * file,const int lineno,int strict,const char * ifname,unsigned int parent,unsigned int handle,unsigned int protocol,unsigned int priority,const char * f_kind)634 int tst_netdev_remove_traffic_filter(const char *file, const int lineno,
635 	int strict, const char *ifname, unsigned int parent,
636 	unsigned int handle, unsigned int protocol, unsigned int priority,
637 	const char *f_kind)
638 {
639 	return modify_qdisc(file, lineno, strict, "traffic filter",
640 		RTM_DELTFILTER, 0, ifname, AF_UNSPEC, parent, handle,
641 		TC_H_MAKE(priority << 16, htons(protocol)), f_kind, NULL);
642 }
643