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 -NLE_INVAL;
00065
00066 sfq = sfq_alloc(qdisc);
00067 if (!sfq)
00068 return -NLE_NOMEM;
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 void sfq_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p)
00091 {
00092 struct rtnl_sfq *sfq = sfq_qdisc(qdisc);
00093
00094 if (sfq)
00095 nl_dump(p, " quantum %u perturb %us", sfq->qs_quantum,
00096 nl_ticks2us(sfq->qs_perturb * nl_get_hz()));
00097 }
00098
00099 static void sfq_dump_details(struct rtnl_qdisc *qdisc, struct nl_dump_params *p)
00100 {
00101 struct rtnl_sfq *sfq = sfq_qdisc(qdisc);
00102
00103 if (sfq)
00104 nl_dump(p, "limit %u divisor %u",
00105 sfq->qs_limit, sfq->qs_divisor);
00106 }
00107
00108 static struct nl_msg *sfq_get_opts(struct rtnl_qdisc *qdisc)
00109 {
00110 struct rtnl_sfq *sfq;
00111 struct tc_sfq_qopt opts;
00112 struct nl_msg *msg;
00113
00114 sfq = sfq_qdisc(qdisc);
00115 if (!sfq)
00116 return NULL;
00117
00118 msg = nlmsg_alloc();
00119 if (!msg)
00120 goto errout;
00121
00122 memset(&opts, 0, sizeof(opts));
00123 opts.quantum = sfq->qs_quantum;
00124 opts.perturb_period = sfq->qs_perturb;
00125 opts.limit = sfq->qs_limit;
00126
00127 if (nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD) < 0)
00128 goto errout;
00129
00130 return msg;
00131 errout:
00132 nlmsg_free(msg);
00133 return NULL;
00134 }
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147 int rtnl_sfq_set_quantum(struct rtnl_qdisc *qdisc, int quantum)
00148 {
00149 struct rtnl_sfq *sfq;
00150
00151 sfq = sfq_alloc(qdisc);
00152 if (!sfq)
00153 return -NLE_NOMEM;
00154
00155 sfq->qs_quantum = quantum;
00156 sfq->qs_mask |= SCH_SFQ_ATTR_QUANTUM;
00157
00158 return 0;
00159 }
00160
00161
00162
00163
00164
00165
00166 int rtnl_sfq_get_quantum(struct rtnl_qdisc *qdisc)
00167 {
00168 struct rtnl_sfq *sfq;
00169
00170 sfq = sfq_qdisc(qdisc);
00171 if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_QUANTUM)
00172 return sfq->qs_quantum;
00173 else
00174 return -NLE_NOATTR;
00175 }
00176
00177
00178
00179
00180
00181
00182
00183 int rtnl_sfq_set_limit(struct rtnl_qdisc *qdisc, int limit)
00184 {
00185 struct rtnl_sfq *sfq;
00186
00187 sfq = sfq_alloc(qdisc);
00188 if (!sfq)
00189 return -NLE_NOMEM;
00190
00191 sfq->qs_limit = limit;
00192 sfq->qs_mask |= SCH_SFQ_ATTR_LIMIT;
00193
00194 return 0;
00195 }
00196
00197
00198
00199
00200
00201
00202 int rtnl_sfq_get_limit(struct rtnl_qdisc *qdisc)
00203 {
00204 struct rtnl_sfq *sfq;
00205
00206 sfq = sfq_qdisc(qdisc);
00207 if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_LIMIT)
00208 return sfq->qs_limit;
00209 else
00210 return -NLE_NOATTR;
00211 }
00212
00213
00214
00215
00216
00217
00218
00219
00220 int rtnl_sfq_set_perturb(struct rtnl_qdisc *qdisc, int perturb)
00221 {
00222 struct rtnl_sfq *sfq;
00223
00224 sfq = sfq_alloc(qdisc);
00225 if (!sfq)
00226 return -NLE_NOMEM;
00227
00228 sfq->qs_perturb = perturb;
00229 sfq->qs_mask |= SCH_SFQ_ATTR_PERTURB;
00230
00231 return 0;
00232 }
00233
00234
00235
00236
00237
00238
00239 int rtnl_sfq_get_perturb(struct rtnl_qdisc *qdisc)
00240 {
00241 struct rtnl_sfq *sfq;
00242
00243 sfq = sfq_qdisc(qdisc);
00244 if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_PERTURB)
00245 return sfq->qs_perturb;
00246 else
00247 return -NLE_NOATTR;
00248 }
00249
00250
00251
00252
00253
00254
00255 int rtnl_sfq_get_divisor(struct rtnl_qdisc *qdisc)
00256 {
00257 struct rtnl_sfq *sfq;
00258
00259 sfq = sfq_qdisc(qdisc);
00260 if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_DIVISOR)
00261 return sfq->qs_divisor;
00262 else
00263 return -NLE_NOATTR;
00264 }
00265
00266
00267
00268 static struct rtnl_qdisc_ops sfq_ops = {
00269 .qo_kind = "sfq",
00270 .qo_msg_parser = sfq_msg_parser,
00271 .qo_free_data = sfq_free_data,
00272 .qo_dump = {
00273 [NL_DUMP_LINE] = sfq_dump_line,
00274 [NL_DUMP_DETAILS] = sfq_dump_details,
00275 },
00276 .qo_get_opts = sfq_get_opts,
00277 };
00278
00279 static void __init sfq_init(void)
00280 {
00281 rtnl_qdisc_register(&sfq_ops);
00282 }
00283
00284 static void __exit sfq_exit(void)
00285 {
00286 rtnl_qdisc_unregister(&sfq_ops);
00287 }
00288
00289