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@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
37static inline struct rtnl_red *red_qdisc(struct rtnl_qdisc *qdisc)
38{
39	return (struct rtnl_red *) qdisc->q_subdata;
40}
41
42static 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
50static struct nla_policy red_policy[TCA_RED_MAX+1] = {
51	[TCA_RED_PARMS]		= { .minlen = sizeof(struct tc_red_qopt) },
52};
53
54static 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
92static 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
101static 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
110static 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
119static 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;
143errout:
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 */
159int 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 */
178int 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
191static 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
202static void __init red_init(void)
203{
204	rtnl_qdisc_register(&red_ops);
205}
206
207static void __exit red_exit(void)
208{
209	rtnl_qdisc_unregister(&red_ops);
210}
211
212/** @} */
213