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