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 #include <netlink-local.h>
00027 #include <netlink-tc.h>
00028 #include <netlink/netlink.h>
00029 #include <netlink/utils.h>
00030 #include <netlink/route/qdisc.h>
00031 #include <netlink/route/qdisc-modules.h>
00032 #include <netlink/route/sch/sfq.h>
00033
00034
00035 #define SCH_SFQ_ATTR_QUANTUM 0x01
00036 #define SCH_SFQ_ATTR_PERTURB 0x02
00037 #define SCH_SFQ_ATTR_LIMIT 0x04
00038 #define SCH_SFQ_ATTR_DIVISOR 0x08
00039 #define SCH_SFQ_ATTR_FLOWS 0x10
00040
00041
00042 static inline struct rtnl_sfq *sfq_qdisc(struct rtnl_qdisc *qdisc)
00043 {
00044 return (struct rtnl_sfq *) qdisc->q_subdata;
00045 }
00046
00047 static inline struct rtnl_sfq *sfq_alloc(struct rtnl_qdisc *qdisc)
00048 {
00049 if (!qdisc->q_subdata)
00050 qdisc->q_subdata = calloc(1, sizeof(struct rtnl_sfq));
00051
00052 return sfq_qdisc(qdisc);
00053 }
00054
00055 static int sfq_msg_parser(struct rtnl_qdisc *qdisc)
00056 {
00057 struct rtnl_sfq *sfq;
00058 struct tc_sfq_qopt *opts;
00059
00060 if (!(qdisc->ce_mask & TCA_ATTR_OPTS))
00061 return 0;
00062
00063 if (qdisc->q_opts->d_size < sizeof(*opts))
00064 return nl_error(EINVAL, "SFQ specific options size mismatch");
00065
00066 sfq = sfq_alloc(qdisc);
00067 if (!sfq)
00068 return nl_errno(ENOMEM);
00069
00070 opts = (struct tc_sfq_qopt *) qdisc->q_opts->d_data;
00071
00072 sfq->qs_quantum = opts->quantum;
00073 sfq->qs_perturb = opts->perturb_period;
00074 sfq->qs_limit = opts->limit;
00075 sfq->qs_divisor = opts->divisor;
00076 sfq->qs_flows = opts->flows;
00077
00078 sfq->qs_mask = (SCH_SFQ_ATTR_QUANTUM | SCH_SFQ_ATTR_PERTURB |
00079 SCH_SFQ_ATTR_LIMIT | SCH_SFQ_ATTR_DIVISOR |
00080 SCH_SFQ_ATTR_FLOWS);
00081
00082 return 0;
00083 }
00084
00085 static void sfq_free_data(struct rtnl_qdisc *qdisc)
00086 {
00087 free(qdisc->q_subdata);
00088 }
00089
00090 static int sfq_dump_brief(struct rtnl_qdisc *qdisc, struct nl_dump_params *p,
00091 int line)
00092 {
00093 struct rtnl_sfq *sfq = sfq_qdisc(qdisc);
00094
00095 if (sfq)
00096 dp_dump(p, " quantum %u perturb %us",
00097 sfq->qs_quantum,
00098 nl_ticks2us(sfq->qs_perturb * nl_get_hz()));
00099
00100 return line;
00101 }
00102
00103 static int sfq_dump_full(struct rtnl_qdisc *qdisc, struct nl_dump_params *p,
00104 int line)
00105 {
00106 struct rtnl_sfq *sfq = sfq_qdisc(qdisc);
00107
00108 if (sfq)
00109 dp_dump(p, "limit %u divisor %u",
00110 sfq->qs_limit, sfq->qs_divisor);
00111
00112 return line;
00113 }
00114
00115 static struct nl_msg *sfq_get_opts(struct rtnl_qdisc *qdisc)
00116 {
00117 struct rtnl_sfq *sfq;
00118 struct tc_sfq_qopt opts;
00119 struct nl_msg *msg;
00120
00121 sfq = sfq_qdisc(qdisc);
00122 if (!sfq)
00123 return NULL;
00124
00125 msg = nlmsg_alloc();
00126 if (!msg)
00127 goto errout;
00128
00129 memset(&opts, 0, sizeof(opts));
00130 opts.quantum = sfq->qs_quantum;
00131 opts.perturb_period = sfq->qs_perturb;
00132 opts.limit = sfq->qs_limit;
00133
00134 if (nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD) < 0)
00135 goto errout;
00136
00137 return msg;
00138 errout:
00139 nlmsg_free(msg);
00140 return NULL;
00141 }
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154 int rtnl_sfq_set_quantum(struct rtnl_qdisc *qdisc, int quantum)
00155 {
00156 struct rtnl_sfq *sfq;
00157
00158 sfq = sfq_alloc(qdisc);
00159 if (!sfq)
00160 return nl_errno(ENOMEM);
00161
00162 sfq->qs_quantum = quantum;
00163 sfq->qs_mask |= SCH_SFQ_ATTR_QUANTUM;
00164
00165 return 0;
00166 }
00167
00168
00169
00170
00171
00172
00173 int rtnl_sfq_get_quantum(struct rtnl_qdisc *qdisc)
00174 {
00175 struct rtnl_sfq *sfq;
00176
00177 sfq = sfq_qdisc(qdisc);
00178 if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_QUANTUM)
00179 return sfq->qs_quantum;
00180 else
00181 return nl_errno(ENOENT);
00182 }
00183
00184
00185
00186
00187
00188
00189
00190 int rtnl_sfq_set_limit(struct rtnl_qdisc *qdisc, int limit)
00191 {
00192 struct rtnl_sfq *sfq;
00193
00194 sfq = sfq_alloc(qdisc);
00195 if (!sfq)
00196 return nl_errno(ENOMEM);
00197
00198 sfq->qs_limit = limit;
00199 sfq->qs_mask |= SCH_SFQ_ATTR_LIMIT;
00200
00201 return 0;
00202 }
00203
00204
00205
00206
00207
00208
00209 int rtnl_sfq_get_limit(struct rtnl_qdisc *qdisc)
00210 {
00211 struct rtnl_sfq *sfq;
00212
00213 sfq = sfq_qdisc(qdisc);
00214 if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_LIMIT)
00215 return sfq->qs_limit;
00216 else
00217 return nl_errno(ENOENT);
00218 }
00219
00220
00221
00222
00223
00224
00225
00226
00227 int rtnl_sfq_set_perturb(struct rtnl_qdisc *qdisc, int perturb)
00228 {
00229 struct rtnl_sfq *sfq;
00230
00231 sfq = sfq_alloc(qdisc);
00232 if (!sfq)
00233 return nl_errno(ENOMEM);
00234
00235 sfq->qs_perturb = perturb;
00236 sfq->qs_mask |= SCH_SFQ_ATTR_PERTURB;
00237
00238 return 0;
00239 }
00240
00241
00242
00243
00244
00245
00246 int rtnl_sfq_get_perturb(struct rtnl_qdisc *qdisc)
00247 {
00248 struct rtnl_sfq *sfq;
00249
00250 sfq = sfq_qdisc(qdisc);
00251 if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_PERTURB)
00252 return sfq->qs_perturb;
00253 else
00254 return nl_errno(ENOENT);
00255 }
00256
00257
00258
00259
00260
00261
00262 int rtnl_sfq_get_divisor(struct rtnl_qdisc *qdisc)
00263 {
00264 struct rtnl_sfq *sfq;
00265
00266 sfq = sfq_qdisc(qdisc);
00267 if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_DIVISOR)
00268 return sfq->qs_divisor;
00269 else
00270 return nl_errno(ENOENT);
00271 }
00272
00273
00274
00275 static struct rtnl_qdisc_ops sfq_ops = {
00276 .qo_kind = "sfq",
00277 .qo_msg_parser = sfq_msg_parser,
00278 .qo_free_data = sfq_free_data,
00279 .qo_dump[NL_DUMP_BRIEF] = sfq_dump_brief,
00280 .qo_dump[NL_DUMP_FULL] = sfq_dump_full,
00281 .qo_get_opts = sfq_get_opts,
00282 };
00283
00284 static void __init sfq_init(void)
00285 {
00286 rtnl_qdisc_register(&sfq_ops);
00287 }
00288
00289 static void __exit sfq_exit(void)
00290 {
00291 rtnl_qdisc_unregister(&sfq_ops);
00292 }
00293
00294