File Index
Files and directories
Sign in
FILE

tc-filter-add.c

File preview with syntax highlighting.

linux-6.19.14/tools/net/ynl/samples/tc-filter-add.c 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.