1 /* 2 * lib/route/qdisc/tbf.c TBF Qdisc 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 (at) suug.ch> 10 */ 11 12 /** 13 * @ingroup qdisc 14 * @defgroup qdisc_tbf Token Bucket Filter (TBF) 15 * @{ 16 */ 17 18 #include <netlink-private/netlink.h> 19 #include <netlink-private/tc.h> 20 #include <netlink/netlink.h> 21 #include <netlink/cache.h> 22 #include <netlink/utils.h> 23 #include <netlink-private/route/tc-api.h> 24 #include <netlink/route/qdisc.h> 25 #include <netlink/route/class.h> 26 #include <netlink/route/link.h> 27 #include <netlink/route/qdisc/tbf.h> 28 29 /** @cond SKIP */ 30 #define TBF_ATTR_LIMIT 0x01 31 #define TBF_ATTR_RATE 0x02 32 #define TBF_ATTR_PEAKRATE 0x10 33 /** @endcond */ 34 35 static struct nla_policy tbf_policy[TCA_TBF_MAX+1] = { 36 [TCA_TBF_PARMS] = { .minlen = sizeof(struct tc_tbf_qopt) }, 37 }; 38 39 static int tbf_msg_parser(struct rtnl_tc *tc, void *data) 40 { 41 struct nlattr *tb[TCA_TBF_MAX + 1]; 42 struct rtnl_tbf *tbf = data; 43 int err; 44 45 if ((err = tca_parse(tb, TCA_TBF_MAX, tc, tbf_policy)) < 0) 46 return err; 47 48 if (tb[TCA_TBF_PARMS]) { 49 struct tc_tbf_qopt opts; 50 int bufsize; 51 52 nla_memcpy(&opts, tb[TCA_TBF_PARMS], sizeof(opts)); 53 tbf->qt_limit = opts.limit; 54 55 rtnl_copy_ratespec(&tbf->qt_rate, &opts.rate); 56 tbf->qt_rate_txtime = opts.buffer; 57 bufsize = rtnl_tc_calc_bufsize(nl_ticks2us(opts.buffer), 58 opts.rate.rate); 59 tbf->qt_rate_bucket = bufsize; 60 61 rtnl_copy_ratespec(&tbf->qt_peakrate, &opts.peakrate); 62 tbf->qt_peakrate_txtime = opts.mtu; 63 bufsize = rtnl_tc_calc_bufsize(nl_ticks2us(opts.mtu), 64 opts.peakrate.rate); 65 tbf->qt_peakrate_bucket = bufsize; 66 67 rtnl_tc_set_mpu(tc, tbf->qt_rate.rs_mpu); 68 rtnl_tc_set_overhead(tc, tbf->qt_rate.rs_overhead); 69 70 tbf->qt_mask = (TBF_ATTR_LIMIT | TBF_ATTR_RATE | TBF_ATTR_PEAKRATE); 71 } 72 73 return 0; 74 } 75 76 static void tbf_dump_line(struct rtnl_tc *tc, void *data, 77 struct nl_dump_params *p) 78 { 79 double r, rbit, lim; 80 char *ru, *rubit, *limu; 81 struct rtnl_tbf *tbf = data; 82 83 if (!tbf) 84 return; 85 86 r = nl_cancel_down_bytes(tbf->qt_rate.rs_rate, &ru); 87 rbit = nl_cancel_down_bits(tbf->qt_rate.rs_rate*8, &rubit); 88 lim = nl_cancel_down_bytes(tbf->qt_limit, &limu); 89 90 nl_dump(p, " rate %.2f%s/s (%.0f%s) limit %.2f%s", 91 r, ru, rbit, rubit, lim, limu); 92 } 93 94 static void tbf_dump_details(struct rtnl_tc *tc, void *data, 95 struct nl_dump_params *p) 96 { 97 struct rtnl_tbf *tbf = data; 98 99 if (!tbf) 100 return; 101 102 if (1) { 103 char *bu, *cu; 104 double bs = nl_cancel_down_bytes(tbf->qt_rate_bucket, &bu); 105 double cl = nl_cancel_down_bytes(1 << tbf->qt_rate.rs_cell_log, 106 &cu); 107 108 nl_dump(p, "rate-bucket-size %1.f%s " 109 "rate-cell-size %.1f%s\n", 110 bs, bu, cl, cu); 111 112 } 113 114 if (tbf->qt_mask & TBF_ATTR_PEAKRATE) { 115 char *pru, *prbu, *bsu, *clu; 116 double pr, prb, bs, cl; 117 118 pr = nl_cancel_down_bytes(tbf->qt_peakrate.rs_rate, &pru); 119 prb = nl_cancel_down_bits(tbf->qt_peakrate.rs_rate * 8, &prbu); 120 bs = nl_cancel_down_bits(tbf->qt_peakrate_bucket, &bsu); 121 cl = nl_cancel_down_bits(1 << tbf->qt_peakrate.rs_cell_log, 122 &clu); 123 124 nl_dump_line(p, " peak-rate %.2f%s/s (%.0f%s) " 125 "bucket-size %.1f%s cell-size %.1f%s" 126 "latency %.1f%s", 127 pr, pru, prb, prbu, bs, bsu, cl, clu); 128 } 129 } 130 131 static int tbf_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) 132 { 133 uint32_t rtab[RTNL_TC_RTABLE_SIZE], ptab[RTNL_TC_RTABLE_SIZE]; 134 struct tc_tbf_qopt opts; 135 struct rtnl_tbf *tbf = data; 136 int required = TBF_ATTR_RATE | TBF_ATTR_LIMIT; 137 138 if ((tbf->qt_mask & required) != required) 139 return -NLE_MISSING_ATTR; 140 141 memset(&opts, 0, sizeof(opts)); 142 opts.limit = tbf->qt_limit; 143 opts.buffer = tbf->qt_rate_txtime; 144 145 rtnl_tc_build_rate_table(tc, &tbf->qt_rate, rtab); 146 rtnl_rcopy_ratespec(&opts.rate, &tbf->qt_rate); 147 148 if (tbf->qt_mask & TBF_ATTR_PEAKRATE) { 149 opts.mtu = tbf->qt_peakrate_txtime; 150 rtnl_tc_build_rate_table(tc, &tbf->qt_peakrate, ptab); 151 rtnl_rcopy_ratespec(&opts.peakrate, &tbf->qt_peakrate); 152 153 } 154 155 NLA_PUT(msg, TCA_TBF_PARMS, sizeof(opts), &opts); 156 NLA_PUT(msg, TCA_TBF_RTAB, sizeof(rtab), rtab); 157 158 if (tbf->qt_mask & TBF_ATTR_PEAKRATE) 159 NLA_PUT(msg, TCA_TBF_PTAB, sizeof(ptab), ptab); 160 161 return 0; 162 163 nla_put_failure: 164 return -NLE_MSGSIZE; 165 } 166 167 /** 168 * @name Attribute Access 169 * @{ 170 */ 171 172 /** 173 * Set limit of TBF qdisc. 174 * @arg qdisc TBF qdisc to be modified. 175 * @arg limit New limit in bytes. 176 * @return 0 on success or a negative error code. 177 */ 178 void rtnl_qdisc_tbf_set_limit(struct rtnl_qdisc *qdisc, int limit) 179 { 180 struct rtnl_tbf *tbf; 181 182 if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) 183 BUG(); 184 185 tbf->qt_limit = limit; 186 tbf->qt_mask |= TBF_ATTR_LIMIT; 187 } 188 189 static inline double calc_limit(struct rtnl_ratespec *spec, int latency, 190 int bucket) 191 { 192 double limit; 193 194 limit = (double) spec->rs_rate * ((double) latency / 1000000.); 195 limit += bucket; 196 197 return limit; 198 } 199 200 /** 201 * Set limit of TBF qdisc by latency. 202 * @arg qdisc TBF qdisc to be modified. 203 * @arg latency Latency in micro seconds. 204 * 205 * Calculates and sets the limit based on the desired latency and the 206 * configured rate and peak rate. In order for this operation to succeed, 207 * the rate and if required the peak rate must have been set in advance. 208 * 209 * @f[ 210 * limit_n = \frac{{rate_n} \times {latency}}{10^6}+{bucketsize}_n 211 * @f] 212 * @f[ 213 * limit = min(limit_{rate},limit_{peak}) 214 * @f] 215 * 216 * @return 0 on success or a negative error code. 217 */ 218 int rtnl_qdisc_tbf_set_limit_by_latency(struct rtnl_qdisc *qdisc, int latency) 219 { 220 struct rtnl_tbf *tbf; 221 double limit, limit2; 222 223 if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) 224 BUG(); 225 226 if (!(tbf->qt_mask & TBF_ATTR_RATE)) 227 return -NLE_MISSING_ATTR; 228 229 limit = calc_limit(&tbf->qt_rate, latency, tbf->qt_rate_bucket); 230 231 if (tbf->qt_mask & TBF_ATTR_PEAKRATE) { 232 limit2 = calc_limit(&tbf->qt_peakrate, latency, 233 tbf->qt_peakrate_bucket); 234 235 if (limit2 < limit) 236 limit = limit2; 237 } 238 239 rtnl_qdisc_tbf_set_limit(qdisc, (int) limit); 240 241 return 0; 242 } 243 244 /** 245 * Get limit of TBF qdisc. 246 * @arg qdisc TBF qdisc. 247 * @return Limit in bytes or a negative error code. 248 */ 249 int rtnl_qdisc_tbf_get_limit(struct rtnl_qdisc *qdisc) 250 { 251 struct rtnl_tbf *tbf; 252 253 if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) 254 BUG(); 255 256 if (tbf->qt_mask & TBF_ATTR_LIMIT) 257 return tbf->qt_limit; 258 else 259 return -NLE_NOATTR; 260 } 261 262 static inline int calc_cell_log(int cell, int bucket) 263 { 264 cell = rtnl_tc_calc_cell_log(cell); 265 return cell; 266 } 267 268 /** 269 * Set rate of TBF qdisc. 270 * @arg qdisc TBF qdisc to be modified. 271 * @arg rate New rate in bytes per second. 272 * @arg bucket Size of bucket in bytes. 273 * @arg cell Size of a rate cell or 0 to get default value. 274 * @return 0 on success or a negative error code. 275 */ 276 void rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc *qdisc, int rate, int bucket, 277 int cell) 278 { 279 struct rtnl_tbf *tbf; 280 int cell_log; 281 282 if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) 283 BUG(); 284 285 if (!cell) 286 cell_log = UINT8_MAX; 287 else 288 cell_log = rtnl_tc_calc_cell_log(cell); 289 290 tbf->qt_rate.rs_rate = rate; 291 tbf->qt_rate_bucket = bucket; 292 tbf->qt_rate.rs_cell_log = cell_log; 293 tbf->qt_rate_txtime = nl_us2ticks(rtnl_tc_calc_txtime(bucket, rate)); 294 tbf->qt_mask |= TBF_ATTR_RATE; 295 } 296 297 /** 298 * Get rate of TBF qdisc. 299 * @arg qdisc TBF qdisc. 300 * @return Rate in bytes per seconds or a negative error code. 301 */ 302 int rtnl_qdisc_tbf_get_rate(struct rtnl_qdisc *qdisc) 303 { 304 struct rtnl_tbf *tbf; 305 306 if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) 307 BUG(); 308 309 if (tbf->qt_mask & TBF_ATTR_RATE) 310 return tbf->qt_rate.rs_rate; 311 else 312 return -1; 313 } 314 315 /** 316 * Get rate bucket size of TBF qdisc. 317 * @arg qdisc TBF qdisc. 318 * @return Size of rate bucket or a negative error code. 319 */ 320 int rtnl_qdisc_tbf_get_rate_bucket(struct rtnl_qdisc *qdisc) 321 { 322 struct rtnl_tbf *tbf; 323 324 if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) 325 BUG(); 326 327 if (tbf->qt_mask & TBF_ATTR_RATE) 328 return tbf->qt_rate_bucket; 329 else 330 return -1; 331 } 332 333 /** 334 * Get rate cell size of TBF qdisc. 335 * @arg qdisc TBF qdisc. 336 * @return Size of rate cell in bytes or a negative error code. 337 */ 338 int rtnl_qdisc_tbf_get_rate_cell(struct rtnl_qdisc *qdisc) 339 { 340 struct rtnl_tbf *tbf; 341 342 if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) 343 BUG(); 344 345 if (tbf->qt_mask & TBF_ATTR_RATE) 346 return (1 << tbf->qt_rate.rs_cell_log); 347 else 348 return -1; 349 } 350 351 /** 352 * Set peak rate of TBF qdisc. 353 * @arg qdisc TBF qdisc to be modified. 354 * @arg rate New peak rate in bytes per second. 355 * @arg bucket Size of peakrate bucket. 356 * @arg cell Size of a peakrate cell or 0 to get default value. 357 * @return 0 on success or a negative error code. 358 */ 359 int rtnl_qdisc_tbf_set_peakrate(struct rtnl_qdisc *qdisc, int rate, int bucket, 360 int cell) 361 { 362 struct rtnl_tbf *tbf; 363 int cell_log; 364 365 if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) 366 BUG(); 367 368 cell_log = calc_cell_log(cell, bucket); 369 if (cell_log < 0) 370 return cell_log; 371 372 tbf->qt_peakrate.rs_rate = rate; 373 tbf->qt_peakrate_bucket = bucket; 374 tbf->qt_peakrate.rs_cell_log = cell_log; 375 tbf->qt_peakrate_txtime = nl_us2ticks(rtnl_tc_calc_txtime(bucket, rate)); 376 377 tbf->qt_mask |= TBF_ATTR_PEAKRATE; 378 379 return 0; 380 } 381 382 /** 383 * Get peak rate of TBF qdisc. 384 * @arg qdisc TBF qdisc. 385 * @return Peak rate in bytes per seconds or a negative error code. 386 */ 387 int rtnl_qdisc_tbf_get_peakrate(struct rtnl_qdisc *qdisc) 388 { 389 struct rtnl_tbf *tbf; 390 391 if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) 392 BUG(); 393 394 if (tbf->qt_mask & TBF_ATTR_PEAKRATE) 395 return tbf->qt_peakrate.rs_rate; 396 else 397 return -1; 398 } 399 400 /** 401 * Get peak rate bucket size of TBF qdisc. 402 * @arg qdisc TBF qdisc. 403 * @return Size of peak rate bucket or a negative error code. 404 */ 405 int rtnl_qdisc_tbf_get_peakrate_bucket(struct rtnl_qdisc *qdisc) 406 { 407 struct rtnl_tbf *tbf; 408 409 if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) 410 BUG(); 411 412 if (tbf->qt_mask & TBF_ATTR_PEAKRATE) 413 return tbf->qt_peakrate_bucket; 414 else 415 return -1; 416 } 417 418 /** 419 * Get peak rate cell size of TBF qdisc. 420 * @arg qdisc TBF qdisc. 421 * @return Size of peak rate cell in bytes or a negative error code. 422 */ 423 int rtnl_qdisc_tbf_get_peakrate_cell(struct rtnl_qdisc *qdisc) 424 { 425 struct rtnl_tbf *tbf; 426 427 if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) 428 BUG(); 429 430 if (tbf->qt_mask & TBF_ATTR_PEAKRATE) 431 return (1 << tbf->qt_peakrate.rs_cell_log); 432 else 433 return -1; 434 } 435 436 /** @} */ 437 438 static struct rtnl_tc_ops tbf_tc_ops = { 439 .to_kind = "tbf", 440 .to_type = RTNL_TC_TYPE_QDISC, 441 .to_size = sizeof(struct rtnl_tbf), 442 .to_msg_parser = tbf_msg_parser, 443 .to_dump = { 444 [NL_DUMP_LINE] = tbf_dump_line, 445 [NL_DUMP_DETAILS] = tbf_dump_details, 446 }, 447 .to_msg_fill = tbf_msg_fill, 448 }; 449 450 static void __init tbf_init(void) 451 { 452 rtnl_tc_register(&tbf_tc_ops); 453 } 454 455 static void __exit tbf_exit(void) 456 { 457 rtnl_tc_unregister(&tbf_tc_ops); 458 } 459 460 /** @} */ 461