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