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