xref: /linux/tools/net/ynl/tests/tc.c (revision 91a4855d6c03e770e42f17c798a36a3c46e63de2)
1e0aa0c61SJakub Kicinski // SPDX-License-Identifier: GPL-2.0
2*6cf8fb47SJakub Kicinski #define _GNU_SOURCE
3*6cf8fb47SJakub Kicinski #include <sched.h>
4e0aa0c61SJakub Kicinski #include <stdio.h>
5e0aa0c61SJakub Kicinski #include <string.h>
6*6cf8fb47SJakub Kicinski #include <stdlib.h>
7*6cf8fb47SJakub Kicinski #include <arpa/inet.h>
8*6cf8fb47SJakub Kicinski #include <linux/pkt_sched.h>
9*6cf8fb47SJakub Kicinski #include <linux/tc_act/tc_vlan.h>
10*6cf8fb47SJakub Kicinski #include <linux/tc_act/tc_gact.h>
11*6cf8fb47SJakub Kicinski #include <linux/if_ether.h>
12*6cf8fb47SJakub Kicinski #include <net/if.h>
13e0aa0c61SJakub Kicinski 
14e0aa0c61SJakub Kicinski #include <ynl.h>
15e0aa0c61SJakub Kicinski 
16*6cf8fb47SJakub Kicinski #include <kselftest_harness.h>
17e0aa0c61SJakub Kicinski 
18e0aa0c61SJakub Kicinski #include "tc-user.h"
19e0aa0c61SJakub Kicinski 
20*6cf8fb47SJakub Kicinski #define TC_HANDLE (0xFFFF << 16)
21*6cf8fb47SJakub Kicinski 
22*6cf8fb47SJakub Kicinski static bool tc_qdisc_print(struct __test_metadata *_metadata,
23*6cf8fb47SJakub Kicinski 			   struct tc_getqdisc_rsp *q)
24e0aa0c61SJakub Kicinski {
25*6cf8fb47SJakub Kicinski 	bool was_fq_codel = false;
26e0aa0c61SJakub Kicinski 	char ifname[IF_NAMESIZE];
27e0aa0c61SJakub Kicinski 	const char *name;
28e0aa0c61SJakub Kicinski 
29e0aa0c61SJakub Kicinski 	name = if_indextoname(q->_hdr.tcm_ifindex, ifname);
30*6cf8fb47SJakub Kicinski 	EXPECT_TRUE((bool)name);
31*6cf8fb47SJakub Kicinski 	ksft_print_msg("%16s: ", name ?: "no-name");
32e0aa0c61SJakub Kicinski 
33e0aa0c61SJakub Kicinski 	if (q->_len.kind) {
34e0aa0c61SJakub Kicinski 		printf("%s  ", q->kind);
35e0aa0c61SJakub Kicinski 
36e0aa0c61SJakub Kicinski 		if (q->options._present.fq_codel) {
37e0aa0c61SJakub Kicinski 			struct tc_fq_codel_attrs *fq_codel;
38e0aa0c61SJakub Kicinski 			struct tc_fq_codel_xstats *stats;
39e0aa0c61SJakub Kicinski 
40e0aa0c61SJakub Kicinski 			fq_codel = &q->options.fq_codel;
41e0aa0c61SJakub Kicinski 			stats = q->stats2.app.fq_codel;
42e0aa0c61SJakub Kicinski 
43*6cf8fb47SJakub Kicinski 			EXPECT_EQ(true,
44*6cf8fb47SJakub Kicinski 				  fq_codel->_present.limit &&
45*6cf8fb47SJakub Kicinski 				  fq_codel->_present.target &&
46*6cf8fb47SJakub Kicinski 				  q->stats2.app._len.fq_codel);
47*6cf8fb47SJakub Kicinski 
48e0aa0c61SJakub Kicinski 			if (fq_codel->_present.limit)
49e0aa0c61SJakub Kicinski 				printf("limit: %dp ", fq_codel->limit);
50e0aa0c61SJakub Kicinski 			if (fq_codel->_present.target)
51e0aa0c61SJakub Kicinski 				printf("target: %dms ",
52e0aa0c61SJakub Kicinski 				       (fq_codel->target + 500) / 1000);
53e0aa0c61SJakub Kicinski 			if (q->stats2.app._len.fq_codel)
54e0aa0c61SJakub Kicinski 				printf("new_flow_cnt: %d ",
55e0aa0c61SJakub Kicinski 				       stats->qdisc_stats.new_flow_count);
56*6cf8fb47SJakub Kicinski 			was_fq_codel = true;
57e0aa0c61SJakub Kicinski 		}
58e0aa0c61SJakub Kicinski 	}
59*6cf8fb47SJakub Kicinski 	printf("\n");
60*6cf8fb47SJakub Kicinski 
61*6cf8fb47SJakub Kicinski 	return was_fq_codel;
62*6cf8fb47SJakub Kicinski }
63e0aa0c61SJakub Kicinski 
64*6cf8fb47SJakub Kicinski static const char *vlan_act_name(struct tc_vlan *p)
65*6cf8fb47SJakub Kicinski {
66*6cf8fb47SJakub Kicinski 	switch (p->v_action) {
67*6cf8fb47SJakub Kicinski 	case TCA_VLAN_ACT_POP:
68*6cf8fb47SJakub Kicinski 		return "pop";
69*6cf8fb47SJakub Kicinski 	case TCA_VLAN_ACT_PUSH:
70*6cf8fb47SJakub Kicinski 		return "push";
71*6cf8fb47SJakub Kicinski 	case TCA_VLAN_ACT_MODIFY:
72*6cf8fb47SJakub Kicinski 		return "modify";
73*6cf8fb47SJakub Kicinski 	default:
74*6cf8fb47SJakub Kicinski 		break;
75*6cf8fb47SJakub Kicinski 	}
76*6cf8fb47SJakub Kicinski 
77*6cf8fb47SJakub Kicinski 	return "not supported";
78*6cf8fb47SJakub Kicinski }
79*6cf8fb47SJakub Kicinski 
80*6cf8fb47SJakub Kicinski static const char *gact_act_name(struct tc_gact *p)
81*6cf8fb47SJakub Kicinski {
82*6cf8fb47SJakub Kicinski 	switch (p->action) {
83*6cf8fb47SJakub Kicinski 	case TC_ACT_SHOT:
84*6cf8fb47SJakub Kicinski 		return "drop";
85*6cf8fb47SJakub Kicinski 	case TC_ACT_OK:
86*6cf8fb47SJakub Kicinski 		return "ok";
87*6cf8fb47SJakub Kicinski 	case TC_ACT_PIPE:
88*6cf8fb47SJakub Kicinski 		return "pipe";
89*6cf8fb47SJakub Kicinski 	default:
90*6cf8fb47SJakub Kicinski 		break;
91*6cf8fb47SJakub Kicinski 	}
92*6cf8fb47SJakub Kicinski 
93*6cf8fb47SJakub Kicinski 	return "not supported";
94*6cf8fb47SJakub Kicinski }
95*6cf8fb47SJakub Kicinski 
96*6cf8fb47SJakub Kicinski static void print_vlan(struct tc_act_vlan_attrs *vlan)
97*6cf8fb47SJakub Kicinski {
98*6cf8fb47SJakub Kicinski 	printf("%s ", vlan_act_name(vlan->parms));
99*6cf8fb47SJakub Kicinski 	if (vlan->_present.push_vlan_id)
100*6cf8fb47SJakub Kicinski 		printf("id %u ", vlan->push_vlan_id);
101*6cf8fb47SJakub Kicinski 	if (vlan->_present.push_vlan_protocol)
102*6cf8fb47SJakub Kicinski 		printf("protocol %#x ", ntohs(vlan->push_vlan_protocol));
103*6cf8fb47SJakub Kicinski 	if (vlan->_present.push_vlan_priority)
104*6cf8fb47SJakub Kicinski 		printf("priority %u ", vlan->push_vlan_priority);
105*6cf8fb47SJakub Kicinski }
106*6cf8fb47SJakub Kicinski 
107*6cf8fb47SJakub Kicinski static void print_gact(struct tc_act_gact_attrs *gact)
108*6cf8fb47SJakub Kicinski {
109*6cf8fb47SJakub Kicinski 	struct tc_gact *p = gact->parms;
110*6cf8fb47SJakub Kicinski 
111*6cf8fb47SJakub Kicinski 	printf("%s ", gact_act_name(p));
112*6cf8fb47SJakub Kicinski }
113*6cf8fb47SJakub Kicinski 
114*6cf8fb47SJakub Kicinski static void flower_print(struct tc_flower_attrs *flower, const char *kind)
115*6cf8fb47SJakub Kicinski {
116*6cf8fb47SJakub Kicinski 	struct tc_act_attrs *a;
117*6cf8fb47SJakub Kicinski 	unsigned int i;
118*6cf8fb47SJakub Kicinski 
119*6cf8fb47SJakub Kicinski 	ksft_print_msg("%s:\n", kind);
120*6cf8fb47SJakub Kicinski 
121*6cf8fb47SJakub Kicinski 	if (flower->_present.key_vlan_id)
122*6cf8fb47SJakub Kicinski 		ksft_print_msg("  vlan_id: %u\n", flower->key_vlan_id);
123*6cf8fb47SJakub Kicinski 	if (flower->_present.key_vlan_prio)
124*6cf8fb47SJakub Kicinski 		ksft_print_msg("  vlan_prio: %u\n", flower->key_vlan_prio);
125*6cf8fb47SJakub Kicinski 	if (flower->_present.key_num_of_vlans)
126*6cf8fb47SJakub Kicinski 		ksft_print_msg("  num_of_vlans: %u\n",
127*6cf8fb47SJakub Kicinski 			       flower->key_num_of_vlans);
128*6cf8fb47SJakub Kicinski 
129*6cf8fb47SJakub Kicinski 	for (i = 0; i < flower->_count.act; i++) {
130*6cf8fb47SJakub Kicinski 		a = &flower->act[i];
131*6cf8fb47SJakub Kicinski 		ksft_print_msg("action order: %i %s ", i + 1, a->kind);
132*6cf8fb47SJakub Kicinski 		if (a->options._present.vlan)
133*6cf8fb47SJakub Kicinski 			print_vlan(&a->options.vlan);
134*6cf8fb47SJakub Kicinski 		else if (a->options._present.gact)
135*6cf8fb47SJakub Kicinski 			print_gact(&a->options.gact);
136e0aa0c61SJakub Kicinski 		printf("\n");
137e0aa0c61SJakub Kicinski 	}
138*6cf8fb47SJakub Kicinski }
139e0aa0c61SJakub Kicinski 
140*6cf8fb47SJakub Kicinski static void tc_filter_print(struct __test_metadata *_metadata,
141*6cf8fb47SJakub Kicinski 			     struct tc_gettfilter_rsp *f)
142e0aa0c61SJakub Kicinski {
143*6cf8fb47SJakub Kicinski 	struct tc_options_msg *opt = &f->options;
144e0aa0c61SJakub Kicinski 
145*6cf8fb47SJakub Kicinski 	if (opt->_present.flower) {
146*6cf8fb47SJakub Kicinski 		EXPECT_TRUE((bool)f->_len.kind);
147*6cf8fb47SJakub Kicinski 		flower_print(&opt->flower, f->kind);
148*6cf8fb47SJakub Kicinski 	} else if (f->_len.kind) {
149*6cf8fb47SJakub Kicinski 		ksft_print_msg("%s pref %u proto: %#x\n", f->kind,
150*6cf8fb47SJakub Kicinski 			       (f->_hdr.tcm_info >> 16),
151*6cf8fb47SJakub Kicinski 			       ntohs(TC_H_MIN(f->_hdr.tcm_info)));
152*6cf8fb47SJakub Kicinski 	}
153e0aa0c61SJakub Kicinski }
154e0aa0c61SJakub Kicinski 
155*6cf8fb47SJakub Kicinski static int tc_clsact_add(struct ynl_sock *ys, int ifi)
156*6cf8fb47SJakub Kicinski {
157*6cf8fb47SJakub Kicinski 	struct tc_newqdisc_req *req;
158*6cf8fb47SJakub Kicinski 	int ret;
159*6cf8fb47SJakub Kicinski 
160*6cf8fb47SJakub Kicinski 	req = tc_newqdisc_req_alloc();
161e0aa0c61SJakub Kicinski 	if (!req)
162*6cf8fb47SJakub Kicinski 		return -1;
163*6cf8fb47SJakub Kicinski 	memset(req, 0, sizeof(*req));
164e0aa0c61SJakub Kicinski 
165*6cf8fb47SJakub Kicinski 	req->_hdr.tcm_ifindex = ifi;
166*6cf8fb47SJakub Kicinski 	req->_hdr.tcm_parent = TC_H_CLSACT;
167*6cf8fb47SJakub Kicinski 	req->_hdr.tcm_handle = TC_HANDLE;
168*6cf8fb47SJakub Kicinski 	tc_newqdisc_req_set_nlflags(req,
169*6cf8fb47SJakub Kicinski 				    NLM_F_REQUEST | NLM_F_EXCL | NLM_F_CREATE);
170*6cf8fb47SJakub Kicinski 	tc_newqdisc_req_set_kind(req, "clsact");
171e0aa0c61SJakub Kicinski 
172*6cf8fb47SJakub Kicinski 	ret = tc_newqdisc(ys, req);
173*6cf8fb47SJakub Kicinski 	tc_newqdisc_req_free(req);
174e0aa0c61SJakub Kicinski 
175*6cf8fb47SJakub Kicinski 	return ret;
176e0aa0c61SJakub Kicinski }
177*6cf8fb47SJakub Kicinski 
178*6cf8fb47SJakub Kicinski static int tc_clsact_del(struct ynl_sock *ys, int ifi)
179*6cf8fb47SJakub Kicinski {
180*6cf8fb47SJakub Kicinski 	struct tc_delqdisc_req *req;
181*6cf8fb47SJakub Kicinski 	int ret;
182*6cf8fb47SJakub Kicinski 
183*6cf8fb47SJakub Kicinski 	req = tc_delqdisc_req_alloc();
184*6cf8fb47SJakub Kicinski 	if (!req)
185*6cf8fb47SJakub Kicinski 		return -1;
186*6cf8fb47SJakub Kicinski 	memset(req, 0, sizeof(*req));
187*6cf8fb47SJakub Kicinski 
188*6cf8fb47SJakub Kicinski 	req->_hdr.tcm_ifindex = ifi;
189*6cf8fb47SJakub Kicinski 	req->_hdr.tcm_parent = TC_H_CLSACT;
190*6cf8fb47SJakub Kicinski 	req->_hdr.tcm_handle = TC_HANDLE;
191*6cf8fb47SJakub Kicinski 	tc_delqdisc_req_set_nlflags(req, NLM_F_REQUEST);
192*6cf8fb47SJakub Kicinski 
193*6cf8fb47SJakub Kicinski 	ret = tc_delqdisc(ys, req);
194*6cf8fb47SJakub Kicinski 	tc_delqdisc_req_free(req);
195*6cf8fb47SJakub Kicinski 
196*6cf8fb47SJakub Kicinski 	return ret;
197*6cf8fb47SJakub Kicinski }
198*6cf8fb47SJakub Kicinski 
199*6cf8fb47SJakub Kicinski static int tc_filter_add(struct ynl_sock *ys, int ifi)
200*6cf8fb47SJakub Kicinski {
201*6cf8fb47SJakub Kicinski 	struct tc_newtfilter_req *req;
202*6cf8fb47SJakub Kicinski 	struct tc_act_attrs *acts;
203*6cf8fb47SJakub Kicinski 	struct tc_vlan p = {
204*6cf8fb47SJakub Kicinski 		.action = TC_ACT_PIPE,
205*6cf8fb47SJakub Kicinski 		.v_action = TCA_VLAN_ACT_PUSH
206*6cf8fb47SJakub Kicinski 	};
207*6cf8fb47SJakub Kicinski 	int ret;
208*6cf8fb47SJakub Kicinski 
209*6cf8fb47SJakub Kicinski 	req = tc_newtfilter_req_alloc();
210*6cf8fb47SJakub Kicinski 	if (!req)
211*6cf8fb47SJakub Kicinski 		return -1;
212*6cf8fb47SJakub Kicinski 	memset(req, 0, sizeof(*req));
213*6cf8fb47SJakub Kicinski 
214*6cf8fb47SJakub Kicinski 	acts = tc_act_attrs_alloc(3);
215*6cf8fb47SJakub Kicinski 	if (!acts) {
216*6cf8fb47SJakub Kicinski 		tc_newtfilter_req_free(req);
217*6cf8fb47SJakub Kicinski 		return -1;
218*6cf8fb47SJakub Kicinski 	}
219*6cf8fb47SJakub Kicinski 	memset(acts, 0, sizeof(*acts) * 3);
220*6cf8fb47SJakub Kicinski 
221*6cf8fb47SJakub Kicinski 	req->_hdr.tcm_ifindex = ifi;
222*6cf8fb47SJakub Kicinski 	req->_hdr.tcm_parent = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS);
223*6cf8fb47SJakub Kicinski 	req->_hdr.tcm_info = TC_H_MAKE(1 << 16, htons(ETH_P_8021Q));
224*6cf8fb47SJakub Kicinski 	req->chain = 0;
225*6cf8fb47SJakub Kicinski 
226*6cf8fb47SJakub Kicinski 	tc_newtfilter_req_set_nlflags(req, NLM_F_REQUEST | NLM_F_EXCL | NLM_F_CREATE);
227*6cf8fb47SJakub Kicinski 	tc_newtfilter_req_set_kind(req, "flower");
228*6cf8fb47SJakub Kicinski 	tc_newtfilter_req_set_options_flower_key_vlan_id(req, 100);
229*6cf8fb47SJakub Kicinski 	tc_newtfilter_req_set_options_flower_key_vlan_prio(req, 5);
230*6cf8fb47SJakub Kicinski 	tc_newtfilter_req_set_options_flower_key_num_of_vlans(req, 3);
231*6cf8fb47SJakub Kicinski 
232*6cf8fb47SJakub Kicinski 	__tc_newtfilter_req_set_options_flower_act(req, acts, 3);
233*6cf8fb47SJakub Kicinski 
234*6cf8fb47SJakub Kicinski 	/* Skip action at index 0 because in TC, the action array
235*6cf8fb47SJakub Kicinski 	 * index starts at 1, with each index defining the action's
236*6cf8fb47SJakub Kicinski 	 * order. In contrast, in YNL indexed arrays start at index 0.
237*6cf8fb47SJakub Kicinski 	 */
238*6cf8fb47SJakub Kicinski 	tc_act_attrs_set_kind(&acts[1], "vlan");
239*6cf8fb47SJakub Kicinski 	tc_act_attrs_set_options_vlan_parms(&acts[1], &p, sizeof(p));
240*6cf8fb47SJakub Kicinski 	tc_act_attrs_set_options_vlan_push_vlan_id(&acts[1], 200);
241*6cf8fb47SJakub Kicinski 	tc_act_attrs_set_kind(&acts[2], "vlan");
242*6cf8fb47SJakub Kicinski 	tc_act_attrs_set_options_vlan_parms(&acts[2], &p, sizeof(p));
243*6cf8fb47SJakub Kicinski 	tc_act_attrs_set_options_vlan_push_vlan_id(&acts[2], 300);
244*6cf8fb47SJakub Kicinski 
245*6cf8fb47SJakub Kicinski 	tc_newtfilter_req_set_options_flower_flags(req, 0);
246*6cf8fb47SJakub Kicinski 	tc_newtfilter_req_set_options_flower_key_eth_type(req, htons(0x8100));
247*6cf8fb47SJakub Kicinski 
248*6cf8fb47SJakub Kicinski 	ret = tc_newtfilter(ys, req);
249*6cf8fb47SJakub Kicinski 	tc_newtfilter_req_free(req);
250*6cf8fb47SJakub Kicinski 
251*6cf8fb47SJakub Kicinski 	return ret;
252*6cf8fb47SJakub Kicinski }
253*6cf8fb47SJakub Kicinski 
254*6cf8fb47SJakub Kicinski static int tc_filter_del(struct ynl_sock *ys, int ifi)
255*6cf8fb47SJakub Kicinski {
256*6cf8fb47SJakub Kicinski 	struct tc_deltfilter_req *req;
257*6cf8fb47SJakub Kicinski 	int ret;
258*6cf8fb47SJakub Kicinski 
259*6cf8fb47SJakub Kicinski 	req = tc_deltfilter_req_alloc();
260*6cf8fb47SJakub Kicinski 	if (!req)
261*6cf8fb47SJakub Kicinski 		return -1;
262*6cf8fb47SJakub Kicinski 	memset(req, 0, sizeof(*req));
263*6cf8fb47SJakub Kicinski 
264*6cf8fb47SJakub Kicinski 	req->_hdr.tcm_ifindex = ifi;
265*6cf8fb47SJakub Kicinski 	req->_hdr.tcm_parent = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS);
266*6cf8fb47SJakub Kicinski 	req->_hdr.tcm_info = TC_H_MAKE(1 << 16, htons(ETH_P_8021Q));
267*6cf8fb47SJakub Kicinski 	tc_deltfilter_req_set_nlflags(req, NLM_F_REQUEST);
268*6cf8fb47SJakub Kicinski 
269*6cf8fb47SJakub Kicinski 	ret = tc_deltfilter(ys, req);
270*6cf8fb47SJakub Kicinski 	tc_deltfilter_req_free(req);
271*6cf8fb47SJakub Kicinski 
272*6cf8fb47SJakub Kicinski 	return ret;
273*6cf8fb47SJakub Kicinski }
274*6cf8fb47SJakub Kicinski 
275*6cf8fb47SJakub Kicinski FIXTURE(tc)
276*6cf8fb47SJakub Kicinski {
277*6cf8fb47SJakub Kicinski 	struct ynl_sock *ys;
278*6cf8fb47SJakub Kicinski 	int ifindex;
279*6cf8fb47SJakub Kicinski };
280*6cf8fb47SJakub Kicinski 
281*6cf8fb47SJakub Kicinski FIXTURE_SETUP(tc)
282*6cf8fb47SJakub Kicinski {
283*6cf8fb47SJakub Kicinski 	struct ynl_error yerr;
284*6cf8fb47SJakub Kicinski 	int ret;
285*6cf8fb47SJakub Kicinski 
286*6cf8fb47SJakub Kicinski 	ret = unshare(CLONE_NEWNET);
287*6cf8fb47SJakub Kicinski 	ASSERT_EQ(0, ret);
288*6cf8fb47SJakub Kicinski 
289*6cf8fb47SJakub Kicinski 	self->ifindex = 1; /* loopback */
290*6cf8fb47SJakub Kicinski 
291*6cf8fb47SJakub Kicinski 	self->ys = ynl_sock_create(&ynl_tc_family, &yerr);
292*6cf8fb47SJakub Kicinski 	ASSERT_NE(NULL, self->ys) {
293*6cf8fb47SJakub Kicinski 		TH_LOG("failed to create tc socket: %s", yerr.msg);
294*6cf8fb47SJakub Kicinski 	}
295*6cf8fb47SJakub Kicinski }
296*6cf8fb47SJakub Kicinski 
297*6cf8fb47SJakub Kicinski FIXTURE_TEARDOWN(tc)
298*6cf8fb47SJakub Kicinski {
299*6cf8fb47SJakub Kicinski 	ynl_sock_destroy(self->ys);
300*6cf8fb47SJakub Kicinski }
301*6cf8fb47SJakub Kicinski 
302*6cf8fb47SJakub Kicinski TEST_F(tc, qdisc)
303*6cf8fb47SJakub Kicinski {
304*6cf8fb47SJakub Kicinski 	struct tc_getqdisc_req_dump *dreq;
305*6cf8fb47SJakub Kicinski 	struct tc_newqdisc_req *add_req;
306*6cf8fb47SJakub Kicinski 	struct tc_delqdisc_req *del_req;
307*6cf8fb47SJakub Kicinski 	struct tc_getqdisc_list *rsp;
308*6cf8fb47SJakub Kicinski 	bool found = false;
309*6cf8fb47SJakub Kicinski 	int ret;
310*6cf8fb47SJakub Kicinski 
311*6cf8fb47SJakub Kicinski 	add_req = tc_newqdisc_req_alloc();
312*6cf8fb47SJakub Kicinski 	ASSERT_NE(NULL, add_req);
313*6cf8fb47SJakub Kicinski 	memset(add_req, 0, sizeof(*add_req));
314*6cf8fb47SJakub Kicinski 
315*6cf8fb47SJakub Kicinski 	add_req->_hdr.tcm_ifindex = self->ifindex;
316*6cf8fb47SJakub Kicinski 	add_req->_hdr.tcm_parent = TC_H_ROOT;
317*6cf8fb47SJakub Kicinski 	tc_newqdisc_req_set_nlflags(add_req,
318*6cf8fb47SJakub Kicinski 				    NLM_F_REQUEST | NLM_F_CREATE);
319*6cf8fb47SJakub Kicinski 	tc_newqdisc_req_set_kind(add_req, "fq_codel");
320*6cf8fb47SJakub Kicinski 
321*6cf8fb47SJakub Kicinski 	ret = tc_newqdisc(self->ys, add_req);
322*6cf8fb47SJakub Kicinski 	tc_newqdisc_req_free(add_req);
323*6cf8fb47SJakub Kicinski 	ASSERT_EQ(0, ret) {
324*6cf8fb47SJakub Kicinski 		TH_LOG("qdisc add failed: %s", self->ys->err.msg);
325*6cf8fb47SJakub Kicinski 	}
326*6cf8fb47SJakub Kicinski 
327*6cf8fb47SJakub Kicinski 	dreq = tc_getqdisc_req_dump_alloc();
328*6cf8fb47SJakub Kicinski 	ASSERT_NE(NULL, dreq);
329*6cf8fb47SJakub Kicinski 	rsp = tc_getqdisc_dump(self->ys, dreq);
330*6cf8fb47SJakub Kicinski 	tc_getqdisc_req_dump_free(dreq);
331*6cf8fb47SJakub Kicinski 	ASSERT_NE(NULL, rsp) {
332*6cf8fb47SJakub Kicinski 		TH_LOG("dump failed: %s", self->ys->err.msg);
333*6cf8fb47SJakub Kicinski 	}
334*6cf8fb47SJakub Kicinski 	ASSERT_FALSE(ynl_dump_empty(rsp));
335*6cf8fb47SJakub Kicinski 
336*6cf8fb47SJakub Kicinski 	ynl_dump_foreach(rsp, qdisc) {
337*6cf8fb47SJakub Kicinski 		found |= tc_qdisc_print(_metadata, qdisc);
338*6cf8fb47SJakub Kicinski 	}
339*6cf8fb47SJakub Kicinski 	tc_getqdisc_list_free(rsp);
340*6cf8fb47SJakub Kicinski 	EXPECT_TRUE(found);
341*6cf8fb47SJakub Kicinski 
342*6cf8fb47SJakub Kicinski 	del_req = tc_delqdisc_req_alloc();
343*6cf8fb47SJakub Kicinski 	ASSERT_NE(NULL, del_req);
344*6cf8fb47SJakub Kicinski 	memset(del_req, 0, sizeof(*del_req));
345*6cf8fb47SJakub Kicinski 
346*6cf8fb47SJakub Kicinski 	del_req->_hdr.tcm_ifindex = self->ifindex;
347*6cf8fb47SJakub Kicinski 	del_req->_hdr.tcm_parent = TC_H_ROOT;
348*6cf8fb47SJakub Kicinski 	tc_delqdisc_req_set_nlflags(del_req, NLM_F_REQUEST);
349*6cf8fb47SJakub Kicinski 
350*6cf8fb47SJakub Kicinski 	ret = tc_delqdisc(self->ys, del_req);
351*6cf8fb47SJakub Kicinski 	tc_delqdisc_req_free(del_req);
352*6cf8fb47SJakub Kicinski 	EXPECT_EQ(0, ret) {
353*6cf8fb47SJakub Kicinski 		TH_LOG("qdisc del failed: %s", self->ys->err.msg);
354*6cf8fb47SJakub Kicinski 	}
355*6cf8fb47SJakub Kicinski }
356*6cf8fb47SJakub Kicinski 
357*6cf8fb47SJakub Kicinski TEST_F(tc, flower)
358*6cf8fb47SJakub Kicinski {
359*6cf8fb47SJakub Kicinski 	struct tc_gettfilter_req_dump *dreq;
360*6cf8fb47SJakub Kicinski 	struct tc_gettfilter_list *rsp;
361*6cf8fb47SJakub Kicinski 	bool found = false;
362*6cf8fb47SJakub Kicinski 	int ret;
363*6cf8fb47SJakub Kicinski 
364*6cf8fb47SJakub Kicinski 	ret = tc_clsact_add(self->ys, self->ifindex);
365*6cf8fb47SJakub Kicinski 	if (ret)
366*6cf8fb47SJakub Kicinski 		SKIP(return, "clsact not supported: %s", self->ys->err.msg);
367*6cf8fb47SJakub Kicinski 
368*6cf8fb47SJakub Kicinski 	ret = tc_filter_add(self->ys, self->ifindex);
369*6cf8fb47SJakub Kicinski 	ASSERT_EQ(0, ret) {
370*6cf8fb47SJakub Kicinski 		TH_LOG("filter add failed: %s", self->ys->err.msg);
371*6cf8fb47SJakub Kicinski 	}
372*6cf8fb47SJakub Kicinski 
373*6cf8fb47SJakub Kicinski 	dreq = tc_gettfilter_req_dump_alloc();
374*6cf8fb47SJakub Kicinski 	ASSERT_NE(NULL, dreq);
375*6cf8fb47SJakub Kicinski 	memset(dreq, 0, sizeof(*dreq));
376*6cf8fb47SJakub Kicinski 	dreq->_hdr.tcm_ifindex = self->ifindex;
377*6cf8fb47SJakub Kicinski 	dreq->_hdr.tcm_parent = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS);
378*6cf8fb47SJakub Kicinski 	dreq->_present.chain = 1;
379*6cf8fb47SJakub Kicinski 	dreq->chain = 0;
380*6cf8fb47SJakub Kicinski 
381*6cf8fb47SJakub Kicinski 	rsp = tc_gettfilter_dump(self->ys, dreq);
382*6cf8fb47SJakub Kicinski 	tc_gettfilter_req_dump_free(dreq);
383*6cf8fb47SJakub Kicinski 	ASSERT_NE(NULL, rsp) {
384*6cf8fb47SJakub Kicinski 		TH_LOG("filter dump failed: %s", self->ys->err.msg);
385*6cf8fb47SJakub Kicinski 	}
386*6cf8fb47SJakub Kicinski 
387*6cf8fb47SJakub Kicinski 	ynl_dump_foreach(rsp, flt) {
388*6cf8fb47SJakub Kicinski 		tc_filter_print(_metadata, flt);
389*6cf8fb47SJakub Kicinski 		if (flt->options._present.flower) {
390*6cf8fb47SJakub Kicinski 			EXPECT_EQ(100, flt->options.flower.key_vlan_id);
391*6cf8fb47SJakub Kicinski 			EXPECT_EQ(5, flt->options.flower.key_vlan_prio);
392*6cf8fb47SJakub Kicinski 			found = true;
393*6cf8fb47SJakub Kicinski 		}
394*6cf8fb47SJakub Kicinski 	}
395*6cf8fb47SJakub Kicinski 	tc_gettfilter_list_free(rsp);
396*6cf8fb47SJakub Kicinski 	EXPECT_TRUE(found);
397*6cf8fb47SJakub Kicinski 
398*6cf8fb47SJakub Kicinski 	ret = tc_filter_del(self->ys, self->ifindex);
399*6cf8fb47SJakub Kicinski 	EXPECT_EQ(0, ret) {
400*6cf8fb47SJakub Kicinski 		TH_LOG("filter del failed: %s", self->ys->err.msg);
401*6cf8fb47SJakub Kicinski 	}
402*6cf8fb47SJakub Kicinski 
403*6cf8fb47SJakub Kicinski 	ret = tc_clsact_del(self->ys, self->ifindex);
404*6cf8fb47SJakub Kicinski 	EXPECT_EQ(0, ret) {
405*6cf8fb47SJakub Kicinski 		TH_LOG("clsact del failed: %s", self->ys->err.msg);
406*6cf8fb47SJakub Kicinski 	}
407*6cf8fb47SJakub Kicinski }
408*6cf8fb47SJakub Kicinski 
409*6cf8fb47SJakub Kicinski TEST_HARNESS_MAIN
410