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 -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
00154
00155
00156
00157
00158
00159
00160
00161
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
00179
00180
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
00195
00196
00197
00198
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
00229
00230
00231
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
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
00262
00263
00264
00265
00266
00267
00268
00269
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
00278
00279
00280
00281
00282
00283
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