1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3 * Copyright (c) 2003-2011 Thomas Graf <[email protected]>
4 */
5
6 /**
7 * @ingroup rtnl
8 * @defgroup tc Traffic Control
9 * @{
10 */
11
12 #include "nl-default.h"
13
14 #include <linux/if_arp.h>
15 #include <linux/gen_stats.h>
16
17 #include <linux/atm.h>
18
19 #include <netlink/netlink.h>
20 #include <netlink/utils.h>
21 #include <netlink/route/rtnl.h>
22 #include <netlink/route/link.h>
23 #include <netlink/route/tc.h>
24
25 #include "tc-api.h"
26
27 /** @cond SKIP */
28
29 static struct nl_list_head tc_ops_list[__RTNL_TC_TYPE_MAX];
30 static struct rtnl_tc_type_ops *tc_type_ops[__RTNL_TC_TYPE_MAX];
31
32 static struct nla_policy tc_policy[TCA_MAX+1] = {
33 [TCA_KIND] = { .type = NLA_STRING,
34 .maxlen = TCKINDSIZ },
35 [TCA_CHAIN] = { .type = NLA_U32 },
36 [TCA_STATS] = { .minlen = sizeof(struct tc_stats) },
37 [TCA_STATS2] = { .type = NLA_NESTED },
38 };
39
tca_parse(struct nlattr ** tb,int maxattr,struct rtnl_tc * g,const struct nla_policy * policy)40 int tca_parse(struct nlattr **tb, int maxattr, struct rtnl_tc *g,
41 const struct nla_policy *policy)
42 {
43
44 if (g->ce_mask & TCA_ATTR_OPTS)
45 return nla_parse(tb, maxattr,
46 (struct nlattr *) g->tc_opts->d_data,
47 g->tc_opts->d_size, policy);
48 else {
49 /* Ugly but tb[] must be in a defined state even if no
50 * attributes can be found. */
51 memset(tb, 0, sizeof(struct nlattr *) * (maxattr + 1));
52 return 0;
53 }
54 }
55
56 static struct nla_policy tc_stats2_policy[TCA_STATS_MAX+1] = {
57 [TCA_STATS_BASIC] = { .minlen = sizeof(struct gnet_stats_basic) },
58 [TCA_STATS_RATE_EST] = { .minlen = sizeof(struct gnet_stats_rate_est) },
59 [TCA_STATS_QUEUE] = { .minlen = sizeof(struct gnet_stats_queue) },
60 };
61
rtnl_tc_msg_parse(struct nlmsghdr * n,struct rtnl_tc * tc)62 int rtnl_tc_msg_parse(struct nlmsghdr *n, struct rtnl_tc *tc)
63 {
64 struct nl_cache *link_cache;
65 struct rtnl_tc_ops *ops;
66 struct nlattr *tb[TCA_MAX + 1];
67 char kind[TCKINDSIZ];
68 struct tcmsg *tm;
69 int err;
70
71 tc->ce_msgtype = n->nlmsg_type;
72
73 err = nlmsg_parse(n, sizeof(*tm), tb, TCA_MAX, tc_policy);
74 if (err < 0)
75 return err;
76
77 if (tb[TCA_KIND] == NULL)
78 return -NLE_MISSING_ATTR;
79
80 nla_strlcpy(kind, tb[TCA_KIND], sizeof(kind));
81 rtnl_tc_set_kind(tc, kind);
82
83 if (tb[TCA_CHAIN])
84 rtnl_tc_set_chain(tc, nla_get_u32(tb[TCA_CHAIN]));
85
86 tm = nlmsg_data(n);
87 tc->tc_family = tm->tcm_family;
88 tc->tc_ifindex = tm->tcm_ifindex;
89 tc->tc_handle = tm->tcm_handle;
90 tc->tc_parent = tm->tcm_parent;
91 tc->tc_info = tm->tcm_info;
92
93 tc->ce_mask |= (TCA_ATTR_FAMILY | TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE|
94 TCA_ATTR_PARENT | TCA_ATTR_INFO);
95
96 if (tb[TCA_OPTIONS]) {
97 tc->tc_opts = nl_data_alloc_attr(tb[TCA_OPTIONS]);
98 if (!tc->tc_opts)
99 return -NLE_NOMEM;
100 tc->ce_mask |= TCA_ATTR_OPTS;
101 }
102
103 if (tb[TCA_STATS2]) {
104 struct nlattr *tbs[TCA_STATS_MAX + 1];
105
106 err = nla_parse_nested(tbs, TCA_STATS_MAX, tb[TCA_STATS2],
107 tc_stats2_policy);
108 if (err < 0)
109 return err;
110
111 if (tbs[TCA_STATS_BASIC]) {
112 struct gnet_stats_basic bs;
113
114 memcpy(&bs, nla_data(tbs[TCA_STATS_BASIC]), sizeof(bs));
115 tc->tc_stats[RTNL_TC_BYTES] = bs.bytes;
116 tc->tc_stats[RTNL_TC_PACKETS] = bs.packets;
117 }
118
119 if (tbs[TCA_STATS_RATE_EST]) {
120 struct gnet_stats_rate_est *re;
121
122 re = nla_data(tbs[TCA_STATS_RATE_EST]);
123 tc->tc_stats[RTNL_TC_RATE_BPS] = re->bps;
124 tc->tc_stats[RTNL_TC_RATE_PPS] = re->pps;
125 }
126
127 if (tbs[TCA_STATS_QUEUE]) {
128 struct gnet_stats_queue *q;
129
130 q = nla_data(tbs[TCA_STATS_QUEUE]);
131 tc->tc_stats[RTNL_TC_QLEN] = q->qlen;
132 tc->tc_stats[RTNL_TC_BACKLOG] = q->backlog;
133 tc->tc_stats[RTNL_TC_DROPS] = q->drops;
134 tc->tc_stats[RTNL_TC_REQUEUES] = q->requeues;
135 tc->tc_stats[RTNL_TC_OVERLIMITS] = q->overlimits;
136 }
137
138 tc->ce_mask |= TCA_ATTR_STATS;
139
140 if (tbs[TCA_STATS_APP]) {
141 tc->tc_xstats = nl_data_alloc_attr(tbs[TCA_STATS_APP]);
142 if (tc->tc_xstats == NULL)
143 return -NLE_NOMEM;
144 tc->ce_mask |= TCA_ATTR_XSTATS;
145 } else
146 goto compat_xstats;
147 } else {
148 if (tb[TCA_STATS]) {
149 struct tc_stats st;
150
151 memcpy(&st, nla_data(tb[TCA_STATS]), sizeof(st));
152 tc->tc_stats[RTNL_TC_BYTES] = st.bytes;
153 tc->tc_stats[RTNL_TC_PACKETS] = st.packets;
154 tc->tc_stats[RTNL_TC_RATE_BPS] = st.bps;
155 tc->tc_stats[RTNL_TC_RATE_PPS] = st.pps;
156 tc->tc_stats[RTNL_TC_QLEN] = st.qlen;
157 tc->tc_stats[RTNL_TC_BACKLOG] = st.backlog;
158 tc->tc_stats[RTNL_TC_DROPS] = st.drops;
159 tc->tc_stats[RTNL_TC_OVERLIMITS]= st.overlimits;
160
161 tc->ce_mask |= TCA_ATTR_STATS;
162 }
163
164 compat_xstats:
165 if (tb[TCA_XSTATS]) {
166 tc->tc_xstats = nl_data_alloc_attr(tb[TCA_XSTATS]);
167 if (tc->tc_xstats == NULL)
168 return -NLE_NOMEM;
169 tc->ce_mask |= TCA_ATTR_XSTATS;
170 }
171 }
172
173 ops = rtnl_tc_get_ops(tc);
174 if (ops && ops->to_msg_parser) {
175 void *data = rtnl_tc_data(tc);
176
177 if (!data)
178 return -NLE_NOMEM;
179
180 err = ops->to_msg_parser(tc, data);
181 if (err < 0)
182 return err;
183 }
184
185 if ((link_cache = __nl_cache_mngt_require("route/link"))) {
186 struct rtnl_link *link;
187
188 if ((link = rtnl_link_get(link_cache, tc->tc_ifindex))) {
189 rtnl_tc_set_link(tc, link);
190
191 /* rtnl_tc_set_link incs refcnt */
192 rtnl_link_put(link);
193 }
194 }
195
196 return 0;
197 }
198
rtnl_tc_msg_build(struct rtnl_tc * tc,int type,int flags,struct nl_msg ** result)199 int rtnl_tc_msg_build(struct rtnl_tc *tc, int type, int flags,
200 struct nl_msg **result)
201 {
202 struct nl_msg *msg;
203 struct rtnl_tc_ops *ops;
204 struct tcmsg tchdr = {
205 .tcm_family = AF_UNSPEC,
206 .tcm_ifindex = tc->tc_ifindex,
207 .tcm_handle = tc->tc_handle,
208 .tcm_parent = tc->tc_parent,
209 };
210 int err;
211
212 msg = nlmsg_alloc_simple(type, flags);
213 if (!msg)
214 return -NLE_NOMEM;
215
216 if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0) {
217 err = -NLE_MSGSIZE;
218 goto out_err;
219 }
220
221 if (tc->ce_mask & TCA_ATTR_KIND)
222 NLA_PUT_STRING(msg, TCA_KIND, tc->tc_kind);
223
224 if (tc->ce_mask & TCA_ATTR_CHAIN)
225 NLA_PUT_U32(msg, TCA_CHAIN, tc->tc_chain);
226
227 ops = rtnl_tc_get_ops(tc);
228 if (ops && (ops->to_msg_fill || ops->to_msg_fill_raw)) {
229 struct nlattr *opts;
230 void *data = rtnl_tc_data(tc);
231
232 if (ops->to_msg_fill) {
233 if (!(opts = nla_nest_start(msg, TCA_OPTIONS))) {
234 err = -NLE_NOMEM;
235 goto out_err;
236 }
237
238 if ((err = ops->to_msg_fill(tc, data, msg)) < 0)
239 goto out_err;
240
241 if (strcmp("cgroup", tc->tc_kind))
242 nla_nest_end(msg, opts);
243 else
244 nla_nest_end_keep_empty(msg, opts);
245 } else if ((err = ops->to_msg_fill_raw(tc, data, msg)) < 0)
246 goto out_err;
247 }
248
249 *result = msg;
250 return 0;
251
252 nla_put_failure:
253 err = -NLE_NOMEM;
254 out_err:
255 nlmsg_free(msg);
256 return err;
257 }
258
259
260 /** @endcond */
261
262 /**
263 * @name Attributes
264 * @{
265 */
266
267 /**
268 * Set interface index of traffic control object
269 * @arg tc traffic control object
270 * @arg ifindex interface index.
271 *
272 * Sets the interface index of a traffic control object. The interface
273 * index defines the network device which this tc object is attached to.
274 * This function will overwrite any network device assigned with previous
275 * calls to rtnl_tc_set_ifindex() or rtnl_tc_set_link().
276 */
rtnl_tc_set_ifindex(struct rtnl_tc * tc,int ifindex)277 void rtnl_tc_set_ifindex(struct rtnl_tc *tc, int ifindex)
278 {
279 /* Obsolete possible old link reference */
280 rtnl_link_put(tc->tc_link);
281 tc->tc_link = NULL;
282 tc->ce_mask &= ~TCA_ATTR_LINK;
283
284 tc->tc_ifindex = ifindex;
285 tc->ce_mask |= TCA_ATTR_IFINDEX;
286 }
287
288 /**
289 * Return interface index of traffic control object
290 * @arg tc traffic control object
291 */
rtnl_tc_get_ifindex(struct rtnl_tc * tc)292 int rtnl_tc_get_ifindex(struct rtnl_tc *tc)
293 {
294 return tc->tc_ifindex;
295 }
296
297 /**
298 * Set link of traffic control object
299 * @arg tc traffic control object
300 * @arg link link object
301 *
302 * Sets the link of a traffic control object. This function serves
303 * the same purpose as rtnl_tc_set_ifindex() but due to the continued
304 * allowed access to the link object it gives it the possibility to
305 * retrieve sane default values for the the MTU and the linktype.
306 * Always prefer this function over rtnl_tc_set_ifindex() if you can
307 * spare to have an additional link object around.
308 */
rtnl_tc_set_link(struct rtnl_tc * tc,struct rtnl_link * link)309 void rtnl_tc_set_link(struct rtnl_tc *tc, struct rtnl_link *link)
310 {
311 rtnl_link_put(tc->tc_link);
312
313 if (!link)
314 return;
315 if (!link->l_index)
316 BUG();
317
318 nl_object_get(OBJ_CAST(link));
319 tc->tc_link = link;
320 tc->tc_ifindex = link->l_index;
321 tc->ce_mask |= TCA_ATTR_LINK | TCA_ATTR_IFINDEX;
322 }
323
324 /**
325 * Get link of traffic control object
326 * @arg tc traffic control object
327 *
328 * Returns the link of a traffic control object. The link is only
329 * returned if it has been set before via rtnl_tc_set_link() or
330 * if a link cache was available while parsing the tc object. This
331 * function may still return NULL even if an ifindex is assigned to
332 * the tc object. It will _not_ look up the link by itself.
333 *
334 * @note The returned link will have its reference counter incremented.
335 * It is in the responsibility of the caller to return the
336 * reference.
337 *
338 * @return link object or NULL if not set.
339 */
rtnl_tc_get_link(struct rtnl_tc * tc)340 struct rtnl_link *rtnl_tc_get_link(struct rtnl_tc *tc)
341 {
342 if (tc->tc_link) {
343 nl_object_get(OBJ_CAST(tc->tc_link));
344 return tc->tc_link;
345 }
346
347 return NULL;
348 }
349
350 /**
351 * Set the Maximum Transmission Unit (MTU) of traffic control object
352 * @arg tc traffic control object
353 * @arg mtu largest packet size expected
354 *
355 * Sets the MTU of a traffic control object. Not all traffic control
356 * objects will make use of this but it helps while calculating rate
357 * tables. This value is typically derived directly from the link
358 * the tc object is attached to if the link has been assigned via
359 * rtnl_tc_set_link(). It is usually not necessary to set the MTU
360 * manually, this function is provided to allow overwriting the derived
361 * value.
362 */
rtnl_tc_set_mtu(struct rtnl_tc * tc,uint32_t mtu)363 void rtnl_tc_set_mtu(struct rtnl_tc *tc, uint32_t mtu)
364 {
365 tc->tc_mtu = mtu;
366 tc->ce_mask |= TCA_ATTR_MTU;
367 }
368
369 /**
370 * Return the MTU of traffic control object
371 * @arg tc traffic control object
372 *
373 * Returns the MTU of a traffic control object which has been set via:
374 * -# User specified value set via rtnl_tc_set_mtu()
375 * -# Dervied from link set via rtnl_tc_set_link()
376 * -# Fall back to default: ethernet = 1500
377 */
rtnl_tc_get_mtu(struct rtnl_tc * tc)378 uint32_t rtnl_tc_get_mtu(struct rtnl_tc *tc)
379 {
380 if (tc->ce_mask & TCA_ATTR_MTU)
381 return tc->tc_mtu;
382 else if (tc->ce_mask & TCA_ATTR_LINK)
383 return tc->tc_link->l_mtu;
384 else
385 return 1500; /* default to ethernet */
386 }
387
388 /**
389 * Set the Minimum Packet Unit (MPU) of a traffic control object
390 * @arg tc traffic control object
391 * @arg mpu minimum packet size expected
392 *
393 * Sets the MPU of a traffic contorl object. It specifies the minimum
394 * packet size to ever hit this traffic control object. Not all traffic
395 * control objects will make use of this but it helps while calculating
396 * rate tables.
397 */
rtnl_tc_set_mpu(struct rtnl_tc * tc,uint32_t mpu)398 void rtnl_tc_set_mpu(struct rtnl_tc *tc, uint32_t mpu)
399 {
400 tc->tc_mpu = mpu;
401 tc->ce_mask |= TCA_ATTR_MPU;
402 }
403
404 /**
405 * Return the Minimum Packet Unit (MPU) of a traffic control object
406 * @arg tc traffic control object
407 *
408 * @return The MPU previously set via rtnl_tc_set_mpu() or 0.
409 */
rtnl_tc_get_mpu(struct rtnl_tc * tc)410 uint32_t rtnl_tc_get_mpu(struct rtnl_tc *tc)
411 {
412 return tc->tc_mpu;
413 }
414
415 /**
416 * Set per packet overhead of a traffic control object
417 * @arg tc traffic control object
418 * @arg overhead overhead per packet in bytes
419 *
420 * Sets the per packet overhead in bytes occuring on the link not seen
421 * by the kernel. This value can be used to correct size calculations
422 * if the packet size on the wire does not match the packet sizes seen
423 * in the network stack. Not all traffic control objects will make use
424 * this but it helps while calculating accurate packet sizes in the
425 * kernel.
426 */
rtnl_tc_set_overhead(struct rtnl_tc * tc,uint32_t overhead)427 void rtnl_tc_set_overhead(struct rtnl_tc *tc, uint32_t overhead)
428 {
429 tc->tc_overhead = overhead;
430 tc->ce_mask |= TCA_ATTR_OVERHEAD;
431 }
432
433 /**
434 * Return per packet overhead of a traffic control object
435 * @arg tc traffic control object
436 *
437 * @return The overhead previously set by rtnl_tc_set_overhead() or 0.
438 */
rtnl_tc_get_overhead(struct rtnl_tc * tc)439 uint32_t rtnl_tc_get_overhead(struct rtnl_tc *tc)
440 {
441 return tc->tc_overhead;
442 }
443
444 /**
445 * Set the linktype of a traffic control object
446 * @arg tc traffic control object
447 * @arg type type of link (e.g. ARPHRD_ATM, ARPHRD_ETHER)
448 *
449 * Overwrites the type of link this traffic control object is attached to.
450 * This value is typically derived from the link this tc object is attached
451 * if the link has been assigned via rtnl_tc_set_link(). It is usually not
452 * necessary to set the linktype manually. This function is provided to
453 * allow overwriting the linktype.
454 */
rtnl_tc_set_linktype(struct rtnl_tc * tc,uint32_t type)455 void rtnl_tc_set_linktype(struct rtnl_tc *tc, uint32_t type)
456 {
457 tc->tc_linktype = type;
458 tc->ce_mask |= TCA_ATTR_LINKTYPE;
459 }
460
461 /**
462 * Return the linktype of a traffic control object
463 * @arg tc traffic control object
464 *
465 * Returns the linktype of the link the traffic control object is attached to:
466 * -# User specified value via rtnl_tc_set_linktype()
467 * -# Value derived from link set via rtnl_tc_set_link()
468 * -# Default fall-back: ARPHRD_ETHER
469 */
rtnl_tc_get_linktype(struct rtnl_tc * tc)470 uint32_t rtnl_tc_get_linktype(struct rtnl_tc *tc)
471 {
472 if (tc->ce_mask & TCA_ATTR_LINKTYPE)
473 return tc->tc_linktype;
474 else if (tc->ce_mask & TCA_ATTR_LINK)
475 return tc->tc_link->l_arptype;
476 else
477 return ARPHRD_ETHER; /* default to ethernet */
478 }
479
480 /**
481 * Set identifier of traffic control object
482 * @arg tc traffic control object
483 * @arg id unique identifier
484 */
rtnl_tc_set_handle(struct rtnl_tc * tc,uint32_t id)485 void rtnl_tc_set_handle(struct rtnl_tc *tc, uint32_t id)
486 {
487 tc->tc_handle = id;
488 tc->ce_mask |= TCA_ATTR_HANDLE;
489 }
490
491 /**
492 * Return identifier of a traffic control object
493 * @arg tc traffic control object
494 */
rtnl_tc_get_handle(struct rtnl_tc * tc)495 uint32_t rtnl_tc_get_handle(struct rtnl_tc *tc)
496 {
497 return tc->tc_handle;
498 }
499
500 /**
501 * Set the parent identifier of a traffic control object
502 * @arg tc traffic control object
503 * @arg parent identifier of parent traffif control object
504 *
505 */
rtnl_tc_set_parent(struct rtnl_tc * tc,uint32_t parent)506 void rtnl_tc_set_parent(struct rtnl_tc *tc, uint32_t parent)
507 {
508 tc->tc_parent = parent;
509 tc->ce_mask |= TCA_ATTR_PARENT;
510 }
511
512 /**
513 * Return parent identifier of a traffic control object
514 * @arg tc traffic control object
515 */
rtnl_tc_get_parent(struct rtnl_tc * tc)516 uint32_t rtnl_tc_get_parent(struct rtnl_tc *tc)
517 {
518 return tc->tc_parent;
519 }
520
521 /**
522 * Define the type of traffic control object
523 * @arg tc traffic control object
524 * @arg kind name of the tc object type
525 *
526 * @return 0 on success or a negative error code
527 */
rtnl_tc_set_kind(struct rtnl_tc * tc,const char * kind)528 int rtnl_tc_set_kind(struct rtnl_tc *tc, const char *kind)
529 {
530 if (tc->ce_mask & TCA_ATTR_KIND)
531 return -NLE_EXIST;
532
533 if ( !kind
534 || strlen (kind) >= sizeof (tc->tc_kind))
535 return -NLE_INVAL;
536
537 _nl_strncpy_assert(tc->tc_kind, kind, sizeof(tc->tc_kind));
538
539 tc->ce_mask |= TCA_ATTR_KIND;
540
541 /* Force allocation of data */
542 rtnl_tc_data(tc);
543
544 return 0;
545 }
546
547 /**
548 * Return kind of traffic control object
549 * @arg tc traffic control object
550 *
551 * @return Kind of traffic control object or NULL if not set.
552 */
rtnl_tc_get_kind(struct rtnl_tc * tc)553 char *rtnl_tc_get_kind(struct rtnl_tc *tc)
554 {
555 if (tc->ce_mask & TCA_ATTR_KIND)
556 return tc->tc_kind;
557 else
558 return NULL;
559 }
560
561 /**
562 * Return value of a statistical counter of a traffic control object
563 * @arg tc traffic control object
564 * @arg id identifier of statistical counter
565 *
566 * @return Value of requested statistic counter or 0.
567 */
rtnl_tc_get_stat(struct rtnl_tc * tc,enum rtnl_tc_stat id)568 uint64_t rtnl_tc_get_stat(struct rtnl_tc *tc, enum rtnl_tc_stat id)
569 {
570 if ((unsigned int) id > RTNL_TC_STATS_MAX)
571 return 0;
572
573 return tc->tc_stats[id];
574 }
575
576 /**
577 * Set the chain index of a traffic control object
578 * @arg tc traffic control object
579 * @arg chain chain index of traffic control object
580 *
581 */
rtnl_tc_set_chain(struct rtnl_tc * tc,uint32_t chain)582 void rtnl_tc_set_chain(struct rtnl_tc *tc, uint32_t chain)
583 {
584 tc->tc_chain = chain;
585 tc->ce_mask |= TCA_ATTR_CHAIN;
586 }
587
588 /**
589 * Return chain index of traffic control object
590 * @arg tc traffic control object
591 * @arg out_value output argument.
592 *
593 * @return 0 of the output value was successfully returned, or a negative
594 * error code on failure.
595 */
rtnl_tc_get_chain(struct rtnl_tc * tc,uint32_t * out_value)596 int rtnl_tc_get_chain(struct rtnl_tc *tc, uint32_t *out_value)
597 {
598 if (!(tc->ce_mask & TCA_ATTR_CHAIN))
599 return -NLE_MISSING_ATTR;
600 *out_value = tc->tc_chain;
601 return 0;
602 }
603
604 /** @} */
605
606 /**
607 * @name Utilities
608 * @{
609 */
610
611 static const struct trans_tbl tc_stats[] = {
612 __ADD(RTNL_TC_PACKETS, packets),
613 __ADD(RTNL_TC_BYTES, bytes),
614 __ADD(RTNL_TC_RATE_BPS, rate_bps),
615 __ADD(RTNL_TC_RATE_PPS, rate_pps),
616 __ADD(RTNL_TC_QLEN, qlen),
617 __ADD(RTNL_TC_BACKLOG, backlog),
618 __ADD(RTNL_TC_DROPS, drops),
619 __ADD(RTNL_TC_REQUEUES, requeues),
620 __ADD(RTNL_TC_OVERLIMITS, overlimits),
621 };
622
rtnl_tc_stat2str(enum rtnl_tc_stat st,char * buf,size_t len)623 char *rtnl_tc_stat2str(enum rtnl_tc_stat st, char *buf, size_t len)
624 {
625 return __type2str(st, buf, len, tc_stats, ARRAY_SIZE(tc_stats));
626 }
627
rtnl_tc_str2stat(const char * name)628 int rtnl_tc_str2stat(const char *name)
629 {
630 return __str2type(name, tc_stats, ARRAY_SIZE(tc_stats));
631 }
632
633 /**
634 * Calculate time required to transmit buffer at a specific rate
635 * @arg bufsize Size of buffer to be transmited in bytes.
636 * @arg rate Transmit rate in bytes per second.
637 *
638 * Calculates the number of micro seconds required to transmit a
639 * specific buffer at a specific transmit rate.
640 *
641 * @f[
642 * txtime=\frac{bufsize}{rate}10^6
643 * @f]
644 *
645 * @return Required transmit time in micro seconds.
646 */
rtnl_tc_calc_txtime(int bufsize,int rate)647 int rtnl_tc_calc_txtime(int bufsize, int rate)
648 {
649 return ((double) bufsize / (double) rate) * 1000000.0;
650 }
651
652 /**
653 * Calculate buffer size able to transmit in a specific time and rate.
654 * @arg txtime Available transmit time in micro seconds.
655 * @arg rate Transmit rate in bytes per second.
656 *
657 * Calculates the size of the buffer that can be transmitted in a
658 * specific time period at a specific transmit rate.
659 *
660 * @f[
661 * bufsize=\frac{{txtime} \times {rate}}{10^6}
662 * @f]
663 *
664 * @return Size of buffer in bytes.
665 */
rtnl_tc_calc_bufsize(int txtime,int rate)666 int rtnl_tc_calc_bufsize(int txtime, int rate)
667 {
668 return ((double) txtime * (double) rate) / 1000000.0;
669 }
670
671 /**
672 * Calculate the binary logarithm for a specific cell size
673 * @arg cell_size Size of cell, must be a power of two.
674 * @return Binary logarithm of cell size or a negative error code.
675 */
rtnl_tc_calc_cell_log(int cell_size)676 int rtnl_tc_calc_cell_log(int cell_size)
677 {
678 int i;
679
680 for (i = 0; i < 32; i++)
681 if ((((uint32_t)1u) << i) == ((uint32_t)cell_size))
682 return i;
683
684 return -NLE_INVAL;
685 }
686
687
688 /** @} */
689
690 /**
691 * @name Rate Tables
692 * @{
693 */
694
695 /*
696 * COPYRIGHT NOTE:
697 * align_to_atm() and adjust_size() derived/coped from iproute2 source.
698 */
699
700 /*
701 * The align to ATM cells is used for determining the (ATM) SAR
702 * alignment overhead at the ATM layer. (SAR = Segmentation And
703 * Reassembly). This is for example needed when scheduling packet on
704 * an ADSL connection. Note that the extra ATM-AAL overhead is _not_
705 * included in this calculation. This overhead is added in the kernel
706 * before doing the rate table lookup, as this gives better precision
707 * (as the table will always be aligned for 48 bytes).
708 * --Hawk, d.7/11-2004. <[email protected]>
709 */
align_to_atm(unsigned int size)710 static unsigned int align_to_atm(unsigned int size)
711 {
712 int linksize, cells;
713 cells = size / ATM_CELL_PAYLOAD;
714 if ((size % ATM_CELL_PAYLOAD) > 0)
715 cells++;
716
717 linksize = cells * ATM_CELL_SIZE; /* Use full cell size to add ATM tax */
718 return linksize;
719 }
720
adjust_size(unsigned int size,unsigned int mpu,uint32_t linktype)721 static unsigned int adjust_size(unsigned int size, unsigned int mpu,
722 uint32_t linktype)
723 {
724 if (size < mpu)
725 size = mpu;
726
727 switch (linktype) {
728 case ARPHRD_ATM:
729 return align_to_atm(size);
730
731 case ARPHRD_ETHER:
732 default:
733 return size;
734 }
735 }
736
737 /**
738 * Compute a transmission time lookup table
739 * @arg tc traffic control object
740 * @arg spec Rate specification
741 * @arg dst Destination buffer of RTNL_TC_RTABLE_SIZE uint32_t[].
742 *
743 * Computes a table of RTNL_TC_RTABLE_SIZE entries specyfing the
744 * transmission times for various packet sizes, e.g. the transmission
745 * time for a packet of size \c pktsize could be looked up:
746 * @code
747 * txtime = table[pktsize >> log2(mtu)];
748 * @endcode
749 */
rtnl_tc_build_rate_table(struct rtnl_tc * tc,struct rtnl_ratespec * spec,uint32_t * dst)750 int rtnl_tc_build_rate_table(struct rtnl_tc *tc, struct rtnl_ratespec *spec,
751 uint32_t *dst)
752 {
753 uint32_t mtu = rtnl_tc_get_mtu(tc);
754 uint32_t linktype = rtnl_tc_get_linktype(tc);
755 uint8_t cell_log = spec->rs_cell_log;
756 unsigned int size, i;
757
758 spec->rs_mpu = rtnl_tc_get_mpu(tc);
759 spec->rs_overhead = rtnl_tc_get_overhead(tc);
760
761 if (mtu == 0)
762 mtu = 2047;
763
764 if (cell_log == UINT8_MAX) {
765 /*
766 * cell_log not specified, calculate it. It has to specify the
767 * minimum number of rshifts required to break the MTU to below
768 * RTNL_TC_RTABLE_SIZE.
769 */
770 cell_log = 0;
771 while ((mtu >> cell_log) >= RTNL_TC_RTABLE_SIZE)
772 cell_log++;
773 }
774
775 for (i = 0; i < RTNL_TC_RTABLE_SIZE; i++) {
776 size = adjust_size((i + 1) << cell_log, spec->rs_mpu, linktype);
777 dst[i] = nl_us2ticks(rtnl_tc_calc_txtime64(size, spec->rs_rate64));
778 }
779
780 spec->rs_cell_align = -1;
781 spec->rs_cell_log = cell_log;
782
783 return 0;
784 }
785
786 /** @} */
787
788 /**
789 * @name TC implementation of cache functions
790 */
791
rtnl_tc_free_data(struct nl_object * obj)792 void rtnl_tc_free_data(struct nl_object *obj)
793 {
794 struct rtnl_tc *tc = TC_CAST(obj);
795 struct rtnl_tc_ops *ops;
796
797 rtnl_link_put(tc->tc_link);
798 nl_data_free(tc->tc_opts);
799 nl_data_free(tc->tc_xstats);
800
801 if (tc->tc_subdata) {
802 ops = rtnl_tc_get_ops(tc);
803 if (ops && ops->to_free_data)
804 ops->to_free_data(tc, nl_data_get(tc->tc_subdata));
805
806 nl_data_free(tc->tc_subdata);
807 }
808 }
809
rtnl_tc_clone(struct nl_object * dstobj,struct nl_object * srcobj)810 int rtnl_tc_clone(struct nl_object *dstobj, struct nl_object *srcobj)
811 {
812 struct rtnl_tc *dst = TC_CAST(dstobj);
813 struct rtnl_tc *src = TC_CAST(srcobj);
814 struct rtnl_tc_ops *ops;
815
816 dst->tc_opts = NULL;
817 dst->tc_xstats = NULL;
818 dst->tc_subdata = NULL;
819 dst->tc_link = NULL;
820 dst->tc_ops = NULL;
821
822 if (src->tc_link) {
823 nl_object_get(OBJ_CAST(src->tc_link));
824 dst->tc_link = src->tc_link;
825 }
826
827 dst->ce_mask &= ~(TCA_ATTR_OPTS |
828 TCA_ATTR_XSTATS);
829
830 if (src->tc_opts) {
831 dst->tc_opts = nl_data_clone(src->tc_opts);
832 if (!dst->tc_opts)
833 return -NLE_NOMEM;
834 dst->ce_mask |= TCA_ATTR_OPTS;
835 }
836
837 if (src->tc_xstats) {
838 dst->tc_xstats = nl_data_clone(src->tc_xstats);
839 if (!dst->tc_xstats)
840 return -NLE_NOMEM;
841 dst->ce_mask |= TCA_ATTR_XSTATS;
842 }
843
844 if (src->tc_subdata) {
845 if (!(dst->tc_subdata = nl_data_clone(src->tc_subdata))) {
846 return -NLE_NOMEM;
847 }
848
849 /* Warning: if the data contains pointer, then at this point, dst->tc_subdata
850 * will alias those pointers.
851 *
852 * ops->to_clone() MUST fix that.
853 *
854 * If the type is actually "struct rtnl_act", then to_clone() must also
855 * fix dangling "a_next" pointer. */
856
857 ops = rtnl_tc_get_ops(src);
858 if (ops && ops->to_clone) {
859 return ops->to_clone(rtnl_tc_data(dst), rtnl_tc_data(src));
860 }
861 }
862
863 return 0;
864 }
865
tc_dump(struct rtnl_tc * tc,enum nl_dump_type type,struct nl_dump_params * p)866 static int tc_dump(struct rtnl_tc *tc, enum nl_dump_type type,
867 struct nl_dump_params *p)
868 {
869 struct rtnl_tc_type_ops *type_ops;
870 struct rtnl_tc_ops *ops;
871 void *data = rtnl_tc_data(tc);
872
873 type_ops = tc_type_ops[tc->tc_type];
874 if (type_ops && type_ops->tt_dump[type])
875 type_ops->tt_dump[type](tc, p);
876
877 ops = rtnl_tc_get_ops(tc);
878 if (ops && ops->to_dump[type]) {
879 ops->to_dump[type](tc, data, p);
880 return 1;
881 }
882
883 return 0;
884 }
885
rtnl_tc_dump_line(struct nl_object * obj,struct nl_dump_params * p)886 void rtnl_tc_dump_line(struct nl_object *obj, struct nl_dump_params *p)
887 {
888 struct rtnl_tc_type_ops *type_ops;
889 struct rtnl_tc *tc = TC_CAST(obj);
890 struct nl_cache *link_cache;
891 char buf[32];
892
893 nl_new_line(p);
894
895 type_ops = tc_type_ops[tc->tc_type];
896 if (type_ops && type_ops->tt_dump_prefix)
897 nl_dump(p, "%s ", type_ops->tt_dump_prefix);
898
899 nl_dump(p, "%s ", tc->tc_kind);
900
901 if ((link_cache = nl_cache_mngt_require_safe("route/link"))) {
902 nl_dump(p, "dev %s ",
903 rtnl_link_i2name(link_cache, tc->tc_ifindex,
904 buf, sizeof(buf)));
905 } else
906 nl_dump(p, "dev %u ", tc->tc_ifindex);
907
908 nl_dump(p, "id %s ",
909 rtnl_tc_handle2str(tc->tc_handle, buf, sizeof(buf)));
910
911 nl_dump(p, "parent %s",
912 rtnl_tc_handle2str(tc->tc_parent, buf, sizeof(buf)));
913
914 tc_dump(tc, NL_DUMP_LINE, p);
915 nl_dump(p, "\n");
916
917 if (link_cache)
918 nl_cache_put(link_cache);
919 }
920
rtnl_tc_dump_details(struct nl_object * obj,struct nl_dump_params * p)921 void rtnl_tc_dump_details(struct nl_object *obj, struct nl_dump_params *p)
922 {
923 struct rtnl_tc *tc = TC_CAST(obj);
924
925 rtnl_tc_dump_line(OBJ_CAST(tc), p);
926
927 nl_dump_line(p, " ");
928
929 if (tc->ce_mask & TCA_ATTR_MTU)
930 nl_dump(p, " mtu %u", tc->tc_mtu);
931
932 if (tc->ce_mask & TCA_ATTR_MPU)
933 nl_dump(p, " mpu %u", tc->tc_mpu);
934
935 if (tc->ce_mask & TCA_ATTR_OVERHEAD)
936 nl_dump(p, " overhead %u", tc->tc_overhead);
937
938 if (!tc_dump(tc, NL_DUMP_DETAILS, p))
939 nl_dump(p, "no options");
940 nl_dump(p, "\n");
941 }
942
rtnl_tc_dump_stats(struct nl_object * obj,struct nl_dump_params * p)943 void rtnl_tc_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
944 {
945 struct rtnl_tc *tc = TC_CAST(obj);
946 char *unit;
947 float res;
948
949 rtnl_tc_dump_details(OBJ_CAST(tc), p);
950
951 nl_dump_line(p,
952 " stats: %-14s %-10s %-10s %-10s %-10s %-10s\n",
953 "bytes", "packets", "drops", "overlimits", "qlen", "backlog");
954
955 res = nl_cancel_down_bytes(tc->tc_stats[RTNL_TC_BYTES], &unit);
956
957 nl_dump_line(
958 p,
959 " %10.2f %3s %10llu %-10llu %-10llu %-10llu %-10llu\n",
960 res, unit, (long long unsigned)tc->tc_stats[RTNL_TC_PACKETS],
961 (long long unsigned)tc->tc_stats[RTNL_TC_DROPS],
962 (long long unsigned)tc->tc_stats[RTNL_TC_OVERLIMITS],
963 (long long unsigned)tc->tc_stats[RTNL_TC_QLEN],
964 (long long unsigned)tc->tc_stats[RTNL_TC_BACKLOG]);
965
966 res = nl_cancel_down_bytes(tc->tc_stats[RTNL_TC_RATE_BPS], &unit);
967
968 nl_dump_line(p, " %10.2f %3s/s %10llu/s\n", res, unit,
969 (long long unsigned)tc->tc_stats[RTNL_TC_RATE_PPS]);
970 }
971
rtnl_tc_compare(struct nl_object * aobj,struct nl_object * bobj,uint64_t attrs,int flags)972 uint64_t rtnl_tc_compare(struct nl_object *aobj, struct nl_object *bobj,
973 uint64_t attrs, int flags)
974 {
975 struct rtnl_tc *a = TC_CAST(aobj);
976 struct rtnl_tc *b = TC_CAST(bobj);
977 uint64_t diff = 0;
978
979 #define _DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ATTR, a, b, EXPR)
980 diff |= _DIFF(TCA_ATTR_HANDLE, a->tc_handle != b->tc_handle);
981 diff |= _DIFF(TCA_ATTR_PARENT, a->tc_parent != b->tc_parent);
982 diff |= _DIFF(TCA_ATTR_IFINDEX, a->tc_ifindex != b->tc_ifindex);
983 diff |= _DIFF(TCA_ATTR_KIND, strcmp(a->tc_kind, b->tc_kind));
984 #undef _DIFF
985
986 return diff;
987 }
988
989 /** @} */
990
991 /**
992 * @name Modules API
993 */
994
rtnl_tc_lookup_ops(enum rtnl_tc_type type,const char * kind)995 struct rtnl_tc_ops *rtnl_tc_lookup_ops(enum rtnl_tc_type type, const char *kind)
996 {
997 struct rtnl_tc_ops *ops;
998
999 nl_list_for_each_entry(ops, &tc_ops_list[type], to_list)
1000 if (!strcmp(kind, ops->to_kind))
1001 return ops;
1002
1003 return NULL;
1004 }
1005
rtnl_tc_get_ops(struct rtnl_tc * tc)1006 struct rtnl_tc_ops *rtnl_tc_get_ops(struct rtnl_tc *tc)
1007 {
1008 if (!tc->tc_ops)
1009 tc->tc_ops = rtnl_tc_lookup_ops(tc->tc_type, tc->tc_kind);
1010
1011 return tc->tc_ops;
1012 }
1013
1014 /**
1015 * Register a traffic control module
1016 * @arg ops traffic control module operations
1017 */
rtnl_tc_register(struct rtnl_tc_ops * ops)1018 int rtnl_tc_register(struct rtnl_tc_ops *ops)
1019 {
1020 static int init = 0;
1021
1022 /*
1023 * Initialiation hack, make sure list is initialized when
1024 * the first tc module registers. Putting this in a
1025 * separate _nl_init would required correct ordering of init
1026 * functions
1027 */
1028 if (!init) {
1029 int i;
1030
1031 for (i = 0; i < __RTNL_TC_TYPE_MAX; i++)
1032 nl_init_list_head(&tc_ops_list[i]);
1033
1034 init = 1;
1035 }
1036
1037 if (!ops->to_kind || ops->to_type > RTNL_TC_TYPE_MAX)
1038 BUG();
1039
1040 if (rtnl_tc_lookup_ops(ops->to_type, ops->to_kind))
1041 return -NLE_EXIST;
1042
1043 nl_list_add_tail(&ops->to_list, &tc_ops_list[ops->to_type]);
1044
1045 return 0;
1046 }
1047
1048 /**
1049 * Unregister a traffic control module
1050 * @arg ops traffic control module operations
1051 */
rtnl_tc_unregister(struct rtnl_tc_ops * ops)1052 void rtnl_tc_unregister(struct rtnl_tc_ops *ops)
1053 {
1054 nl_list_del(&ops->to_list);
1055 }
1056
1057 /**
1058 * Returns the private data of the traffic control object.
1059 * Contrary to rtnl_tc_data(), this returns NULL if the data is
1060 * not yet allocated
1061 * @arg tc traffic control object
1062 *
1063 * @return pointer to the private data or NULL if not allocated.
1064 */
rtnl_tc_data_peek(struct rtnl_tc * tc)1065 void *rtnl_tc_data_peek(struct rtnl_tc *tc)
1066 {
1067 return tc->tc_subdata ? nl_data_get(tc->tc_subdata) : NULL;
1068 }
1069
1070 /**
1071 * Return pointer to private data of traffic control object
1072 * @arg tc traffic control object
1073 *
1074 * Allocates the private traffic control object data section
1075 * as necessary and returns it.
1076 *
1077 * @return Pointer to private tc data or NULL if allocation failed.
1078 */
rtnl_tc_data(struct rtnl_tc * tc)1079 void *rtnl_tc_data(struct rtnl_tc *tc)
1080 {
1081 if (!tc->tc_subdata) {
1082 size_t size;
1083
1084 if (!tc->tc_ops) {
1085 if (!rtnl_tc_get_ops(tc))
1086 return NULL;
1087 }
1088
1089 if (!(size = tc->tc_ops->to_size))
1090 BUG();
1091
1092 if (!(tc->tc_subdata = nl_data_alloc(NULL, size)))
1093 return NULL;
1094 }
1095
1096 return nl_data_get(tc->tc_subdata);
1097 }
1098
1099 /**
1100 * Check traffic control object type and return private data section
1101 * @arg tc traffic control object
1102 * @arg ops expected traffic control object operations
1103 * @arg err the place where saves the error code if fails
1104 *
1105 * Checks whether the traffic control object matches the type
1106 * specified with the traffic control object operations. If the
1107 * type matches, the private tc object data is returned. If type
1108 * mismatches, APPBUG() will print a application bug warning.
1109 *
1110 * @see rtnl_tc_data()
1111 *
1112 * @return Pointer to private tc data or NULL if type mismatches.
1113 */
rtnl_tc_data_check(struct rtnl_tc * tc,struct rtnl_tc_ops * ops,int * err)1114 void *rtnl_tc_data_check(struct rtnl_tc *tc, struct rtnl_tc_ops *ops, int *err)
1115 {
1116 void *ret;
1117
1118 if (tc->tc_ops != ops) {
1119 char buf[64];
1120
1121 snprintf(buf, sizeof(buf),
1122 "tc object %p used in %s context but is of type %s",
1123 tc, ops->to_kind, tc->tc_ops->to_kind);
1124 APPBUG(buf);
1125
1126 if (err)
1127 *err = -NLE_OPNOTSUPP;
1128 return NULL;
1129 }
1130
1131 ret = rtnl_tc_data(tc);
1132 if (ret == NULL) {
1133 if (err)
1134 *err = -NLE_NOMEM;
1135 }
1136
1137 return ret;
1138 }
1139
1140 struct nl_af_group tc_groups[] = {
1141 { AF_UNSPEC, RTNLGRP_TC },
1142 { END_OF_GROUP_LIST },
1143 };
1144
1145
rtnl_tc_type_register(struct rtnl_tc_type_ops * ops)1146 void rtnl_tc_type_register(struct rtnl_tc_type_ops *ops)
1147 {
1148 if (ops->tt_type > RTNL_TC_TYPE_MAX)
1149 BUG();
1150
1151 tc_type_ops[ops->tt_type] = ops;
1152 }
1153
rtnl_tc_type_unregister(struct rtnl_tc_type_ops * ops)1154 void rtnl_tc_type_unregister(struct rtnl_tc_type_ops *ops)
1155 {
1156 if (ops->tt_type > RTNL_TC_TYPE_MAX)
1157 BUG();
1158
1159 tc_type_ops[ops->tt_type] = NULL;
1160 }
1161
1162 /** @} */
1163
1164 /** @} */
1165