libnl 2.0
|
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 /** @} */