libnl 2.0

/tmp/buildd/libnl2-2.0/lib/route/sch/prio.c

00001 /*
00002  * lib/route/sch/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-2008 Thomas Graf <tgraf@suug.ch>
00010  */
00011 
00012 /**
00013  * @ingroup qdisc_api
00014  * @defgroup 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/qdisc.h>
00034 #include <netlink/route/qdisc-modules.h>
00035 #include <netlink/route/sch/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 inline struct rtnl_prio *prio_qdisc(struct rtnl_qdisc *qdisc)
00043 {
00044         return (struct rtnl_prio *) qdisc->q_subdata;
00045 }
00046 
00047 static inline struct rtnl_prio *prio_alloc(struct rtnl_qdisc *qdisc)
00048 {
00049         if (!qdisc->q_subdata)
00050                 qdisc->q_subdata = calloc(1, sizeof(struct rtnl_prio));
00051 
00052         return prio_qdisc(qdisc);
00053 }
00054 
00055 static int prio_msg_parser(struct rtnl_qdisc *qdisc)
00056 {
00057         struct rtnl_prio *prio;
00058         struct tc_prio_qopt *opt;
00059 
00060         if (qdisc->q_opts->d_size < sizeof(*opt))
00061                 return -NLE_INVAL;
00062 
00063         prio = prio_alloc(qdisc);
00064         if (!prio)
00065                 return -NLE_NOMEM;
00066 
00067         opt = (struct tc_prio_qopt *) qdisc->q_opts->d_data;
00068         prio->qp_bands = opt->bands;
00069         memcpy(prio->qp_priomap, opt->priomap, sizeof(prio->qp_priomap));
00070         prio->qp_mask = (SCH_PRIO_ATTR_BANDS | SCH_PRIO_ATTR_PRIOMAP);
00071         
00072         return 0;
00073 }
00074 
00075 static void prio_free_data(struct rtnl_qdisc *qdisc)
00076 {
00077         free(qdisc->q_subdata);
00078 }
00079 
00080 static void prio_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p)
00081 {
00082         struct rtnl_prio *prio = prio_qdisc(qdisc);
00083 
00084         if (prio)
00085                 nl_dump(p, " bands %u", prio->qp_bands);
00086 }
00087 
00088 static void prio_dump_details(struct rtnl_qdisc *qdisc,struct nl_dump_params *p)
00089 {
00090         struct rtnl_prio *prio = prio_qdisc(qdisc);
00091         int i, hp;
00092 
00093         if (!prio)
00094                 return;
00095 
00096         nl_dump(p, "priomap [");
00097         
00098         for (i = 0; i <= TC_PRIO_MAX; i++)
00099                 nl_dump(p, "%u%s", prio->qp_priomap[i],
00100                         i < TC_PRIO_MAX ? " " : "");
00101 
00102         nl_dump(p, "]\n");
00103         nl_new_line(p);
00104 
00105         hp = (((TC_PRIO_MAX/2) + 1) & ~1);
00106 
00107         for (i = 0; i < hp; i++) {
00108                 char a[32];
00109                 nl_dump(p, "    %18s => %u",
00110                         rtnl_prio2str(i, a, sizeof(a)),
00111                         prio->qp_priomap[i]);
00112                 if (hp+i <= TC_PRIO_MAX) {
00113                         nl_dump(p, " %18s => %u",
00114                                 rtnl_prio2str(hp+i, a, sizeof(a)),
00115                                 prio->qp_priomap[hp+i]);
00116                         if (i < (hp - 1)) {
00117                                 nl_dump(p, "\n");
00118                                 nl_new_line(p);
00119                         }
00120                 }
00121         }
00122 }
00123 
00124 static struct nl_msg *prio_get_opts(struct rtnl_qdisc *qdisc)
00125 {
00126         struct rtnl_prio *prio;
00127         struct tc_prio_qopt opts;
00128         struct nl_msg *msg;
00129 
00130         prio = prio_qdisc(qdisc);
00131         if (!prio ||
00132             !(prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP))
00133                 goto errout;
00134 
00135         opts.bands = prio->qp_bands;
00136         memcpy(opts.priomap, prio->qp_priomap, sizeof(opts.priomap));
00137 
00138         msg = nlmsg_alloc();
00139         if (!msg)
00140                 goto errout;
00141 
00142         if (nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD) < 0) {
00143                 nlmsg_free(msg);
00144                 goto errout;
00145         }
00146 
00147         return msg;
00148 errout:
00149         return NULL;
00150 }
00151 
00152 /**
00153  * @name Attribute Modification
00154  * @{
00155  */
00156 
00157 /**
00158  * Set number of bands of PRIO qdisc.
00159  * @arg qdisc           PRIO qdisc to be modified.
00160  * @arg bands           New number of bands.
00161  * @return 0 on success or a negative error code.
00162  */
00163 int rtnl_qdisc_prio_set_bands(struct rtnl_qdisc *qdisc, int bands)
00164 {
00165         struct rtnl_prio *prio;
00166         
00167         prio = prio_alloc(qdisc);
00168         if (!prio)
00169                 return -NLE_NOMEM;
00170 
00171         prio->qp_bands = bands;
00172         prio->qp_mask |= SCH_PRIO_ATTR_BANDS;
00173 
00174         return 0;
00175 }
00176 
00177 /**
00178  * Get number of bands of PRIO qdisc.
00179  * @arg qdisc           PRIO qdisc.
00180  * @return Number of bands or a negative error code.
00181  */
00182 int rtnl_qdisc_prio_get_bands(struct rtnl_qdisc *qdisc)
00183 {
00184         struct rtnl_prio *prio;
00185 
00186         prio = prio_qdisc(qdisc);
00187         if (prio && prio->qp_mask & SCH_PRIO_ATTR_BANDS)
00188                 return prio->qp_bands;
00189         else
00190                 return -NLE_NOMEM;
00191 }
00192 
00193 /**
00194  * Set priomap of the PRIO qdisc.
00195  * @arg qdisc           PRIO qdisc to be modified.
00196  * @arg priomap         New priority mapping.
00197  * @arg len             Length of priomap (# of elements).
00198  * @return 0 on success or a negative error code.
00199  */
00200 int rtnl_qdisc_prio_set_priomap(struct rtnl_qdisc *qdisc, uint8_t priomap[],
00201                                 int len)
00202 {
00203         struct rtnl_prio *prio;
00204         int i;
00205 
00206         prio = prio_alloc(qdisc);
00207         if (!prio)
00208                 return -NLE_NOMEM;
00209 
00210         if (!(prio->qp_mask & SCH_PRIO_ATTR_BANDS))
00211                 return -NLE_MISSING_ATTR;
00212 
00213         if ((len / sizeof(uint8_t)) > (TC_PRIO_MAX+1))
00214                 return -NLE_RANGE;
00215 
00216         for (i = 0; i <= TC_PRIO_MAX; i++) {
00217                 if (priomap[i] > prio->qp_bands)
00218                         return -NLE_RANGE;
00219         }
00220 
00221         memcpy(prio->qp_priomap, priomap, len);
00222         prio->qp_mask |= SCH_PRIO_ATTR_PRIOMAP;
00223 
00224         return 0;
00225 }
00226 
00227 /**
00228  * Get priomap of a PRIO qdisc.
00229  * @arg qdisc           PRIO qdisc.
00230  * @return Priority mapping as array of size TC_PRIO_MAX+1
00231  *         or NULL if an error occured.
00232  */
00233 uint8_t *rtnl_qdisc_prio_get_priomap(struct rtnl_qdisc *qdisc)
00234 {
00235         struct rtnl_prio *prio;
00236 
00237         prio = prio_qdisc(qdisc);
00238         if (prio && prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP)
00239                 return prio->qp_priomap;
00240         else
00241                 return NULL;
00242 }
00243 
00244 /** @} */
00245 
00246 /**
00247  * @name Priority Band Translations
00248  * @{
00249  */
00250 
00251 static struct trans_tbl prios[] = {
00252         __ADD(TC_PRIO_BESTEFFORT,besteffort)
00253         __ADD(TC_PRIO_FILLER,filler)
00254         __ADD(TC_PRIO_BULK,bulk)
00255         __ADD(TC_PRIO_INTERACTIVE_BULK,interactive_bulk)
00256         __ADD(TC_PRIO_INTERACTIVE,interactive)
00257         __ADD(TC_PRIO_CONTROL,control)
00258 };
00259 
00260 /**
00261  * Convert priority to character string.
00262  * @arg prio            Priority.
00263  * @arg buf             Destination buffer
00264  * @arg size            Size of destination buffer.
00265  *
00266  * Converts a priority to a character string and stores the result in
00267  * the specified destination buffer.
00268  *
00269  * @return Name of priority as character string.
00270  */
00271 char * rtnl_prio2str(int prio, char *buf, size_t size)
00272 {
00273         return __type2str(prio, buf, size, prios, ARRAY_SIZE(prios));
00274 }
00275 
00276 /**
00277  * Convert character string to priority.
00278  * @arg name            Name of priority.
00279  *
00280  * Converts the provided character string specifying a priority
00281  * to the corresponding numeric value.
00282  *
00283  * @return Numeric priority or a negative value if no match was found.
00284  */
00285 int rtnl_str2prio(const char *name)
00286 {
00287         return __str2type(name, prios, ARRAY_SIZE(prios));
00288 }
00289 
00290 /** @} */
00291 
00292 static struct rtnl_qdisc_ops prio_ops = {
00293         .qo_kind                = "prio",
00294         .qo_msg_parser          = prio_msg_parser,
00295         .qo_free_data           = prio_free_data,
00296         .qo_dump = {
00297             [NL_DUMP_LINE]      = prio_dump_line,
00298             [NL_DUMP_DETAILS]   = prio_dump_details,
00299         },
00300         .qo_get_opts            = prio_get_opts,
00301 };
00302 
00303 static struct rtnl_qdisc_ops pfifo_fast_ops = {
00304         .qo_kind                = "pfifo_fast",
00305         .qo_msg_parser          = prio_msg_parser,
00306         .qo_free_data           = prio_free_data,
00307         .qo_dump = {
00308             [NL_DUMP_LINE]      = prio_dump_line,
00309             [NL_DUMP_DETAILS]   = prio_dump_details,
00310         },
00311         .qo_get_opts            = prio_get_opts,
00312 };
00313 
00314 static void __init prio_init(void)
00315 {
00316         rtnl_qdisc_register(&prio_ops);
00317         rtnl_qdisc_register(&pfifo_fast_ops);
00318 }
00319 
00320 static void __exit prio_exit(void)
00321 {
00322         rtnl_qdisc_unregister(&prio_ops);
00323         rtnl_qdisc_unregister(&pfifo_fast_ops);
00324 }
00325 
00326 /** @} */