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