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

00001 /*
00002  * lib/route/qdisc.c            Queueing Disciplines
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 qdisc Queueing Disciplines
00015  *
00016  * @par Qdisc Handles
00017  * In general, qdiscs are identified by the major part of a traffic control
00018  * handle (the upper 16 bits). A few special values exist though:
00019  *  - \c TC_H_ROOT: root qdisc (directly attached to the device)
00020  *  - \c TC_H_INGRESS: ingress qdisc (directly attached to the device)
00021  *  - \c TC_H_UNSPEC: unspecified qdisc (no reference)
00022  *
00023  * @par 1) Adding a Qdisc
00024  * @code
00025  * // Allocate a new empty qdisc to be filled out
00026  * struct rtnl_qdisc *qdisc = rtnl_qdisc_alloc();
00027  *
00028  * // ... specify the kind of the Qdisc
00029  * rtnl_qdisc_set_kind(qdisc, "pfifo");
00030  *
00031  * // Specify the device the qdisc should be attached to
00032  * rtnl_qdisc_set_ifindex(qdisc, ifindex);
00033  *
00034  * // ... specify the parent qdisc
00035  * rtnl_qdisc_set_parent(qdisc, TC_H_ROOT);
00036  *
00037  * // Specifying the handle is not required but makes reidentifying easier
00038  * // and may help to avoid adding a qdisc twice.
00039  * rtnl_qdisc_set_handle(qdisc, 0x000A0000);
00040  *
00041  * // Now on to specify the qdisc specific options, see the relevant qdisc
00042  * // modules for documentation, in this example we set the upper limit of
00043  * // the packet fifo qdisc to 64
00044  * rtnl_qdisc_fifo_set_limit(qdisc, 64);
00045  *
00046  * rtnl_qdisc_add(handle, qdisc, NLM_R_REPLACE);
00047  *
00048  * // Free up the memory
00049  * rtnl_qdisc_put(qdisc);
00050  * @endcode
00051  *
00052  * @par 2) Deleting a Qdisc
00053  * @code
00054  * // Allocate a new empty qdisc to be filled out with the parameters
00055  * // specifying the qdisc to be deleted. Alternatively a fully equiped
00056  * // Qdisc object from a cache can be used.
00057  * struct rtnl_qdisc *qdisc = rtnl_qdisc_alloc();
00058  *
00059  * // The interface index of the device the qdisc is on and the parent handle
00060  * // are the least required fields to be filled out.
00061  * // Note: Specify TC_H_ROOT or TC_H_INGRESS as parent handle to delete the
00062  * //       root respectively root ingress qdisc.
00063  * rtnl_qdisc_set_ifindex(qdisc, ifindex);
00064  * rtnl_qdisc_set_parent(qdisc, parent_handle);
00065  *
00066  * // If required for identification, the handle can be specified as well.
00067  * rtnl_qdisc_set_handle(qdisc, qdisc_handle);
00068  *
00069  * // Not required but maybe helpful as sanity check, the kind of the qdisc
00070  * // can be specified to avoid mistakes.
00071  * rtnl_qdisc_set_kind(qdisc, "pfifo");
00072  *
00073  * // Finally delete the qdisc with rtnl_qdisc_delete(), alternatively
00074  * // rtnl_qdisc_build_delete_request() can be invoked to generate an
00075  * // appropritate netlink message to send out.
00076  * rtnl_qdisc_delete(handle, qdisc);
00077  *
00078  * // Free up the memory
00079  * rtnl_qdisc_put(qdisc);
00080  * @endcode
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 /** @cond SKIP */
00097 static struct nl_cache_ops rtnl_qdisc_ops;
00098 /** @endcond */
00099 
00100 static struct rtnl_qdisc_ops *qdisc_ops_list;
00101 
00102 static struct rtnl_qdisc_ops *qdisc_lookup_ops(const char *kind)
00103 {
00104         struct rtnl_qdisc_ops *ops;
00105 
00106         for (ops = qdisc_ops_list; ops; ops = ops->qo_next)
00107                 if (!strcmp(kind, ops->qo_kind))
00108                         return ops;
00109 
00110         return NULL;
00111 }
00112 
00113 static inline struct rtnl_qdisc_ops *qdisc_ops(struct rtnl_qdisc *qdisc)
00114 {
00115         if (!qdisc->q_ops)
00116                 qdisc->q_ops = qdisc_lookup_ops(qdisc->q_kind);
00117 
00118         return qdisc->q_ops;
00119 }
00120 
00121 /**
00122  * @name QDisc Module API
00123  * @{
00124  */
00125 
00126 /**
00127  * Register a qdisc module
00128  * @arg ops             qdisc module operations
00129  */
00130 int rtnl_qdisc_register(struct rtnl_qdisc_ops *ops)
00131 {
00132         struct rtnl_qdisc_ops *o, **op;
00133 
00134         if (!ops->qo_kind[0])
00135                 BUG();
00136 
00137         for (op = &qdisc_ops_list; (o = *op) != NULL; op = &o->qo_next)
00138                 if (!strcasecmp(ops->qo_kind, o->qo_kind))
00139                         return nl_errno(EEXIST);
00140 
00141         ops->qo_next = NULL;
00142         *op = ops;
00143 
00144         return 0;
00145 }
00146 
00147 /**
00148  * Unregister a qdisc module
00149  * @arg ops             qdisc module operations
00150  */
00151 int rtnl_qdisc_unregister(struct rtnl_qdisc_ops *ops)
00152 {
00153         struct rtnl_qdisc_ops *o, **op;
00154 
00155         for (op = &qdisc_ops_list; (o = *op) != NULL; op = &o->qo_next)
00156                 if (!strcasecmp(ops->qo_kind, o->qo_kind))
00157                         break;
00158 
00159         if (!o)
00160                 return nl_errno(ENOENT);
00161 
00162         *op = ops->qo_next;
00163 
00164         return 0;
00165 }
00166 
00167 /** @} */
00168 
00169 static int qdisc_msg_parser(struct sockaddr_nl *who, struct nlmsghdr *n,
00170                             void *arg)
00171 {
00172         int err = -ENOMEM;
00173         struct nl_parser_param *pp = arg;
00174         struct rtnl_qdisc *qdisc;
00175         struct rtnl_qdisc_ops *ops;
00176 
00177         qdisc = rtnl_qdisc_alloc();
00178         if (!qdisc) {
00179                 err = nl_errno(ENOMEM);
00180                 goto errout;
00181         }
00182 
00183         qdisc->ce_msgtype = n->nlmsg_type;
00184 
00185         err = tca_msg_parser(n, (struct rtnl_tca *) qdisc);
00186         if (err < 0)
00187                 goto errout_free;
00188 
00189         ops = qdisc_ops(qdisc);
00190         if (ops && ops->qo_msg_parser) {
00191                 err = ops->qo_msg_parser(qdisc);
00192                 if (err < 0)
00193                         goto errout_free;
00194         }
00195 
00196         err = pp->pp_cb((struct nl_object *) qdisc, pp);
00197         if (err < 0)
00198                 goto errout_free;
00199 
00200         return P_ACCEPT;
00201 
00202 errout_free:
00203         rtnl_qdisc_put(qdisc);
00204 errout:
00205         return err;
00206 }
00207 
00208 static int qdisc_request_update(struct nl_cache *c, struct nl_handle *h)
00209 {
00210         struct tcmsg tchdr = {
00211                 .tcm_family = AF_UNSPEC,
00212                 .tcm_ifindex = c->c_iarg1,
00213         };
00214 
00215         return nl_send_simple(h, RTM_GETQDISC, NLM_F_DUMP, &tchdr,
00216                               sizeof(tchdr));
00217 }
00218 
00219 static void qdisc_free_data(struct nl_object *obj)
00220 {
00221         struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) obj;
00222         struct rtnl_qdisc_ops *ops;
00223 
00224         tca_free_data((struct rtnl_tca *) qdisc);
00225 
00226         ops = qdisc_ops(qdisc);
00227         if (ops && ops->qo_free_data)
00228                 ops->qo_free_data(qdisc);
00229 }
00230 
00231 static int qdisc_dump_brief(struct nl_object *obj, struct nl_dump_params *p)
00232 {
00233         struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) obj;
00234         struct rtnl_qdisc_ops *ops;
00235 
00236         int line = tca_dump_brief((struct rtnl_tca *) qdisc, "qdisc", p, 0);
00237 
00238         ops = qdisc_ops(qdisc);
00239         if (ops && ops->qo_dump[NL_DUMP_BRIEF])
00240                 line = ops->qo_dump[NL_DUMP_BRIEF](qdisc, p, line);
00241 
00242         dp_dump(p, "\n");
00243 
00244         return line;
00245 }
00246 
00247 static int qdisc_dump_full(struct nl_object *arg, struct nl_dump_params *p)
00248 {
00249         struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) arg;
00250         struct rtnl_qdisc_ops *ops;
00251 
00252         int line = qdisc_dump_brief(arg, p);
00253 
00254         line = tca_dump_full((struct rtnl_tca *) qdisc, p, line);
00255         dp_dump(p, "refcnt %u ", qdisc->q_info);
00256 
00257         ops = qdisc_ops(qdisc);
00258         if (ops && ops->qo_dump[NL_DUMP_FULL])
00259                 line = ops->qo_dump[NL_DUMP_FULL](qdisc, p, line);
00260 
00261         dp_dump(p, "\n");
00262         return line;
00263 }
00264 
00265 static int qdisc_dump_stats(struct nl_object *arg, struct nl_dump_params *p)
00266 {
00267         struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) arg;
00268         struct rtnl_qdisc_ops *ops;
00269 
00270         int line = qdisc_dump_full(arg, p);
00271         line = tca_dump_stats((struct rtnl_tca *) qdisc, p, line );
00272         dp_dump(p, "\n");
00273 
00274         ops = qdisc_ops(qdisc);
00275         if (ops && ops->qo_dump[NL_DUMP_STATS])
00276                 line = ops->qo_dump[NL_DUMP_STATS](qdisc, p, line);
00277 
00278         return line;
00279 }
00280 
00281 static int qdisc_filter(struct nl_object *obj, struct nl_object *filter)
00282 {
00283         return tca_filter((struct rtnl_tca *) obj, (struct rtnl_tca *) filter);
00284 }
00285 
00286 /**
00287  * @name QDisc Addition
00288  * @{
00289  */
00290 
00291 static struct nl_msg *qdisc_build(struct rtnl_qdisc *qdisc, int type, int flags)
00292 {
00293         struct rtnl_qdisc_ops *ops;
00294         struct nl_msg *msg;
00295         int err;
00296 
00297         msg = tca_build_msg((struct rtnl_tca *) qdisc, type, flags);
00298         if (!msg)
00299                 goto errout;
00300 
00301         ops = qdisc_ops(qdisc);
00302         if (ops && ops->qo_get_opts) {
00303                 struct nl_msg *opts;
00304                 
00305                 opts = ops->qo_get_opts(qdisc);
00306                 if (opts) {
00307                         err = nla_put_nested(msg, TCA_OPTIONS, opts);
00308                         nlmsg_free(opts);
00309                         if (err < 0)
00310                                 goto errout;
00311                 }
00312         }
00313 
00314         return msg;
00315 errout:
00316         nlmsg_free(msg);
00317 
00318         return NULL;
00319 }
00320 
00321 /**
00322  * Build a netlink message to add a new qdisc
00323  * @arg qdisc           qdisc to add 
00324  * @arg flags           additional netlink message flags
00325  *
00326  * Builds a new netlink message requesting an addition of a qdisc.
00327  * The netlink message header isn't fully equipped with all relevant
00328  * fields and must be sent out via nl_send_auto_complete() or
00329  * supplemented as needed. 
00330  *
00331  * Common message flags used:
00332  *  - NLM_F_REPLACE - replace a potential existing qdisc
00333  *
00334  * @return New netlink message
00335  */
00336 struct nl_msg *rtnl_qdisc_build_add_request(struct rtnl_qdisc *qdisc,
00337                                             int flags)
00338 {
00339         struct nl_msg *msg;
00340 
00341         msg = qdisc_build(qdisc, RTM_NEWQDISC, NLM_F_CREATE | flags);
00342         if (!msg)
00343                 nl_errno(ENOMEM);
00344 
00345         return msg;
00346 }
00347 
00348 /**
00349  * Add a new qdisc
00350  * @arg handle          netlink handle
00351  * @arg qdisc           qdisc to delete
00352  * @arg flags           additional netlink message flags
00353  *
00354  * Builds a netlink message by calling rtnl_qdisc_build_add_request(),
00355  * sends the request to the kernel and waits for the ACK to be
00356  * received and thus blocks until the request has been processed.
00357  *
00358  * Common message flags used:
00359  *  - NLM_F_REPLACE - replace a potential existing qdisc
00360  *
00361  * @return 0 on success or a negative error code
00362  */
00363 int rtnl_qdisc_add(struct nl_handle *handle, struct rtnl_qdisc *qdisc,
00364                    int flags)
00365 {
00366         struct nl_msg *msg;
00367         int err;
00368 
00369         msg = rtnl_qdisc_build_add_request(qdisc, flags);
00370         if (!msg)
00371                 return nl_errno(ENOMEM);
00372 
00373         err = nl_send_auto_complete(handle, msg);
00374         if (err < 0)
00375                 return err;
00376 
00377         nlmsg_free(msg);
00378         return nl_wait_for_ack(handle);
00379 }
00380 
00381 /** @} */
00382 
00383 /**
00384  * @name QDisc Modification
00385  * @{
00386  */
00387 
00388 /**
00389  * Build a netlink message to change attributes of a existing qdisc
00390  * @arg qdisc           qdisc to change
00391  * @arg new             new qdisc attributes
00392  *
00393  * Builds a new netlink message requesting an change of qdisc
00394  * attributes. The netlink message header isn't fully equipped
00395  * with all relevant fields and must be sent out via
00396  * nl_send_auto_complete() or supplemented as needed. 
00397  *
00398  * @return New netlink message
00399  */
00400 struct nl_msg *rtnl_qdisc_build_change_request(struct rtnl_qdisc *qdisc,
00401                                                struct rtnl_qdisc *new)
00402 {
00403         return qdisc_build(qdisc, RTM_NEWQDISC, NLM_F_REPLACE);
00404 }
00405 
00406 /**
00407  * Change attributes of a qdisc
00408  * @arg handle          netlink handle
00409  * @arg qdisc           qdisc to change
00410  * @arg new             new qdisc attributes
00411  *
00412  * Builds a netlink message by calling rtnl_qdisc_build_change_request(),
00413  * sends the request to the kernel and waits for the ACK to be
00414  * received and thus blocks until the request has been processed.
00415  *
00416  * @return 0 on success or a negative error code
00417  */
00418 int rtnl_qdisc_change(struct nl_handle *handle, struct rtnl_qdisc *qdisc,
00419                       struct rtnl_qdisc *new)
00420 {
00421         struct nl_msg *msg;
00422         int err;
00423 
00424         msg = rtnl_qdisc_build_change_request(qdisc, new);
00425         if (!msg)
00426                 return nl_errno(ENOMEM);
00427 
00428         err = nl_send_auto_complete(handle, msg);
00429         if (err < 0)
00430                 return err;
00431 
00432         nlmsg_free(msg);
00433         return nl_wait_for_ack(handle);
00434 }
00435 
00436 /** @} */
00437 
00438 /**
00439  * @name QDisc Deletion
00440  * @{
00441  */
00442 
00443 /**
00444  * Build a netlink request message to delete a qdisc
00445  * @arg qdisc           qdisc to delete
00446  *
00447  * Builds a new netlink message requesting a deletion of a qdisc.
00448  * The netlink message header isn't fully equipped with all relevant
00449  * fields and must thus be sent out via nl_send_auto_complete()
00450  * or supplemented as needed.
00451  *
00452  * @return New netlink message
00453  */
00454 struct nl_msg *rtnl_qdisc_build_delete_request(struct rtnl_qdisc *qdisc)
00455 {
00456         struct nl_msg *msg;
00457         struct tcmsg tchdr;
00458         int required = TCA_ATTR_IFINDEX | TCA_ATTR_PARENT;
00459 
00460         if ((qdisc->q_mask & required) != required)
00461                 BUG();
00462 
00463         msg = nlmsg_build_simple(RTM_DELQDISC, 0);
00464         if (!msg)
00465                 return NULL;
00466 
00467         tchdr.tcm_family = AF_UNSPEC,
00468         tchdr.tcm_handle = qdisc->q_handle,
00469         tchdr.tcm_parent = qdisc->q_parent,
00470         tchdr.tcm_ifindex = qdisc->q_ifindex,
00471         nlmsg_append(msg, &tchdr, sizeof(tchdr), 1);
00472 
00473         return msg;
00474 }
00475 
00476 /**
00477  * Delete a qdisc
00478  * @arg handle          netlink handle
00479  * @arg qdisc           qdisc to delete
00480  *
00481  * Builds a netlink message by calling rtnl_qdisc_build_delete_request(),
00482  * sends the request to the kernel and waits for the ACK to be
00483  * received and thus blocks until the request has been processed.
00484  *
00485  * @return 0 on success or a negative error code
00486  */
00487 int rtnl_qdisc_delete(struct nl_handle *handle, struct rtnl_qdisc *qdisc)
00488 {
00489         struct nl_msg *msg;
00490         int err;
00491 
00492         msg = rtnl_qdisc_build_delete_request(qdisc);
00493         if (!msg)
00494                 return nl_errno(ENOMEM);
00495 
00496         err = nl_send_auto_complete(handle, msg);
00497         if (err < 0)
00498                 return err;
00499 
00500         nlmsg_free(msg);
00501         return nl_wait_for_ack(handle);
00502 }
00503 
00504 /** @} */
00505 
00506 /**
00507  * @name General
00508  * @{
00509  */
00510 
00511 /**
00512  * Allocate a new qdisc object
00513  * @return New qdisc object
00514  */
00515 struct rtnl_qdisc *rtnl_qdisc_alloc(void)
00516 {
00517         return (struct rtnl_qdisc *) nl_object_alloc_from_ops(&rtnl_qdisc_ops);
00518 }
00519 
00520 /**
00521  * Give back reference on rqdisc object.
00522  * @arg qdisc           Qdisc object to be given back.
00523  *
00524  * Decrements the reference counter and frees the object if the
00525  * last reference has been released.
00526  */
00527 void rtnl_qdisc_put(struct rtnl_qdisc *qdisc)
00528 {
00529         nl_object_put((struct nl_object *) qdisc);
00530 }
00531 /**
00532  * Free qdisc object.
00533  * @arg qdisc           Qdisc object to be freed.
00534  *
00535  * @note Always use rtnl_qdisc_put() unless you're absolutely sure
00536  *       that no other user may have a reference on this object.
00537  */
00538 void rtnl_qdisc_free(struct rtnl_qdisc *qdisc)
00539 {
00540         nl_object_free((struct nl_object *) qdisc);
00541 }
00542 
00543 /** @} */
00544 
00545 /**
00546  * @name Qdisc Cache Management
00547  * @{
00548  */
00549 
00550 /**
00551  * Build a qdisc cache including all qdiscs currently configured in
00552  * the kernel
00553  * @arg handle          netlink handle
00554  *
00555  * Allocates a new cache, initializes it properly and updates it to
00556  * include all qdiscs currently configured in the kernel.
00557  *
00558  * @note The caller is responsible for destroying and freeing the
00559  *       cache after using it.
00560  * @return The cache or NULL if an error has occured.
00561  */
00562 struct nl_cache * rtnl_qdisc_alloc_cache(struct nl_handle *handle)
00563 {
00564         struct nl_cache * cache;
00565         
00566         cache = nl_cache_alloc_from_ops(&rtnl_qdisc_ops);
00567         if (cache == NULL)
00568                 return NULL;
00569 
00570         if (nl_cache_update(handle, cache) < 0) {
00571                 nl_cache_free(cache);
00572                 return NULL;
00573         }
00574 
00575         return cache;
00576 }
00577 
00578 /**
00579  * Look up qdisc by its parent in the provided cache
00580  * @arg cache           qdisc cache
00581  * @arg ifindex         interface the qdisc is attached to
00582  * @arg parent          parent handle
00583  * @return pointer to qdisc inside the cache or NULL if no match was found.
00584  */
00585 struct rtnl_qdisc * rtnl_qdisc_get_by_parent(struct nl_cache *cache,
00586                                              int ifindex, uint32_t parent)
00587 {
00588         struct rtnl_qdisc *q;
00589 
00590         if (cache->c_ops != &rtnl_qdisc_ops)
00591                 return NULL;
00592 
00593         nl_list_for_each_entry(q, &cache->c_items, ce_list) {
00594                 if (q->q_parent == parent && q->q_ifindex == ifindex) {
00595                         nl_object_get((struct nl_object *) q);
00596                         return q;
00597                 }
00598         }
00599 
00600         return NULL;
00601 }
00602 
00603 /**
00604  * Look up qdisc by its handle in the provided cache
00605  * @arg cache           qdisc cache
00606  * @arg ifindex         interface the qdisc is attached to
00607  * @arg handle          qdisc handle
00608  * @return pointer to qdisc inside the cache or NULL if no match was found.
00609  */
00610 struct rtnl_qdisc * rtnl_qdisc_get(struct nl_cache *cache,
00611                                    int ifindex, uint32_t handle)
00612 {
00613         struct rtnl_qdisc *q;
00614 
00615         if (cache->c_ops != &rtnl_qdisc_ops)
00616                 return NULL;
00617 
00618         nl_list_for_each_entry(q, &cache->c_items, ce_list) {
00619                 if (q->q_handle == handle && q->q_ifindex == ifindex) {
00620                         nl_object_get((struct nl_object *) q);
00621                         return q;
00622                 }
00623         }
00624 
00625         return NULL;
00626 }
00627 
00628 /** @} */
00629 
00630 /**
00631  * @name Qdisc Specific Options
00632  * @{
00633  */
00634 
00635 /**
00636  * Return qdisc specific options for use in TCA_OPTIONS
00637  * @arg qdisc           qdisc carrying the optiosn
00638  * 
00639  * @return new headerless netlink message carrying the options as payload
00640  */
00641 struct nl_msg *rtnl_qdisc_get_opts(struct rtnl_qdisc *qdisc)
00642 {
00643         struct rtnl_qdisc_ops *ops;
00644 
00645         ops = qdisc_ops(qdisc);
00646         if (ops && ops->qo_get_opts)
00647                 return ops->qo_get_opts(qdisc);
00648 
00649         return NULL;
00650 }
00651 
00652 /** @} */
00653 
00654 /**
00655  * @name Iterators
00656  * @{
00657  */
00658 
00659 /**
00660  * Call a callback for each child class of a qdisc
00661  * @arg qdisc           the parent qdisc
00662  * @arg cache           a class cache including all classes of the interface
00663  *                      the specified qdisc is attached to
00664  * @arg cb              callback function
00665  * @arg arg             argument to be passed to callback function
00666  */
00667 void rtnl_qdisc_foreach_child(struct rtnl_qdisc *qdisc, struct nl_cache *cache,
00668                               void (*cb)(struct nl_object *, void *), void *arg)
00669 {
00670         struct rtnl_class *filter;
00671         
00672         filter = rtnl_class_alloc();
00673         if (!filter)
00674                 return;
00675 
00676         rtnl_class_set_parent(filter, qdisc->q_handle);
00677         rtnl_class_set_ifindex(filter, qdisc->q_ifindex);
00678         rtnl_class_set_kind(filter, qdisc->q_kind);
00679 
00680         nl_cache_foreach_filter(cache, (struct nl_object *) filter, cb, arg);
00681 
00682         rtnl_class_put(filter);
00683 }
00684 
00685 /**
00686  * Call a callback for each filter attached to the qdisc
00687  * @arg qdisc           the parent qdisc
00688  * @arg cache           a filter cache including at least all the filters
00689  *                      attached to the specified qdisc
00690  * @arg cb              callback function
00691  * @arg arg             argument to be passed to callback function
00692  */
00693 void rtnl_qdisc_foreach_cls(struct rtnl_qdisc *qdisc, struct nl_cache *cache,
00694                             void (*cb)(struct nl_object *, void *), void *arg)
00695 {
00696         struct rtnl_cls *filter;
00697 
00698         filter = rtnl_cls_alloc();
00699         if (!filter)
00700                 return;
00701 
00702         rtnl_cls_set_ifindex(filter, qdisc->q_ifindex);
00703         rtnl_cls_set_parent(filter, qdisc->q_parent);
00704 
00705         nl_cache_foreach_filter(cache, (struct nl_object *) filter, cb, arg);
00706         rtnl_cls_put(filter);
00707 }
00708 
00709 /** @} */
00710 
00711 /**
00712  * @name Attribute Modification
00713  * @{
00714  */
00715 
00716 /**
00717  * Set the interface index of a qdisc to the specified value
00718  * @arg qdisc           qdisc to be changed
00719  * @arg ifindex         new interface index
00720  */
00721 void rtnl_qdisc_set_ifindex(struct rtnl_qdisc *qdisc, int ifindex)
00722 {
00723         tca_set_ifindex((struct rtnl_tca *) qdisc, ifindex);
00724 }
00725 
00726 /**
00727  * Get the interface index of a qdisc
00728  * @arg qdisc           qdisc handle
00729  * @return Interface index or RTNL_LINK_NOT_FOUND if not set
00730  */
00731 int rtnl_qdisc_get_ifindex(struct rtnl_qdisc *qdisc)
00732 {
00733         return tca_get_ifindex((struct rtnl_tca *) qdisc);
00734 }
00735 
00736 /**
00737  * Set the handle of a qdisc to the specified value
00738  * @arg qdisc           qdisc to be changed
00739  * @arg handle          new handle
00740  */
00741 void rtnl_qdisc_set_handle(struct rtnl_qdisc *qdisc, uint32_t handle)
00742 {
00743         tca_set_handle((struct rtnl_tca *) qdisc, handle);
00744 }
00745 
00746 /**
00747  * Get the handle of a qdisc
00748  * @arg qdisc           qdisc handle
00749  * @return Handle or 0 if not set
00750  */
00751 uint32_t rtnl_qdisc_get_handle(struct rtnl_qdisc *qdisc)
00752 {
00753         return tca_get_handle((struct rtnl_tca *) qdisc);
00754 }
00755 
00756 /**
00757  * Set the parent handle of a qdisc to the specified value
00758  * @arg qdisc           qdisc to be changed
00759  * @arg parent          new parent handle
00760  */
00761 void rtnl_qdisc_set_parent(struct rtnl_qdisc *qdisc, uint32_t parent)
00762 {
00763         tca_set_parent((struct rtnl_tca *) qdisc, parent);
00764 }
00765 
00766 /**
00767  * Get the parent handle of a qdisc
00768  * @arg qdisc           qdisc handle
00769  * @return Parent handle or 0 if not set
00770  */
00771 uint32_t rtnl_qdisc_get_parent(struct rtnl_qdisc *qdisc)
00772 {
00773         return tca_get_parent((struct rtnl_tca *) qdisc);
00774 }
00775 
00776 /**
00777  * Set the kind of a qdisc to the specified value
00778  * @arg qdisc           qdisc to be changed
00779  * @arg name            new kind name
00780  */
00781 void rtnl_qdisc_set_kind(struct rtnl_qdisc *qdisc, const char *name)
00782 {
00783         tca_set_kind((struct rtnl_tca *) qdisc, name);
00784         qdisc->q_ops = qdisc_lookup_ops(name);
00785 }
00786 
00787 /**
00788  * Get the kind of a qdisc
00789  * @arg qdisc           qdisc handle
00790  * @return Kind or NULL if not set
00791  */
00792 char *rtnl_qdisc_get_kind(struct rtnl_qdisc *qdisc)
00793 {
00794         return tca_get_kind((struct rtnl_tca *) qdisc);
00795 }
00796 
00797 /**
00798  * Get the statistic specified by the id
00799  * @arg qdisc           qdisc handle
00800  * @arg id              statistic id
00801  * @return The current counter of the specified statistic
00802  */
00803 uint64_t rtnl_qdisc_get_stat(struct rtnl_qdisc *qdisc,
00804                              enum rtnl_tc_stats_id id)
00805 {
00806         return tca_get_stat((struct rtnl_tca *) qdisc, id);
00807 }
00808 
00809 /** @} */
00810 
00811 static struct nl_cache_ops rtnl_qdisc_ops = {
00812         .co_name                = "route/qdisc",
00813         .co_size                = sizeof(struct rtnl_qdisc),
00814         .co_hdrsize             = sizeof(struct tcmsg),
00815         .co_msgtypes            = {
00816                                         { RTM_NEWQDISC, "new" },
00817                                         { RTM_DELQDISC, "delete" },
00818                                         { RTM_GETQDISC, "get" },
00819                                         { -1, NULL },
00820                                   },
00821         .co_protocol            = NETLINK_ROUTE,
00822         .co_request_update      = qdisc_request_update,
00823         .co_msg_parser          = qdisc_msg_parser,
00824         .co_free_data           = qdisc_free_data,
00825         .co_dump[NL_DUMP_BRIEF] = qdisc_dump_brief,
00826         .co_dump[NL_DUMP_FULL]  = qdisc_dump_full,
00827         .co_dump[NL_DUMP_STATS] = qdisc_dump_stats,
00828         .co_filter              = qdisc_filter,
00829 };
00830 
00831 static void __init qdisc_init(void)
00832 {
00833         nl_cache_mngt_register(&rtnl_qdisc_ops);
00834 }
00835 
00836 static void __exit qdisc_exit(void)
00837 {
00838         nl_cache_mngt_unregister(&rtnl_qdisc_ops);
00839 }
00840 
00841 /** @} */

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