Home | History | Annotate | Download | only in qdisc
      1 /*
      2  * lib/route/qdisc/fq_codel.c		fq_codel
      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) 2013 Cong Wang <xiyou.wangcong (at) gmail.com>
     10  */
     11 
     12 /**
     13  * @ingroup qdisc
     14  * @defgroup qdisc_fq_codel Fair Queue CoDel
     15  * @brief
     16  *
     17  * @{
     18  */
     19 
     20 #include <netlink-private/netlink.h>
     21 #include <netlink-private/tc.h>
     22 #include <netlink/netlink.h>
     23 #include <netlink-private/route/tc-api.h>
     24 #include <netlink/route/qdisc.h>
     25 #include <netlink/route/qdisc/fq_codel.h>
     26 #include <netlink/utils.h>
     27 
     28 /** @cond SKIP */
     29 #define SCH_FQ_CODEL_ATTR_TARGET	0x1
     30 #define SCH_FQ_CODEL_ATTR_LIMIT		0x2
     31 #define SCH_FQ_CODEL_ATTR_INTERVAL	0x4
     32 #define SCH_FQ_CODEL_ATTR_FLOWS		0x8
     33 #define SCH_FQ_CODEL_ATTR_QUANTUM	0x10
     34 #define SCH_FQ_CODEL_ATTR_ECN		0x20
     35 /** @endcond */
     36 
     37 static struct nla_policy fq_codel_policy[TCA_FQ_CODEL_MAX + 1] = {
     38 	[TCA_FQ_CODEL_TARGET]   = { .type = NLA_U32 },
     39 	[TCA_FQ_CODEL_LIMIT]    = { .type = NLA_U32 },
     40 	[TCA_FQ_CODEL_INTERVAL] = { .type = NLA_U32 },
     41 	[TCA_FQ_CODEL_ECN]      = { .type = NLA_U32 },
     42 	[TCA_FQ_CODEL_FLOWS]    = { .type = NLA_U32 },
     43 	[TCA_FQ_CODEL_QUANTUM]  = { .type = NLA_U32 },
     44 };
     45 
     46 static int fq_codel_msg_parser(struct rtnl_tc *tc, void *data)
     47 {
     48 	struct rtnl_fq_codel *fq_codel = data;
     49 	struct nlattr *tb[TCA_FQ_CODEL_MAX + 1];
     50 	int err;
     51 
     52 	err = tca_parse(tb, TCA_FQ_CODEL_MAX, tc, fq_codel_policy);
     53 	if (err < 0)
     54 		return err;
     55 
     56 	if (tb[TCA_FQ_CODEL_TARGET]) {
     57 		fq_codel->fq_target =  nla_get_u32(tb[TCA_FQ_CODEL_TARGET]);
     58 		fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_TARGET;
     59 	}
     60 
     61 	if (tb[TCA_FQ_CODEL_INTERVAL]) {
     62 		fq_codel->fq_interval =  nla_get_u32(tb[TCA_FQ_CODEL_INTERVAL]);
     63 		fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_INTERVAL;
     64 	}
     65 
     66 	if (tb[TCA_FQ_CODEL_LIMIT]) {
     67 		fq_codel->fq_limit =  nla_get_u32(tb[TCA_FQ_CODEL_LIMIT]);
     68 		fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_LIMIT;
     69 	}
     70 
     71 	if (tb[TCA_FQ_CODEL_QUANTUM]) {
     72 		fq_codel->fq_quantum =  nla_get_u32(tb[TCA_FQ_CODEL_QUANTUM]);
     73 		fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_QUANTUM;
     74 	}
     75 
     76 	if (tb[TCA_FQ_CODEL_FLOWS]) {
     77 		fq_codel->fq_flows =  nla_get_u32(tb[TCA_FQ_CODEL_FLOWS]);
     78 		fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_FLOWS;
     79 	}
     80 
     81 	if (tb[TCA_FQ_CODEL_ECN]) {
     82 		fq_codel->fq_ecn =  nla_get_u32(tb[TCA_FQ_CODEL_ECN]);
     83 		fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_ECN;
     84 	}
     85 
     86 	return 0;
     87 }
     88 
     89 static void fq_codel_dump_line(struct rtnl_tc *tc, void *data,
     90 			    struct nl_dump_params *p)
     91 {
     92 	struct rtnl_fq_codel *fq_codel = data;
     93 
     94 	if (!fq_codel)
     95 		return;
     96 
     97 	if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_LIMIT)
     98 		nl_dump(p, " limit %u packets", fq_codel->fq_limit);
     99 	if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_TARGET)
    100 		nl_dump(p, " target %u", fq_codel->fq_target);
    101 	if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_INTERVAL)
    102 		nl_dump(p, " interval %u", fq_codel->fq_interval);
    103 	if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_ECN)
    104 		nl_dump(p, " ecn %u", fq_codel->fq_ecn);
    105 	if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_FLOWS)
    106 		nl_dump(p, " flows %u", fq_codel->fq_flows);
    107 	if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_QUANTUM)
    108 		nl_dump(p, " quantum %u", fq_codel->fq_quantum);
    109 }
    110 
    111 static int fq_codel_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
    112 {
    113 	struct rtnl_fq_codel *fq_codel = data;
    114 
    115 	if (!fq_codel)
    116 		return -NLE_INVAL;
    117 
    118 	if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_LIMIT)
    119 		NLA_PUT_U32(msg, TCA_FQ_CODEL_LIMIT, fq_codel->fq_limit);
    120 	if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_INTERVAL)
    121 		NLA_PUT_U32(msg, TCA_FQ_CODEL_INTERVAL, fq_codel->fq_interval);
    122 	if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_TARGET)
    123 		NLA_PUT_U32(msg, TCA_FQ_CODEL_TARGET, fq_codel->fq_target);
    124 	if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_QUANTUM)
    125 		NLA_PUT_U32(msg, TCA_FQ_CODEL_QUANTUM, fq_codel->fq_quantum);
    126 	if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_FLOWS)
    127 		NLA_PUT_U32(msg, TCA_FQ_CODEL_FLOWS, fq_codel->fq_flows);
    128 	if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_ECN)
    129 		NLA_PUT_U32(msg, TCA_FQ_CODEL_ECN, fq_codel->fq_ecn);
    130 	return 0;
    131 
    132 nla_put_failure:
    133 	return -NLE_MSGSIZE;
    134 
    135 }
    136 
    137 /**
    138  * @name Attribute Modification
    139  * @{
    140  */
    141 
    142 /**
    143  * Set limit of fq_codel qdisc.
    144  * @arg qdisc		fq_codel qdisc to be modified.
    145  * @arg limit		New limit.
    146  * @return 0 on success or a negative error code.
    147  */
    148 int rtnl_qdisc_fq_codel_set_limit(struct rtnl_qdisc *qdisc, int limit)
    149 {
    150 	struct rtnl_fq_codel *fq_codel;
    151 
    152 	if (!(fq_codel = rtnl_tc_data(TC_CAST(qdisc))))
    153 		return -NLE_NOMEM;
    154 
    155 	fq_codel->fq_limit = limit;
    156 	fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_LIMIT;
    157 
    158 	return 0;
    159 }
    160 
    161 /**
    162  * Get limit of a fq_codel qdisc.
    163  * @arg qdisc		fq_codel qdisc.
    164  * @return Numeric limit or a negative error code.
    165  */
    166 int rtnl_qdisc_fq_codel_get_limit(struct rtnl_qdisc *qdisc)
    167 {
    168 	struct rtnl_fq_codel *fq_codel;
    169 
    170 	if (!(fq_codel = rtnl_tc_data(TC_CAST(qdisc))))
    171 		return -NLE_NOMEM;
    172 
    173 	if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_LIMIT)
    174 		return fq_codel->fq_limit;
    175 	else
    176 		return -NLE_NOATTR;
    177 }
    178 
    179 /**
    180  * Set target of fq_codel qdisc.
    181  * @arg qdisc		fq_codel qdisc to be modified.
    182  * @arg target		New target.
    183  * @return 0 on success or a negative error code.
    184  */
    185 int rtnl_qdisc_fq_codel_set_target(struct rtnl_qdisc *qdisc, uint32_t target)
    186 {
    187 	struct rtnl_fq_codel *fq_codel;
    188 
    189 	if (!(fq_codel = rtnl_tc_data(TC_CAST(qdisc))))
    190 		return -NLE_NOMEM;
    191 
    192 	fq_codel->fq_target = target;
    193 	fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_TARGET;
    194 
    195 	return 0;
    196 }
    197 
    198 /**
    199  * Get target of a fq_codel qdisc.
    200  * @arg qdisc		fq_codel qdisc.
    201  * @return Numeric target or zero.
    202  */
    203 uint32_t rtnl_qdisc_fq_codel_get_target(struct rtnl_qdisc *qdisc)
    204 {
    205 	struct rtnl_fq_codel *fq_codel;
    206 
    207 	if ((fq_codel = rtnl_tc_data(TC_CAST(qdisc))) &&
    208 	    fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_TARGET)
    209 		return fq_codel->fq_target;
    210 	else
    211 		return 0;
    212 }
    213 
    214 /**
    215  * Set interval of fq_codel qdisc.
    216  * @arg qdisc		fq_codel qdisc to be modified.
    217  * @arg interval	New interval.
    218  * @return 0 on success or a negative error code.
    219  */
    220 int rtnl_qdisc_fq_codel_set_interval(struct rtnl_qdisc *qdisc, uint32_t interval)
    221 {
    222 	struct rtnl_fq_codel *fq_codel;
    223 
    224 	if (!(fq_codel = rtnl_tc_data(TC_CAST(qdisc))))
    225 		return -NLE_NOMEM;
    226 
    227 	fq_codel->fq_interval = interval;
    228 	fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_INTERVAL;
    229 
    230 	return 0;
    231 }
    232 
    233 /**
    234  * Get target of a fq_codel qdisc.
    235  * @arg qdisc		fq_codel qdisc.
    236  * @return Numeric interval or zero.
    237  */
    238 uint32_t rtnl_qdisc_fq_codel_get_interval(struct rtnl_qdisc *qdisc)
    239 {
    240 	struct rtnl_fq_codel *fq_codel;
    241 
    242 	if ((fq_codel = rtnl_tc_data(TC_CAST(qdisc))) &&
    243 	     fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_INTERVAL)
    244 		return fq_codel->fq_interval;
    245 	else
    246 		return 0;
    247 }
    248 
    249 /**
    250  * Set quantum of fq_codel qdisc.
    251  * @arg qdisc		fq_codel qdisc to be modified.
    252  * @arg quantum		New quantum.
    253  * @return 0 on success or a negative error code.
    254  */
    255 int rtnl_qdisc_fq_codel_set_quantum(struct rtnl_qdisc *qdisc, uint32_t quantum)
    256 {
    257 	struct rtnl_fq_codel *fq_codel;
    258 
    259 	if (!(fq_codel = rtnl_tc_data(TC_CAST(qdisc))))
    260 		return -NLE_NOMEM;
    261 
    262 	fq_codel->fq_quantum = quantum;
    263 	fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_QUANTUM;
    264 
    265 	return 0;
    266 }
    267 
    268 /**
    269  * Get quantum of a fq_codel qdisc.
    270  * @arg qdisc		fq_codel qdisc.
    271  * @return Numeric quantum or zero.
    272  */
    273 uint32_t rtnl_qdisc_fq_codel_get_quantum(struct rtnl_qdisc *qdisc)
    274 {
    275 	struct rtnl_fq_codel *fq_codel;
    276 
    277 	if ((fq_codel = rtnl_tc_data(TC_CAST(qdisc))) &&
    278 	    (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_QUANTUM))
    279 		return fq_codel->fq_quantum;
    280 	else
    281 		return 0;
    282 }
    283 
    284 /**
    285  * Set flows of fq_codel qdisc.
    286  * @arg qdisc		fq_codel qdisc to be modified.
    287  * @arg flows		New flows value.
    288  * @return 0 on success or a negative error code.
    289  */
    290 int rtnl_qdisc_fq_codel_set_flows(struct rtnl_qdisc *qdisc, int flows)
    291 {
    292 	struct rtnl_fq_codel *fq_codel;
    293 
    294 	if (!(fq_codel = rtnl_tc_data(TC_CAST(qdisc))))
    295 		return -NLE_NOMEM;
    296 
    297 	fq_codel->fq_flows = flows;
    298 	fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_FLOWS;
    299 
    300 	return 0;
    301 }
    302 
    303 /**
    304  * Get flows of a fq_codel qdisc.
    305  * @arg qdisc		fq_codel qdisc.
    306  * @return Numeric flows or a negative error code.
    307  */
    308 int rtnl_qdisc_fq_codel_get_flows(struct rtnl_qdisc *qdisc)
    309 {
    310 	struct rtnl_fq_codel *fq_codel;
    311 
    312 	if (!(fq_codel = rtnl_tc_data(TC_CAST(qdisc))))
    313 		return -NLE_NOMEM;
    314 
    315 	if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_FLOWS)
    316 		return fq_codel->fq_flows;
    317 	else
    318 		return -NLE_NOATTR;
    319 }
    320 /**
    321  * Set ecn of fq_codel qdisc.
    322  * @arg qdisc		fq_codel qdisc to be modified.
    323  * @arg ecn		New ecn value.
    324  * @return 0 on success or a negative error code.
    325  */
    326 int rtnl_qdisc_fq_codel_set_ecn(struct rtnl_qdisc *qdisc, int ecn)
    327 {
    328 	struct rtnl_fq_codel *fq_codel;
    329 
    330 	if (!(fq_codel = rtnl_tc_data(TC_CAST(qdisc))))
    331 		return -NLE_NOMEM;
    332 
    333 	fq_codel->fq_ecn = ecn;
    334 	fq_codel->fq_mask |= SCH_FQ_CODEL_ATTR_ECN;
    335 
    336 	return 0;
    337 }
    338 
    339 /**
    340  * Get ecn of a fq_codel qdisc.
    341  * @arg qdisc		fq_codel qdisc.
    342  * @return Numeric ecn or a negative error code.
    343  */
    344 int rtnl_qdisc_fq_codel_get_ecn(struct rtnl_qdisc *qdisc)
    345 {
    346 	struct rtnl_fq_codel *fq_codel;
    347 
    348 	if (!(fq_codel = rtnl_tc_data(TC_CAST(qdisc))))
    349 		return -NLE_NOMEM;
    350 
    351 	if (fq_codel->fq_mask & SCH_FQ_CODEL_ATTR_ECN)
    352 		return fq_codel->fq_ecn;
    353 	else
    354 		return -NLE_NOATTR;
    355 }
    356 /** @} */
    357 
    358 static struct rtnl_tc_ops fq_codel_ops = {
    359 	.to_kind		= "fq_codel",
    360 	.to_type		= RTNL_TC_TYPE_QDISC,
    361 	.to_size		= sizeof(struct rtnl_fq_codel),
    362 	.to_msg_parser		= fq_codel_msg_parser,
    363 	.to_dump[NL_DUMP_LINE]	= fq_codel_dump_line,
    364 	.to_msg_fill		= fq_codel_msg_fill,
    365 };
    366 
    367 static void __init fq_codel_init(void)
    368 {
    369 	rtnl_tc_register(&fq_codel_ops);
    370 }
    371 
    372 static void __exit fq_codel_exit(void)
    373 {
    374 	rtnl_tc_unregister(&fq_codel_ops);
    375 }
    376 
    377 /** @} */
    378