00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <netlink-local.h>
00019 #include <netlink-tc.h>
00020 #include <netlink/netlink.h>
00021 #include <netlink/route/tc-api.h>
00022 #include <netlink/route/class.h>
00023 #include <netlink/route/qdisc.h>
00024 #include <netlink/route/classifier.h>
00025 #include <netlink/utils.h>
00026
00027 static struct nl_cache_ops rtnl_class_ops;
00028 static struct nl_object_ops class_obj_ops;
00029
00030 static void class_dump_details(struct rtnl_tc *tc, struct nl_dump_params *p)
00031 {
00032 struct rtnl_class *class = (struct rtnl_class *) tc;
00033 char buf[32];
00034
00035 if (class->c_info)
00036 nl_dump(p, "child-qdisc %s ",
00037 rtnl_tc_handle2str(class->c_info, buf, sizeof(buf)));
00038 }
00039
00040
00041 static int class_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
00042 struct nlmsghdr *nlh, struct nl_parser_param *pp)
00043 {
00044 struct rtnl_class *class;
00045 int err;
00046
00047 if (!(class = rtnl_class_alloc()))
00048 return -NLE_NOMEM;
00049
00050 if ((err = rtnl_tc_msg_parse(nlh, TC_CAST(class))) < 0)
00051 goto errout;
00052
00053 err = pp->pp_cb(OBJ_CAST(class), pp);
00054 errout:
00055 rtnl_class_put(class);
00056
00057 return err;
00058 }
00059
00060 static int class_request_update(struct nl_cache *cache, struct nl_sock *sk)
00061 {
00062 struct tcmsg tchdr = {
00063 .tcm_family = AF_UNSPEC,
00064 .tcm_ifindex = cache->c_iarg1,
00065 };
00066
00067 return nl_send_simple(sk, RTM_GETTCLASS, NLM_F_DUMP, &tchdr,
00068 sizeof(tchdr));
00069 }
00070
00071
00072
00073
00074
00075
00076 struct rtnl_class *rtnl_class_alloc(void)
00077 {
00078 struct rtnl_tc *tc;
00079
00080 tc = TC_CAST(nl_object_alloc(&class_obj_ops));
00081 if (tc)
00082 tc->tc_type = RTNL_TC_TYPE_CLASS;
00083
00084 return (struct rtnl_class *) tc;
00085 }
00086
00087 void rtnl_class_put(struct rtnl_class *class)
00088 {
00089 nl_object_put((struct nl_object *) class);
00090 }
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100 static int class_build(struct rtnl_class *class, int type, int flags,
00101 struct nl_msg **result)
00102 {
00103 int needed = TCA_ATTR_PARENT | TCA_ATTR_HANDLE;
00104
00105 if ((class->ce_mask & needed) == needed &&
00106 TC_H_MAJ(class->c_parent) && TC_H_MAJ(class->c_handle) &&
00107 TC_H_MAJ(class->c_parent) != TC_H_MAJ(class->c_handle)) {
00108 APPBUG("TC_H_MAJ(parent) must match TC_H_MAJ(handle)");
00109 return -NLE_INVAL;
00110 }
00111
00112 return rtnl_tc_msg_build(TC_CAST(class), type, flags, result);
00113 }
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129 int rtnl_class_build_add_request(struct rtnl_class *class, int flags,
00130 struct nl_msg **result)
00131 {
00132 return class_build(class, RTM_NEWTCLASS, flags, result);
00133 }
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171 int rtnl_class_add(struct nl_sock *sk, struct rtnl_class *class, int flags)
00172 {
00173 struct nl_msg *msg;
00174 int err;
00175
00176 if ((err = rtnl_class_build_add_request(class, flags, &msg)) < 0)
00177 return err;
00178
00179 return nl_send_sync(sk, msg);
00180 }
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195 int rtnl_class_build_delete_request(struct rtnl_class *class, struct nl_msg **result)
00196 {
00197 struct nl_msg *msg;
00198 struct tcmsg tchdr;
00199 int required = TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE;
00200
00201 if ((class->ce_mask & required) != required) {
00202 APPBUG("ifindex and handle must be specified");
00203 return -NLE_MISSING_ATTR;
00204 }
00205
00206 if (!(msg = nlmsg_alloc_simple(RTM_DELTCLASS, 0)))
00207 return -NLE_NOMEM;
00208
00209 memset(&tchdr, 0, sizeof(tchdr));
00210 tchdr.tcm_family = AF_UNSPEC;
00211 tchdr.tcm_ifindex = class->c_ifindex;
00212 tchdr.tcm_handle = class->c_handle;
00213
00214 if (class->ce_mask & TCA_ATTR_PARENT)
00215 tchdr.tcm_parent = class->c_parent;
00216
00217 if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0) {
00218 nlmsg_free(msg);
00219 return -NLE_MSGSIZE;
00220 }
00221
00222 *result = msg;
00223 return 0;
00224 }
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252 int rtnl_class_delete(struct nl_sock *sk, struct rtnl_class *class)
00253 {
00254 struct nl_msg *msg;
00255 int err;
00256
00257 if ((err = rtnl_class_build_delete_request(class, &msg)) < 0)
00258 return err;
00259
00260 return nl_send_sync(sk, msg);
00261 }
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277 struct rtnl_qdisc *rtnl_class_leaf_qdisc(struct rtnl_class *class,
00278 struct nl_cache *cache)
00279 {
00280 struct rtnl_qdisc *leaf;
00281
00282 if (!class->c_info)
00283 return NULL;
00284
00285 leaf = rtnl_qdisc_get_by_parent(cache, class->c_ifindex,
00286 class->c_handle);
00287 if (!leaf || leaf->q_handle != class->c_info)
00288 return NULL;
00289
00290 return leaf;
00291 }
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312 int rtnl_class_alloc_cache(struct nl_sock *sk, int ifindex,
00313 struct nl_cache **result)
00314 {
00315 struct nl_cache * cache;
00316 int err;
00317
00318 if (!ifindex) {
00319 APPBUG("ifindex must be specified");
00320 return -NLE_INVAL;
00321 }
00322
00323 if (!(cache = nl_cache_alloc(&rtnl_class_ops)))
00324 return -NLE_NOMEM;
00325
00326 cache->c_iarg1 = ifindex;
00327
00328 if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
00329 nl_cache_free(cache);
00330 return err;
00331 }
00332
00333 *result = cache;
00334 return 0;
00335 }
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353 struct rtnl_class *rtnl_class_get(struct nl_cache *cache, int ifindex,
00354 uint32_t handle)
00355 {
00356 struct rtnl_class *class;
00357
00358 if (cache->c_ops != &rtnl_class_ops)
00359 return NULL;
00360
00361 nl_list_for_each_entry(class, &cache->c_items, ce_list) {
00362 if (class->c_handle == handle && class->c_ifindex == ifindex) {
00363 nl_object_get((struct nl_object *) class);
00364 return class;
00365 }
00366 }
00367 return NULL;
00368 }
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383 void rtnl_class_foreach_child(struct rtnl_class *class, struct nl_cache *cache,
00384 void (*cb)(struct nl_object *, void *), void *arg)
00385 {
00386 struct rtnl_class *filter;
00387
00388 filter = rtnl_class_alloc();
00389 if (!filter)
00390 return;
00391
00392 rtnl_tc_set_parent(TC_CAST(filter), class->c_handle);
00393 rtnl_tc_set_ifindex(TC_CAST(filter), class->c_ifindex);
00394 rtnl_tc_set_kind(TC_CAST(filter), class->c_kind);
00395
00396 nl_cache_foreach_filter(cache, OBJ_CAST(filter), cb, arg);
00397 rtnl_class_put(filter);
00398 }
00399
00400
00401
00402
00403
00404
00405
00406 void rtnl_class_foreach_cls(struct rtnl_class *class, struct nl_cache *cache,
00407 void (*cb)(struct nl_object *, void *), void *arg)
00408 {
00409 struct rtnl_cls *filter;
00410
00411 filter = rtnl_cls_alloc();
00412 if (!filter)
00413 return;
00414
00415 rtnl_tc_set_ifindex((struct rtnl_tc *) filter, class->c_ifindex);
00416 rtnl_tc_set_parent((struct rtnl_tc *) filter, class->c_parent);
00417
00418 nl_cache_foreach_filter(cache, (struct nl_object *) filter, cb, arg);
00419 rtnl_cls_put(filter);
00420 }
00421
00422
00423
00424 static struct rtnl_tc_type_ops class_ops = {
00425 .tt_type = RTNL_TC_TYPE_CLASS,
00426 .tt_dump_prefix = "class",
00427 .tt_dump = {
00428 [NL_DUMP_DETAILS] = class_dump_details,
00429 },
00430 };
00431
00432 static struct nl_object_ops class_obj_ops = {
00433 .oo_name = "route/class",
00434 .oo_size = sizeof(struct rtnl_class),
00435 .oo_free_data = rtnl_tc_free_data,
00436 .oo_clone = rtnl_tc_clone,
00437 .oo_dump = {
00438 [NL_DUMP_LINE] = rtnl_tc_dump_line,
00439 [NL_DUMP_DETAILS] = rtnl_tc_dump_details,
00440 [NL_DUMP_STATS] = rtnl_tc_dump_stats,
00441 },
00442 .oo_compare = rtnl_tc_compare,
00443 .oo_id_attrs = (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE),
00444 };
00445
00446 static struct nl_cache_ops rtnl_class_ops = {
00447 .co_name = "route/class",
00448 .co_hdrsize = sizeof(struct tcmsg),
00449 .co_msgtypes = {
00450 { RTM_NEWTCLASS, NL_ACT_NEW, "new" },
00451 { RTM_DELTCLASS, NL_ACT_DEL, "del" },
00452 { RTM_GETTCLASS, NL_ACT_GET, "get" },
00453 END_OF_MSGTYPES_LIST,
00454 },
00455 .co_protocol = NETLINK_ROUTE,
00456 .co_request_update = &class_request_update,
00457 .co_msg_parser = &class_msg_parser,
00458 .co_obj_ops = &class_obj_ops,
00459 };
00460
00461 static void __init class_init(void)
00462 {
00463 rtnl_tc_type_register(&class_ops);
00464 nl_cache_mngt_register(&rtnl_class_ops);
00465 }
00466
00467 static void __exit class_exit(void)
00468 {
00469 nl_cache_mngt_unregister(&rtnl_class_ops);
00470 rtnl_tc_type_unregister(&class_ops);
00471 }
00472
00473