libnl 3.0
|
00001 /* 00002 * lib/route/qdisc/htb.c HTB Qdisc 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation version 2.1 00007 * of the License. 00008 * 00009 * Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch> 00010 * Copyright (c) 2005-2006 Petr Gotthard <petr.gotthard@siemens.com> 00011 * Copyright (c) 2005-2006 Siemens AG Oesterreich 00012 */ 00013 00014 /** 00015 * @ingroup qdisc 00016 * @ingroup class 00017 * @defgroup qdisc_htb Hierachical Token Bucket (HTB) 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 /** @cond SKIP */ 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 /** @endcond */ 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 /* line 1 */ 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 /* if not set, zero (0) is used as priority */ 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 * If not set, configured rate is used as ceil, which implies 00231 * no borrowing. 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; /* XXX */ 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; /* XXX */ 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 * @name Attribute Modifications 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 * Set default class of the htb qdisc to the specified value 00281 * @arg qdisc qdisc to change 00282 * @arg defcls new default class 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 * Set rate of HTB class. 00308 * @arg class HTB class to be modified. 00309 * @arg rate New rate in bytes per second. 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; /* use default value */ 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 * Set ceil of HTB class. 00335 * @arg class HTB class to be modified. 00336 * @arg ceil New ceil in bytes per second. 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; /* use default value */ 00346 htb->ch_ceil.rs_rate = ceil; 00347 htb->ch_mask |= SCH_HTB_HAS_CEIL; 00348 } 00349 00350 /** 00351 * Set size of the rate bucket of HTB class. 00352 * @arg class HTB class to be modified. 00353 * @arg rbuffer New size in bytes. 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 * Set size of the ceil bucket of HTB class. 00368 * @arg class HTB class to be modified. 00369 * @arg cbuffer New size in bytes. 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 * Set how much bytes to serve from leaf at once of HTB class {use r2q}. 00384 * @arg class HTB class to be modified. 00385 * @arg quantum New size in bytes. 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 /** @} */