00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <netlink-local.h>
00022 #include <netlink-tc.h>
00023 #include <netlink/netlink.h>
00024 #include <netlink/cache.h>
00025 #include <netlink/utils.h>
00026 #include <netlink/route/tc-api.h>
00027 #include <netlink/route/qdisc.h>
00028 #include <netlink/route/class.h>
00029 #include <netlink/route/link.h>
00030 #include <netlink/route/qdisc/htb.h>
00031
00032
00033 #define SCH_HTB_HAS_RATE2QUANTUM 0x01
00034 #define SCH_HTB_HAS_DEFCLS 0x02
00035
00036 #define SCH_HTB_HAS_PRIO 0x001
00037 #define SCH_HTB_HAS_RATE 0x002
00038 #define SCH_HTB_HAS_CEIL 0x004
00039 #define SCH_HTB_HAS_RBUFFER 0x008
00040 #define SCH_HTB_HAS_CBUFFER 0x010
00041 #define SCH_HTB_HAS_QUANTUM 0x020
00042 #define SCH_HTB_HAS_LEVEL 0x040
00043
00044
00045 static struct nla_policy htb_policy[TCA_HTB_MAX+1] = {
00046 [TCA_HTB_INIT] = { .minlen = sizeof(struct tc_htb_glob) },
00047 [TCA_HTB_PARMS] = { .minlen = sizeof(struct tc_htb_opt) },
00048 };
00049
00050 static int htb_qdisc_msg_parser(struct rtnl_tc *tc, void *data)
00051 {
00052 struct nlattr *tb[TCA_HTB_MAX + 1];
00053 struct rtnl_htb_qdisc *htb = data;
00054 int err;
00055
00056 if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0)
00057 return err;
00058
00059 if (tb[TCA_HTB_INIT]) {
00060 struct tc_htb_glob opts;
00061
00062 nla_memcpy(&opts, tb[TCA_HTB_INIT], sizeof(opts));
00063 htb->qh_rate2quantum = opts.rate2quantum;
00064 htb->qh_defcls = opts.defcls;
00065 htb->qh_direct_pkts = opts.direct_pkts;
00066
00067 htb->qh_mask = (SCH_HTB_HAS_RATE2QUANTUM | SCH_HTB_HAS_DEFCLS);
00068 }
00069
00070 return 0;
00071 }
00072
00073 static int htb_class_msg_parser(struct rtnl_tc *tc, void *data)
00074 {
00075 struct nlattr *tb[TCA_HTB_MAX + 1];
00076 struct rtnl_htb_class *htb = data;
00077 int err;
00078
00079 if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0)
00080 return err;
00081
00082 if (tb[TCA_HTB_PARMS]) {
00083 struct tc_htb_opt opts;
00084
00085 nla_memcpy(&opts, tb[TCA_HTB_PARMS], sizeof(opts));
00086 htb->ch_prio = opts.prio;
00087 rtnl_copy_ratespec(&htb->ch_rate, &opts.rate);
00088 rtnl_copy_ratespec(&htb->ch_ceil, &opts.ceil);
00089 htb->ch_rbuffer = rtnl_tc_calc_bufsize(opts.buffer,
00090 opts.rate.rate);
00091 htb->ch_cbuffer = rtnl_tc_calc_bufsize(opts.cbuffer,
00092 opts.ceil.rate);
00093 htb->ch_quantum = opts.quantum;
00094 htb->ch_level = opts.level;
00095
00096 rtnl_tc_set_mpu(tc, htb->ch_rate.rs_mpu);
00097 rtnl_tc_set_overhead(tc, htb->ch_rate.rs_overhead);
00098
00099 htb->ch_mask = (SCH_HTB_HAS_PRIO | SCH_HTB_HAS_RATE |
00100 SCH_HTB_HAS_CEIL | SCH_HTB_HAS_RBUFFER |
00101 SCH_HTB_HAS_CBUFFER | SCH_HTB_HAS_QUANTUM |
00102 SCH_HTB_HAS_LEVEL);
00103 }
00104
00105 return 0;
00106 }
00107
00108 static void htb_qdisc_dump_line(struct rtnl_tc *tc, void *data,
00109 struct nl_dump_params *p)
00110 {
00111 struct rtnl_htb_qdisc *htb = data;
00112
00113 if (!htb)
00114 return;
00115
00116 if (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM)
00117 nl_dump(p, " r2q %u", htb->qh_rate2quantum);
00118
00119 if (htb->qh_mask & SCH_HTB_HAS_DEFCLS) {
00120 char buf[64];
00121 nl_dump(p, " default-class %s",
00122 rtnl_tc_handle2str(htb->qh_defcls, buf, sizeof(buf)));
00123 }
00124 }
00125
00126 static void htb_class_dump_line(struct rtnl_tc *tc, void *data,
00127 struct nl_dump_params *p)
00128 {
00129 struct rtnl_htb_class *htb = data;
00130
00131 if (!htb)
00132 return;
00133
00134 if (htb->ch_mask & SCH_HTB_HAS_RATE) {
00135 double r, rbit;
00136 char *ru, *rubit;
00137
00138 r = nl_cancel_down_bytes(htb->ch_rate.rs_rate, &ru);
00139 rbit = nl_cancel_down_bits(htb->ch_rate.rs_rate*8, &rubit);
00140
00141 nl_dump(p, " rate %.2f%s/s (%.0f%s) log %u",
00142 r, ru, rbit, rubit, 1<<htb->ch_rate.rs_cell_log);
00143 }
00144 }
00145
00146 static void htb_class_dump_details(struct rtnl_tc *tc, void *data,
00147 struct nl_dump_params *p)
00148 {
00149 struct rtnl_htb_class *htb = data;
00150
00151 if (!htb)
00152 return;
00153
00154
00155 if (htb->ch_mask & SCH_HTB_HAS_CEIL) {
00156 double r, rbit;
00157 char *ru, *rubit;
00158
00159 r = nl_cancel_down_bytes(htb->ch_ceil.rs_rate, &ru);
00160 rbit = nl_cancel_down_bits(htb->ch_ceil.rs_rate*8, &rubit);
00161
00162 nl_dump(p, " ceil %.2f%s/s (%.0f%s) log %u",
00163 r, ru, rbit, rubit, 1<<htb->ch_ceil.rs_cell_log);
00164 }
00165
00166 if (htb->ch_mask & SCH_HTB_HAS_PRIO)
00167 nl_dump(p, " prio %u", htb->ch_prio);
00168
00169 if (htb->ch_mask & SCH_HTB_HAS_RBUFFER) {
00170 double b;
00171 char *bu;
00172
00173 b = nl_cancel_down_bytes(htb->ch_rbuffer, &bu);
00174 nl_dump(p, " rbuffer %.2f%s", b, bu);
00175 }
00176
00177 if (htb->ch_mask & SCH_HTB_HAS_CBUFFER) {
00178 double b;
00179 char *bu;
00180
00181 b = nl_cancel_down_bytes(htb->ch_cbuffer, &bu);
00182 nl_dump(p, " cbuffer %.2f%s", b, bu);
00183 }
00184
00185 if (htb->ch_mask & SCH_HTB_HAS_QUANTUM)
00186 nl_dump(p, " quantum %u", htb->ch_quantum);
00187 }
00188
00189 static int htb_qdisc_msg_fill(struct rtnl_tc *tc, void *data,
00190 struct nl_msg *msg)
00191 {
00192 struct rtnl_htb_qdisc *htb = data;
00193 struct tc_htb_glob opts = {0};
00194
00195 opts.version = TC_HTB_PROTOVER;
00196 opts.rate2quantum = 10;
00197
00198 if (htb) {
00199 if (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM)
00200 opts.rate2quantum = htb->qh_rate2quantum;
00201
00202 if (htb->qh_mask & SCH_HTB_HAS_DEFCLS)
00203 opts.defcls = htb->qh_defcls;
00204 }
00205
00206 return nla_put(msg, TCA_HTB_INIT, sizeof(opts), &opts);
00207 }
00208
00209 static int htb_class_msg_fill(struct rtnl_tc *tc, void *data,
00210 struct nl_msg *msg)
00211 {
00212 struct rtnl_htb_class *htb = data;
00213 uint32_t mtu, rtable[RTNL_TC_RTABLE_SIZE], ctable[RTNL_TC_RTABLE_SIZE];
00214 struct tc_htb_opt opts;
00215 int buffer, cbuffer;
00216
00217 if (!htb || !(htb->ch_mask & SCH_HTB_HAS_RATE))
00218 BUG();
00219
00220 memset(&opts, 0, sizeof(opts));
00221
00222
00223 if (htb->ch_mask & SCH_HTB_HAS_PRIO)
00224 opts.prio = htb->ch_prio;
00225
00226 mtu = rtnl_tc_get_mtu(tc);
00227
00228 rtnl_tc_build_rate_table(tc, &htb->ch_rate, rtable);
00229 rtnl_rcopy_ratespec(&opts.rate, &htb->ch_rate);
00230
00231 if (htb->ch_mask & SCH_HTB_HAS_CEIL) {
00232 rtnl_tc_build_rate_table(tc, &htb->ch_ceil, ctable);
00233 rtnl_rcopy_ratespec(&opts.ceil, &htb->ch_ceil);
00234 } else {
00235
00236
00237
00238
00239 memcpy(&opts.ceil, &opts.rate, sizeof(struct tc_ratespec));
00240 }
00241
00242 if (htb->ch_mask & SCH_HTB_HAS_RBUFFER)
00243 buffer = htb->ch_rbuffer;
00244 else
00245 buffer = opts.rate.rate / nl_get_user_hz() + mtu;
00246
00247 opts.buffer = rtnl_tc_calc_txtime(buffer, opts.rate.rate);
00248
00249 if (htb->ch_mask & SCH_HTB_HAS_CBUFFER)
00250 cbuffer = htb->ch_cbuffer;
00251 else
00252 cbuffer = opts.ceil.rate / nl_get_user_hz() + mtu;
00253
00254 opts.cbuffer = rtnl_tc_calc_txtime(cbuffer, opts.ceil.rate);
00255
00256 if (htb->ch_mask & SCH_HTB_HAS_QUANTUM)
00257 opts.quantum = htb->ch_quantum;
00258
00259 NLA_PUT(msg, TCA_HTB_PARMS, sizeof(opts), &opts);
00260 NLA_PUT(msg, TCA_HTB_RTAB, sizeof(rtable), &rtable);
00261 NLA_PUT(msg, TCA_HTB_CTAB, sizeof(ctable), &ctable);
00262
00263 return 0;
00264
00265 nla_put_failure:
00266 return -NLE_MSGSIZE;
00267 }
00268
00269 static struct rtnl_tc_ops htb_qdisc_ops;
00270 static struct rtnl_tc_ops htb_class_ops;
00271
00272 static struct rtnl_htb_qdisc *htb_qdisc_data(struct rtnl_qdisc *qdisc)
00273 {
00274 return rtnl_tc_data_check(TC_CAST(qdisc), &htb_qdisc_ops);
00275 }
00276
00277 static struct rtnl_htb_class *htb_class_data(struct rtnl_class *class)
00278 {
00279 return rtnl_tc_data_check(TC_CAST(class), &htb_class_ops);
00280 }
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293 uint32_t rtnl_htb_get_rate2quantum(struct rtnl_qdisc *qdisc)
00294 {
00295 struct rtnl_htb_qdisc *htb;
00296
00297 if ((htb = htb_qdisc_data(qdisc)) &&
00298 htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM)
00299 return htb->qh_rate2quantum;
00300
00301 return 0;
00302 }
00303
00304 int rtnl_htb_set_rate2quantum(struct rtnl_qdisc *qdisc, uint32_t rate2quantum)
00305 {
00306 struct rtnl_htb_qdisc *htb;
00307
00308 if (!(htb = htb_qdisc_data(qdisc)))
00309 return -NLE_OPNOTSUPP;
00310
00311 htb->qh_rate2quantum = rate2quantum;
00312 htb->qh_mask |= SCH_HTB_HAS_RATE2QUANTUM;
00313
00314 return 0;
00315 }
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326 uint32_t rtnl_htb_get_defcls(struct rtnl_qdisc *qdisc)
00327 {
00328 struct rtnl_htb_qdisc *htb;
00329
00330 if ((htb = htb_qdisc_data(qdisc)) &&
00331 htb->qh_mask & SCH_HTB_HAS_DEFCLS)
00332 return htb->qh_defcls;
00333
00334 return TC_H_UNSPEC;
00335 }
00336
00337
00338
00339
00340
00341
00342 int rtnl_htb_set_defcls(struct rtnl_qdisc *qdisc, uint32_t defcls)
00343 {
00344 struct rtnl_htb_qdisc *htb;
00345
00346 if (!(htb = htb_qdisc_data(qdisc)))
00347 return -NLE_OPNOTSUPP;
00348
00349 htb->qh_defcls = defcls;
00350 htb->qh_mask |= SCH_HTB_HAS_DEFCLS;
00351
00352 return 0;
00353 }
00354
00355 uint32_t rtnl_htb_get_prio(struct rtnl_class *class)
00356 {
00357 struct rtnl_htb_class *htb;
00358
00359 if ((htb = htb_class_data(class)) && htb->ch_mask & SCH_HTB_HAS_PRIO)
00360 return htb->ch_prio;
00361
00362 return 0;
00363 }
00364
00365 int rtnl_htb_set_prio(struct rtnl_class *class, uint32_t prio)
00366 {
00367 struct rtnl_htb_class *htb;
00368
00369 if (!(htb = htb_class_data(class)))
00370 return -NLE_OPNOTSUPP;
00371
00372 htb->ch_prio = prio;
00373 htb->ch_mask |= SCH_HTB_HAS_PRIO;
00374
00375 return 0;
00376 }
00377
00378
00379
00380
00381
00382
00383
00384 uint32_t rtnl_htb_get_rate(struct rtnl_class *class)
00385 {
00386 struct rtnl_htb_class *htb;
00387
00388 if ((htb = htb_class_data(class)) && htb->ch_mask & SCH_HTB_HAS_RATE)
00389 return htb->ch_rate.rs_rate;
00390
00391 return 0;
00392 }
00393
00394
00395
00396
00397
00398
00399
00400
00401 int rtnl_htb_set_rate(struct rtnl_class *class, uint32_t rate)
00402 {
00403 struct rtnl_htb_class *htb;
00404
00405 if (!(htb = htb_class_data(class)))
00406 return -NLE_OPNOTSUPP;
00407
00408 htb->ch_rate.rs_cell_log = UINT8_MAX;
00409 htb->ch_rate.rs_rate = rate;
00410 htb->ch_mask |= SCH_HTB_HAS_RATE;
00411
00412 return 0;
00413 }
00414
00415
00416
00417
00418
00419
00420
00421 uint32_t rtnl_htb_get_ceil(struct rtnl_class *class)
00422 {
00423 struct rtnl_htb_class *htb;
00424
00425 if ((htb = htb_class_data(class)) && htb->ch_mask & SCH_HTB_HAS_CEIL)
00426 return htb->ch_ceil.rs_rate;
00427
00428 return 0;
00429 }
00430
00431
00432
00433
00434
00435
00436
00437
00438 int rtnl_htb_set_ceil(struct rtnl_class *class, uint32_t ceil)
00439 {
00440 struct rtnl_htb_class *htb;
00441
00442 if (!(htb = htb_class_data(class)))
00443 return -NLE_OPNOTSUPP;
00444
00445 htb->ch_ceil.rs_cell_log = UINT8_MAX;
00446 htb->ch_ceil.rs_rate = ceil;
00447 htb->ch_mask |= SCH_HTB_HAS_CEIL;
00448
00449 return 0;
00450 }
00451
00452
00453
00454
00455
00456
00457
00458 uint32_t rtnl_htb_get_rbuffer(struct rtnl_class *class)
00459 {
00460 struct rtnl_htb_class *htb;
00461
00462 if ((htb = htb_class_data(class)) &&
00463 htb->ch_mask & SCH_HTB_HAS_RBUFFER)
00464 return htb->ch_rbuffer;
00465
00466 return 0;
00467 }
00468
00469
00470
00471
00472
00473
00474 int rtnl_htb_set_rbuffer(struct rtnl_class *class, uint32_t rbuffer)
00475 {
00476 struct rtnl_htb_class *htb;
00477
00478 if (!(htb = htb_class_data(class)))
00479 return -NLE_OPNOTSUPP;
00480
00481 htb->ch_rbuffer = rbuffer;
00482 htb->ch_mask |= SCH_HTB_HAS_RBUFFER;
00483
00484 return 0;
00485 }
00486
00487
00488
00489
00490
00491
00492
00493 uint32_t rtnl_htb_get_cbuffer(struct rtnl_class *class)
00494 {
00495 struct rtnl_htb_class *htb;
00496
00497 if ((htb = htb_class_data(class)) &&
00498 htb->ch_mask & SCH_HTB_HAS_CBUFFER)
00499 return htb->ch_cbuffer;
00500
00501 return 0;
00502 }
00503
00504
00505
00506
00507
00508
00509 int rtnl_htb_set_cbuffer(struct rtnl_class *class, uint32_t cbuffer)
00510 {
00511 struct rtnl_htb_class *htb;
00512
00513 if (!(htb = htb_class_data(class)))
00514 return -NLE_OPNOTSUPP;
00515
00516 htb->ch_cbuffer = cbuffer;
00517 htb->ch_mask |= SCH_HTB_HAS_CBUFFER;
00518
00519 return 0;
00520 }
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530 uint32_t rtnl_htb_get_quantum(struct rtnl_class *class)
00531 {
00532 struct rtnl_htb_class *htb;
00533
00534 if ((htb = htb_class_data(class)) &&
00535 htb->ch_mask & SCH_HTB_HAS_QUANTUM)
00536 return htb->ch_quantum;
00537
00538 return 0;
00539 }
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550 int rtnl_htb_set_quantum(struct rtnl_class *class, uint32_t quantum)
00551 {
00552 struct rtnl_htb_class *htb;
00553
00554 if (!(htb = htb_class_data(class)))
00555 return -NLE_OPNOTSUPP;
00556
00557 htb->ch_quantum = quantum;
00558 htb->ch_mask |= SCH_HTB_HAS_QUANTUM;
00559
00560 return 0;
00561 }
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573 int rtnl_htb_get_level(struct rtnl_class *class)
00574 {
00575 struct rtnl_htb_class *htb;
00576
00577 if ((htb = htb_class_data(class)) && htb->ch_mask & SCH_HTB_HAS_LEVEL)
00578 return htb->ch_level;
00579
00580 return -NLE_OPNOTSUPP;
00581 }
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595 int rtnl_htb_set_level(struct rtnl_class *class, int level)
00596 {
00597 struct rtnl_htb_class *htb;
00598
00599 if (!(htb = htb_class_data(class)))
00600 return -NLE_OPNOTSUPP;
00601
00602 htb->ch_level = level;
00603 htb->ch_mask |= SCH_HTB_HAS_LEVEL;
00604
00605 return 0;
00606 }
00607
00608
00609
00610 static struct rtnl_tc_ops htb_qdisc_ops = {
00611 .to_kind = "htb",
00612 .to_type = RTNL_TC_TYPE_QDISC,
00613 .to_size = sizeof(struct rtnl_htb_qdisc),
00614 .to_msg_parser = htb_qdisc_msg_parser,
00615 .to_dump[NL_DUMP_LINE] = htb_qdisc_dump_line,
00616 .to_msg_fill = htb_qdisc_msg_fill,
00617 };
00618
00619 static struct rtnl_tc_ops htb_class_ops = {
00620 .to_kind = "htb",
00621 .to_type = RTNL_TC_TYPE_CLASS,
00622 .to_size = sizeof(struct rtnl_htb_class),
00623 .to_msg_parser = htb_class_msg_parser,
00624 .to_dump = {
00625 [NL_DUMP_LINE] = htb_class_dump_line,
00626 [NL_DUMP_DETAILS] = htb_class_dump_details,
00627 },
00628 .to_msg_fill = htb_class_msg_fill,
00629 };
00630
00631 static void __init htb_init(void)
00632 {
00633 rtnl_tc_register(&htb_qdisc_ops);
00634 rtnl_tc_register(&htb_class_ops);
00635 }
00636
00637 static void __exit htb_exit(void)
00638 {
00639 rtnl_tc_unregister(&htb_qdisc_ops);
00640 rtnl_tc_unregister(&htb_class_ops);
00641 }
00642
00643