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/tc-api.h>
00034 #include <netlink/route/qdisc.h>
00035 #include <netlink/route/qdisc/prio.h>
00036
00037
00038 #define SCH_PRIO_ATTR_BANDS 1
00039 #define SCH_PRIO_ATTR_PRIOMAP 2
00040
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
00120
00121
00122
00123
00124
00125
00126
00127
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
00142
00143
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
00160
00161
00162
00163
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
00193
00194
00195
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
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
00228
00229
00230
00231
00232
00233
00234
00235
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
00244
00245
00246
00247
00248
00249
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