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
00043
00044 static struct nla_policy htb_policy[TCA_HTB_MAX+1] = {
00045 [TCA_HTB_INIT] = { .minlen = sizeof(struct tc_htb_glob) },
00046 [TCA_HTB_PARMS] = { .minlen = sizeof(struct tc_htb_opt) },
00047 };
00048
00049 static int htb_qdisc_msg_parser(struct rtnl_tc *tc, void *data)
00050 {
00051 struct nlattr *tb[TCA_HTB_MAX + 1];
00052 struct rtnl_htb_qdisc *htb = data;
00053 int err;
00054
00055 if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0)
00056 return err;
00057
00058 if (tb[TCA_HTB_INIT]) {
00059 struct tc_htb_glob opts;
00060
00061 nla_memcpy(&opts, tb[TCA_HTB_INIT], sizeof(opts));
00062 htb->qh_rate2quantum = opts.rate2quantum;
00063 htb->qh_defcls = opts.defcls;
00064
00065 htb->qh_mask = (SCH_HTB_HAS_RATE2QUANTUM | SCH_HTB_HAS_DEFCLS);
00066 }
00067
00068 return 0;
00069 }
00070
00071 static int htb_class_msg_parser(struct rtnl_tc *tc, void *data)
00072 {
00073 struct nlattr *tb[TCA_HTB_MAX + 1];
00074 struct rtnl_htb_class *htb = data;
00075 int err;
00076
00077 if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0)
00078 return err;
00079
00080 if (tb[TCA_HTB_PARMS]) {
00081 struct tc_htb_opt opts;
00082
00083 nla_memcpy(&opts, tb[TCA_HTB_PARMS], sizeof(opts));
00084 htb->ch_prio = opts.prio;
00085 rtnl_copy_ratespec(&htb->ch_rate, &opts.rate);
00086 rtnl_copy_ratespec(&htb->ch_ceil, &opts.ceil);
00087 htb->ch_rbuffer = rtnl_tc_calc_bufsize(opts.buffer, opts.rate.rate);
00088 htb->ch_cbuffer = rtnl_tc_calc_bufsize(opts.cbuffer, opts.ceil.rate);
00089 htb->ch_quantum = opts.quantum;
00090
00091 rtnl_tc_set_mpu(tc, htb->ch_rate.rs_mpu);
00092 rtnl_tc_set_overhead(tc, htb->ch_rate.rs_overhead);
00093
00094 htb->ch_mask = (SCH_HTB_HAS_PRIO | SCH_HTB_HAS_RATE |
00095 SCH_HTB_HAS_CEIL | SCH_HTB_HAS_RBUFFER |
00096 SCH_HTB_HAS_CBUFFER | SCH_HTB_HAS_QUANTUM);
00097 }
00098
00099 return 0;
00100 }
00101
00102 static void htb_qdisc_dump_line(struct rtnl_tc *tc, void *data,
00103 struct nl_dump_params *p)
00104 {
00105 struct rtnl_htb_qdisc *htb = data;
00106
00107 if (!htb)
00108 return;
00109
00110 if (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM)
00111 nl_dump(p, " r2q %u", htb->qh_rate2quantum);
00112
00113 if (htb->qh_mask & SCH_HTB_HAS_DEFCLS) {
00114 char buf[32];
00115 nl_dump(p, " default %s",
00116 rtnl_tc_handle2str(htb->qh_defcls, buf, sizeof(buf)));
00117 }
00118 }
00119
00120 static void htb_class_dump_line(struct rtnl_tc *tc, void *data,
00121 struct nl_dump_params *p)
00122 {
00123 struct rtnl_htb_class *htb = data;
00124
00125 if (!htb)
00126 return;
00127
00128 if (htb->ch_mask & SCH_HTB_HAS_RATE) {
00129 double r, rbit;
00130 char *ru, *rubit;
00131
00132 r = nl_cancel_down_bytes(htb->ch_rate.rs_rate, &ru);
00133 rbit = nl_cancel_down_bits(htb->ch_rate.rs_rate*8, &rubit);
00134
00135 nl_dump(p, " rate %.2f%s/s (%.0f%s) log %u",
00136 r, ru, rbit, rubit, 1<<htb->ch_rate.rs_cell_log);
00137 }
00138 }
00139
00140 static void htb_class_dump_details(struct rtnl_tc *tc, void *data,
00141 struct nl_dump_params *p)
00142 {
00143 struct rtnl_htb_class *htb = data;
00144
00145 if (!htb)
00146 return;
00147
00148
00149 if (htb->ch_mask & SCH_HTB_HAS_CEIL) {
00150 double r, rbit;
00151 char *ru, *rubit;
00152
00153 r = nl_cancel_down_bytes(htb->ch_ceil.rs_rate, &ru);
00154 rbit = nl_cancel_down_bits(htb->ch_ceil.rs_rate*8, &rubit);
00155
00156 nl_dump(p, " ceil %.2f%s/s (%.0f%s) log %u",
00157 r, ru, rbit, rubit, 1<<htb->ch_ceil.rs_cell_log);
00158 }
00159
00160 if (htb->ch_mask & SCH_HTB_HAS_PRIO)
00161 nl_dump(p, " prio %u", htb->ch_prio);
00162
00163 if (htb->ch_mask & SCH_HTB_HAS_RBUFFER) {
00164 double b;
00165 char *bu;
00166
00167 b = nl_cancel_down_bytes(htb->ch_rbuffer, &bu);
00168 nl_dump(p, " rbuffer %.2f%s", b, bu);
00169 }
00170
00171 if (htb->ch_mask & SCH_HTB_HAS_CBUFFER) {
00172 double b;
00173 char *bu;
00174
00175 b = nl_cancel_down_bytes(htb->ch_cbuffer, &bu);
00176 nl_dump(p, " cbuffer %.2f%s", b, bu);
00177 }
00178
00179 if (htb->ch_mask & SCH_HTB_HAS_QUANTUM)
00180 nl_dump(p, " quantum %u", htb->ch_quantum);
00181 }
00182
00183 static int htb_qdisc_msg_fill(struct rtnl_tc *tc, void *data,
00184 struct nl_msg *msg)
00185 {
00186 struct rtnl_htb_qdisc *htb = data;
00187 struct tc_htb_glob opts = {0};
00188
00189 opts.version = TC_HTB_PROTOVER;
00190 opts.rate2quantum = 10;
00191
00192 if (htb) {
00193 if (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM)
00194 opts.rate2quantum = htb->qh_rate2quantum;
00195
00196 if (htb->qh_mask & SCH_HTB_HAS_DEFCLS)
00197 opts.defcls = htb->qh_defcls;
00198 }
00199
00200 return nla_put(msg, TCA_HTB_INIT, sizeof(opts), &opts);
00201 }
00202
00203 static int htb_class_msg_fill(struct rtnl_tc *tc, void *data,
00204 struct nl_msg *msg)
00205 {
00206 struct rtnl_htb_class *htb = data;
00207 uint32_t mtu, rtable[RTNL_TC_RTABLE_SIZE], ctable[RTNL_TC_RTABLE_SIZE];
00208 struct tc_htb_opt opts;
00209 int buffer, cbuffer;
00210
00211 if (!htb || !(htb->ch_mask & SCH_HTB_HAS_RATE))
00212 BUG();
00213
00214
00215 if (htb->ch_mask & SCH_HTB_HAS_PRIO)
00216 opts.prio = htb->ch_prio;
00217
00218 memset(&opts, 0, sizeof(opts));
00219
00220 mtu = rtnl_tc_get_mtu(tc);
00221
00222 rtnl_tc_build_rate_table(tc, &htb->ch_rate, rtable);
00223 rtnl_rcopy_ratespec(&opts.rate, &htb->ch_rate);
00224
00225 if (htb->ch_mask & SCH_HTB_HAS_CEIL) {
00226 rtnl_tc_build_rate_table(tc, &htb->ch_ceil, ctable);
00227 rtnl_rcopy_ratespec(&opts.ceil, &htb->ch_ceil);
00228 } else {
00229
00230
00231
00232
00233 memcpy(&opts.ceil, &opts.rate, sizeof(struct tc_ratespec));
00234 }
00235
00236 if (htb->ch_mask & SCH_HTB_HAS_RBUFFER)
00237 buffer = htb->ch_rbuffer;
00238 else
00239 buffer = opts.rate.rate / nl_get_user_hz() + mtu;
00240
00241 opts.buffer = rtnl_tc_calc_txtime(buffer, opts.rate.rate);
00242
00243 if (htb->ch_mask & SCH_HTB_HAS_CBUFFER)
00244 cbuffer = htb->ch_cbuffer;
00245 else
00246 cbuffer = opts.ceil.rate / nl_get_user_hz() + mtu;
00247
00248 opts.cbuffer = rtnl_tc_calc_txtime(cbuffer, opts.ceil.rate);
00249
00250 if (htb->ch_mask & SCH_HTB_HAS_QUANTUM)
00251 opts.quantum = htb->ch_quantum;
00252
00253 NLA_PUT(msg, TCA_HTB_PARMS, sizeof(opts), &opts);
00254 NLA_PUT(msg, TCA_HTB_RTAB, sizeof(rtable), &rtable);
00255 NLA_PUT(msg, TCA_HTB_CTAB, sizeof(ctable), &ctable);
00256
00257 return 0;
00258
00259 nla_put_failure:
00260 return -NLE_MSGSIZE;
00261 }
00262
00263
00264
00265
00266
00267
00268 void rtnl_htb_set_rate2quantum(struct rtnl_qdisc *qdisc, uint32_t rate2quantum)
00269 {
00270 struct rtnl_htb_qdisc *htb;
00271
00272 if (!(htb = rtnl_tc_data(TC_CAST(qdisc))))
00273 BUG();
00274
00275 htb->qh_rate2quantum = rate2quantum;
00276 htb->qh_mask |= SCH_HTB_HAS_RATE2QUANTUM;
00277 }
00278
00279
00280
00281
00282
00283
00284 void rtnl_htb_set_defcls(struct rtnl_qdisc *qdisc, uint32_t defcls)
00285 {
00286 struct rtnl_htb_qdisc *htb;
00287
00288 if (!(htb = rtnl_tc_data(TC_CAST(qdisc))))
00289 BUG();
00290
00291 htb->qh_defcls = defcls;
00292 htb->qh_mask |= SCH_HTB_HAS_DEFCLS;
00293 }
00294
00295 void rtnl_htb_set_prio(struct rtnl_class *class, uint32_t prio)
00296 {
00297 struct rtnl_htb_class *htb;
00298
00299 if (!(htb = rtnl_tc_data(TC_CAST(class))))
00300 BUG();
00301
00302 htb->ch_prio = prio;
00303 htb->ch_mask |= SCH_HTB_HAS_PRIO;
00304 }
00305
00306
00307
00308
00309
00310
00311 void rtnl_htb_set_rate(struct rtnl_class *class, uint32_t rate)
00312 {
00313 struct rtnl_htb_class *htb;
00314
00315 if (!(htb = rtnl_tc_data(TC_CAST(class))))
00316 BUG();
00317
00318 htb->ch_rate.rs_cell_log = UINT8_MAX;
00319 htb->ch_rate.rs_rate = rate;
00320 htb->ch_mask |= SCH_HTB_HAS_RATE;
00321 }
00322
00323 uint32_t rtnl_htb_get_rate(struct rtnl_class *class)
00324 {
00325 struct rtnl_htb_class *htb;
00326
00327 if (!(htb = rtnl_tc_data(TC_CAST(class))))
00328 return 0;
00329
00330 return htb->ch_rate.rs_rate;
00331 }
00332
00333
00334
00335
00336
00337
00338 void rtnl_htb_set_ceil(struct rtnl_class *class, uint32_t ceil)
00339 {
00340 struct rtnl_htb_class *htb;
00341
00342 if (!(htb = rtnl_tc_data(TC_CAST(class))))
00343 BUG();
00344
00345 htb->ch_ceil.rs_cell_log = UINT8_MAX;
00346 htb->ch_ceil.rs_rate = ceil;
00347 htb->ch_mask |= SCH_HTB_HAS_CEIL;
00348 }
00349
00350
00351
00352
00353
00354
00355 void rtnl_htb_set_rbuffer(struct rtnl_class *class, uint32_t rbuffer)
00356 {
00357 struct rtnl_htb_class *htb;
00358
00359 if (!(htb = rtnl_tc_data(TC_CAST(class))))
00360 BUG();
00361
00362 htb->ch_rbuffer = rbuffer;
00363 htb->ch_mask |= SCH_HTB_HAS_RBUFFER;
00364 }
00365
00366
00367
00368
00369
00370
00371 void rtnl_htb_set_cbuffer(struct rtnl_class *class, uint32_t cbuffer)
00372 {
00373 struct rtnl_htb_class *htb;
00374
00375 if (!(htb = rtnl_tc_data(TC_CAST(class))))
00376 BUG();
00377
00378 htb->ch_cbuffer = cbuffer;
00379 htb->ch_mask |= SCH_HTB_HAS_CBUFFER;
00380 }
00381
00382
00383
00384
00385
00386
00387 void rtnl_htb_set_quantum(struct rtnl_class *class, uint32_t quantum)
00388 {
00389 struct rtnl_htb_class *htb;
00390
00391 if (!(htb = rtnl_tc_data(TC_CAST(class))))
00392 BUG();
00393
00394 htb->ch_quantum = quantum;
00395 htb->ch_mask |= SCH_HTB_HAS_QUANTUM;
00396 }
00397
00398
00399
00400 static struct rtnl_tc_ops htb_qdisc_ops = {
00401 .to_kind = "htb",
00402 .to_type = RTNL_TC_TYPE_QDISC,
00403 .to_size = sizeof(struct rtnl_htb_qdisc),
00404 .to_msg_parser = htb_qdisc_msg_parser,
00405 .to_dump[NL_DUMP_LINE] = htb_qdisc_dump_line,
00406 .to_msg_fill = htb_qdisc_msg_fill,
00407 };
00408
00409 static struct rtnl_tc_ops htb_class_ops = {
00410 .to_kind = "htb",
00411 .to_type = RTNL_TC_TYPE_CLASS,
00412 .to_size = sizeof(struct rtnl_htb_class),
00413 .to_msg_parser = htb_class_msg_parser,
00414 .to_dump = {
00415 [NL_DUMP_LINE] = htb_class_dump_line,
00416 [NL_DUMP_DETAILS] = htb_class_dump_details,
00417 },
00418 .to_msg_fill = htb_class_msg_fill,
00419 };
00420
00421 static void __init htb_init(void)
00422 {
00423 rtnl_tc_register(&htb_qdisc_ops);
00424 rtnl_tc_register(&htb_class_ops);
00425 }
00426
00427 static void __exit htb_exit(void)
00428 {
00429 rtnl_tc_unregister(&htb_qdisc_ops);
00430 rtnl_tc_unregister(&htb_class_ops);
00431 }
00432
00433