Home | History | Annotate | Download | only in sch
      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 (at) 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 
     31 static 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  */
     49 char *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  */
     62 int nl_str2ovl_strategy(const char *name)
     63 {
     64 	return __str2type(name, ovl_strategies, ARRAY_SIZE(ovl_strategies));
     65 }
     66 
     67 static 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 
     76 static inline struct rtnl_cbq *cbq_qdisc(struct rtnl_tca *tca)
     77 {
     78 	return (struct rtnl_cbq *) tca->tc_subdata;
     79 }
     80 
     81 static 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 
     90 static 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 
    116 static int cbq_qdisc_msg_parser(struct rtnl_qdisc *qdisc)
    117 {
    118 	return cbq_msg_parser((struct rtnl_tca *) qdisc);
    119 }
    120 
    121 static int cbq_class_msg_parser(struct rtnl_class *class)
    122 {
    123 	return cbq_msg_parser((struct rtnl_tca *) class);
    124 }
    125 
    126 static void cbq_qdisc_free_data(struct rtnl_qdisc *qdisc)
    127 {
    128 	free(qdisc->q_subdata);
    129 }
    130 
    131 static 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 
    141 static 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 
    146 static void cbq_class_free_data(struct rtnl_class *class)
    147 {
    148 	free(class->c_subdata);
    149 }
    150 
    151 static 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 
    156 static 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 
    173 static 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 
    179 static 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 
    185 static 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 
    225 static 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 
    231 static 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 
    237 static 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 
    250 static 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 
    256 static 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 
    262 static 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 
    274 static 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 
    286 static void __init cbq_init(void)
    287 {
    288 	rtnl_qdisc_register(&cbq_qdisc_ops);
    289 	rtnl_class_register(&cbq_class_ops);
    290 }
    291 
    292 static void __exit cbq_exit(void)
    293 {
    294 	rtnl_qdisc_unregister(&cbq_qdisc_ops);
    295 	rtnl_class_unregister(&cbq_class_ops);
    296 }
    297 
    298 /** @} */
    299