libnl 1.1
|
00001 /* 00002 * lib/route/sch/cbq.c Class Based Queueing 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-2006 Thomas Graf <tgraf@suug.ch> 00010 */ 00011 00012 #include <netlink-local.h> 00013 #include <netlink-tc.h> 00014 #include <netlink/netlink.h> 00015 #include <netlink/utils.h> 00016 #include <netlink/route/qdisc.h> 00017 #include <netlink/route/qdisc-modules.h> 00018 #include <netlink/route/class.h> 00019 #include <netlink/route/class-modules.h> 00020 #include <netlink/route/link.h> 00021 #include <netlink/route/sch/cbq.h> 00022 #include <netlink/route/cls/police.h> 00023 00024 /** 00025 * @ingroup qdisc_api 00026 * @ingroup class_api 00027 * @defgroup cbq Class Based Queueing (CBQ) 00028 * @{ 00029 */ 00030 00031 static struct trans_tbl ovl_strategies[] = { 00032 __ADD(TC_CBQ_OVL_CLASSIC,classic) 00033 __ADD(TC_CBQ_OVL_DELAY,delay) 00034 __ADD(TC_CBQ_OVL_LOWPRIO,lowprio) 00035 __ADD(TC_CBQ_OVL_DROP,drop) 00036 __ADD(TC_CBQ_OVL_RCLASSIC,rclassic) 00037 }; 00038 00039 /** 00040 * Convert a CBQ OVL strategy to a character string 00041 * @arg type CBQ OVL strategy 00042 * @arg buf destination buffer 00043 * @arg len length of destination buffer 00044 * 00045 * Converts a CBQ OVL strategy to a character string and stores in the 00046 * provided buffer. Returns the destination buffer or the type 00047 * encoded in hex if no match was found. 00048 */ 00049 char *nl_ovl_strategy2str(int type, char *buf, size_t len) 00050 { 00051 return __type2str(type, buf, len, ovl_strategies, 00052 ARRAY_SIZE(ovl_strategies)); 00053 } 00054 00055 /** 00056 * Convert a string to a CBQ OVL strategy 00057 * @arg name CBQ OVL stragegy name 00058 * 00059 * Converts a CBQ OVL stragegy name to it's corresponding CBQ OVL strategy 00060 * type. Returns the type or -1 if none was found. 00061 */ 00062 int nl_str2ovl_strategy(const char *name) 00063 { 00064 return __str2type(name, ovl_strategies, ARRAY_SIZE(ovl_strategies)); 00065 } 00066 00067 static struct nla_policy cbq_policy[TCA_CBQ_MAX+1] = { 00068 [TCA_CBQ_LSSOPT] = { .minlen = sizeof(struct tc_cbq_lssopt) }, 00069 [TCA_CBQ_RATE] = { .minlen = sizeof(struct tc_ratespec) }, 00070 [TCA_CBQ_WRROPT] = { .minlen = sizeof(struct tc_cbq_wrropt) }, 00071 [TCA_CBQ_OVL_STRATEGY] = { .minlen = sizeof(struct tc_cbq_ovl) }, 00072 [TCA_CBQ_FOPT] = { .minlen = sizeof(struct tc_cbq_fopt) }, 00073 [TCA_CBQ_POLICE] = { .minlen = sizeof(struct tc_cbq_police) }, 00074 }; 00075 00076 static inline struct rtnl_cbq *cbq_qdisc(struct rtnl_tca *tca) 00077 { 00078 return (struct rtnl_cbq *) tca->tc_subdata; 00079 } 00080 00081 static inline struct rtnl_cbq *cbq_alloc(struct rtnl_tca *tca) 00082 { 00083 if (!tca->tc_subdata) 00084 tca->tc_subdata = calloc(1, sizeof(struct rtnl_qdisc)); 00085 00086 return cbq_qdisc(tca); 00087 } 00088 00089 00090 static int cbq_msg_parser(struct rtnl_tca *tca) 00091 { 00092 struct nlattr *tb[TCA_CBQ_MAX + 1]; 00093 struct rtnl_cbq *cbq; 00094 int err; 00095 00096 err = tca_parse(tb, TCA_CBQ_MAX, tca, cbq_policy); 00097 if (err < 0) 00098 return err; 00099 00100 cbq = cbq_alloc(tca); 00101 if (!cbq) 00102 return nl_errno(ENOMEM); 00103 00104 nla_memcpy(&cbq->cbq_lss, tb[TCA_CBQ_LSSOPT], sizeof(cbq->cbq_lss)); 00105 nla_memcpy(&cbq->cbq_rate, tb[TCA_CBQ_RATE], sizeof(cbq->cbq_rate)); 00106 nla_memcpy(&cbq->cbq_wrr, tb[TCA_CBQ_WRROPT], sizeof(cbq->cbq_wrr)); 00107 nla_memcpy(&cbq->cbq_fopt, tb[TCA_CBQ_FOPT], sizeof(cbq->cbq_fopt)); 00108 nla_memcpy(&cbq->cbq_ovl, tb[TCA_CBQ_OVL_STRATEGY], 00109 sizeof(cbq->cbq_ovl)); 00110 nla_memcpy(&cbq->cbq_police, tb[TCA_CBQ_POLICE], 00111 sizeof(cbq->cbq_police)); 00112 00113 return 0; 00114 } 00115 00116 static int cbq_qdisc_msg_parser(struct rtnl_qdisc *qdisc) 00117 { 00118 return cbq_msg_parser((struct rtnl_tca *) qdisc); 00119 } 00120 00121 static int cbq_class_msg_parser(struct rtnl_class *class) 00122 { 00123 return cbq_msg_parser((struct rtnl_tca *) class); 00124 } 00125 00126 static void cbq_qdisc_free_data(struct rtnl_qdisc *qdisc) 00127 { 00128 free(qdisc->q_subdata); 00129 } 00130 00131 static int cbq_clone(struct rtnl_tca *_dst, struct rtnl_tca *_src) 00132 { 00133 struct rtnl_cbq *src = cbq_qdisc(_src); 00134 00135 if (src && !cbq_alloc(_dst)) 00136 return nl_errno(ENOMEM); 00137 else 00138 return 0; 00139 } 00140 00141 static int cbq_qdisc_clone(struct rtnl_qdisc *dst, struct rtnl_qdisc *src) 00142 { 00143 return cbq_clone((struct rtnl_tca *) dst, (struct rtnl_tca *) src); 00144 } 00145 00146 static void cbq_class_free_data(struct rtnl_class *class) 00147 { 00148 free(class->c_subdata); 00149 } 00150 00151 static int cbq_class_clone(struct rtnl_class *dst, struct rtnl_class *src) 00152 { 00153 return cbq_clone((struct rtnl_tca *) dst, (struct rtnl_tca *) src); 00154 } 00155 00156 static int cbq_dump_brief(struct rtnl_tca *tca, struct nl_dump_params *p, 00157 int line) 00158 { 00159 struct rtnl_cbq *cbq; 00160 double r, rbit; 00161 char *ru, *rubit; 00162 00163 cbq = cbq_qdisc(tca); 00164 if (!cbq) 00165 goto ignore; 00166 00167 r = nl_cancel_down_bytes(cbq->cbq_rate.rate, &ru); 00168 rbit = nl_cancel_down_bits(cbq->cbq_rate.rate * 8, &rubit); 00169 00170 dp_dump(p, " rate %.2f%s/s (%.0f%s) prio %u", 00171 r, ru, rbit, rubit, cbq->cbq_wrr.priority); 00172 00173 ignore: 00174 return line; 00175 } 00176 00177 static int cbq_qdisc_dump_brief(struct rtnl_qdisc *qdisc, 00178 struct nl_dump_params *p, int line) 00179 { 00180 return cbq_dump_brief((struct rtnl_tca *) qdisc, p, line); 00181 } 00182 00183 static int cbq_class_dump_brief(struct rtnl_class *class, 00184 struct nl_dump_params *p, int line) 00185 { 00186 return cbq_dump_brief((struct rtnl_tca *) class, p, line); 00187 } 00188 00189 static int cbq_dump_full(struct rtnl_tca *tca, struct nl_dump_params *p, 00190 int line) 00191 { 00192 struct rtnl_cbq *cbq; 00193 char *unit, buf[32]; 00194 double w; 00195 uint32_t el; 00196 00197 cbq = cbq_qdisc(tca); 00198 if (!cbq) 00199 goto ignore; 00200 00201 w = nl_cancel_down_bits(cbq->cbq_wrr.weight * 8, &unit); 00202 00203 dp_dump(p, "avgpkt %u mpu %u cell %u allot %u weight %.0f%s\n", 00204 cbq->cbq_lss.avpkt, 00205 cbq->cbq_rate.mpu, 00206 1 << cbq->cbq_rate.cell_log, 00207 cbq->cbq_wrr.allot, w, unit); 00208 00209 el = cbq->cbq_lss.ewma_log; 00210 dp_dump_line(p, line++, " minidle %uus maxidle %uus offtime " 00211 "%uus level %u ewma_log %u\n", 00212 nl_ticks2us(cbq->cbq_lss.minidle >> el), 00213 nl_ticks2us(cbq->cbq_lss.maxidle >> el), 00214 nl_ticks2us(cbq->cbq_lss.offtime >> el), 00215 cbq->cbq_lss.level, 00216 cbq->cbq_lss.ewma_log); 00217 00218 dp_dump_line(p, line++, " penalty %uus strategy %s ", 00219 nl_ticks2us(cbq->cbq_ovl.penalty), 00220 nl_ovl_strategy2str(cbq->cbq_ovl.strategy, buf, sizeof(buf))); 00221 00222 dp_dump(p, "split %s defmap 0x%08x ", 00223 rtnl_tc_handle2str(cbq->cbq_fopt.split, buf, sizeof(buf)), 00224 cbq->cbq_fopt.defmap); 00225 00226 dp_dump(p, "police %s", 00227 nl_police2str(cbq->cbq_police.police, buf, sizeof(buf))); 00228 00229 ignore: 00230 return line; 00231 } 00232 00233 static int cbq_qdisc_dump_full(struct rtnl_qdisc *qdisc, 00234 struct nl_dump_params *p, int line) 00235 { 00236 return cbq_dump_full((struct rtnl_tca *) qdisc, p, line); 00237 } 00238 00239 static int cbq_class_dump_full(struct rtnl_class *class, 00240 struct nl_dump_params *p, int line) 00241 { 00242 return cbq_dump_full((struct rtnl_tca *) class, p, line); 00243 } 00244 00245 static int cbq_dump_with_stats(struct rtnl_tca *tca, struct nl_dump_params *p, 00246 int line) 00247 { 00248 struct tc_cbq_xstats *x = tca_xstats(tca); 00249 00250 if (!x) 00251 goto ignore; 00252 00253 dp_dump_line(p, line++, " borrows overact " 00254 " avgidle undertime\n"); 00255 dp_dump_line(p, line++, " %10u %10u %10u %10u\n", 00256 x->borrows, x->overactions, x->avgidle, x->undertime); 00257 00258 ignore: 00259 return line; 00260 } 00261 00262 static int cbq_qdisc_dump_with_stats(struct rtnl_qdisc *qdisc, 00263 struct nl_dump_params *p, int line) 00264 { 00265 return cbq_dump_with_stats((struct rtnl_tca *) qdisc, p, line); 00266 } 00267 00268 static int cbq_class_dump_with_stats(struct rtnl_class *class, 00269 struct nl_dump_params *p, int line) 00270 { 00271 return cbq_dump_with_stats((struct rtnl_tca *) class, p, line); 00272 } 00273 00274 static struct rtnl_qdisc_ops cbq_qdisc_ops = { 00275 .qo_kind = "cbq", 00276 .qo_msg_parser = cbq_qdisc_msg_parser, 00277 .qo_free_data = cbq_qdisc_free_data, 00278 .qo_clone = cbq_qdisc_clone, 00279 .qo_dump[NL_DUMP_BRIEF] = cbq_qdisc_dump_brief, 00280 .qo_dump[NL_DUMP_FULL] = cbq_qdisc_dump_full, 00281 .qo_dump[NL_DUMP_STATS] = cbq_qdisc_dump_with_stats, 00282 }; 00283 00284 static struct rtnl_class_ops cbq_class_ops = { 00285 .co_kind = "cbq", 00286 .co_msg_parser = cbq_class_msg_parser, 00287 .co_free_data = cbq_class_free_data, 00288 .co_clone = cbq_class_clone, 00289 .co_dump[NL_DUMP_BRIEF] = cbq_class_dump_brief, 00290 .co_dump[NL_DUMP_FULL] = cbq_class_dump_full, 00291 .co_dump[NL_DUMP_STATS] = cbq_class_dump_with_stats, 00292 }; 00293 00294 static void __init cbq_init(void) 00295 { 00296 rtnl_qdisc_register(&cbq_qdisc_ops); 00297 rtnl_class_register(&cbq_class_ops); 00298 } 00299 00300 static void __exit cbq_exit(void) 00301 { 00302 rtnl_qdisc_unregister(&cbq_qdisc_ops); 00303 rtnl_class_unregister(&cbq_class_ops); 00304 } 00305 00306 /** @} */