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