cbq.c revision d84430702496f617c01c5e2d27d0e82e02390bb7
1/* 2 * lib/route/sch/cbq.c Class Based Queueing 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-2008 Thomas Graf <tgraf@suug.ch> 10 */ 11 12#include <netlink-local.h> 13#include <netlink-tc.h> 14#include <netlink/netlink.h> 15#include <netlink/utils.h> 16#include <netlink/route/qdisc.h> 17#include <netlink/route/qdisc-modules.h> 18#include <netlink/route/class.h> 19#include <netlink/route/class-modules.h> 20#include <netlink/route/link.h> 21#include <netlink/route/sch/cbq.h> 22#include <netlink/route/cls/police.h> 23 24/** 25 * @ingroup qdisc_api 26 * @ingroup class_api 27 * @defgroup cbq Class Based Queueing (CBQ) 28 * @{ 29 */ 30 31static struct trans_tbl ovl_strategies[] = { 32 __ADD(TC_CBQ_OVL_CLASSIC,classic) 33 __ADD(TC_CBQ_OVL_DELAY,delay) 34 __ADD(TC_CBQ_OVL_LOWPRIO,lowprio) 35 __ADD(TC_CBQ_OVL_DROP,drop) 36 __ADD(TC_CBQ_OVL_RCLASSIC,rclassic) 37}; 38 39/** 40 * Convert a CBQ OVL strategy to a character string 41 * @arg type CBQ OVL strategy 42 * @arg buf destination buffer 43 * @arg len length of destination buffer 44 * 45 * Converts a CBQ OVL strategy to a character string and stores in the 46 * provided buffer. Returns the destination buffer or the type 47 * encoded in hex if no match was found. 48 */ 49char *nl_ovl_strategy2str(int type, char *buf, size_t len) 50{ 51 return __type2str(type, buf, len, ovl_strategies, 52 ARRAY_SIZE(ovl_strategies)); 53} 54 55/** 56 * Convert a string to a CBQ OVL strategy 57 * @arg name CBQ OVL stragegy name 58 * 59 * Converts a CBQ OVL stragegy name to it's corresponding CBQ OVL strategy 60 * type. Returns the type or -1 if none was found. 61 */ 62int nl_str2ovl_strategy(const char *name) 63{ 64 return __str2type(name, ovl_strategies, ARRAY_SIZE(ovl_strategies)); 65} 66 67static struct nla_policy cbq_policy[TCA_CBQ_MAX+1] = { 68 [TCA_CBQ_LSSOPT] = { .minlen = sizeof(struct tc_cbq_lssopt) }, 69 [TCA_CBQ_RATE] = { .minlen = sizeof(struct tc_ratespec) }, 70 [TCA_CBQ_WRROPT] = { .minlen = sizeof(struct tc_cbq_wrropt) }, 71 [TCA_CBQ_OVL_STRATEGY] = { .minlen = sizeof(struct tc_cbq_ovl) }, 72 [TCA_CBQ_FOPT] = { .minlen = sizeof(struct tc_cbq_fopt) }, 73 [TCA_CBQ_POLICE] = { .minlen = sizeof(struct tc_cbq_police) }, 74}; 75 76static inline struct rtnl_cbq *cbq_qdisc(struct rtnl_tca *tca) 77{ 78 return (struct rtnl_cbq *) tca->tc_subdata; 79} 80 81static inline struct rtnl_cbq *cbq_alloc(struct rtnl_tca *tca) 82{ 83 if (!tca->tc_subdata) 84 tca->tc_subdata = calloc(1, sizeof(struct rtnl_qdisc)); 85 86 return cbq_qdisc(tca); 87} 88 89 90static int cbq_msg_parser(struct rtnl_tca *tca) 91{ 92 struct nlattr *tb[TCA_CBQ_MAX + 1]; 93 struct rtnl_cbq *cbq; 94 int err; 95 96 err = tca_parse(tb, TCA_CBQ_MAX, tca, cbq_policy); 97 if (err < 0) 98 return err; 99 100 cbq = cbq_alloc(tca); 101 if (!cbq) 102 return -NLE_NOMEM; 103 104 nla_memcpy(&cbq->cbq_lss, tb[TCA_CBQ_LSSOPT], sizeof(cbq->cbq_lss)); 105 nla_memcpy(&cbq->cbq_rate, tb[TCA_CBQ_RATE], sizeof(cbq->cbq_rate)); 106 nla_memcpy(&cbq->cbq_wrr, tb[TCA_CBQ_WRROPT], sizeof(cbq->cbq_wrr)); 107 nla_memcpy(&cbq->cbq_fopt, tb[TCA_CBQ_FOPT], sizeof(cbq->cbq_fopt)); 108 nla_memcpy(&cbq->cbq_ovl, tb[TCA_CBQ_OVL_STRATEGY], 109 sizeof(cbq->cbq_ovl)); 110 nla_memcpy(&cbq->cbq_police, tb[TCA_CBQ_POLICE], 111 sizeof(cbq->cbq_police)); 112 113 return 0; 114} 115 116static int cbq_qdisc_msg_parser(struct rtnl_qdisc *qdisc) 117{ 118 return cbq_msg_parser((struct rtnl_tca *) qdisc); 119} 120 121static int cbq_class_msg_parser(struct rtnl_class *class) 122{ 123 return cbq_msg_parser((struct rtnl_tca *) class); 124} 125 126static void cbq_qdisc_free_data(struct rtnl_qdisc *qdisc) 127{ 128 free(qdisc->q_subdata); 129} 130 131static int cbq_clone(struct rtnl_tca *_dst, struct rtnl_tca *_src) 132{ 133 struct rtnl_cbq *src = cbq_qdisc(_src); 134 135 if (src && !cbq_alloc(_dst)) 136 return -NLE_NOMEM; 137 else 138 return 0; 139} 140 141static int cbq_qdisc_clone(struct rtnl_qdisc *dst, struct rtnl_qdisc *src) 142{ 143 return cbq_clone((struct rtnl_tca *) dst, (struct rtnl_tca *) src); 144} 145 146static void cbq_class_free_data(struct rtnl_class *class) 147{ 148 free(class->c_subdata); 149} 150 151static int cbq_class_clone(struct rtnl_class *dst, struct rtnl_class *src) 152{ 153 return cbq_clone((struct rtnl_tca *) dst, (struct rtnl_tca *) src); 154} 155 156static void cbq_dump_line(struct rtnl_tca *tca, struct nl_dump_params *p) 157{ 158 struct rtnl_cbq *cbq; 159 double r, rbit; 160 char *ru, *rubit; 161 162 cbq = cbq_qdisc(tca); 163 if (!cbq) 164 return; 165 166 r = nl_cancel_down_bytes(cbq->cbq_rate.rate, &ru); 167 rbit = nl_cancel_down_bits(cbq->cbq_rate.rate * 8, &rubit); 168 169 nl_dump(p, " rate %.2f%s/s (%.0f%s) prio %u", 170 r, ru, rbit, rubit, cbq->cbq_wrr.priority); 171} 172 173static void cbq_qdisc_dump_line(struct rtnl_qdisc *qdisc, 174 struct nl_dump_params *p) 175{ 176 cbq_dump_line((struct rtnl_tca *) qdisc, p); 177} 178 179static void cbq_class_dump_line(struct rtnl_class *class, 180 struct nl_dump_params *p) 181{ 182 cbq_dump_line((struct rtnl_tca *) class, p); 183} 184 185static void cbq_dump_details(struct rtnl_tca *tca, struct nl_dump_params *p) 186{ 187 struct rtnl_cbq *cbq; 188 char *unit, buf[32]; 189 double w; 190 uint32_t el; 191 192 cbq = cbq_qdisc(tca); 193 if (!cbq) 194 return; 195 196 w = nl_cancel_down_bits(cbq->cbq_wrr.weight * 8, &unit); 197 198 nl_dump(p, "avgpkt %u mpu %u cell %u allot %u weight %.0f%s\n", 199 cbq->cbq_lss.avpkt, 200 cbq->cbq_rate.mpu, 201 1 << cbq->cbq_rate.cell_log, 202 cbq->cbq_wrr.allot, w, unit); 203 204 el = cbq->cbq_lss.ewma_log; 205 nl_dump_line(p, " minidle %uus maxidle %uus offtime " 206 "%uus level %u ewma_log %u\n", 207 nl_ticks2us(cbq->cbq_lss.minidle >> el), 208 nl_ticks2us(cbq->cbq_lss.maxidle >> el), 209 nl_ticks2us(cbq->cbq_lss.offtime >> el), 210 cbq->cbq_lss.level, 211 cbq->cbq_lss.ewma_log); 212 213 nl_dump_line(p, " penalty %uus strategy %s ", 214 nl_ticks2us(cbq->cbq_ovl.penalty), 215 nl_ovl_strategy2str(cbq->cbq_ovl.strategy, buf, sizeof(buf))); 216 217 nl_dump(p, "split %s defmap 0x%08x ", 218 rtnl_tc_handle2str(cbq->cbq_fopt.split, buf, sizeof(buf)), 219 cbq->cbq_fopt.defmap); 220 221 nl_dump(p, "police %s", 222 nl_police2str(cbq->cbq_police.police, buf, sizeof(buf))); 223} 224 225static void cbq_qdisc_dump_details(struct rtnl_qdisc *qdisc, 226 struct nl_dump_params *p) 227{ 228 cbq_dump_details((struct rtnl_tca *) qdisc, p); 229} 230 231static void cbq_class_dump_details(struct rtnl_class *class, 232 struct nl_dump_params *p) 233{ 234 cbq_dump_details((struct rtnl_tca *) class, p); 235} 236 237static void cbq_dump_stats(struct rtnl_tca *tca, struct nl_dump_params *p) 238{ 239 struct tc_cbq_xstats *x = tca_xstats(tca); 240 241 if (!x) 242 return; 243 244 nl_dump_line(p, " borrows overact " 245 " avgidle undertime\n"); 246 nl_dump_line(p, " %10u %10u %10u %10u\n", 247 x->borrows, x->overactions, x->avgidle, x->undertime); 248} 249 250static void cbq_qdisc_dump_stats(struct rtnl_qdisc *qdisc, 251 struct nl_dump_params *p) 252{ 253 cbq_dump_stats((struct rtnl_tca *) qdisc, p); 254} 255 256static void cbq_class_dump_stats(struct rtnl_class *class, 257 struct nl_dump_params *p) 258{ 259 cbq_dump_stats((struct rtnl_tca *) class, p); 260} 261 262static struct rtnl_qdisc_ops cbq_qdisc_ops = { 263 .qo_kind = "cbq", 264 .qo_msg_parser = cbq_qdisc_msg_parser, 265 .qo_free_data = cbq_qdisc_free_data, 266 .qo_clone = cbq_qdisc_clone, 267 .qo_dump = { 268 [NL_DUMP_LINE] = cbq_qdisc_dump_line, 269 [NL_DUMP_DETAILS] = cbq_qdisc_dump_details, 270 [NL_DUMP_STATS] = cbq_qdisc_dump_stats, 271 }, 272}; 273 274static struct rtnl_class_ops cbq_class_ops = { 275 .co_kind = "cbq", 276 .co_msg_parser = cbq_class_msg_parser, 277 .co_free_data = cbq_class_free_data, 278 .co_clone = cbq_class_clone, 279 .co_dump = { 280 [NL_DUMP_LINE] = cbq_class_dump_line, 281 [NL_DUMP_DETAILS] = cbq_class_dump_details, 282 [NL_DUMP_STATS] = cbq_class_dump_stats, 283 }, 284}; 285 286static void __init cbq_init(void) 287{ 288 rtnl_qdisc_register(&cbq_qdisc_ops); 289 rtnl_class_register(&cbq_class_ops); 290} 291 292static void __exit cbq_exit(void) 293{ 294 rtnl_qdisc_unregister(&cbq_qdisc_ops); 295 rtnl_class_unregister(&cbq_class_ops); 296} 297 298/** @} */ 299