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