Home | History | Annotate | Download | only in qdisc
      1 /*
      2  * lib/route/qdisc/prio.c		PRIO Qdisc/Class
      3  *
      4  *	This library is free software; you can redistribute it and/or
      5  *	modify it under the terms of the GNU Lesser General Public
      6  *	License as published by the Free Software Foundation version 2.1
      7  *	of the License.
      8  *
      9  * Copyright (c) 2003-2011 Thomas Graf <tgraf (at) suug.ch>
     10  */
     11 
     12 /**
     13  * @ingroup qdisc
     14  * @defgroup qdisc_prio (Fast) Prio
     15  * @brief
     16  *
     17  * @par 1) Typical PRIO configuration
     18  * @code
     19  * // Specify the maximal number of bands to be used for this PRIO qdisc.
     20  * rtnl_qdisc_prio_set_bands(qdisc, QDISC_PRIO_DEFAULT_BANDS);
     21  *
     22  * // Provide a map assigning each priority to a band number.
     23  * uint8_t map[] = QDISC_PRIO_DEFAULT_PRIOMAP;
     24  * rtnl_qdisc_prio_set_priomap(qdisc, map, sizeof(map));
     25  * @endcode
     26  * @{
     27  */
     28 
     29 #include <netlink-private/netlink.h>
     30 #include <netlink-private/tc.h>
     31 #include <netlink/netlink.h>
     32 #include <netlink/utils.h>
     33 #include <netlink-private/route/tc-api.h>
     34 #include <netlink/route/qdisc.h>
     35 #include <netlink/route/qdisc/prio.h>
     36 
     37 /** @cond SKIP */
     38 #define SCH_PRIO_ATTR_BANDS	1
     39 #define SCH_PRIO_ATTR_PRIOMAP	2
     40 /** @endcond */
     41 
     42 static int prio_msg_parser(struct rtnl_tc *tc, void *data)
     43 {
     44 	struct rtnl_prio *prio = data;
     45 	struct tc_prio_qopt *opt;
     46 
     47 	if (tc->tc_opts->d_size < sizeof(*opt))
     48 		return -NLE_INVAL;
     49 
     50 	opt = (struct tc_prio_qopt *) tc->tc_opts->d_data;
     51 	prio->qp_bands = opt->bands;
     52 	memcpy(prio->qp_priomap, opt->priomap, sizeof(prio->qp_priomap));
     53 	prio->qp_mask = (SCH_PRIO_ATTR_BANDS | SCH_PRIO_ATTR_PRIOMAP);
     54 
     55 	return 0;
     56 }
     57 
     58 static void prio_dump_line(struct rtnl_tc *tc, void *data,
     59 			   struct nl_dump_params *p)
     60 {
     61 	struct rtnl_prio *prio = data;
     62 
     63 	if (prio)
     64 		nl_dump(p, " bands %u", prio->qp_bands);
     65 }
     66 
     67 static void prio_dump_details(struct rtnl_tc *tc, void *data,
     68 			      struct nl_dump_params *p)
     69 {
     70 	struct rtnl_prio *prio = data;
     71 	int i, hp;
     72 
     73 	if (!prio)
     74 		return;
     75 
     76 	nl_dump(p, "priomap [");
     77 
     78 	for (i = 0; i <= TC_PRIO_MAX; i++)
     79 		nl_dump(p, "%u%s", prio->qp_priomap[i],
     80 			i < TC_PRIO_MAX ? " " : "");
     81 
     82 	nl_dump(p, "]\n");
     83 	nl_new_line(p);
     84 
     85 	hp = (((TC_PRIO_MAX/2) + 1) & ~1);
     86 
     87 	for (i = 0; i < hp; i++) {
     88 		char a[32];
     89 		nl_dump(p, "    %18s => %u",
     90 			rtnl_prio2str(i, a, sizeof(a)),
     91 			prio->qp_priomap[i]);
     92 		if (hp+i <= TC_PRIO_MAX) {
     93 			nl_dump(p, " %18s => %u",
     94 				rtnl_prio2str(hp+i, a, sizeof(a)),
     95 				prio->qp_priomap[hp+i]);
     96 			if (i < (hp - 1)) {
     97 				nl_dump(p, "\n");
     98 				nl_new_line(p);
     99 			}
    100 		}
    101 	}
    102 }
    103 
    104 static int prio_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
    105 {
    106 	struct rtnl_prio *prio = data;
    107 	struct tc_prio_qopt opts;
    108 
    109 	if (!prio || !(prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP))
    110 		BUG();
    111 
    112 	opts.bands = prio->qp_bands;
    113 	memcpy(opts.priomap, prio->qp_priomap, sizeof(opts.priomap));
    114 
    115 	return nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD);
    116 }
    117 
    118 /**
    119  * @name Attribute Modification
    120  * @{
    121  */
    122 
    123 /**
    124  * Set number of bands of PRIO qdisc.
    125  * @arg qdisc		PRIO qdisc to be modified.
    126  * @arg bands		New number of bands.
    127  * @return 0 on success or a negative error code.
    128  */
    129 void rtnl_qdisc_prio_set_bands(struct rtnl_qdisc *qdisc, int bands)
    130 {
    131 	struct rtnl_prio *prio;
    132 
    133 	if (!(prio = rtnl_tc_data(TC_CAST(qdisc))))
    134 		BUG();
    135 
    136 	prio->qp_bands = bands;
    137 	prio->qp_mask |= SCH_PRIO_ATTR_BANDS;
    138 }
    139 
    140 /**
    141  * Get number of bands of PRIO qdisc.
    142  * @arg qdisc		PRIO qdisc.
    143  * @return Number of bands or a negative error code.
    144  */
    145 int rtnl_qdisc_prio_get_bands(struct rtnl_qdisc *qdisc)
    146 {
    147 	struct rtnl_prio *prio;
    148 
    149 	if (!(prio = rtnl_tc_data(TC_CAST(qdisc))))
    150 		BUG();
    151 
    152 	if (prio->qp_mask & SCH_PRIO_ATTR_BANDS)
    153 		return prio->qp_bands;
    154 	else
    155 		return -NLE_NOMEM;
    156 }
    157 
    158 /**
    159  * Set priomap of the PRIO qdisc.
    160  * @arg qdisc		PRIO qdisc to be modified.
    161  * @arg priomap		New priority mapping.
    162  * @arg len		Length of priomap (# of elements).
    163  * @return 0 on success or a negative error code.
    164  */
    165 int rtnl_qdisc_prio_set_priomap(struct rtnl_qdisc *qdisc, uint8_t priomap[],
    166 				int len)
    167 {
    168 	struct rtnl_prio *prio;
    169 	int i;
    170 
    171 	if (!(prio = rtnl_tc_data(TC_CAST(qdisc))))
    172 		BUG();
    173 
    174 	if (!(prio->qp_mask & SCH_PRIO_ATTR_BANDS))
    175 		return -NLE_MISSING_ATTR;
    176 
    177 	if ((len / sizeof(uint8_t)) > (TC_PRIO_MAX+1))
    178 		return -NLE_RANGE;
    179 
    180 	for (i = 0; i <= TC_PRIO_MAX; i++) {
    181 		if (priomap[i] > prio->qp_bands)
    182 			return -NLE_RANGE;
    183 	}
    184 
    185 	memcpy(prio->qp_priomap, priomap, len);
    186 	prio->qp_mask |= SCH_PRIO_ATTR_PRIOMAP;
    187 
    188 	return 0;
    189 }
    190 
    191 /**
    192  * Get priomap of a PRIO qdisc.
    193  * @arg qdisc		PRIO qdisc.
    194  * @return Priority mapping as array of size TC_PRIO_MAX+1
    195  *         or NULL if an error occured.
    196  */
    197 uint8_t *rtnl_qdisc_prio_get_priomap(struct rtnl_qdisc *qdisc)
    198 {
    199 	struct rtnl_prio *prio;
    200 
    201 	if (!(prio = rtnl_tc_data(TC_CAST(qdisc))))
    202 		BUG();
    203 
    204 	if (prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP)
    205 		return prio->qp_priomap;
    206 	else
    207 		return NULL;
    208 }
    209 
    210 /** @} */
    211 
    212 /**
    213  * @name Priority Band Translations
    214  * @{
    215  */
    216 
    217 static const struct trans_tbl prios[] = {
    218 	__ADD(TC_PRIO_BESTEFFORT,besteffort)
    219 	__ADD(TC_PRIO_FILLER,filler)
    220 	__ADD(TC_PRIO_BULK,bulk)
    221 	__ADD(TC_PRIO_INTERACTIVE_BULK,interactive_bulk)
    222 	__ADD(TC_PRIO_INTERACTIVE,interactive)
    223 	__ADD(TC_PRIO_CONTROL,control)
    224 };
    225 
    226 /**
    227  * Convert priority to character string.
    228  * @arg prio		Priority.
    229  * @arg buf		Destination buffer
    230  * @arg size		Size of destination buffer.
    231  *
    232  * Converts a priority to a character string and stores the result in
    233  * the specified destination buffer.
    234  *
    235  * @return Name of priority as character string.
    236  */
    237 char * rtnl_prio2str(int prio, char *buf, size_t size)
    238 {
    239 	return __type2str(prio, buf, size, prios, ARRAY_SIZE(prios));
    240 }
    241 
    242 /**
    243  * Convert character string to priority.
    244  * @arg name		Name of priority.
    245  *
    246  * Converts the provided character string specifying a priority
    247  * to the corresponding numeric value.
    248  *
    249  * @return Numeric priority or a negative value if no match was found.
    250  */
    251 int rtnl_str2prio(const char *name)
    252 {
    253 	return __str2type(name, prios, ARRAY_SIZE(prios));
    254 }
    255 
    256 /** @} */
    257 
    258 static struct rtnl_tc_ops prio_ops = {
    259 	.to_kind		= "prio",
    260 	.to_type		= RTNL_TC_TYPE_QDISC,
    261 	.to_size		= sizeof(struct rtnl_prio),
    262 	.to_msg_parser		= prio_msg_parser,
    263 	.to_dump = {
    264 	    [NL_DUMP_LINE]	= prio_dump_line,
    265 	    [NL_DUMP_DETAILS]	= prio_dump_details,
    266 	},
    267 	.to_msg_fill		= prio_msg_fill,
    268 };
    269 
    270 static struct rtnl_tc_ops pfifo_fast_ops = {
    271 	.to_kind		= "pfifo_fast",
    272 	.to_type		= RTNL_TC_TYPE_QDISC,
    273 	.to_size		= sizeof(struct rtnl_prio),
    274 	.to_msg_parser		= prio_msg_parser,
    275 	.to_dump = {
    276 	    [NL_DUMP_LINE]	= prio_dump_line,
    277 	    [NL_DUMP_DETAILS]	= prio_dump_details,
    278 	},
    279 	.to_msg_fill		= prio_msg_fill,
    280 };
    281 
    282 static void __init prio_init(void)
    283 {
    284 	rtnl_tc_register(&prio_ops);
    285 	rtnl_tc_register(&pfifo_fast_ops);
    286 }
    287 
    288 static void __exit prio_exit(void)
    289 {
    290 	rtnl_tc_unregister(&prio_ops);
    291 	rtnl_tc_unregister(&pfifo_fast_ops);
    292 }
    293 
    294 /** @} */
    295