/build/buildd/libnl-1.0~pre6/lib/route/class.c

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-2006 Thomas Graf <tgraf@suug.ch>
00010  */
00011 
00012 /**
00013  * @ingroup tc
00014  * @defgroup class Classes
00015  * @{
00016  */
00017 
00018 #include <netlink-local.h>
00019 #include <netlink-tc.h>
00020 #include <netlink/netlink.h>
00021 #include <netlink/route/tc.h>
00022 #include <netlink/route/class.h>
00023 #include <netlink/route/class-modules.h>
00024 #include <netlink/route/qdisc.h>
00025 #include <netlink/route/classifier.h>
00026 #include <netlink/utils.h>
00027 
00028 /** @cond SKIP */
00029 static struct nl_cache_ops rtnl_class_ops;
00030 /** @endcond */
00031 
00032 static struct rtnl_class_ops *class_ops_list;
00033 
00034 static struct rtnl_class_ops *class_lookup_ops(const char *kind)
00035 {
00036         struct rtnl_class_ops *ops;
00037 
00038         for (ops = class_ops_list; ops; ops = ops->co_next)
00039                 if (!strcmp(kind, ops->co_kind))
00040                         return ops;
00041 
00042         return NULL;
00043 }
00044 
00045 static inline struct rtnl_class_ops *class_ops(struct rtnl_class *class)
00046 {
00047         if (!class->c_ops)
00048                 class->c_ops = class_lookup_ops(class->c_kind);
00049 
00050         return class->c_ops;
00051 }
00052 
00053 /**
00054  * @name Class Module API
00055  * @{
00056  */
00057 
00058 /**
00059  * Register a class module
00060  * @arg ops             class module operations
00061  */
00062 int rtnl_class_register(struct rtnl_class_ops *ops)
00063 {
00064         struct rtnl_class_ops *o, **op;
00065 
00066         if (!ops->co_kind[0])
00067                 BUG();
00068 
00069         for (op = &class_ops_list; (o = *op) != NULL; op = &o->co_next)
00070                 if (!strcasecmp(ops->co_kind, o->co_kind))
00071                         return nl_errno(EEXIST);
00072 
00073         ops->co_next = NULL;
00074         *op = ops;
00075 
00076         return 0;
00077 }
00078 
00079 /**
00080  * Unregister a class module
00081  * @arg ops             class module operations
00082  */
00083 int rtnl_class_unregister(struct rtnl_class_ops *ops)
00084 {
00085         struct rtnl_class_ops *o, **op;
00086 
00087         for (op = &class_ops_list; (o = *op) != NULL; op = &o->co_next)
00088                 if (!strcasecmp(ops->co_kind, o->co_kind))
00089                         break;
00090 
00091         if (!o)
00092                 return nl_errno(ENOENT);
00093 
00094         *op = ops->co_next;
00095 
00096         return 0;
00097 }
00098 
00099 /** @} */
00100 
00101 static int class_msg_parser(struct sockaddr_nl *who, struct nlmsghdr *n,
00102                             void *arg)
00103 {
00104         int err;
00105         struct nl_parser_param *pp = arg;
00106         struct rtnl_class *class;
00107         struct rtnl_class_ops *ops;
00108 
00109         class = rtnl_class_alloc();
00110         if (!class) {
00111                 err = nl_errno(ENOMEM);
00112                 goto errout;
00113         }
00114         class->ce_msgtype = n->nlmsg_type;
00115 
00116         err = tca_msg_parser(n, (struct rtnl_tca *) class);
00117         if (err < 0)
00118                 goto errout_free;
00119 
00120         ops = class_ops(class);
00121         if (ops && ops->co_msg_parser) {
00122                 err = ops->co_msg_parser(class);
00123                 if (err < 0)
00124                         goto errout_free;
00125         }
00126 
00127         err = pp->pp_cb((struct nl_object *) class, pp);
00128         if (err < 0)
00129                 goto errout_free;
00130 
00131         return P_ACCEPT;
00132 
00133 errout_free:
00134         rtnl_class_put(class);
00135 errout:
00136         return err;
00137 }
00138 
00139 static int class_request_update(struct nl_cache *cache,
00140                                 struct nl_handle *handle)
00141 {
00142         struct tcmsg tchdr = {
00143                 .tcm_family = AF_UNSPEC,
00144                 .tcm_ifindex = cache->c_iarg1,
00145         };
00146 
00147         return nl_send_simple(handle, RTM_GETTCLASS, NLM_F_DUMP, &tchdr,
00148                               sizeof(tchdr));
00149 }
00150 
00151 static void class_free_data(struct nl_object *obj)
00152 {
00153         struct rtnl_class *class = (struct rtnl_class *) obj;
00154         struct rtnl_class_ops *ops;
00155         
00156         tca_free_data((struct rtnl_tca *) class);
00157 
00158         ops = class_ops(class);
00159         if (ops && ops->co_free_data)
00160                 ops->co_free_data(class);
00161 }
00162 
00163 static int class_dump_brief(struct nl_object *obj, struct nl_dump_params *p)
00164 {
00165         struct rtnl_class *class = (struct rtnl_class *) obj;
00166         struct rtnl_class_ops *ops;
00167 
00168         int line = tca_dump_brief((struct rtnl_tca *) class, "class", p, 0);
00169 
00170         ops = class_ops(class);
00171         if (ops && ops->co_dump[NL_DUMP_BRIEF])
00172                 line = ops->co_dump[NL_DUMP_BRIEF](class, p, line);
00173         dp_dump(p, "\n");
00174 
00175         return line;
00176 }
00177 
00178 static int class_dump_full(struct nl_object *obj, struct nl_dump_params *p)
00179 {
00180         struct rtnl_class *class = (struct rtnl_class *) obj;
00181         struct rtnl_class_ops *ops;
00182         int line;
00183 
00184         line = class_dump_brief(obj, p);
00185         line = tca_dump_full((struct rtnl_tca *) class, p, line);
00186         
00187         if (class->c_info) {
00188                 char buf[32];
00189                 dp_dump(p, "child-qdisc %s ",
00190                         rtnl_tc_handle2str(class->c_info, buf, sizeof(buf)));
00191         }
00192 
00193         ops = class_ops(class);
00194         if (ops && ops->co_dump[NL_DUMP_FULL])
00195                 line = ops->co_dump[NL_DUMP_FULL](class, p, line);
00196         else if (!class->c_info)
00197                 dp_dump(p, "noop (no leaf qdisc)");
00198 
00199         dp_dump(p, "\n");
00200 
00201         return line;
00202 }
00203 
00204 static int class_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
00205 {
00206         struct rtnl_class *class = (struct rtnl_class *) obj;
00207         struct rtnl_class_ops *ops;
00208         int line;
00209 
00210         line = class_dump_full(obj, p);
00211         line = tca_dump_stats((struct rtnl_tca *) class, p, line);
00212         dp_dump(p, "\n");
00213 
00214         ops = class_ops(class);
00215         if (ops && ops->co_dump[NL_DUMP_STATS])
00216                 line = ops->co_dump[NL_DUMP_STATS](class, p, line);
00217 
00218         return line;
00219 }
00220 
00221 static int class_filter(struct nl_object *obj, struct nl_object *filter)
00222 {
00223         return tca_filter((struct rtnl_tca *) obj, (struct rtnl_tca *) filter);
00224 }
00225 
00226 /**
00227  * @name Class Addition/Modification
00228  * @{
00229  */
00230 
00231 static struct nl_msg *class_build(struct rtnl_class *class, int type, int flags)
00232 {
00233         struct rtnl_class_ops *ops;
00234         struct nl_msg *msg;
00235         int err;
00236 
00237         msg = tca_build_msg((struct rtnl_tca *) class, type, flags);
00238         if (!msg)
00239                 goto errout;
00240 
00241         ops = class_ops(class);
00242         if (ops && ops->co_get_opts) {
00243                 struct nl_msg *opts;
00244                 
00245                 opts = ops->co_get_opts(class);
00246                 if (opts) {
00247                         err = nla_put_nested(msg, TCA_OPTIONS, opts);
00248                         nlmsg_free(opts);
00249                         if (err < 0)
00250                                 goto errout;
00251                 }
00252         }
00253 
00254         return msg;
00255 errout:
00256         nlmsg_free(msg);
00257         return NULL;
00258 }
00259 
00260 /**
00261  * Build a netlink message to add a new class
00262  * @arg class           class to add 
00263  * @arg flags           additional netlink message flags
00264  *
00265  * Builds a new netlink message requesting an addition of a class.
00266  * The netlink message header isn't fully equipped with all relevant
00267  * fields and must be sent out via nl_send_auto_complete() or
00268  * supplemented as needed. 
00269  *
00270  * Common message flags
00271  *   - NLM_F_REPLACE - replace possibly existing classes
00272  *
00273  * @return New netlink message
00274  */
00275 struct nl_msg *rtnl_class_build_add_request(struct rtnl_class *class, int flags)
00276 {
00277         return class_build(class, RTM_NEWTCLASS, NLM_F_CREATE | flags);
00278 }
00279 
00280 /**
00281  * Add a new class
00282  * @arg handle          netlink handle
00283  * @arg class           class to delete
00284  * @arg flags           additional netlink message flags
00285  *
00286  * Builds a netlink message by calling rtnl_qdisc_build_add_request(),
00287  * sends the request to the kernel and waits for the next ACK to be
00288  * received and thus blocks until the request has been processed.
00289  *
00290  * Common message flags
00291  *   - NLM_F_REPLACE - replace possibly existing classes
00292  *
00293  * @return 0 on success or a negative error code
00294  */
00295 int rtnl_class_add(struct nl_handle *handle, struct rtnl_class *class,
00296                    int flags)
00297 {
00298         struct nl_msg *msg;
00299         int err;
00300 
00301         msg = rtnl_class_build_add_request(class, flags);
00302         if (!msg)
00303                 return nl_errno(ENOMEM);
00304 
00305         err = nl_send_auto_complete(handle, msg);
00306         if (err < 0)
00307                 return err;
00308 
00309         nlmsg_free(msg);
00310         return nl_wait_for_ack(handle);
00311 }
00312 
00313 /** @} */
00314 
00315 /**
00316  * @name General
00317  * @{
00318  */
00319 
00320 /**
00321  * Allocate a new class object
00322  * @return New class object
00323  */
00324 struct rtnl_class *rtnl_class_alloc(void)
00325 {
00326         return (struct rtnl_class *) nl_object_alloc_from_ops(&rtnl_class_ops);
00327 }
00328 
00329 /**
00330  * Give back reference on rclass object.
00331  * @arg class           Class object to be given back.
00332  *
00333  * Decrements the reference counter and frees the object if the
00334  * last reference has been released.
00335  */
00336 void rtnl_class_put(struct rtnl_class *class)
00337 {
00338         nl_object_put((struct nl_object *) class);
00339 }
00340 
00341 /**
00342  * Free class object.
00343  * @arg class           Class object to be freed.
00344  *
00345  * @note Always use rtnl_class_put() unless you're absolutely sure
00346  *       that no other user may have a reference on this object.
00347  */
00348 void rtnl_class_free(struct rtnl_class *class)
00349 {
00350         nl_object_free((struct nl_object *) class);
00351 }
00352 
00353 /**
00354  * Build a class cache including all classes attached to the specified interface
00355  * @arg handle          netlink handle
00356  * @arg ifindex         interface index of the link the classes are
00357  *                      attached to.
00358  *
00359  * Allocates a new cache, initializes it properly and updates it to
00360  * include all classes attached to the specified interface.
00361  *
00362  * @note The caller is responsible for destroying and freeing the
00363  *       cache after using it.
00364  * @return The cache or NULL if an error has occured.
00365  */
00366 struct nl_cache * rtnl_class_alloc_cache(struct nl_handle *handle, int ifindex)
00367 {
00368         struct nl_cache * cache;
00369         
00370         cache = nl_cache_alloc_from_ops(&rtnl_class_ops);
00371         if (!cache)
00372                 return NULL;
00373 
00374         cache->c_iarg1 = ifindex;
00375         
00376         if (nl_cache_update(handle, cache) < 0) {
00377                 nl_cache_free(cache);
00378                 return NULL;
00379         }
00380 
00381         return cache;
00382 }
00383 
00384 /** @} */
00385 
00386 /**
00387  * @name Leaf Qdisc Access
00388  * @{
00389  */
00390 
00391 /**
00392  * Determine if the class has a leaf qdisc attached
00393  * @arg class           class to check
00394  */
00395 int rtnl_class_has_leaf_qdisc(struct rtnl_class *class)
00396 {
00397         return !!class->c_info;
00398 }
00399 
00400 /**
00401  * Lookup the leaf qdisc of a class
00402  * @arg class           the parent class
00403  * @arg cache           a qdisc cache including at laest all qdiscs of the
00404  *                      interface the specified class is attached to
00405  * @return The qdisc from the cache or NULL if the class has no leaf qdisc
00406  */
00407 struct rtnl_qdisc *rtnl_class_leaf_qdisc(struct rtnl_class *class,
00408                                          struct nl_cache *cache)
00409 {
00410         struct rtnl_qdisc *leaf;
00411 
00412         if (!rtnl_class_has_leaf_qdisc(class))
00413                 return NULL;
00414 
00415         leaf = rtnl_qdisc_get_by_parent(cache, class->c_ifindex,
00416                                         class->c_handle);
00417         if (!leaf || leaf->q_handle != class->c_info)
00418                 return NULL;
00419 
00420         return leaf;
00421 }
00422 
00423 /** @} */
00424 
00425 /**
00426  * @name Iterators
00427  * @{
00428  */
00429 
00430 /**
00431  * Call a callback for each child class of a class
00432  * @arg class           the parent class
00433  * @arg cache           a class cache including all classes of the interface
00434  *                      the specified class is attached to
00435  * @arg cb              callback function
00436  * @arg arg             argument to be passed to callback function
00437  */
00438 void rtnl_class_foreach_child(struct rtnl_class *class, struct nl_cache *cache,
00439                               void (*cb)(struct nl_object *, void *), void *arg)
00440 {
00441         struct rtnl_class *filter;
00442         
00443         filter = rtnl_class_alloc();
00444         if (!filter)
00445                 return;
00446 
00447         rtnl_class_set_parent(filter, class->c_handle);
00448         rtnl_class_set_ifindex(filter, class->c_ifindex);
00449         rtnl_class_set_kind(filter, class->c_kind);
00450 
00451         nl_cache_foreach_filter(cache, (struct nl_object *) filter, cb, arg);
00452         rtnl_class_put(filter);
00453 }
00454 
00455 /**
00456  * Call a callback for each classifier attached to the class
00457  * @arg class           the parent class
00458  * @arg cache           a filter cache including at least all the filters
00459  *                      attached to the specified class
00460  * @arg cb              callback function
00461  * @arg arg             argument to be passed to callback function
00462  */
00463 void rtnl_class_foreach_cls(struct rtnl_class *class, struct nl_cache *cache,
00464                             void (*cb)(struct nl_object *, void *), void *arg)
00465 {
00466         struct rtnl_cls *filter;
00467 
00468         filter = rtnl_cls_alloc();
00469         if (!filter)
00470                 return;
00471 
00472         rtnl_cls_set_ifindex(filter, class->c_ifindex);
00473         rtnl_cls_set_parent(filter, class->c_parent);
00474 
00475         nl_cache_foreach_filter(cache, (struct nl_object *) filter, cb, arg);
00476         rtnl_cls_put(filter);
00477 }
00478 
00479 /** @} */
00480 
00481 /**
00482  * @name Attribute Modifications
00483  * @{
00484  */
00485 
00486 /**
00487  * Set the interface index of a class to the specified value
00488  * @arg class           class to be changed
00489  * @arg ifindex         new interface index
00490  */
00491 void rtnl_class_set_ifindex(struct rtnl_class *class, int ifindex)
00492 {
00493         tca_set_ifindex((struct rtnl_tca *) class, ifindex);
00494 }
00495 
00496 /**
00497  * Get the interface index of a class
00498  * @arg class           class handle
00499  * @return Interface index or RTNL_LINK_NOT_FOUND if not set
00500  */
00501 int rtnl_class_get_ifindex(struct rtnl_class *class)
00502 {
00503         return tca_get_ifindex((struct rtnl_tca *) class);
00504 }
00505 
00506 
00507 /**
00508  * Set the handle of a class to the specified value
00509  * @arg class           class to be changed
00510  * @arg handle          new handle
00511  */
00512 void rtnl_class_set_handle(struct rtnl_class *class, uint32_t handle)
00513 {
00514         tca_set_handle((struct rtnl_tca *) class, handle);
00515 }
00516 
00517 /**
00518  * Get the handle of a class
00519  * @arg class           class handle
00520  * @return Handle or 0 if not set
00521  */
00522 uint32_t rtnl_class_get_handle(struct rtnl_class *class)
00523 {
00524         return tca_get_handle((struct rtnl_tca *) class);
00525 }
00526 
00527 /**
00528  * Set the parent handle of a class to the specified value
00529  * @arg class           class to be changed
00530  * @arg parent          new parent handle
00531  */
00532 void rtnl_class_set_parent(struct rtnl_class *class, uint32_t parent)
00533 {
00534         tca_set_parent((struct rtnl_tca *) class, parent);
00535 }
00536 
00537 /**
00538  * Get the parent handle of a class
00539  * @arg class           class handle
00540  * @return Parent handle or 0 if not set
00541  */
00542 uint32_t rtnl_class_get_parent(struct rtnl_class *class)
00543 {
00544         return tca_get_parent((struct rtnl_tca *) class);
00545 }
00546 
00547 /**
00548  * Set the kind of a class to the specified value
00549  * @arg class           class to be changed
00550  * @arg name            new kind name
00551  */
00552 void rtnl_class_set_kind(struct rtnl_class *class, const char *name)
00553 {
00554         tca_set_kind((struct rtnl_tca *) class, name);
00555 }
00556 
00557 /**
00558  * Get the kind of a class
00559  * @arg class           class handle
00560  * @return Kind or NULL if not set
00561  */
00562 char *rtnl_class_get_kind(struct rtnl_class *class)
00563 {
00564         return tca_get_kind((struct rtnl_tca *) class);
00565 }
00566 
00567 /**
00568  * Get the statistic specified by the id
00569  * @arg class           class handle
00570  * @arg id              statistic id
00571  * @return The current counter of the specified statistic
00572  */
00573 uint64_t rtnl_class_get_stat(struct rtnl_class *class,
00574                              enum rtnl_tc_stats_id id)
00575 {
00576         return tca_get_stat((struct rtnl_tca *) class, id);
00577 }
00578 
00579 /** @} */
00580 
00581 static struct nl_cache_ops rtnl_class_ops = {
00582         .co_name                = "route/class",
00583         .co_size                = sizeof(struct rtnl_class),
00584         .co_hdrsize             = sizeof(struct tcmsg),
00585         .co_msgtypes            = {
00586                                         { RTM_NEWTCLASS, "new" },
00587                                         { RTM_DELTCLASS, "del" },
00588                                         { RTM_GETTCLASS, "get" },
00589                                         { -1, NULL },
00590                                   },
00591         .co_protocol            = NETLINK_ROUTE,
00592         .co_request_update      = &class_request_update,
00593         .co_msg_parser          = &class_msg_parser,
00594         .co_free_data           = &class_free_data,
00595         .co_dump[NL_DUMP_BRIEF] = &class_dump_brief,
00596         .co_dump[NL_DUMP_FULL]  = &class_dump_full,
00597         .co_dump[NL_DUMP_STATS] = &class_dump_stats,
00598         .co_filter              = &class_filter,
00599 };
00600 
00601 static void __init class_init(void)
00602 {
00603         nl_cache_mngt_register(&rtnl_class_ops);
00604 }
00605 
00606 static void __exit class_exit(void)
00607 {
00608         nl_cache_mngt_unregister(&rtnl_class_ops);
00609 }
00610 
00611 /** @} */

Generated on Fri Apr 27 14:14:07 2007 for libnl by  doxygen 1.5.1