Home | History | Annotate | Download | only in sch
      1 /*
      2  * lib/route/sch/sfq.c		SFQ Qdisc
      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 /**
     13  * @ingroup qdisc_api
     14  * @defgroup sfq Stochastic Fairness Queueing (SFQ)
     15  * @brief
     16  *
     17  * @par Parameter Description
     18  * - \b Quantum: Number of bytes to send out per slot and round.
     19  * - \b Perturbation: Timer period between changing the hash function.
     20  * - \b Limit:  Upper limit of queue in number of packets before SFQ starts
     21  *	        dropping packets.
     22  * - \b Divisor: Hash table divisor, i.e. size of hash table.
     23  * @{
     24  */
     25 
     26 #include <netlink-local.h>
     27 #include <netlink-tc.h>
     28 #include <netlink/netlink.h>
     29 #include <netlink/utils.h>
     30 #include <netlink/route/qdisc.h>
     31 #include <netlink/route/qdisc-modules.h>
     32 #include <netlink/route/sch/sfq.h>
     33 
     34 /** @cond SKIP */
     35 #define SCH_SFQ_ATTR_QUANTUM	0x01
     36 #define SCH_SFQ_ATTR_PERTURB	0x02
     37 #define SCH_SFQ_ATTR_LIMIT	0x04
     38 #define SCH_SFQ_ATTR_DIVISOR	0x08
     39 #define SCH_SFQ_ATTR_FLOWS	0x10
     40 /** @endcond */
     41 
     42 static inline struct rtnl_sfq *sfq_qdisc(struct rtnl_qdisc *qdisc)
     43 {
     44 	return (struct rtnl_sfq *) qdisc->q_subdata;
     45 }
     46 
     47 static inline struct rtnl_sfq *sfq_alloc(struct rtnl_qdisc *qdisc)
     48 {
     49 	if (!qdisc->q_subdata)
     50 		qdisc->q_subdata = calloc(1, sizeof(struct rtnl_sfq));
     51 
     52 	return sfq_qdisc(qdisc);
     53 }
     54 
     55 static int sfq_msg_parser(struct rtnl_qdisc *qdisc)
     56 {
     57 	struct rtnl_sfq *sfq;
     58 	struct tc_sfq_qopt *opts;
     59 
     60 	if (!(qdisc->ce_mask & TCA_ATTR_OPTS))
     61 		return 0;
     62 
     63 	if (qdisc->q_opts->d_size < sizeof(*opts))
     64 		return -NLE_INVAL;
     65 
     66 	sfq = sfq_alloc(qdisc);
     67 	if (!sfq)
     68 		return -NLE_NOMEM;
     69 
     70 	opts = (struct tc_sfq_qopt *) qdisc->q_opts->d_data;
     71 
     72 	sfq->qs_quantum = opts->quantum;
     73 	sfq->qs_perturb = opts->perturb_period;
     74 	sfq->qs_limit = opts->limit;
     75 	sfq->qs_divisor = opts->divisor;
     76 	sfq->qs_flows = opts->flows;
     77 
     78 	sfq->qs_mask = (SCH_SFQ_ATTR_QUANTUM | SCH_SFQ_ATTR_PERTURB |
     79 			SCH_SFQ_ATTR_LIMIT | SCH_SFQ_ATTR_DIVISOR |
     80 			SCH_SFQ_ATTR_FLOWS);
     81 
     82 	return 0;
     83 }
     84 
     85 static void sfq_free_data(struct rtnl_qdisc *qdisc)
     86 {
     87 	free(qdisc->q_subdata);
     88 }
     89 
     90 static void sfq_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p)
     91 {
     92 	struct rtnl_sfq *sfq = sfq_qdisc(qdisc);
     93 
     94 	if (sfq)
     95 		nl_dump(p, " quantum %u perturb %us", sfq->qs_quantum,
     96 			nl_ticks2us(sfq->qs_perturb * nl_get_hz()));
     97 }
     98 
     99 static void sfq_dump_details(struct rtnl_qdisc *qdisc, struct nl_dump_params *p)
    100 {
    101 	struct rtnl_sfq *sfq = sfq_qdisc(qdisc);
    102 
    103 	if (sfq)
    104 		nl_dump(p, "limit %u divisor %u",
    105 			sfq->qs_limit, sfq->qs_divisor);
    106 }
    107 
    108 static struct nl_msg *sfq_get_opts(struct rtnl_qdisc *qdisc)
    109 {
    110 	struct rtnl_sfq *sfq;
    111 	struct tc_sfq_qopt opts;
    112 	struct nl_msg *msg;
    113 
    114 	sfq = sfq_qdisc(qdisc);
    115 	if (!sfq)
    116 		return NULL;
    117 
    118 	msg = nlmsg_alloc();
    119 	if (!msg)
    120 		goto errout;
    121 
    122 	memset(&opts, 0, sizeof(opts));
    123 	opts.quantum = sfq->qs_quantum;
    124 	opts.perturb_period = sfq->qs_perturb;
    125 	opts.limit = sfq->qs_limit;
    126 
    127 	if (nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD) < 0)
    128 		goto errout;
    129 
    130 	return msg;
    131 errout:
    132 	nlmsg_free(msg);
    133 	return NULL;
    134 }
    135 
    136 /**
    137  * @name Attribute Access
    138  * @{
    139  */
    140 
    141 /**
    142  * Set quantum of SFQ qdisc.
    143  * @arg qdisc		SFQ qdisc to be modified.
    144  * @arg quantum		New quantum in bytes.
    145  * @return 0 on success or a negative error code.
    146  */
    147 int rtnl_sfq_set_quantum(struct rtnl_qdisc *qdisc, int quantum)
    148 {
    149 	struct rtnl_sfq *sfq;
    150 
    151 	sfq = sfq_alloc(qdisc);
    152 	if (!sfq)
    153 		return -NLE_NOMEM;
    154 
    155 	sfq->qs_quantum = quantum;
    156 	sfq->qs_mask |= SCH_SFQ_ATTR_QUANTUM;
    157 
    158 	return 0;
    159 }
    160 
    161 /**
    162  * Get quantum of SFQ qdisc.
    163  * @arg qdisc		SFQ qdisc.
    164  * @return Quantum in bytes or a negative error code.
    165  */
    166 int rtnl_sfq_get_quantum(struct rtnl_qdisc *qdisc)
    167 {
    168 	struct rtnl_sfq *sfq;
    169 
    170 	sfq = sfq_qdisc(qdisc);
    171 	if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_QUANTUM)
    172 		return sfq->qs_quantum;
    173 	else
    174 		return -NLE_NOATTR;
    175 }
    176 
    177 /**
    178  * Set limit of SFQ qdisc.
    179  * @arg qdisc		SFQ qdisc to be modified.
    180  * @arg limit		New limit in number of packets.
    181  * @return 0 on success or a negative error code.
    182  */
    183 int rtnl_sfq_set_limit(struct rtnl_qdisc *qdisc, int limit)
    184 {
    185 	struct rtnl_sfq *sfq;
    186 
    187 	sfq = sfq_alloc(qdisc);
    188 	if (!sfq)
    189 		return -NLE_NOMEM;
    190 
    191 	sfq->qs_limit = limit;
    192 	sfq->qs_mask |= SCH_SFQ_ATTR_LIMIT;
    193 
    194 	return 0;
    195 }
    196 
    197 /**
    198  * Get limit of SFQ qdisc.
    199  * @arg qdisc		SFQ qdisc.
    200  * @return Limit or a negative error code.
    201  */
    202 int rtnl_sfq_get_limit(struct rtnl_qdisc *qdisc)
    203 {
    204 	struct rtnl_sfq *sfq;
    205 
    206 	sfq = sfq_qdisc(qdisc);
    207 	if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_LIMIT)
    208 		return sfq->qs_limit;
    209 	else
    210 		return -NLE_NOATTR;
    211 }
    212 
    213 /**
    214  * Set perturbation interval of SFQ qdisc.
    215  * @arg qdisc		SFQ qdisc to be modified.
    216  * @arg perturb		New perturbation interval in seconds.
    217  * @note A value of 0 disables perturbation altogether.
    218  * @return 0 on success or a negative error code.
    219  */
    220 int rtnl_sfq_set_perturb(struct rtnl_qdisc *qdisc, int perturb)
    221 {
    222 	struct rtnl_sfq *sfq;
    223 
    224 	sfq = sfq_alloc(qdisc);
    225 	if (!sfq)
    226 		return -NLE_NOMEM;
    227 
    228 	sfq->qs_perturb = perturb;
    229 	sfq->qs_mask |= SCH_SFQ_ATTR_PERTURB;
    230 
    231 	return 0;
    232 }
    233 
    234 /**
    235  * Get perturbation interval of SFQ qdisc.
    236  * @arg qdisc		SFQ qdisc.
    237  * @return Perturbation interval in seconds or a negative error code.
    238  */
    239 int rtnl_sfq_get_perturb(struct rtnl_qdisc *qdisc)
    240 {
    241 	struct rtnl_sfq *sfq;
    242 
    243 	sfq = sfq_qdisc(qdisc);
    244 	if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_PERTURB)
    245 		return sfq->qs_perturb;
    246 	else
    247 		return -NLE_NOATTR;
    248 }
    249 
    250 /**
    251  * Get divisor of SFQ qdisc.
    252  * @arg qdisc		SFQ qdisc.
    253  * @return Divisor in number of entries or a negative error code.
    254  */
    255 int rtnl_sfq_get_divisor(struct rtnl_qdisc *qdisc)
    256 {
    257 	struct rtnl_sfq *sfq;
    258 
    259 	sfq = sfq_qdisc(qdisc);
    260 	if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_DIVISOR)
    261 		return sfq->qs_divisor;
    262 	else
    263 		return -NLE_NOATTR;
    264 }
    265 
    266 /** @} */
    267 
    268 static struct rtnl_qdisc_ops sfq_ops = {
    269 	.qo_kind		= "sfq",
    270 	.qo_msg_parser		= sfq_msg_parser,
    271 	.qo_free_data		= sfq_free_data,
    272 	.qo_dump = {
    273 	    [NL_DUMP_LINE]	= sfq_dump_line,
    274 	    [NL_DUMP_DETAILS]	= sfq_dump_details,
    275 	},
    276 	.qo_get_opts		= sfq_get_opts,
    277 };
    278 
    279 static void __init sfq_init(void)
    280 {
    281 	rtnl_qdisc_register(&sfq_ops);
    282 }
    283 
    284 static void __exit sfq_exit(void)
    285 {
    286 	rtnl_qdisc_unregister(&sfq_ops);
    287 }
    288 
    289 /** @} */
    290