libnl 1.1
lib/route/sch/red.c
00001 /*
00002  * lib/route/sch/red.c          RED Qdisc
00003  *
00004  *      This library is free software; you can redistribute it and/or
00005  *      modify it under the terms of the GNU Lesser General Public
00006  *      License as published by the Free Software Foundation version 2.1
00007  *      of the License.
00008  *
00009  * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
00010  */
00011 
00012 /**
00013  * @ingroup qdisc_api
00014  * @defgroup red Random Early Detection (RED)
00015  * @brief
00016  * @{
00017  */
00018 
00019 #include <netlink-local.h>
00020 #include <netlink-tc.h>
00021 #include <netlink/netlink.h>
00022 #include <netlink/utils.h>
00023 #include <netlink/route/qdisc.h>
00024 #include <netlink/route/qdisc-modules.h>
00025 #include <netlink/route/sch/red.h>
00026 
00027 /** @cond SKIP */
00028 #define RED_ATTR_LIMIT          0x01
00029 #define RED_ATTR_QTH_MIN        0x02
00030 #define RED_ATTR_QTH_MAX        0x04
00031 #define RED_ATTR_FLAGS          0x08
00032 #define RED_ATTR_WLOG           0x10
00033 #define RED_ATTR_PLOG           0x20
00034 #define RED_ATTR_SCELL_LOG      0x40
00035 /** @endcond */
00036 
00037 static inline struct rtnl_red *red_qdisc(struct rtnl_qdisc *qdisc)
00038 {
00039         return (struct rtnl_red *) qdisc->q_subdata;
00040 }
00041 
00042 static inline struct rtnl_red *red_alloc(struct rtnl_qdisc *qdisc)
00043 {
00044         if (!qdisc->q_subdata)
00045                 qdisc->q_subdata = calloc(1, sizeof(struct rtnl_red));
00046 
00047         return red_qdisc(qdisc);
00048 }
00049 
00050 static struct nla_policy red_policy[TCA_RED_MAX+1] = {
00051         [TCA_RED_PARMS]         = { .minlen = sizeof(struct tc_red_qopt) },
00052 };
00053 
00054 static int red_msg_parser(struct rtnl_qdisc *qdisc)
00055 {
00056         struct nlattr *tb[TCA_RED_MAX+1];
00057         struct rtnl_red *red;
00058         struct tc_red_qopt *opts;
00059         int err;
00060 
00061         if (!(qdisc->ce_mask & TCA_ATTR_OPTS))
00062                 return 0;
00063 
00064         err = tca_parse(tb, TCA_RED_MAX, (struct rtnl_tca *) qdisc, red_policy);
00065         if (err < 0)
00066                 return err;
00067 
00068         if (!tb[TCA_RED_PARMS])
00069                 return nl_error(EINVAL, "Missing TCA_RED_PARMS");
00070 
00071         red = red_alloc(qdisc);
00072         if (!red)
00073                 return nl_errno(ENOMEM);
00074 
00075         opts = nla_data(tb[TCA_RED_PARMS]);
00076 
00077         red->qr_limit = opts->limit;
00078         red->qr_qth_min = opts->qth_min;
00079         red->qr_qth_max = opts->qth_max;
00080         red->qr_flags = opts->flags;
00081         red->qr_wlog = opts->Wlog;
00082         red->qr_plog = opts->Plog;
00083         red->qr_scell_log = opts->Scell_log;
00084 
00085         red->qr_mask = (RED_ATTR_LIMIT | RED_ATTR_QTH_MIN | RED_ATTR_QTH_MAX |
00086                         RED_ATTR_FLAGS | RED_ATTR_WLOG | RED_ATTR_PLOG |
00087                         RED_ATTR_SCELL_LOG);
00088 
00089         return 0;
00090 }
00091 
00092 static int red_dump_brief(struct rtnl_qdisc *qdisc, struct nl_dump_params *p,
00093                           int line)
00094 {
00095         struct rtnl_red *red = red_qdisc(qdisc);
00096 
00097         if (red) {
00098                 /* XXX: limit, min, max, flags */
00099         }
00100 
00101         return line;
00102 }
00103 
00104 static int red_dump_full(struct rtnl_qdisc *qdisc, struct nl_dump_params *p,
00105                          int line)
00106 {
00107         struct rtnl_red *red = red_qdisc(qdisc);
00108 
00109         if (red) {
00110                 /* XXX: wlog, plog, scell_log */
00111         }
00112 
00113         return line;
00114 }
00115 
00116 static int red_dump_stats(struct rtnl_qdisc *qdisc, struct nl_dump_params *p,
00117                           int line)
00118 {
00119         struct rtnl_red *red = red_qdisc(qdisc);
00120 
00121         if (red) {
00122                 /* XXX: xstats */
00123         }
00124 
00125         return line;
00126 }
00127 
00128 static struct nl_msg *red_get_opts(struct rtnl_qdisc *qdisc)
00129 {
00130         struct rtnl_red *red;
00131         struct nl_msg *msg;
00132 
00133         red = red_qdisc(qdisc);
00134         if (!red)
00135                 return NULL;
00136 
00137         msg = nlmsg_alloc();
00138         if (!msg)
00139                 goto errout;
00140 
00141 #if 0
00142         memset(&opts, 0, sizeof(opts));
00143         opts.quantum = sfq->qs_quantum;
00144         opts.perturb_period = sfq->qs_perturb;
00145         opts.limit = sfq->qs_limit;
00146 
00147         if (nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD) < 0)
00148                 goto errout;
00149 #endif
00150 
00151         return msg;
00152 errout:
00153         nlmsg_free(msg);
00154         return NULL;
00155 }
00156 
00157 /**
00158  * @name Attribute Access
00159  * @{
00160  */
00161 
00162 /**
00163  * Set limit of RED qdisc.
00164  * @arg qdisc           RED qdisc to be modified.
00165  * @arg limit           New limit in number of packets.
00166  * @return 0 on success or a negative error code.
00167  */
00168 int rtnl_red_set_limit(struct rtnl_qdisc *qdisc, int limit)
00169 {
00170         struct rtnl_red *red;
00171 
00172         red = red_alloc(qdisc);
00173         if (!red)
00174                 return nl_errno(ENOMEM);
00175 
00176         red->qr_limit = limit;
00177         red->qr_mask |= RED_ATTR_LIMIT;
00178 
00179         return 0;
00180 }
00181 
00182 /**
00183  * Get limit of RED qdisc.
00184  * @arg qdisc           RED qdisc.
00185  * @return Limit or a negative error code.
00186  */
00187 int rtnl_red_get_limit(struct rtnl_qdisc *qdisc)
00188 {
00189         struct rtnl_red *red;
00190 
00191         red = red_qdisc(qdisc);
00192         if (red && (red->qr_mask & RED_ATTR_LIMIT))
00193                 return red->qr_limit;
00194         else
00195                 return nl_errno(ENOENT);
00196 }
00197 
00198 /** @} */
00199 
00200 static struct rtnl_qdisc_ops red_ops = {
00201         .qo_kind                = "red",
00202         .qo_msg_parser          = red_msg_parser,
00203         .qo_dump[NL_DUMP_BRIEF] = red_dump_brief,
00204         .qo_dump[NL_DUMP_FULL]  = red_dump_full,
00205         .qo_dump[NL_DUMP_STATS] = red_dump_stats,
00206         .qo_get_opts            = red_get_opts,
00207 };
00208 
00209 static void __init red_init(void)
00210 {
00211         rtnl_qdisc_register(&red_ops);
00212 }
00213 
00214 static void __exit red_exit(void)
00215 {
00216         rtnl_qdisc_unregister(&red_ops);
00217 }
00218 
00219 /** @} */