Home | History | Annotate | Download | only in qdisc
      1 /*
      2  * lib/route/qdisc/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-2011 Thomas Graf <tgraf (at) suug.ch>
     10  */
     11 
     12 /**
     13  * @ingroup qdisc
     14  * @defgroup qdisc_red Random Early Detection (RED)
     15  * @brief
     16  * @{
     17  */
     18 
     19 #include <netlink-private/netlink.h>
     20 #include <netlink-private/tc.h>
     21 #include <netlink/netlink.h>
     22 #include <netlink/utils.h>
     23 #include <netlink-private/route/tc-api.h>
     24 #include <netlink/route/qdisc.h>
     25 #include <netlink/route/qdisc/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 struct nla_policy red_policy[TCA_RED_MAX+1] = {
     38 	[TCA_RED_PARMS]		= { .minlen = sizeof(struct tc_red_qopt) },
     39 };
     40 
     41 static int red_msg_parser(struct rtnl_tc *tc, void *data)
     42 {
     43 	struct nlattr *tb[TCA_RED_MAX+1];
     44 	struct rtnl_red *red = data;
     45 	struct tc_red_qopt *opts;
     46 	int err;
     47 
     48 	if (!(tc->ce_mask & TCA_ATTR_OPTS))
     49 		return 0;
     50 
     51 	err = tca_parse(tb, TCA_RED_MAX, tc, red_policy);
     52 	if (err < 0)
     53 		return err;
     54 
     55 	if (!tb[TCA_RED_PARMS])
     56 		return -NLE_MISSING_ATTR;
     57 
     58 	opts = nla_data(tb[TCA_RED_PARMS]);
     59 
     60 	red->qr_limit = opts->limit;
     61 	red->qr_qth_min = opts->qth_min;
     62 	red->qr_qth_max = opts->qth_max;
     63 	red->qr_flags = opts->flags;
     64 	red->qr_wlog = opts->Wlog;
     65 	red->qr_plog = opts->Plog;
     66 	red->qr_scell_log = opts->Scell_log;
     67 
     68 	red->qr_mask = (RED_ATTR_LIMIT | RED_ATTR_QTH_MIN | RED_ATTR_QTH_MAX |
     69 			RED_ATTR_FLAGS | RED_ATTR_WLOG | RED_ATTR_PLOG |
     70 			RED_ATTR_SCELL_LOG);
     71 
     72 	return 0;
     73 }
     74 
     75 static void red_dump_line(struct rtnl_tc *tc, void *data,
     76 			  struct nl_dump_params *p)
     77 {
     78 	struct rtnl_red *red = data;
     79 
     80 	if (red) {
     81 		/* XXX: limit, min, max, flags */
     82 	}
     83 }
     84 
     85 static void red_dump_details(struct rtnl_tc *tc, void *data,
     86 			     struct nl_dump_params *p)
     87 {
     88 	struct rtnl_red *red = data;
     89 
     90 	if (red) {
     91 		/* XXX: wlog, plog, scell_log */
     92 	}
     93 }
     94 
     95 static void red_dump_stats(struct rtnl_tc *tc, void *data,
     96 			   struct nl_dump_params *p)
     97 {
     98 	struct rtnl_red *red = data;
     99 
    100 	if (red) {
    101 		/* XXX: xstats */
    102 	}
    103 }
    104 
    105 static int red_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
    106 {
    107 	struct rtnl_red *red = data;
    108 
    109 	if (!red)
    110 		BUG();
    111 
    112 #if 0
    113 	memset(&opts, 0, sizeof(opts));
    114 	opts.quantum = sfq->qs_quantum;
    115 	opts.perturb_period = sfq->qs_perturb;
    116 	opts.limit = sfq->qs_limit;
    117 
    118 	if (nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD) < 0)
    119 		goto errout;
    120 #endif
    121 
    122 	return -NLE_OPNOTSUPP;
    123 }
    124 
    125 /**
    126  * @name Attribute Access
    127  * @{
    128  */
    129 
    130 /**
    131  * Set limit of RED qdisc.
    132  * @arg qdisc		RED qdisc to be modified.
    133  * @arg limit		New limit in number of packets.
    134  * @return 0 on success or a negative error code.
    135  */
    136 void rtnl_red_set_limit(struct rtnl_qdisc *qdisc, int limit)
    137 {
    138 	struct rtnl_red *red;
    139 
    140 	if (!(red = rtnl_tc_data(TC_CAST(qdisc))))
    141 		BUG();
    142 
    143 	red->qr_limit = limit;
    144 	red->qr_mask |= RED_ATTR_LIMIT;
    145 }
    146 
    147 /**
    148  * Get limit of RED qdisc.
    149  * @arg qdisc		RED qdisc.
    150  * @return Limit or a negative error code.
    151  */
    152 int rtnl_red_get_limit(struct rtnl_qdisc *qdisc)
    153 {
    154 	struct rtnl_red *red;
    155 
    156 	if (!(red = rtnl_tc_data(TC_CAST(qdisc))))
    157 		BUG();
    158 
    159 	if (red->qr_mask & RED_ATTR_LIMIT)
    160 		return red->qr_limit;
    161 	else
    162 		return -NLE_NOATTR;
    163 }
    164 
    165 /** @} */
    166 
    167 static struct rtnl_tc_ops red_ops = {
    168 	.to_kind		= "red",
    169 	.to_type		= RTNL_TC_TYPE_QDISC,
    170 	.to_size		= sizeof(struct rtnl_red),
    171 	.to_msg_parser		= red_msg_parser,
    172 	.to_dump = {
    173 	    [NL_DUMP_LINE]	= red_dump_line,
    174 	    [NL_DUMP_DETAILS]	= red_dump_details,
    175 	    [NL_DUMP_STATS]	= red_dump_stats,
    176 	},
    177 	.to_msg_fill		= red_msg_fill,
    178 };
    179 
    180 static void __init red_init(void)
    181 {
    182 	rtnl_tc_register(&red_ops);
    183 }
    184 
    185 static void __exit red_exit(void)
    186 {
    187 	rtnl_tc_unregister(&red_ops);
    188 }
    189 
    190 /** @} */
    191