00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
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
00038 #define SCH_PRIO_ATTR_BANDS 1
00039 #define SCH_PRIO_ATTR_PRIOMAP 2
00040
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
00161
00162
00163
00164
00165
00166
00167
00168
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
00186
00187
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
00202
00203
00204
00205
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
00237
00238
00239
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
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
00272
00273
00274
00275
00276
00277
00278
00279
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
00288
00289
00290
00291
00292
00293
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