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 static int class_build(struct rtnl_class *class, int type, int flags,
00077 struct nl_msg **result)
00078 {
00079 return rtnl_tc_msg_build(TC_CAST(class), type, flags, result);
00080 }
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098 int rtnl_class_build_add_request(struct rtnl_class *class, int flags,
00099 struct nl_msg **result)
00100 {
00101 return class_build(class, RTM_NEWTCLASS, NLM_F_CREATE | flags, result);
00102 }
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119 int rtnl_class_add(struct nl_sock *sk, struct rtnl_class *class, int flags)
00120 {
00121 struct nl_msg *msg;
00122 int err;
00123
00124 if ((err = rtnl_class_build_add_request(class, flags, &msg)) < 0)
00125 return err;
00126
00127 err = nl_send_auto_complete(sk, msg);
00128 nlmsg_free(msg);
00129 if (err < 0)
00130 return err;
00131
00132 return wait_for_ack(sk);
00133 }
00134
00135 int rtnl_class_build_delete_request(struct rtnl_class *class,
00136 struct nl_msg **result)
00137 {
00138 struct nl_msg *msg;
00139 struct tcmsg tchdr;
00140 int required = TCA_ATTR_IFINDEX | TCA_ATTR_PARENT;
00141
00142 if ((class->ce_mask & required) != required)
00143 BUG();
00144
00145 msg = nlmsg_alloc_simple(RTM_DELTCLASS, 0);
00146 if (!msg)
00147 return -NLE_NOMEM;
00148
00149 tchdr.tcm_family = AF_UNSPEC;
00150 tchdr.tcm_handle = class->c_handle;
00151 tchdr.tcm_parent = class->c_parent;
00152 tchdr.tcm_ifindex = class->c_ifindex;
00153 if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0) {
00154 nlmsg_free(msg);
00155 return -NLE_MSGSIZE;
00156 }
00157
00158 *result = msg;
00159 return 0;
00160 }
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173 int rtnl_class_delete(struct nl_sock *sk, struct rtnl_class *class)
00174 {
00175 struct nl_msg *msg;
00176 int err;
00177
00178 if ((err = rtnl_class_build_delete_request(class, &msg)) < 0)
00179 return err;
00180
00181 err = nl_send_auto_complete(sk, msg);
00182 nlmsg_free(msg);
00183 if (err < 0)
00184 return err;
00185
00186 return wait_for_ack(sk);
00187 }
00188
00189
00190
00191
00192
00193
00194
00195
00196 struct rtnl_class *rtnl_class_alloc(void)
00197 {
00198 struct rtnl_tc *tc;
00199
00200 tc = TC_CAST(nl_object_alloc(&class_obj_ops));
00201 if (tc)
00202 tc->tc_type = RTNL_TC_TYPE_CLASS;
00203
00204 return (struct rtnl_class *) tc;
00205 }
00206
00207 void rtnl_class_put(struct rtnl_class *class)
00208 {
00209 nl_object_put((struct nl_object *) class);
00210 }
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226 struct rtnl_qdisc *rtnl_class_leaf_qdisc(struct rtnl_class *class,
00227 struct nl_cache *cache)
00228 {
00229 struct rtnl_qdisc *leaf;
00230
00231 if (!class->c_info)
00232 return NULL;
00233
00234 leaf = rtnl_qdisc_get_by_parent(cache, class->c_ifindex,
00235 class->c_handle);
00236 if (!leaf || leaf->q_handle != class->c_info)
00237 return NULL;
00238
00239 return leaf;
00240 }
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258 void rtnl_class_foreach_child(struct rtnl_class *class, struct nl_cache *cache,
00259 void (*cb)(struct nl_object *, void *), void *arg)
00260 {
00261 struct rtnl_class *filter;
00262
00263 filter = rtnl_class_alloc();
00264 if (!filter)
00265 return;
00266
00267 rtnl_tc_set_parent(TC_CAST(filter), class->c_handle);
00268 rtnl_tc_set_ifindex(TC_CAST(filter), class->c_ifindex);
00269 rtnl_tc_set_kind(TC_CAST(filter), class->c_kind);
00270
00271 nl_cache_foreach_filter(cache, OBJ_CAST(filter), cb, arg);
00272 rtnl_class_put(filter);
00273 }
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283 void rtnl_class_foreach_cls(struct rtnl_class *class, struct nl_cache *cache,
00284 void (*cb)(struct nl_object *, void *), void *arg)
00285 {
00286 struct rtnl_cls *filter;
00287
00288 filter = rtnl_cls_alloc();
00289 if (!filter)
00290 return;
00291
00292 rtnl_tc_set_ifindex((struct rtnl_tc *) filter, class->c_ifindex);
00293 rtnl_tc_set_parent((struct rtnl_tc *) filter, class->c_parent);
00294
00295 nl_cache_foreach_filter(cache, (struct nl_object *) filter, cb, arg);
00296 rtnl_cls_put(filter);
00297 }
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318 int rtnl_class_alloc_cache(struct nl_sock *sk, int ifindex,
00319 struct nl_cache **result)
00320 {
00321 struct nl_cache * cache;
00322 int err;
00323
00324 cache = nl_cache_alloc(&rtnl_class_ops);
00325 if (!cache)
00326 return -NLE_NOMEM;
00327
00328 cache->c_iarg1 = ifindex;
00329
00330 if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
00331 nl_cache_free(cache);
00332 return err;
00333 }
00334
00335 *result = cache;
00336 return 0;
00337 }
00338
00339
00340
00341
00342
00343
00344
00345
00346 struct rtnl_class *rtnl_class_get(struct nl_cache *cache, int ifindex,
00347 uint32_t handle)
00348 {
00349 struct rtnl_class *class;
00350
00351 if (cache->c_ops != &rtnl_class_ops)
00352 return NULL;
00353
00354 nl_list_for_each_entry(class, &cache->c_items, ce_list) {
00355 if (class->c_handle == handle && class->c_ifindex == ifindex) {
00356 nl_object_get((struct nl_object *) class);
00357 return class;
00358 }
00359 }
00360 return NULL;
00361 }
00362
00363
00364
00365 static struct rtnl_tc_type_ops class_ops = {
00366 .tt_type = RTNL_TC_TYPE_CLASS,
00367 .tt_dump_prefix = "class",
00368 .tt_dump = {
00369 [NL_DUMP_DETAILS] = class_dump_details,
00370 },
00371 };
00372
00373 static struct nl_object_ops class_obj_ops = {
00374 .oo_name = "route/class",
00375 .oo_size = sizeof(struct rtnl_class),
00376 .oo_free_data = rtnl_tc_free_data,
00377 .oo_clone = rtnl_tc_clone,
00378 .oo_dump = {
00379 [NL_DUMP_LINE] = rtnl_tc_dump_line,
00380 [NL_DUMP_DETAILS] = rtnl_tc_dump_details,
00381 [NL_DUMP_STATS] = rtnl_tc_dump_stats,
00382 },
00383 .oo_compare = rtnl_tc_compare,
00384 .oo_id_attrs = (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE),
00385 };
00386
00387 static struct nl_cache_ops rtnl_class_ops = {
00388 .co_name = "route/class",
00389 .co_hdrsize = sizeof(struct tcmsg),
00390 .co_msgtypes = {
00391 { RTM_NEWTCLASS, NL_ACT_NEW, "new" },
00392 { RTM_DELTCLASS, NL_ACT_DEL, "del" },
00393 { RTM_GETTCLASS, NL_ACT_GET, "get" },
00394 END_OF_MSGTYPES_LIST,
00395 },
00396 .co_protocol = NETLINK_ROUTE,
00397 .co_request_update = &class_request_update,
00398 .co_msg_parser = &class_msg_parser,
00399 .co_obj_ops = &class_obj_ops,
00400 };
00401
00402 static void __init class_init(void)
00403 {
00404 rtnl_tc_type_register(&class_ops);
00405 nl_cache_mngt_register(&rtnl_class_ops);
00406 }
00407
00408 static void __exit class_exit(void)
00409 {
00410 nl_cache_mngt_unregister(&rtnl_class_ops);
00411 rtnl_tc_type_unregister(&class_ops);
00412 }
00413
00414