prio.c

00001 /*
00002  * lib/route/qdisc/prio.c               PRIO Qdisc/Class
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-2011 Thomas Graf <tgraf@suug.ch>
00010  */
00011 
00012 /**
00013  * @ingroup qdisc
00014  * @defgroup qdisc_prio (Fast) Prio
00015  * @brief
00016  *
00017  * @par 1) Typical PRIO configuration
00018  * @code
00019  * // Specify the maximal number of bands to be used for this PRIO qdisc.
00020  * rtnl_qdisc_prio_set_bands(qdisc, QDISC_PRIO_DEFAULT_BANDS);
00021  *
00022  * // Provide a map assigning each priority to a band number.
00023  * uint8_t map[] = QDISC_PRIO_DEFAULT_PRIOMAP;
00024  * rtnl_qdisc_prio_set_priomap(qdisc, map, sizeof(map));
00025  * @endcode
00026  * @{
00027  */
00028 
00029 #include <netlink-local.h>
00030 #include <netlink-tc.h>
00031 #include <netlink/netlink.h>
00032 #include <netlink/utils.h>
00033 #include <netlink/route/tc-api.h>
00034 #include <netlink/route/qdisc.h>
00035 #include <netlink/route/qdisc/prio.h>
00036 
00037 /** @cond SKIP */
00038 #define SCH_PRIO_ATTR_BANDS     1
00039 #define SCH_PRIO_ATTR_PRIOMAP   2
00040 /** @endcond */
00041 
00042 static int prio_msg_parser(struct rtnl_tc *tc, void *data)
00043 {
00044         struct rtnl_prio *prio = data;
00045         struct tc_prio_qopt *opt;
00046 
00047         if (tc->tc_opts->d_size < sizeof(*opt))
00048                 return -NLE_INVAL;
00049 
00050         opt = (struct tc_prio_qopt *) tc->tc_opts->d_data;
00051         prio->qp_bands = opt->bands;
00052         memcpy(prio->qp_priomap, opt->priomap, sizeof(prio->qp_priomap));
00053         prio->qp_mask = (SCH_PRIO_ATTR_BANDS | SCH_PRIO_ATTR_PRIOMAP);
00054         
00055         return 0;
00056 }
00057 
00058 static void prio_dump_line(struct rtnl_tc *tc, void *data,
00059                            struct nl_dump_params *p)
00060 {
00061         struct rtnl_prio *prio = data;
00062 
00063         if (prio)
00064                 nl_dump(p, " bands %u", prio->qp_bands);
00065 }
00066 
00067 static void prio_dump_details(struct rtnl_tc *tc, void *data,
00068                               struct nl_dump_params *p)
00069 {
00070         struct rtnl_prio *prio = data;
00071         int i, hp;
00072 
00073         if (!prio)
00074                 return;
00075 
00076         nl_dump(p, "priomap [");
00077         
00078         for (i = 0; i <= TC_PRIO_MAX; i++)
00079                 nl_dump(p, "%u%s", prio->qp_priomap[i],
00080                         i < TC_PRIO_MAX ? " " : "");
00081 
00082         nl_dump(p, "]\n");
00083         nl_new_line(p);
00084 
00085         hp = (((TC_PRIO_MAX/2) + 1) & ~1);
00086 
00087         for (i = 0; i < hp; i++) {
00088                 char a[32];
00089                 nl_dump(p, "    %18s => %u",
00090                         rtnl_prio2str(i, a, sizeof(a)),
00091                         prio->qp_priomap[i]);
00092                 if (hp+i <= TC_PRIO_MAX) {
00093                         nl_dump(p, " %18s => %u",
00094                                 rtnl_prio2str(hp+i, a, sizeof(a)),
00095                                 prio->qp_priomap[hp+i]);
00096                         if (i < (hp - 1)) {
00097                                 nl_dump(p, "\n");
00098                                 nl_new_line(p);
00099                         }
00100                 }
00101         }
00102 }
00103 
00104 static int prio_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
00105 {
00106         struct rtnl_prio *prio = data;
00107         struct tc_prio_qopt opts;
00108 
00109         if (!prio || !(prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP))
00110                 BUG();
00111 
00112         opts.bands = prio->qp_bands;
00113         memcpy(opts.priomap, prio->qp_priomap, sizeof(opts.priomap));
00114 
00115         return nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD);
00116 }
00117 
00118 /**
00119  * @name Attribute Modification
00120  * @{
00121  */
00122 
00123 /**
00124  * Set number of bands of PRIO qdisc.
00125  * @arg qdisc           PRIO qdisc to be modified.
00126  * @arg bands           New number of bands.
00127  * @return 0 on success or a negative error code.
00128  */
00129 void rtnl_qdisc_prio_set_bands(struct rtnl_qdisc *qdisc, int bands)
00130 {
00131         struct rtnl_prio *prio;
00132 
00133         if (!(prio = rtnl_tc_data(TC_CAST(qdisc))))
00134                 BUG();
00135 
00136         prio->qp_bands = bands;
00137         prio->qp_mask |= SCH_PRIO_ATTR_BANDS;
00138 }
00139 
00140 /**
00141  * Get number of bands of PRIO qdisc.
00142  * @arg qdisc           PRIO qdisc.
00143  * @return Number of bands or a negative error code.
00144  */
00145 int rtnl_qdisc_prio_get_bands(struct rtnl_qdisc *qdisc)
00146 {
00147         struct rtnl_prio *prio;
00148 
00149         if (!(prio = rtnl_tc_data(TC_CAST(qdisc))))
00150                 BUG();
00151 
00152         if (prio->qp_mask & SCH_PRIO_ATTR_BANDS)
00153                 return prio->qp_bands;
00154         else
00155                 return -NLE_NOMEM;
00156 }
00157 
00158 /**
00159  * Set priomap of the PRIO qdisc.
00160  * @arg qdisc           PRIO qdisc to be modified.
00161  * @arg priomap         New priority mapping.
00162  * @arg len             Length of priomap (# of elements).
00163  * @return 0 on success or a negative error code.
00164  */
00165 int rtnl_qdisc_prio_set_priomap(struct rtnl_qdisc *qdisc, uint8_t priomap[],
00166                                 int len)
00167 {
00168         struct rtnl_prio *prio;
00169         int i;
00170 
00171         if (!(prio = rtnl_tc_data(TC_CAST(qdisc))))
00172                 BUG();
00173 
00174         if (!(prio->qp_mask & SCH_PRIO_ATTR_BANDS))
00175                 return -NLE_MISSING_ATTR;
00176 
00177         if ((len / sizeof(uint8_t)) > (TC_PRIO_MAX+1))
00178                 return -NLE_RANGE;
00179 
00180         for (i = 0; i <= TC_PRIO_MAX; i++) {
00181                 if (priomap[i] > prio->qp_bands)
00182                         return -NLE_RANGE;
00183         }
00184 
00185         memcpy(prio->qp_priomap, priomap, len);
00186         prio->qp_mask |= SCH_PRIO_ATTR_PRIOMAP;
00187 
00188         return 0;
00189 }
00190 
00191 /**
00192  * Get priomap of a PRIO qdisc.
00193  * @arg qdisc           PRIO qdisc.
00194  * @return Priority mapping as array of size TC_PRIO_MAX+1
00195  *         or NULL if an error occured.
00196  */
00197 uint8_t *rtnl_qdisc_prio_get_priomap(struct rtnl_qdisc *qdisc)
00198 {
00199         struct rtnl_prio *prio;
00200 
00201         if (!(prio = rtnl_tc_data(TC_CAST(qdisc))))
00202                 BUG();
00203 
00204         if (prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP)
00205                 return prio->qp_priomap;
00206         else
00207                 return NULL;
00208 }
00209 
00210 /** @} */
00211 
00212 /**
00213  * @name Priority Band Translations
00214  * @{
00215  */
00216 
00217 static const struct trans_tbl prios[] = {
00218         __ADD(TC_PRIO_BESTEFFORT,besteffort)
00219         __ADD(TC_PRIO_FILLER,filler)
00220         __ADD(TC_PRIO_BULK,bulk)
00221         __ADD(TC_PRIO_INTERACTIVE_BULK,interactive_bulk)
00222         __ADD(TC_PRIO_INTERACTIVE,interactive)
00223         __ADD(TC_PRIO_CONTROL,control)
00224 };
00225 
00226 /**
00227  * Convert priority to character string.
00228  * @arg prio            Priority.
00229  * @arg buf             Destination buffer
00230  * @arg size            Size of destination buffer.
00231  *
00232  * Converts a priority to a character string and stores the result in
00233  * the specified destination buffer.
00234  *
00235  * @return Name of priority as character string.
00236  */
00237 char * rtnl_prio2str(int prio, char *buf, size_t size)
00238 {
00239         return __type2str(prio, buf, size, prios, ARRAY_SIZE(prios));
00240 }
00241 
00242 /**
00243  * Convert character string to priority.
00244  * @arg name            Name of priority.
00245  *
00246  * Converts the provided character string specifying a priority
00247  * to the corresponding numeric value.
00248  *
00249  * @return Numeric priority or a negative value if no match was found.
00250  */
00251 int rtnl_str2prio(const char *name)
00252 {
00253         return __str2type(name, prios, ARRAY_SIZE(prios));
00254 }
00255 
00256 /** @} */
00257 
00258 static struct rtnl_tc_ops prio_ops = {
00259         .to_kind                = "prio",
00260         .to_type                = RTNL_TC_TYPE_QDISC,
00261         .to_size                = sizeof(struct rtnl_prio),
00262         .to_msg_parser          = prio_msg_parser,
00263         .to_dump = {
00264             [NL_DUMP_LINE]      = prio_dump_line,
00265             [NL_DUMP_DETAILS]   = prio_dump_details,
00266         },
00267         .to_msg_fill            = prio_msg_fill,
00268 };
00269 
00270 static struct rtnl_tc_ops pfifo_fast_ops = {
00271         .to_kind                = "pfifo_fast",
00272         .to_type                = RTNL_TC_TYPE_QDISC,
00273         .to_size                = sizeof(struct rtnl_prio),
00274         .to_msg_parser          = prio_msg_parser,
00275         .to_dump = {
00276             [NL_DUMP_LINE]      = prio_dump_line,
00277             [NL_DUMP_DETAILS]   = prio_dump_details,
00278         },
00279         .to_msg_fill            = prio_msg_fill,
00280 };
00281 
00282 static void __init prio_init(void)
00283 {
00284         rtnl_tc_register(&prio_ops);
00285         rtnl_tc_register(&pfifo_fast_ops);
00286 }
00287 
00288 static void __exit prio_exit(void)
00289 {
00290         rtnl_tc_unregister(&prio_ops);
00291         rtnl_tc_unregister(&pfifo_fast_ops);
00292 }
00293 
00294 /** @} */