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