libnl 1.1
|
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-2006 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 nl_error(EINVAL, "prio specific option size mismatch"); 00062 00063 prio = prio_alloc(qdisc); 00064 if (!prio) 00065 return nl_errno(ENOMEM); 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 int prio_dump_brief(struct rtnl_qdisc *qdisc, 00081 struct nl_dump_params *p, int line) 00082 { 00083 struct rtnl_prio *prio = prio_qdisc(qdisc); 00084 00085 if (prio) 00086 dp_dump(p, " bands %u", prio->qp_bands); 00087 00088 return line; 00089 } 00090 00091 static int prio_dump_full(struct rtnl_qdisc *qdisc, 00092 struct nl_dump_params *p, int line) 00093 { 00094 struct rtnl_prio *prio = prio_qdisc(qdisc); 00095 int i, hp; 00096 00097 if (!prio) 00098 goto ignore; 00099 00100 dp_dump(p, "priomap ["); 00101 00102 for (i = 0; i <= TC_PRIO_MAX; i++) 00103 dp_dump(p, "%u%s", prio->qp_priomap[i], 00104 i < TC_PRIO_MAX ? " " : ""); 00105 00106 dp_dump(p, "]\n"); 00107 dp_new_line(p, line++); 00108 00109 hp = (((TC_PRIO_MAX/2) + 1) & ~1); 00110 00111 for (i = 0; i < hp; i++) { 00112 char a[32]; 00113 dp_dump(p, " %18s => %u", 00114 rtnl_prio2str(i, a, sizeof(a)), 00115 prio->qp_priomap[i]); 00116 if (hp+i <= TC_PRIO_MAX) { 00117 dp_dump(p, " %18s => %u", 00118 rtnl_prio2str(hp+i, a, sizeof(a)), 00119 prio->qp_priomap[hp+i]); 00120 if (i < (hp - 1)) { 00121 dp_dump(p, "\n"); 00122 dp_new_line(p, line++); 00123 } 00124 } 00125 } 00126 00127 ignore: 00128 return line; 00129 } 00130 00131 static struct nl_msg *prio_get_opts(struct rtnl_qdisc *qdisc) 00132 { 00133 struct rtnl_prio *prio; 00134 struct tc_prio_qopt opts; 00135 struct nl_msg *msg; 00136 00137 prio = prio_qdisc(qdisc); 00138 if (!prio || 00139 !(prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP)) 00140 goto errout; 00141 00142 opts.bands = prio->qp_bands; 00143 memcpy(opts.priomap, prio->qp_priomap, sizeof(opts.priomap)); 00144 00145 msg = nlmsg_alloc(); 00146 if (!msg) 00147 goto errout; 00148 00149 if (nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD) < 0) { 00150 nlmsg_free(msg); 00151 goto errout; 00152 } 00153 00154 return msg; 00155 errout: 00156 return NULL; 00157 } 00158 00159 /** 00160 * @name Attribute Modification 00161 * @{ 00162 */ 00163 00164 /** 00165 * Set number of bands of PRIO qdisc. 00166 * @arg qdisc PRIO qdisc to be modified. 00167 * @arg bands New number of bands. 00168 * @return 0 on success or a negative error code. 00169 */ 00170 int rtnl_qdisc_prio_set_bands(struct rtnl_qdisc *qdisc, int bands) 00171 { 00172 struct rtnl_prio *prio; 00173 00174 prio = prio_alloc(qdisc); 00175 if (!prio) 00176 return nl_errno(ENOMEM); 00177 00178 prio->qp_bands = bands; 00179 prio->qp_mask |= SCH_PRIO_ATTR_BANDS; 00180 00181 return 0; 00182 } 00183 00184 /** 00185 * Get number of bands of PRIO qdisc. 00186 * @arg qdisc PRIO qdisc. 00187 * @return Number of bands or a negative error code. 00188 */ 00189 int rtnl_qdisc_prio_get_bands(struct rtnl_qdisc *qdisc) 00190 { 00191 struct rtnl_prio *prio; 00192 00193 prio = prio_qdisc(qdisc); 00194 if (prio && prio->qp_mask & SCH_PRIO_ATTR_BANDS) 00195 return prio->qp_bands; 00196 else 00197 return nl_errno(ENOMEM); 00198 } 00199 00200 /** 00201 * Set priomap of the PRIO qdisc. 00202 * @arg qdisc PRIO qdisc to be modified. 00203 * @arg priomap New priority mapping. 00204 * @arg len Length of priomap (# of elements). 00205 * @return 0 on success or a negative error code. 00206 */ 00207 int rtnl_qdisc_prio_set_priomap(struct rtnl_qdisc *qdisc, uint8_t priomap[], 00208 int len) 00209 { 00210 struct rtnl_prio *prio; 00211 int i; 00212 00213 prio = prio_alloc(qdisc); 00214 if (!prio) 00215 return nl_errno(ENOMEM); 00216 00217 if (!(prio->qp_mask & SCH_PRIO_ATTR_BANDS)) 00218 return nl_error(EINVAL, "Set number of bands first"); 00219 00220 if ((len / sizeof(uint8_t)) > (TC_PRIO_MAX+1)) 00221 return nl_error(ERANGE, "priomap length out of bounds"); 00222 00223 for (i = 0; i <= TC_PRIO_MAX; i++) { 00224 if (priomap[i] > prio->qp_bands) 00225 return nl_error(ERANGE, "priomap element %d " \ 00226 "out of bounds, increase bands number"); 00227 } 00228 00229 memcpy(prio->qp_priomap, priomap, len); 00230 prio->qp_mask |= SCH_PRIO_ATTR_PRIOMAP; 00231 00232 return 0; 00233 } 00234 00235 /** 00236 * Get priomap of a PRIO qdisc. 00237 * @arg qdisc PRIO qdisc. 00238 * @return Priority mapping as array of size TC_PRIO_MAX+1 00239 * or NULL if an error occured. 00240 */ 00241 uint8_t *rtnl_qdisc_prio_get_priomap(struct rtnl_qdisc *qdisc) 00242 { 00243 struct rtnl_prio *prio; 00244 00245 prio = prio_qdisc(qdisc); 00246 if (prio && prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP) 00247 return prio->qp_priomap; 00248 else { 00249 nl_errno(ENOENT); 00250 return NULL; 00251 } 00252 } 00253 00254 /** @} */ 00255 00256 /** 00257 * @name Priority Band Translations 00258 * @{ 00259 */ 00260 00261 static struct trans_tbl prios[] = { 00262 __ADD(TC_PRIO_BESTEFFORT,besteffort) 00263 __ADD(TC_PRIO_FILLER,filler) 00264 __ADD(TC_PRIO_BULK,bulk) 00265 __ADD(TC_PRIO_INTERACTIVE_BULK,interactive_bulk) 00266 __ADD(TC_PRIO_INTERACTIVE,interactive) 00267 __ADD(TC_PRIO_CONTROL,control) 00268 }; 00269 00270 /** 00271 * Convert priority to character string. 00272 * @arg prio Priority. 00273 * @arg buf Destination buffer 00274 * @arg size Size of destination buffer. 00275 * 00276 * Converts a priority to a character string and stores the result in 00277 * the specified destination buffer. 00278 * 00279 * @return Name of priority as character string. 00280 */ 00281 char * rtnl_prio2str(int prio, char *buf, size_t size) 00282 { 00283 return __type2str(prio, buf, size, prios, ARRAY_SIZE(prios)); 00284 } 00285 00286 /** 00287 * Convert character string to priority. 00288 * @arg name Name of priority. 00289 * 00290 * Converts the provided character string specifying a priority 00291 * to the corresponding numeric value. 00292 * 00293 * @return Numeric priority or a negative value if no match was found. 00294 */ 00295 int rtnl_str2prio(const char *name) 00296 { 00297 return __str2type(name, prios, ARRAY_SIZE(prios)); 00298 } 00299 00300 /** @} */ 00301 00302 static struct rtnl_qdisc_ops prio_ops = { 00303 .qo_kind = "prio", 00304 .qo_msg_parser = prio_msg_parser, 00305 .qo_free_data = prio_free_data, 00306 .qo_dump[NL_DUMP_BRIEF] = prio_dump_brief, 00307 .qo_dump[NL_DUMP_FULL] = prio_dump_full, 00308 .qo_get_opts = prio_get_opts, 00309 }; 00310 00311 static struct rtnl_qdisc_ops pfifo_fast_ops = { 00312 .qo_kind = "pfifo_fast", 00313 .qo_msg_parser = prio_msg_parser, 00314 .qo_free_data = prio_free_data, 00315 .qo_dump[NL_DUMP_BRIEF] = prio_dump_brief, 00316 .qo_dump[NL_DUMP_FULL] = prio_dump_full, 00317 .qo_get_opts = prio_get_opts, 00318 }; 00319 00320 static void __init prio_init(void) 00321 { 00322 rtnl_qdisc_register(&prio_ops); 00323 rtnl_qdisc_register(&pfifo_fast_ops); 00324 } 00325 00326 static void __exit prio_exit(void) 00327 { 00328 rtnl_qdisc_unregister(&prio_ops); 00329 rtnl_qdisc_unregister(&pfifo_fast_ops); 00330 } 00331 00332 /** @} */