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@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 42static 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 58static 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 67static 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 104static 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 */ 129void 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 */ 145int 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 */ 165int 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 */ 197uint8_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 217static 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 */ 237char * 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 */ 251int rtnl_str2prio(const char *name) 252{ 253 return __str2type(name, prios, ARRAY_SIZE(prios)); 254} 255 256/** @} */ 257 258static 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 270static 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 282static void __init prio_init(void) 283{ 284 rtnl_tc_register(&prio_ops); 285 rtnl_tc_register(&pfifo_fast_ops); 286} 287 288static void __exit prio_exit(void) 289{ 290 rtnl_tc_unregister(&prio_ops); 291 rtnl_tc_unregister(&pfifo_fast_ops); 292} 293 294/** @} */ 295