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
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085 #include <netlink-local.h>
00086 #include <netlink-tc.h>
00087 #include <netlink/netlink.h>
00088 #include <netlink/utils.h>
00089 #include <netlink/route/link.h>
00090 #include <netlink/route/tc.h>
00091 #include <netlink/route/qdisc.h>
00092 #include <netlink/route/class.h>
00093 #include <netlink/route/classifier.h>
00094 #include <netlink/route/qdisc-modules.h>
00095
00096 static struct nl_cache_ops rtnl_qdisc_ops;
00097
00098 static int qdisc_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
00099 struct nlmsghdr *n, struct nl_parser_param *pp)
00100 {
00101 int err;
00102 struct rtnl_qdisc *qdisc;
00103 struct rtnl_qdisc_ops *qops;
00104
00105 qdisc = rtnl_qdisc_alloc();
00106 if (!qdisc) {
00107 err = -NLE_NOMEM;
00108 goto errout;
00109 }
00110
00111 qdisc->ce_msgtype = n->nlmsg_type;
00112
00113 err = tca_msg_parser(n, (struct rtnl_tca *) qdisc);
00114 if (err < 0)
00115 goto errout_free;
00116
00117 qops = rtnl_qdisc_lookup_ops(qdisc);
00118 if (qops && qops->qo_msg_parser) {
00119 err = qops->qo_msg_parser(qdisc);
00120 if (err < 0)
00121 goto errout_free;
00122 }
00123
00124 err = pp->pp_cb((struct nl_object *) qdisc, pp);
00125 errout_free:
00126 rtnl_qdisc_put(qdisc);
00127 errout:
00128 return err;
00129 }
00130
00131 static int qdisc_request_update(struct nl_cache *c, struct nl_sock *sk)
00132 {
00133 struct tcmsg tchdr = {
00134 .tcm_family = AF_UNSPEC,
00135 .tcm_ifindex = c->c_iarg1,
00136 };
00137
00138 return nl_send_simple(sk, RTM_GETQDISC, NLM_F_DUMP, &tchdr,
00139 sizeof(tchdr));
00140 }
00141
00142
00143
00144
00145
00146
00147 static int qdisc_build(struct rtnl_qdisc *qdisc, int type, int flags,
00148 struct nl_msg **result)
00149 {
00150 struct rtnl_qdisc_ops *qops;
00151 int err;
00152
00153 err = tca_build_msg((struct rtnl_tca *) qdisc, type, flags, result);
00154 if (err < 0)
00155 return err;
00156
00157 qops = rtnl_qdisc_lookup_ops(qdisc);
00158 if (qops && qops->qo_get_opts) {
00159 struct nl_msg *opts;
00160
00161 opts = qops->qo_get_opts(qdisc);
00162 if (opts) {
00163 err = nla_put_nested(*result, TCA_OPTIONS, opts);
00164 nlmsg_free(opts);
00165 if (err < 0)
00166 goto errout;
00167 }
00168 }
00169
00170
00171
00172 else if (qops && qops->qo_build_msg) {
00173 err = qops->qo_build_msg(qdisc, *result);
00174 if (err < 0)
00175 goto errout;
00176 }
00177
00178 return 0;
00179 errout:
00180 nlmsg_free(*result);
00181
00182 return err;
00183 }
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201 int rtnl_qdisc_build_add_request(struct rtnl_qdisc *qdisc, int flags,
00202 struct nl_msg **result)
00203 {
00204 return qdisc_build(qdisc, RTM_NEWQDISC, NLM_F_CREATE | flags, result);
00205 }
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222 int rtnl_qdisc_add(struct nl_sock *sk, struct rtnl_qdisc *qdisc,
00223 int flags)
00224 {
00225 struct nl_msg *msg;
00226 int err;
00227
00228 if ((err = rtnl_qdisc_build_add_request(qdisc, flags, &msg)) < 0)
00229 return err;
00230
00231 err = nl_send_auto_complete(sk, msg);
00232 nlmsg_free(msg);
00233 if (err < 0)
00234 return err;
00235
00236 return wait_for_ack(sk);
00237 }
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259 int rtnl_qdisc_build_change_request(struct rtnl_qdisc *qdisc,
00260 struct rtnl_qdisc *new,
00261 struct nl_msg **result)
00262 {
00263 return qdisc_build(qdisc, RTM_NEWQDISC, NLM_F_REPLACE, result);
00264 }
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278 int rtnl_qdisc_change(struct nl_sock *sk, struct rtnl_qdisc *qdisc,
00279 struct rtnl_qdisc *new)
00280 {
00281 struct nl_msg *msg;
00282 int err;
00283
00284 if ((err = rtnl_qdisc_build_change_request(qdisc, new, &msg)) < 0)
00285 return err;
00286
00287 err = nl_send_auto_complete(sk, msg);
00288 nlmsg_free(msg);
00289 if (err < 0)
00290 return err;
00291
00292 return wait_for_ack(sk);
00293 }
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314 int rtnl_qdisc_build_delete_request(struct rtnl_qdisc *qdisc,
00315 struct nl_msg **result)
00316 {
00317 struct nl_msg *msg;
00318 struct tcmsg tchdr;
00319 int required = TCA_ATTR_IFINDEX | TCA_ATTR_PARENT;
00320
00321 if ((qdisc->ce_mask & required) != required)
00322 BUG();
00323
00324 msg = nlmsg_alloc_simple(RTM_DELQDISC, 0);
00325 if (!msg)
00326 return -NLE_NOMEM;
00327
00328 tchdr.tcm_family = AF_UNSPEC;
00329 tchdr.tcm_handle = qdisc->q_handle;
00330 tchdr.tcm_parent = qdisc->q_parent;
00331 tchdr.tcm_ifindex = qdisc->q_ifindex;
00332 if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0) {
00333 nlmsg_free(msg);
00334 return -NLE_MSGSIZE;
00335 }
00336
00337 *result = msg;
00338 return 0;
00339 }
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352 int rtnl_qdisc_delete(struct nl_sock *sk, struct rtnl_qdisc *qdisc)
00353 {
00354 struct nl_msg *msg;
00355 int err;
00356
00357 if ((err = rtnl_qdisc_build_delete_request(qdisc, &msg)) < 0)
00358 return err;
00359
00360 err = nl_send_auto_complete(sk, msg);
00361 nlmsg_free(msg);
00362 if (err < 0)
00363 return err;
00364
00365 return wait_for_ack(sk);
00366 }
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386 int rtnl_qdisc_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
00387 {
00388 return nl_cache_alloc_and_fill(&rtnl_qdisc_ops, sk, result);
00389 }
00390
00391
00392
00393
00394
00395
00396
00397
00398 struct rtnl_qdisc * rtnl_qdisc_get_by_parent(struct nl_cache *cache,
00399 int ifindex, uint32_t parent)
00400 {
00401 struct rtnl_qdisc *q;
00402
00403 if (cache->c_ops != &rtnl_qdisc_ops)
00404 return NULL;
00405
00406 nl_list_for_each_entry(q, &cache->c_items, ce_list) {
00407 if (q->q_parent == parent && q->q_ifindex == ifindex) {
00408 nl_object_get((struct nl_object *) q);
00409 return q;
00410 }
00411 }
00412
00413 return NULL;
00414 }
00415
00416
00417
00418
00419
00420
00421
00422
00423 struct rtnl_qdisc * rtnl_qdisc_get(struct nl_cache *cache,
00424 int ifindex, uint32_t handle)
00425 {
00426 struct rtnl_qdisc *q;
00427
00428 if (cache->c_ops != &rtnl_qdisc_ops)
00429 return NULL;
00430
00431 nl_list_for_each_entry(q, &cache->c_items, ce_list) {
00432 if (q->q_handle == handle && q->q_ifindex == ifindex) {
00433 nl_object_get((struct nl_object *) q);
00434 return q;
00435 }
00436 }
00437
00438 return NULL;
00439 }
00440
00441
00442
00443 static struct nl_cache_ops rtnl_qdisc_ops = {
00444 .co_name = "route/qdisc",
00445 .co_hdrsize = sizeof(struct tcmsg),
00446 .co_msgtypes = {
00447 { RTM_NEWQDISC, NL_ACT_NEW, "new" },
00448 { RTM_DELQDISC, NL_ACT_DEL, "del" },
00449 { RTM_GETQDISC, NL_ACT_GET, "get" },
00450 END_OF_MSGTYPES_LIST,
00451 },
00452 .co_protocol = NETLINK_ROUTE,
00453 .co_request_update = qdisc_request_update,
00454 .co_msg_parser = qdisc_msg_parser,
00455 .co_obj_ops = &qdisc_obj_ops,
00456 };
00457
00458 static void __init qdisc_init(void)
00459 {
00460 nl_cache_mngt_register(&rtnl_qdisc_ops);
00461 }
00462
00463 static void __exit qdisc_exit(void)
00464 {
00465 nl_cache_mngt_unregister(&rtnl_qdisc_ops);
00466 }
00467
00468