144d362409d5469aed47d19e7908d19bd194493aThomas Graf/*
244d362409d5469aed47d19e7908d19bd194493aThomas Graf * lib/route/sch/red.c		RED Qdisc
344d362409d5469aed47d19e7908d19bd194493aThomas Graf *
444d362409d5469aed47d19e7908d19bd194493aThomas Graf *	This library is free software; you can redistribute it and/or
544d362409d5469aed47d19e7908d19bd194493aThomas Graf *	modify it under the terms of the GNU Lesser General Public
644d362409d5469aed47d19e7908d19bd194493aThomas Graf *	License as published by the Free Software Foundation version 2.1
744d362409d5469aed47d19e7908d19bd194493aThomas Graf *	of the License.
844d362409d5469aed47d19e7908d19bd194493aThomas Graf *
98a3efffa5b3fde252675239914118664d36a2c24Thomas Graf * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
1044d362409d5469aed47d19e7908d19bd194493aThomas Graf */
1144d362409d5469aed47d19e7908d19bd194493aThomas Graf
1244d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
1344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @ingroup qdisc_api
1444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @defgroup red Random Early Detection (RED)
1544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @brief
1644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
1744d362409d5469aed47d19e7908d19bd194493aThomas Graf */
1844d362409d5469aed47d19e7908d19bd194493aThomas Graf
1944d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink-local.h>
2044d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink-tc.h>
2144d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/netlink.h>
2244d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/utils.h>
2344d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/qdisc.h>
2444d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/qdisc-modules.h>
2544d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/sch/red.h>
2644d362409d5469aed47d19e7908d19bd194493aThomas Graf
2744d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @cond SKIP */
2844d362409d5469aed47d19e7908d19bd194493aThomas Graf#define RED_ATTR_LIMIT		0x01
2944d362409d5469aed47d19e7908d19bd194493aThomas Graf#define RED_ATTR_QTH_MIN	0x02
3044d362409d5469aed47d19e7908d19bd194493aThomas Graf#define RED_ATTR_QTH_MAX	0x04
3144d362409d5469aed47d19e7908d19bd194493aThomas Graf#define RED_ATTR_FLAGS		0x08
3244d362409d5469aed47d19e7908d19bd194493aThomas Graf#define RED_ATTR_WLOG		0x10
3344d362409d5469aed47d19e7908d19bd194493aThomas Graf#define RED_ATTR_PLOG		0x20
3444d362409d5469aed47d19e7908d19bd194493aThomas Graf#define RED_ATTR_SCELL_LOG	0x40
3544d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @endcond */
3644d362409d5469aed47d19e7908d19bd194493aThomas Graf
3744d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline struct rtnl_red *red_qdisc(struct rtnl_qdisc *qdisc)
3844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
3944d362409d5469aed47d19e7908d19bd194493aThomas Graf	return (struct rtnl_red *) qdisc->q_subdata;
4044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
4144d362409d5469aed47d19e7908d19bd194493aThomas Graf
4244d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic inline struct rtnl_red *red_alloc(struct rtnl_qdisc *qdisc)
4344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
4444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!qdisc->q_subdata)
4544d362409d5469aed47d19e7908d19bd194493aThomas Graf		qdisc->q_subdata = calloc(1, sizeof(struct rtnl_red));
4644d362409d5469aed47d19e7908d19bd194493aThomas Graf
4744d362409d5469aed47d19e7908d19bd194493aThomas Graf	return red_qdisc(qdisc);
4844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
4944d362409d5469aed47d19e7908d19bd194493aThomas Graf
5044d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nla_policy red_policy[TCA_RED_MAX+1] = {
5144d362409d5469aed47d19e7908d19bd194493aThomas Graf	[TCA_RED_PARMS]		= { .minlen = sizeof(struct tc_red_qopt) },
5244d362409d5469aed47d19e7908d19bd194493aThomas Graf};
5344d362409d5469aed47d19e7908d19bd194493aThomas Graf
5444d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int red_msg_parser(struct rtnl_qdisc *qdisc)
5544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
5644d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nlattr *tb[TCA_RED_MAX+1];
5744d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_red *red;
5844d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct tc_red_qopt *opts;
5944d362409d5469aed47d19e7908d19bd194493aThomas Graf	int err;
6044d362409d5469aed47d19e7908d19bd194493aThomas Graf
6144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!(qdisc->ce_mask & TCA_ATTR_OPTS))
6244d362409d5469aed47d19e7908d19bd194493aThomas Graf		return 0;
6344d362409d5469aed47d19e7908d19bd194493aThomas Graf
6444d362409d5469aed47d19e7908d19bd194493aThomas Graf	err = tca_parse(tb, TCA_RED_MAX, (struct rtnl_tca *) qdisc, red_policy);
6544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (err < 0)
6644d362409d5469aed47d19e7908d19bd194493aThomas Graf		return err;
6744d362409d5469aed47d19e7908d19bd194493aThomas Graf
6844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!tb[TCA_RED_PARMS])
698a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_MISSING_ATTR;
7044d362409d5469aed47d19e7908d19bd194493aThomas Graf
7144d362409d5469aed47d19e7908d19bd194493aThomas Graf	red = red_alloc(qdisc);
7244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!red)
738a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_NOMEM;
7444d362409d5469aed47d19e7908d19bd194493aThomas Graf
7544d362409d5469aed47d19e7908d19bd194493aThomas Graf	opts = nla_data(tb[TCA_RED_PARMS]);
7644d362409d5469aed47d19e7908d19bd194493aThomas Graf
7744d362409d5469aed47d19e7908d19bd194493aThomas Graf	red->qr_limit = opts->limit;
7844d362409d5469aed47d19e7908d19bd194493aThomas Graf	red->qr_qth_min = opts->qth_min;
7944d362409d5469aed47d19e7908d19bd194493aThomas Graf	red->qr_qth_max = opts->qth_max;
8044d362409d5469aed47d19e7908d19bd194493aThomas Graf	red->qr_flags = opts->flags;
8144d362409d5469aed47d19e7908d19bd194493aThomas Graf	red->qr_wlog = opts->Wlog;
8244d362409d5469aed47d19e7908d19bd194493aThomas Graf	red->qr_plog = opts->Plog;
8344d362409d5469aed47d19e7908d19bd194493aThomas Graf	red->qr_scell_log = opts->Scell_log;
8444d362409d5469aed47d19e7908d19bd194493aThomas Graf
8544d362409d5469aed47d19e7908d19bd194493aThomas Graf	red->qr_mask = (RED_ATTR_LIMIT | RED_ATTR_QTH_MIN | RED_ATTR_QTH_MAX |
8644d362409d5469aed47d19e7908d19bd194493aThomas Graf			RED_ATTR_FLAGS | RED_ATTR_WLOG | RED_ATTR_PLOG |
8744d362409d5469aed47d19e7908d19bd194493aThomas Graf			RED_ATTR_SCELL_LOG);
8844d362409d5469aed47d19e7908d19bd194493aThomas Graf
8944d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
9044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
9144d362409d5469aed47d19e7908d19bd194493aThomas Graf
92d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Grafstatic void red_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p)
9344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
9444d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_red *red = red_qdisc(qdisc);
9544d362409d5469aed47d19e7908d19bd194493aThomas Graf
9644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (red) {
9744d362409d5469aed47d19e7908d19bd194493aThomas Graf		/* XXX: limit, min, max, flags */
9844d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
9944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
10044d362409d5469aed47d19e7908d19bd194493aThomas Graf
101d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Grafstatic void red_dump_details(struct rtnl_qdisc *qdisc, struct nl_dump_params *p)
10244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
10344d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_red *red = red_qdisc(qdisc);
10444d362409d5469aed47d19e7908d19bd194493aThomas Graf
10544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (red) {
10644d362409d5469aed47d19e7908d19bd194493aThomas Graf		/* XXX: wlog, plog, scell_log */
10744d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
10844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
10944d362409d5469aed47d19e7908d19bd194493aThomas Graf
110d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Grafstatic void red_dump_stats(struct rtnl_qdisc *qdisc, struct nl_dump_params *p)
11144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
11244d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_red *red = red_qdisc(qdisc);
11344d362409d5469aed47d19e7908d19bd194493aThomas Graf
11444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (red) {
11544d362409d5469aed47d19e7908d19bd194493aThomas Graf		/* XXX: xstats */
11644d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
11744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
11844d362409d5469aed47d19e7908d19bd194493aThomas Graf
11944d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nl_msg *red_get_opts(struct rtnl_qdisc *qdisc)
12044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
12144d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_red *red;
12244d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_msg *msg;
12344d362409d5469aed47d19e7908d19bd194493aThomas Graf
12444d362409d5469aed47d19e7908d19bd194493aThomas Graf	red = red_qdisc(qdisc);
12544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!red)
12644d362409d5469aed47d19e7908d19bd194493aThomas Graf		return NULL;
12744d362409d5469aed47d19e7908d19bd194493aThomas Graf
12844d362409d5469aed47d19e7908d19bd194493aThomas Graf	msg = nlmsg_alloc();
12944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!msg)
13044d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto errout;
13144d362409d5469aed47d19e7908d19bd194493aThomas Graf
13244d362409d5469aed47d19e7908d19bd194493aThomas Graf#if 0
13344d362409d5469aed47d19e7908d19bd194493aThomas Graf	memset(&opts, 0, sizeof(opts));
13444d362409d5469aed47d19e7908d19bd194493aThomas Graf	opts.quantum = sfq->qs_quantum;
13544d362409d5469aed47d19e7908d19bd194493aThomas Graf	opts.perturb_period = sfq->qs_perturb;
13644d362409d5469aed47d19e7908d19bd194493aThomas Graf	opts.limit = sfq->qs_limit;
13744d362409d5469aed47d19e7908d19bd194493aThomas Graf
13844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD) < 0)
13944d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto errout;
14044d362409d5469aed47d19e7908d19bd194493aThomas Graf#endif
14144d362409d5469aed47d19e7908d19bd194493aThomas Graf
14244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return msg;
14344d362409d5469aed47d19e7908d19bd194493aThomas Graferrout:
14444d362409d5469aed47d19e7908d19bd194493aThomas Graf	nlmsg_free(msg);
14544d362409d5469aed47d19e7908d19bd194493aThomas Graf	return NULL;
14644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
14744d362409d5469aed47d19e7908d19bd194493aThomas Graf
14844d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
14944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Attribute Access
15044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
15144d362409d5469aed47d19e7908d19bd194493aThomas Graf */
15244d362409d5469aed47d19e7908d19bd194493aThomas Graf
15344d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
15444d362409d5469aed47d19e7908d19bd194493aThomas Graf * Set limit of RED qdisc.
15544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg qdisc		RED qdisc to be modified.
15644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg limit		New limit in number of packets.
15744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return 0 on success or a negative error code.
15844d362409d5469aed47d19e7908d19bd194493aThomas Graf */
15944d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_red_set_limit(struct rtnl_qdisc *qdisc, int limit)
16044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
16144d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_red *red;
16244d362409d5469aed47d19e7908d19bd194493aThomas Graf
16344d362409d5469aed47d19e7908d19bd194493aThomas Graf	red = red_alloc(qdisc);
16444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!red)
1658a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_NOMEM;
16644d362409d5469aed47d19e7908d19bd194493aThomas Graf
16744d362409d5469aed47d19e7908d19bd194493aThomas Graf	red->qr_limit = limit;
16844d362409d5469aed47d19e7908d19bd194493aThomas Graf	red->qr_mask |= RED_ATTR_LIMIT;
16944d362409d5469aed47d19e7908d19bd194493aThomas Graf
17044d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
17144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
17244d362409d5469aed47d19e7908d19bd194493aThomas Graf
17344d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
17444d362409d5469aed47d19e7908d19bd194493aThomas Graf * Get limit of RED qdisc.
17544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg qdisc		RED qdisc.
17644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Limit or a negative error code.
17744d362409d5469aed47d19e7908d19bd194493aThomas Graf */
17844d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_red_get_limit(struct rtnl_qdisc *qdisc)
17944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
18044d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_red *red;
18144d362409d5469aed47d19e7908d19bd194493aThomas Graf
18244d362409d5469aed47d19e7908d19bd194493aThomas Graf	red = red_qdisc(qdisc);
18344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (red && (red->qr_mask & RED_ATTR_LIMIT))
18444d362409d5469aed47d19e7908d19bd194493aThomas Graf		return red->qr_limit;
18544d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
1868a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_NOATTR;
18744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
18844d362409d5469aed47d19e7908d19bd194493aThomas Graf
18944d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
19044d362409d5469aed47d19e7908d19bd194493aThomas Graf
19144d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct rtnl_qdisc_ops red_ops = {
19244d362409d5469aed47d19e7908d19bd194493aThomas Graf	.qo_kind		= "red",
19344d362409d5469aed47d19e7908d19bd194493aThomas Graf	.qo_msg_parser		= red_msg_parser,
194d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	.qo_dump = {
195d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	    [NL_DUMP_LINE]	= red_dump_line,
196d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	    [NL_DUMP_DETAILS]	= red_dump_details,
197d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	    [NL_DUMP_STATS]	= red_dump_stats,
198d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	},
19944d362409d5469aed47d19e7908d19bd194493aThomas Graf	.qo_get_opts		= red_get_opts,
20044d362409d5469aed47d19e7908d19bd194493aThomas Graf};
20144d362409d5469aed47d19e7908d19bd194493aThomas Graf
20244d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic void __init red_init(void)
20344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
20444d362409d5469aed47d19e7908d19bd194493aThomas Graf	rtnl_qdisc_register(&red_ops);
20544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
20644d362409d5469aed47d19e7908d19bd194493aThomas Graf
20744d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic void __exit red_exit(void)
20844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
20944d362409d5469aed47d19e7908d19bd194493aThomas Graf	rtnl_qdisc_unregister(&red_ops);
21044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
21144d362409d5469aed47d19e7908d19bd194493aThomas Graf
21244d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
213