libnl 3.0
|
00001 /* 00002 * lib/route/class.c Queueing Classes 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation version 2.1 00007 * of the License. 00008 * 00009 * Copyright (c) 2003-2010 Thomas Graf <tgraf@suug.ch> 00010 */ 00011 00012 /** 00013 * @ingroup tc 00014 * @defgroup class Queueing Classes 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 * @name Addition/Modification 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 * Build a netlink message to add a new class 00084 * @arg class class to add 00085 * @arg flags additional netlink message flags 00086 * @arg result Pointer to store resulting message. 00087 * 00088 * Builds a new netlink message requesting an addition of a class. 00089 * The netlink message header isn't fully equipped with all relevant 00090 * fields and must be sent out via nl_send_auto_complete() or 00091 * supplemented as needed. 00092 * 00093 * Common message flags 00094 * - NLM_F_REPLACE - replace possibly existing classes 00095 * 00096 * @return 0 on success or a negative error code. 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 * Add a new class 00106 * @arg sk Netlink socket. 00107 * @arg class class to delete 00108 * @arg flags additional netlink message flags 00109 * 00110 * Builds a netlink message by calling rtnl_qdisc_build_add_request(), 00111 * sends the request to the kernel and waits for the next ACK to be 00112 * received and thus blocks until the request has been processed. 00113 * 00114 * Common message flags 00115 * - NLM_F_REPLACE - replace possibly existing classes 00116 * 00117 * @return 0 on success or a negative error code 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 * Delete a class 00164 * @arg sk Netlink socket. 00165 * @arg class class to delete 00166 * 00167 * Builds a netlink message by calling rtnl_class_build_delete_request(), 00168 * sends the request to the kernel and waits for the ACK to be 00169 * received and thus blocks until the request has been processed. 00170 * 00171 * @return 0 on success or a negative error code 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 * @name Allocation/Freeing 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 * @name Leaf Qdisc 00216 * @{ 00217 */ 00218 00219 /** 00220 * Lookup the leaf qdisc of a class 00221 * @arg class the parent class 00222 * @arg cache a qdisc cache including at laest all qdiscs of the 00223 * interface the specified class is attached to 00224 * @return The qdisc from the cache or NULL if the class has no leaf qdisc 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 * @name Iterators 00247 * @{ 00248 */ 00249 00250 /** 00251 * Call a callback for each child of a class 00252 * @arg class the parent class 00253 * @arg cache a class cache including all classes of the interface 00254 * the specified class is attached to 00255 * @arg cb callback function 00256 * @arg arg argument to be passed to callback function 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 * Call a callback for each classifier attached to the class 00277 * @arg class the parent class 00278 * @arg cache a filter cache including at least all the filters 00279 * attached to the specified class 00280 * @arg cb callback function 00281 * @arg arg argument to be passed to callback function 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 * @name Cache Management 00304 * @{ 00305 */ 00306 00307 /** 00308 * Build a class cache including all classes attached to the specified interface 00309 * @arg sk Netlink socket. 00310 * @arg ifindex interface index of the link the classes are 00311 * attached to. 00312 * 00313 * Allocates a new cache, initializes it properly and updates it to 00314 * include all classes attached to the specified interface. 00315 * 00316 * @return The cache or NULL if an error has occured. 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 * Look up class by its handle in the provided cache 00341 * @arg cache class cache 00342 * @arg ifindex interface the class is attached to 00343 * @arg handle class handle 00344 * @return pointer to class inside the cache or NULL if no match was found. 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 /** @} */