Home | History | Annotate | Download | only in sch
      1 /*
      2  * lib/route/sch/red.c		RED 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 red Random Early Detection (RED)
     15  * @brief
     16  * @{
     17  */
     18 
     19 #include <netlink-local.h>
     20 #include <netlink-tc.h>
     21 #include <netlink/netlink.h>
     22 #include <netlink/utils.h>
     23 #include <netlink/route/qdisc.h>
     24 #include <netlink/route/qdisc-modules.h>
     25 #include <netlink/route/sch/red.h>
     26 
     27 /** @cond SKIP */
     28 #define RED_ATTR_LIMIT		0x01
     29 #define RED_ATTR_QTH_MIN	0x02
     30 #define RED_ATTR_QTH_MAX	0x04
     31 #define RED_ATTR_FLAGS		0x08
     32 #define RED_ATTR_WLOG		0x10
     33 #define RED_ATTR_PLOG		0x20
     34 #define RED_ATTR_SCELL_LOG	0x40
     35 /** @endcond */
     36 
     37 static inline struct rtnl_red *red_qdisc(struct rtnl_qdisc *qdisc)
     38 {
     39 	return (struct rtnl_red *) qdisc->q_subdata;
     40 }
     41 
     42 static inline struct rtnl_red *red_alloc(struct rtnl_qdisc *qdisc)
     43 {
     44 	if (!qdisc->q_subdata)
     45 		qdisc->q_subdata = calloc(1, sizeof(struct rtnl_red));
     46 
     47 	return red_qdisc(qdisc);
     48 }
     49 
     50 static struct nla_policy red_policy[TCA_RED_MAX+1] = {
     51 	[TCA_RED_PARMS]		= { .minlen = sizeof(struct tc_red_qopt) },
     52 };
     53 
     54 static int red_msg_parser(struct rtnl_qdisc *qdisc)
     55 {
     56 	struct nlattr *tb[TCA_RED_MAX+1];
     57 	struct rtnl_red *red;
     58 	struct tc_red_qopt *opts;
     59 	int err;
     60 
     61 	if (!(qdisc->ce_mask & TCA_ATTR_OPTS))
     62 		return 0;
     63 
     64 	err = tca_parse(tb, TCA_RED_MAX, (struct rtnl_tca *) qdisc, red_policy);
     65 	if (err < 0)
     66 		return err;
     67 
     68 	if (!tb[TCA_RED_PARMS])
     69 		return -NLE_MISSING_ATTR;
     70 
     71 	red = red_alloc(qdisc);
     72 	if (!red)
     73 		return -NLE_NOMEM;
     74 
     75 	opts = nla_data(tb[TCA_RED_PARMS]);
     76 
     77 	red->qr_limit = opts->limit;
     78 	red->qr_qth_min = opts->qth_min;
     79 	red->qr_qth_max = opts->qth_max;
     80 	red->qr_flags = opts->flags;
     81 	red->qr_wlog = opts->Wlog;
     82 	red->qr_plog = opts->Plog;
     83 	red->qr_scell_log = opts->Scell_log;
     84 
     85 	red->qr_mask = (RED_ATTR_LIMIT | RED_ATTR_QTH_MIN | RED_ATTR_QTH_MAX |
     86 			RED_ATTR_FLAGS | RED_ATTR_WLOG | RED_ATTR_PLOG |
     87 			RED_ATTR_SCELL_LOG);
     88 
     89 	return 0;
     90 }
     91 
     92 static void red_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p)
     93 {
     94 	struct rtnl_red *red = red_qdisc(qdisc);
     95 
     96 	if (red) {
     97 		/* XXX: limit, min, max, flags */
     98 	}
     99 }
    100 
    101 static void red_dump_details(struct rtnl_qdisc *qdisc, struct nl_dump_params *p)
    102 {
    103 	struct rtnl_red *red = red_qdisc(qdisc);
    104 
    105 	if (red) {
    106 		/* XXX: wlog, plog, scell_log */
    107 	}
    108 }
    109 
    110 static void red_dump_stats(struct rtnl_qdisc *qdisc, struct nl_dump_params *p)
    111 {
    112 	struct rtnl_red *red = red_qdisc(qdisc);
    113 
    114 	if (red) {
    115 		/* XXX: xstats */
    116 	}
    117 }
    118 
    119 static struct nl_msg *red_get_opts(struct rtnl_qdisc *qdisc)
    120 {
    121 	struct rtnl_red *red;
    122 	struct nl_msg *msg;
    123 
    124 	red = red_qdisc(qdisc);
    125 	if (!red)
    126 		return NULL;
    127 
    128 	msg = nlmsg_alloc();
    129 	if (!msg)
    130 		goto errout;
    131 
    132 #if 0
    133 	memset(&opts, 0, sizeof(opts));
    134 	opts.quantum = sfq->qs_quantum;
    135 	opts.perturb_period = sfq->qs_perturb;
    136 	opts.limit = sfq->qs_limit;
    137 
    138 	if (nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD) < 0)
    139 		goto errout;
    140 #endif
    141 
    142 	return msg;
    143 errout:
    144 	nlmsg_free(msg);
    145 	return NULL;
    146 }
    147 
    148 /**
    149  * @name Attribute Access
    150  * @{
    151  */
    152 
    153 /**
    154  * Set limit of RED qdisc.
    155  * @arg qdisc		RED qdisc to be modified.
    156  * @arg limit		New limit in number of packets.
    157  * @return 0 on success or a negative error code.
    158  */
    159 int rtnl_red_set_limit(struct rtnl_qdisc *qdisc, int limit)
    160 {
    161 	struct rtnl_red *red;
    162 
    163 	red = red_alloc(qdisc);
    164 	if (!red)
    165 		return -NLE_NOMEM;
    166 
    167 	red->qr_limit = limit;
    168 	red->qr_mask |= RED_ATTR_LIMIT;
    169 
    170 	return 0;
    171 }
    172 
    173 /**
    174  * Get limit of RED qdisc.
    175  * @arg qdisc		RED qdisc.
    176  * @return Limit or a negative error code.
    177  */
    178 int rtnl_red_get_limit(struct rtnl_qdisc *qdisc)
    179 {
    180 	struct rtnl_red *red;
    181 
    182 	red = red_qdisc(qdisc);
    183 	if (red && (red->qr_mask & RED_ATTR_LIMIT))
    184 		return red->qr_limit;
    185 	else
    186 		return -NLE_NOATTR;
    187 }
    188 
    189 /** @} */
    190 
    191 static struct rtnl_qdisc_ops red_ops = {
    192 	.qo_kind		= "red",
    193 	.qo_msg_parser		= red_msg_parser,
    194 	.qo_dump = {
    195 	    [NL_DUMP_LINE]	= red_dump_line,
    196 	    [NL_DUMP_DETAILS]	= red_dump_details,
    197 	    [NL_DUMP_STATS]	= red_dump_stats,
    198 	},
    199 	.qo_get_opts		= red_get_opts,
    200 };
    201 
    202 static void __init red_init(void)
    203 {
    204 	rtnl_qdisc_register(&red_ops);
    205 }
    206 
    207 static void __exit red_exit(void)
    208 {
    209 	rtnl_qdisc_unregister(&red_ops);
    210 }
    211 
    212 /** @} */
    213