~ubuntu-branches/ubuntu/trusty/libnl3/trusty

« back to all changes in this revision

Viewing changes to lib/route/tc.c

  • Committer: Bazaar Package Importer
  • Author(s): Heiko Stuebner
  • Date: 2011-05-21 19:25:13 UTC
  • Revision ID: james.westby@ubuntu.com-20110521192513-1ieyu9w9kym4bt16
Tags: upstream-3.0
ImportĀ upstreamĀ versionĀ 3.0

Show diffs side-by-side

added added

removed removed

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