libnl  3.2.3
/build/buildd/libnl3-3.2.3/lib/route/class.c
00001 /*
00002  * lib/route/class.c            Traffic 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-2011 Thomas Graf <tgraf@suug.ch>
00010  */
00011 
00012 /**
00013  * @ingroup tc
00014  * @defgroup class Traffic 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 Allocation/Freeing
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  * @name Addition/Modification/Deletion
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  * Build a netlink message requesting the addition of a traffic class
00117  * @arg class           Traffic class to add 
00118  * @arg flags           Additional netlink message flags
00119  * @arg result          Pointer to store resulting netlink message
00120  *
00121  * The behaviour of this function is identical to rtnl_class_add() with
00122  * the exception that it will not send the message but return it int the
00123  * provided return pointer instead.
00124  *
00125  * @see rtnl_class_add()
00126  *
00127  * @return 0 on success or a negative error code.
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  * Add/Update traffic class
00137  * @arg sk              Netlink socket
00138  * @arg class           Traffic class to add 
00139  * @arg flags           Additional netlink message flags
00140  *
00141  * Builds a \c RTM_NEWTCLASS netlink message requesting the addition
00142  * of a new traffic class and sends the message to the kernel. The
00143  * configuration of the traffic class is derived from the attributes
00144  * of the specified traffic class.
00145  *
00146  * The following flags may be specified:
00147  *  - \c NLM_F_CREATE:  Create traffic class if it does not exist,
00148  *                      otherwise -NLE_OBJ_NOTFOUND is returned.
00149  *  - \c NLM_F_EXCL:    Return -NLE_EXISTS if a traffic class with
00150  *                      matching handle exists already.
00151  *
00152  * Existing traffic classes with matching handles will be updated,
00153  * unless the flag \c NLM_F_EXCL is specified. If no matching traffic
00154  * class exists, it will be created if the flag \c NLM_F_CREATE is set,
00155  * otherwise the error -NLE_OBJ_NOTFOUND is returned. 
00156  *
00157  * If the parent qdisc does not support classes, the error
00158  * \c NLE_OPNOTSUPP is returned.
00159  *
00160  * After sending, the function will wait for the ACK or an eventual
00161  * error message to be received and will therefore block until the
00162  * operation has been completed.
00163  *
00164  * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
00165  *       this function to return immediately after sending. In this case,
00166  *       it is the responsibility of the caller to handle any error
00167  *       messages returned.
00168  *
00169  * @return 0 on success or a negative error code.
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  * Build netlink message requesting the deletion of a traffic class
00184  * @arg class           Traffic class to delete
00185  * @arg result          Pointer to store resulting netlink message
00186  *
00187  * The behaviour of this function is identical to rtnl_class_delete() with
00188  * the exception that it will not send the message but return it in the
00189  * provided return pointer instead.
00190  *
00191  * @see rtnl_class_delete()
00192  *
00193  * @return 0 on success or a negative error code.
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  * Delete traffic class
00228  * @arg sk              Netlink socket
00229  * @arg class           Traffic class to delete
00230  *
00231  * Builds a \c RTM_DELTCLASS netlink message requesting the deletion
00232  * of a traffic class and sends the message to the kernel.
00233  *
00234  * The message is constructed out of the following attributes:
00235  * - \c ifindex and \c handle (required)
00236  * - \c parent (optional, must match if provided)
00237  *
00238  * All other class attributes including all class type specific
00239  * attributes are ignored.
00240  *
00241  * After sending, the function will wait for the ACK or an eventual
00242  * error message to be received and will therefore block until the
00243  * operation has been completed.
00244  *
00245  * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
00246  *       this function to return immediately after sending. In this case,
00247  *       it is the responsibility of the caller to handle any error
00248  *       messages returned.
00249  *
00250  * @return 0 on success or a negative error code.
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  * @name Leaf Qdisc
00267  * @{
00268  */
00269 
00270 /**
00271  * Lookup the leaf qdisc of a traffic class
00272  * @arg class           the parent traffic class
00273  * @arg cache           a qdisc cache allocated using rtnl_qdisc_alloc_cache()
00274  *
00275  * @return Matching Qdisc or NULL if the traffic class has no leaf qdisc
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  * @name Cache Related Functions
00297  * @{
00298  */
00299 
00300 /**
00301  * Allocate a cache and fill it with all configured traffic classes
00302  * @arg sk              Netlink socket
00303  * @arg ifindex         Interface index of the network device
00304  * @arg result          Pointer to store the created cache
00305  *
00306  * Allocates a new traffic class cache and fills it with a list of all
00307  * configured traffic classes on a specific network device. Release the
00308  * cache with nl_cache_free().
00309  *
00310  * @return 0 on success or a negative error code.
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  * Search traffic class by interface index and handle
00339  * @arg cache           Traffic class cache
00340  * @arg ifindex         Interface index
00341  * @arg handle          ID of traffic class
00342  *
00343  * Searches a traffic class cache previously allocated with
00344  * rtnl_class_alloc_cache() and searches for a traffi class matching
00345  * the interface index and handle.
00346  *
00347  * The reference counter is incremented before returning the traffic
00348  * class, therefore the reference must be given back with rtnl_class_put()
00349  * after usage.
00350  *
00351  * @return Traffic class or NULL if no match was found.
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  * @name Deprecated Functions
00374  * @{
00375  */
00376 
00377 /**
00378  * Call a callback for each child of a class
00379  *
00380  * @deprecated Use of this function is deprecated, it does not allow
00381  *             to handle the out of memory situation that can occur.
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  * Call a callback for each classifier attached to the class
00402  *
00403  * @deprecated Use of this function is deprecated, it does not allow
00404  *             to handle the out of memory situation that can occur.
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 /** @} */