FILE
tc-filter-add.c
File preview with syntax highlighting.
linux-6.19.14/tools/net/ynl/samples/tc-filter-add.c
1// SPDX-License-Identifier: GPL-2.0 2#include <stdio.h> 3#include <string.h> 4#include <stdlib.h> 5#include <arpa/inet.h> 6#include <linux/pkt_sched.h> 7#include <linux/tc_act/tc_vlan.h> 8#include <linux/tc_act/tc_gact.h> 9#include <linux/if_ether.h> 10#include <net/if.h> 11 12#include <ynl.h> 13 14#include "tc-user.h" 15 16#define TC_HANDLE (0xFFFF << 16) 17 18const char *vlan_act_name(struct tc_vlan *p) 19{ 20 switch (p->v_action) { 21 case TCA_VLAN_ACT_POP: 22 return "pop"; 23 case TCA_VLAN_ACT_PUSH: 24 return "push"; 25 case TCA_VLAN_ACT_MODIFY: 26 return "modify"; 27 default: 28 break; 29 } 30 31 return "not supported"; 32} 33 34const char *gact_act_name(struct tc_gact *p) 35{ 36 switch (p->action) { 37 case TC_ACT_SHOT: 38 return "drop"; 39 case TC_ACT_OK: 40 return "ok"; 41 case TC_ACT_PIPE: 42 return "pipe"; 43 default: 44 break; 45 } 46 47 return "not supported"; 48} 49 50static void print_vlan(struct tc_act_vlan_attrs *vlan) 51{ 52 printf("%s ", vlan_act_name(vlan->parms)); 53 if (vlan->_present.push_vlan_id) 54 printf("id %u ", vlan->push_vlan_id); 55 if (vlan->_present.push_vlan_protocol) 56 printf("protocol %#x ", ntohs(vlan->push_vlan_protocol)); 57 if (vlan->_present.push_vlan_priority) 58 printf("priority %u ", vlan->push_vlan_priority); 59} 60 61static void print_gact(struct tc_act_gact_attrs *gact) 62{ 63 struct tc_gact *p = gact->parms; 64 65 printf("%s ", gact_act_name(p)); 66} 67 68static void flower_print(struct tc_flower_attrs *flower, const char *kind) 69{ 70 struct tc_act_attrs *a; 71 unsigned int i; 72 73 printf("%s:\n", kind); 74 75 if (flower->_present.key_vlan_id) 76 printf(" vlan_id: %u\n", flower->key_vlan_id); 77 if (flower->_present.key_vlan_prio) 78 printf(" vlan_prio: %u\n", flower->key_vlan_prio); 79 if (flower->_present.key_num_of_vlans) 80 printf(" num_of_vlans: %u\n", flower->key_num_of_vlans); 81 82 for (i = 0; i < flower->_count.act; i++) { 83 a = &flower->act[i]; 84 printf("action order: %i %s ", i + 1, a->kind); 85 if (a->options._present.vlan) 86 print_vlan(&a->options.vlan); 87 else if (a->options._present.gact) 88 print_gact(&a->options.gact); 89 printf("\n"); 90 } 91 printf("\n"); 92} 93 94static void tc_filter_print(struct tc_gettfilter_rsp *f) 95{ 96 struct tc_options_msg *opt = &f->options; 97 98 if (opt->_present.flower) 99 flower_print(&opt->flower, f->kind); 100 else if (f->_len.kind) 101 printf("%s pref %u proto: %#x\n", f->kind, 102 (f->_hdr.tcm_info >> 16), 103 ntohs(TC_H_MIN(f->_hdr.tcm_info))); 104} 105 106static int tc_filter_add(struct ynl_sock *ys, int ifi) 107{ 108 struct tc_newtfilter_req *req; 109 struct tc_act_attrs *acts; 110 struct tc_vlan p = { 111 .action = TC_ACT_PIPE, 112 .v_action = TCA_VLAN_ACT_PUSH 113 }; 114 __u16 flags = NLM_F_REQUEST | NLM_F_EXCL | NLM_F_CREATE; 115 int ret; 116 117 req = tc_newtfilter_req_alloc(); 118 if (!req) { 119 fprintf(stderr, "tc_newtfilter_req_alloc failed\n"); 120 return -1; 121 } 122 memset(req, 0, sizeof(*req)); 123 124 acts = tc_act_attrs_alloc(3); 125 if (!acts) { 126 fprintf(stderr, "tc_act_attrs_alloc\n"); 127 tc_newtfilter_req_free(req); 128 return -1; 129 } 130 memset(acts, 0, sizeof(*acts) * 3); 131 132 req->_hdr.tcm_ifindex = ifi; 133 req->_hdr.tcm_parent = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS); 134 req->_hdr.tcm_info = TC_H_MAKE(1 << 16, htons(ETH_P_8021Q)); 135 req->chain = 0; 136 137 tc_newtfilter_req_set_nlflags(req, flags); 138 tc_newtfilter_req_set_kind(req, "flower"); 139 tc_newtfilter_req_set_options_flower_key_vlan_id(req, 100); 140 tc_newtfilter_req_set_options_flower_key_vlan_prio(req, 5); 141 tc_newtfilter_req_set_options_flower_key_num_of_vlans(req, 3); 142 143 __tc_newtfilter_req_set_options_flower_act(req, acts, 3); 144 145 /* Skip action at index 0 because in TC, the action array 146 * index starts at 1, with each index defining the action's 147 * order. In contrast, in YNL indexed arrays start at index 0. 148 */ 149 tc_act_attrs_set_kind(&acts[1], "vlan"); 150 tc_act_attrs_set_options_vlan_parms(&acts[1], &p, sizeof(p)); 151 tc_act_attrs_set_options_vlan_push_vlan_id(&acts[1], 200); 152 tc_act_attrs_set_kind(&acts[2], "vlan"); 153 tc_act_attrs_set_options_vlan_parms(&acts[2], &p, sizeof(p)); 154 tc_act_attrs_set_options_vlan_push_vlan_id(&acts[2], 300); 155 156 tc_newtfilter_req_set_options_flower_flags(req, 0); 157 tc_newtfilter_req_set_options_flower_key_eth_type(req, htons(0x8100)); 158 159 ret = tc_newtfilter(ys, req); 160 if (ret) 161 fprintf(stderr, "tc_newtfilter: %s\n", ys->err.msg); 162 163 tc_newtfilter_req_free(req); 164 165 return ret; 166} 167 168static int tc_filter_show(struct ynl_sock *ys, int ifi) 169{ 170 struct tc_gettfilter_req_dump *req; 171 struct tc_gettfilter_list *rsp; 172 173 req = tc_gettfilter_req_dump_alloc(); 174 if (!req) { 175 fprintf(stderr, "tc_gettfilter_req_dump_alloc failed\n"); 176 return -1; 177 } 178 memset(req, 0, sizeof(*req)); 179 180 req->_hdr.tcm_ifindex = ifi; 181 req->_hdr.tcm_parent = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS); 182 req->_present.chain = 1; 183 req->chain = 0; 184 185 rsp = tc_gettfilter_dump(ys, req); 186 tc_gettfilter_req_dump_free(req); 187 if (!rsp) { 188 fprintf(stderr, "YNL: %s\n", ys->err.msg); 189 return -1; 190 } 191 192 if (ynl_dump_empty(rsp)) 193 fprintf(stderr, "Error: no filters reported\n"); 194 else 195 ynl_dump_foreach(rsp, flt) tc_filter_print(flt); 196 197 tc_gettfilter_list_free(rsp); 198 199 return 0; 200} 201 202static int tc_filter_del(struct ynl_sock *ys, int ifi) 203{ 204 struct tc_deltfilter_req *req; 205 __u16 flags = NLM_F_REQUEST; 206 int ret; 207 208 req = tc_deltfilter_req_alloc(); 209 if (!req) { 210 fprintf(stderr, "tc_deltfilter_req_alloc failed\n"); 211 return -1; 212 } 213 memset(req, 0, sizeof(*req)); 214 215 req->_hdr.tcm_ifindex = ifi; 216 req->_hdr.tcm_parent = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS); 217 req->_hdr.tcm_info = TC_H_MAKE(1 << 16, htons(ETH_P_8021Q)); 218 tc_deltfilter_req_set_nlflags(req, flags); 219 220 ret = tc_deltfilter(ys, req); 221 if (ret) 222 fprintf(stderr, "tc_deltfilter failed: %s\n", ys->err.msg); 223 224 tc_deltfilter_req_free(req); 225 226 return ret; 227} 228 229static int tc_clsact_add(struct ynl_sock *ys, int ifi) 230{ 231 struct tc_newqdisc_req *req; 232 __u16 flags = NLM_F_REQUEST | NLM_F_EXCL | NLM_F_CREATE; 233 int ret; 234 235 req = tc_newqdisc_req_alloc(); 236 if (!req) { 237 fprintf(stderr, "tc_newqdisc_req_alloc failed\n"); 238 return -1; 239 } 240 memset(req, 0, sizeof(*req)); 241 242 req->_hdr.tcm_ifindex = ifi; 243 req->_hdr.tcm_parent = TC_H_CLSACT; 244 req->_hdr.tcm_handle = TC_HANDLE; 245 tc_newqdisc_req_set_nlflags(req, flags); 246 tc_newqdisc_req_set_kind(req, "clsact"); 247 248 ret = tc_newqdisc(ys, req); 249 if (ret) 250 fprintf(stderr, "tc_newqdisc failed: %s\n", ys->err.msg); 251 252 tc_newqdisc_req_free(req); 253 254 return ret; 255} 256 257static int tc_clsact_del(struct ynl_sock *ys, int ifi) 258{ 259 struct tc_delqdisc_req *req; 260 __u16 flags = NLM_F_REQUEST; 261 int ret; 262 263 req = tc_delqdisc_req_alloc(); 264 if (!req) { 265 fprintf(stderr, "tc_delqdisc_req_alloc failed\n"); 266 return -1; 267 } 268 memset(req, 0, sizeof(*req)); 269 270 req->_hdr.tcm_ifindex = ifi; 271 req->_hdr.tcm_parent = TC_H_CLSACT; 272 req->_hdr.tcm_handle = TC_HANDLE; 273 tc_delqdisc_req_set_nlflags(req, flags); 274 275 ret = tc_delqdisc(ys, req); 276 if (ret) 277 fprintf(stderr, "tc_delqdisc failed: %s\n", ys->err.msg); 278 279 tc_delqdisc_req_free(req); 280 281 return ret; 282} 283 284static int tc_filter_config(struct ynl_sock *ys, int ifi) 285{ 286 int ret = 0; 287 288 if (tc_filter_add(ys, ifi)) 289 return -1; 290 291 ret = tc_filter_show(ys, ifi); 292 293 if (tc_filter_del(ys, ifi)) 294 return -1; 295 296 return ret; 297} 298 299int main(int argc, char **argv) 300{ 301 struct ynl_error yerr; 302 struct ynl_sock *ys; 303 int ifi, ret = 0; 304 305 if (argc < 2) { 306 fprintf(stderr, "Usage: %s <interface_name>\n", argv[0]); 307 return 1; 308 } 309 ifi = if_nametoindex(argv[1]); 310 if (!ifi) { 311 perror("if_nametoindex"); 312 return 1; 313 } 314 315 ys = ynl_sock_create(&ynl_tc_family, &yerr); 316 if (!ys) { 317 fprintf(stderr, "YNL: %s\n", yerr.msg); 318 return 1; 319 } 320 321 if (tc_clsact_add(ys, ifi)) { 322 ret = 2; 323 goto err_destroy; 324 } 325 326 if (tc_filter_config(ys, ifi)) 327 ret = 3; 328 329 if (tc_clsact_del(ys, ifi)) 330 ret = 4; 331 332err_destroy: 333 ynl_sock_destroy(ys); 334 return ret; 335}
~/
Read-only file preview.