xref: /aosp_15_r20/external/libnl/lib/cli/qdisc/hfsc.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * Copyright (c) 2014 Cong Wang <[email protected]>
4  */
5 
6 #include "nl-default.h"
7 
8 #include <linux/pkt_sched.h>
9 
10 #include <netlink/cli/utils.h>
11 #include <netlink/cli/tc.h>
12 #include <netlink/route/qdisc/hfsc.h>
13 
print_qdisc_usage(void)14 static void print_qdisc_usage(void)
15 {
16 	printf(
17 "Usage: nl-qdisc-add [...] hfsc [OPTIONS]...\n"
18 "\n"
19 "OPTIONS\n"
20 "     --help                Show this help text.\n"
21 "     --default=ID          Default class for unclassified traffic.\n"
22 "\n"
23 "EXAMPLE"
24 "    # Create hfsc root qdisc 1: and direct unclassified traffic to class 1:10\n"
25 "    nl-qdisc-add --dev=eth1 --parent=root --handle=1: hfsc --default=10\n");
26 }
27 
hfsc_parse_qdisc_argv(struct rtnl_tc * tc,int argc,char ** argv)28 static void hfsc_parse_qdisc_argv(struct rtnl_tc *tc, int argc, char **argv)
29 {
30 	struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) tc;
31 
32 	for (;;) {
33 		int c, optidx = 0;
34 		enum {
35 			ARG_DEFAULT = 257,
36 		};
37 		static struct option long_opts[] = {
38 			{ "help", 0, 0, 'h' },
39 			{ "default", 1, 0, ARG_DEFAULT },
40 			{ 0, 0, 0, 0 }
41 		};
42 
43 		c = getopt_long(argc, argv, "hv", long_opts, &optidx);
44 		if (c == -1)
45 			break;
46 
47 		switch (c) {
48 		case 'h':
49 			print_qdisc_usage();
50 			return;
51 
52 		case ARG_DEFAULT:
53 			rtnl_qdisc_hfsc_set_defcls(qdisc, nl_cli_parse_u32(optarg));
54 			break;
55 		}
56 	}
57 }
58 
print_class_usage(void)59 static void print_class_usage(void)
60 {
61 	printf(
62 "Usage: nl-class-add [...] hfsc [OPTIONS]...\n"
63 "\n"
64 "OPTIONS\n"
65 "     --help                Show this help text.\n"
66 "     --ls=SC               Link-sharing service curve\n"
67 "     --rt=SC               Real-time service curve\n"
68 "     --sc=SC               Specifiy both of the above\n"
69 "     --ul=SC               Upper limit\n"
70 "     where SC := [ [ m1 bits ] d usec ] m2 bits\n"
71 "\n"
72 "EXAMPLE"
73 "    # Attach class 1:1 to hfsc qdisc 1: and use rt and ls curve\n"
74 "    nl-class-add --dev=eth1 --parent=1: --classid=1:1 hfsc --sc=m1:250,d:8,m2:100\n");
75 }
76 
77 static int
hfsc_get_sc(char * optarg,struct tc_service_curve * sc)78 hfsc_get_sc(char *optarg, struct tc_service_curve *sc)
79 {
80 	unsigned int m1 = 0, d = 0, m2 = 0;
81 	char *tmp = strdup(optarg);
82 	char *p, *endptr;
83 	char *pp = tmp;
84 
85 	if (!tmp)
86 		return -ENOMEM;
87 
88 	p = strstr(pp, "m1:");
89 	if (p) {
90 		char *q;
91 		p += 3;
92 		if (*p == 0)
93 			goto err;
94 		q = strchr(p, ',');
95 		if (!q)
96 			goto err;
97 		*q = 0;
98 		m1 = strtoul(p, &endptr, 10);
99 		if (endptr == p)
100 			goto err;
101 		pp = q + 1;
102 	}
103 
104 	p = strstr(pp, "d:");
105 	if (p) {
106 		char *q;
107 		p += 2;
108 		if (*p == 0)
109 			goto err;
110 		q = strchr(p, ',');
111 		if (!q)
112 			goto err;
113 		*q = 0;
114 		d = strtoul(p, &endptr, 10);
115 		if (endptr == p)
116 			goto err;
117 		pp = q + 1;
118 	}
119 
120 	p = strstr(pp, "m2:");
121 	if (p) {
122 		p += 3;
123 		if (*p == 0)
124 			goto err;
125 		m2 = strtoul(p, &endptr, 10);
126 		if (endptr == p)
127 			goto err;
128 	} else
129 		goto err;
130 
131 	free(tmp);
132 	sc->m1 = m1;
133 	sc->d  = d;
134 	sc->m2 = m2;
135 	return 0;
136 
137 err:
138 	free(tmp);
139 	return -EINVAL;
140 }
141 
hfsc_parse_class_argv(struct rtnl_tc * tc,int argc,char ** argv)142 static void hfsc_parse_class_argv(struct rtnl_tc *tc, int argc, char **argv)
143 {
144 	struct rtnl_class *class = (struct rtnl_class *) tc;
145 	int arg_ok = 0, ret = -EINVAL;
146 
147 	for (;;) {
148 		int c, optidx = 0;
149 		enum {
150 			ARG_RT = 257,
151 			ARG_LS = 258,
152 			ARG_SC,
153 			ARG_UL,
154 		};
155 		static struct option long_opts[] = {
156 			{ "help", 0, 0, 'h' },
157 			{ "rt", 1, 0, ARG_RT },
158 			{ "ls", 1, 0, ARG_LS },
159 			{ "sc", 1, 0, ARG_SC },
160 			{ "ul", 1, 0, ARG_UL },
161 			{ 0, 0, 0, 0 }
162 		};
163 		struct tc_service_curve tsc;
164 
165 		c = getopt_long(argc, argv, "h", long_opts, &optidx);
166 		if (c == -1)
167 			break;
168 
169 		switch (c) {
170 		case 'h':
171 			print_class_usage();
172 			return;
173 
174 		case ARG_RT:
175 			ret = hfsc_get_sc(optarg, &tsc);
176 			if (ret < 0) {
177 				nl_cli_fatal(ret, "Unable to parse sc "
178 					"\"%s\": Invalid format.", optarg);
179 			}
180 
181 			rtnl_class_hfsc_set_rsc(class, &tsc);
182 			arg_ok++;
183 			break;
184 
185 		case ARG_LS:
186 			ret = hfsc_get_sc(optarg, &tsc);
187 			if (ret < 0) {
188 				nl_cli_fatal(ret, "Unable to parse sc "
189 					"\"%s\": Invalid format.", optarg);
190 			}
191 
192 			rtnl_class_hfsc_set_fsc(class, &tsc);
193 			arg_ok++;
194 			break;
195 
196 		case ARG_SC:
197 			ret = hfsc_get_sc(optarg, &tsc);
198 			if (ret < 0) {
199 				nl_cli_fatal(ret, "Unable to parse sc "
200 					"\"%s\": Invalid format.", optarg);
201 			}
202 
203 			rtnl_class_hfsc_set_rsc(class, &tsc);
204 			rtnl_class_hfsc_set_fsc(class, &tsc);
205 			arg_ok++;
206 			break;
207 
208 		case ARG_UL:
209 			ret = hfsc_get_sc(optarg, &tsc);
210 			if (ret < 0) {
211 				nl_cli_fatal(ret, "Unable to parse sc "
212 					"\"%s\": Invalid format.", optarg);
213 			}
214 
215 			rtnl_class_hfsc_set_usc(class, &tsc);
216 			arg_ok++;
217 			break;
218 		}
219 	}
220 
221 	if (!arg_ok)
222 		nl_cli_fatal(ret, "Invalid arguments");
223 }
224 
225 static struct nl_cli_tc_module hfsc_qdisc_module =
226 {
227 	.tm_name		= "hfsc",
228 	.tm_type		= RTNL_TC_TYPE_QDISC,
229 	.tm_parse_argv		= hfsc_parse_qdisc_argv,
230 };
231 
232 static struct nl_cli_tc_module hfsc_class_module =
233 {
234 	.tm_name		= "hfsc",
235 	.tm_type		= RTNL_TC_TYPE_CLASS,
236 	.tm_parse_argv		= hfsc_parse_class_argv,
237 };
238 
hfsc_init(void)239 static void _nl_init hfsc_init(void)
240 {
241 	nl_cli_tc_register(&hfsc_qdisc_module);
242 	nl_cli_tc_register(&hfsc_class_module);
243 }
244 
hfsc_exit(void)245 static void _nl_exit hfsc_exit(void)
246 {
247 	nl_cli_tc_unregister(&hfsc_class_module);
248 	nl_cli_tc_unregister(&hfsc_qdisc_module);
249 }
250