libnl 2.0

/tmp/buildd/libnl2-2.0/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-2008 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.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 static struct nl_cache_ops rtnl_class_ops;
00029 
00030 static int class_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
00031                             struct nlmsghdr *n, struct nl_parser_param *pp)
00032 {
00033         int err;
00034         struct rtnl_class *class;
00035         struct rtnl_class_ops *cops;
00036 
00037         class = rtnl_class_alloc();
00038         if (!class) {
00039                 err = -NLE_NOMEM;
00040                 goto errout;
00041         }
00042         class->ce_msgtype = n->nlmsg_type;
00043 
00044         err = tca_msg_parser(n, (struct rtnl_tca *) class);
00045         if (err < 0)
00046                 goto errout_free;
00047 
00048         cops = rtnl_class_lookup_ops(class);
00049         if (cops && cops->co_msg_parser) {
00050                 err = cops->co_msg_parser(class);
00051                 if (err < 0)
00052                         goto errout_free;
00053         }
00054 
00055         err = pp->pp_cb((struct nl_object *) class, pp);
00056 errout_free:
00057         rtnl_class_put(class);
00058 errout:
00059         return err;
00060 }
00061 
00062 static int class_request_update(struct nl_cache *cache, struct nl_sock *sk)
00063 {
00064         struct tcmsg tchdr = {
00065                 .tcm_family = AF_UNSPEC,
00066                 .tcm_ifindex = cache->c_iarg1,
00067         };
00068 
00069         return nl_send_simple(sk, RTM_GETTCLASS, NLM_F_DUMP, &tchdr,
00070                               sizeof(tchdr));
00071 }
00072 
00073 /**
00074  * @name Addition/Modification
00075  * @{
00076  */
00077 
00078 static int class_build(struct rtnl_class *class, int type, int flags,
00079                        struct nl_msg **result)
00080 {
00081         struct rtnl_class_ops *cops;
00082         int err;
00083 
00084         err = tca_build_msg((struct rtnl_tca *) class, type, flags, result);
00085         if (err < 0)
00086                 return err;
00087 
00088         cops = rtnl_class_lookup_ops(class);
00089         if (cops && cops->co_get_opts) {
00090                 struct nl_msg *opts;
00091                 
00092                 opts = cops->co_get_opts(class);
00093                 if (opts) {
00094                         err = nla_put_nested(*result, TCA_OPTIONS, opts);
00095                         nlmsg_free(opts);
00096                         if (err < 0)
00097                                 goto errout;
00098                 }
00099         }
00100 
00101         return 0;
00102 errout:
00103         nlmsg_free(*result);
00104         return err;
00105 }
00106 
00107 /**
00108  * Build a netlink message to add a new class
00109  * @arg class           class to add 
00110  * @arg flags           additional netlink message flags
00111  * @arg result          Pointer to store resulting message.
00112  *
00113  * Builds a new netlink message requesting an addition of a class.
00114  * The netlink message header isn't fully equipped with all relevant
00115  * fields and must be sent out via nl_send_auto_complete() or
00116  * supplemented as needed. 
00117  *
00118  * Common message flags
00119  *   - NLM_F_REPLACE - replace possibly existing classes
00120  *
00121  * @return 0 on success or a negative error code.
00122  */
00123 int rtnl_class_build_add_request(struct rtnl_class *class, int flags,
00124                                  struct nl_msg **result)
00125 {
00126         return class_build(class, RTM_NEWTCLASS, NLM_F_CREATE | flags, result);
00127 }
00128 
00129 /**
00130  * Add a new class
00131  * @arg sk              Netlink socket.
00132  * @arg class           class to delete
00133  * @arg flags           additional netlink message flags
00134  *
00135  * Builds a netlink message by calling rtnl_qdisc_build_add_request(),
00136  * sends the request to the kernel and waits for the next ACK to be
00137  * received and thus blocks until the request has been processed.
00138  *
00139  * Common message flags
00140  *   - NLM_F_REPLACE - replace possibly existing classes
00141  *
00142  * @return 0 on success or a negative error code
00143  */
00144 int rtnl_class_add(struct nl_sock *sk, struct rtnl_class *class, int flags)
00145 {
00146         struct nl_msg *msg;
00147         int err;
00148 
00149         if ((err = rtnl_class_build_add_request(class, flags, &msg)) < 0)
00150                 return err;
00151 
00152         err = nl_send_auto_complete(sk, msg);
00153         nlmsg_free(msg);
00154         if (err < 0)
00155                 return err;
00156 
00157         return wait_for_ack(sk);
00158 }
00159 
00160 int rtnl_class_build_delete_request(struct rtnl_class *class,
00161                                                                         struct nl_msg **result)
00162 {
00163         struct nl_msg *msg;
00164         struct tcmsg tchdr;
00165         int required = TCA_ATTR_IFINDEX | TCA_ATTR_PARENT;
00166 
00167         if ((class->ce_mask & required) != required)
00168                 BUG();
00169 
00170         msg = nlmsg_alloc_simple(RTM_DELTCLASS, 0);
00171         if (!msg)
00172                 return -NLE_NOMEM;
00173 
00174         tchdr.tcm_family = AF_UNSPEC;
00175         tchdr.tcm_handle = class->c_handle;
00176         tchdr.tcm_parent = class->c_parent;
00177         tchdr.tcm_ifindex = class->c_ifindex;
00178         if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0) {
00179                 nlmsg_free(msg);
00180                 return -NLE_MSGSIZE;
00181         }
00182 
00183         *result = msg;
00184         return 0;
00185 }
00186 
00187 /**
00188  * Delete a class
00189  * @arg sk              Netlink socket.
00190  * @arg class           class to delete
00191  *
00192  * Builds a netlink message by calling rtnl_class_build_delete_request(),
00193  * sends the request to the kernel and waits for the ACK to be
00194  * received and thus blocks until the request has been processed.
00195  *
00196  * @return 0 on success or a negative error code
00197  */
00198 int rtnl_class_delete(struct nl_sock *sk, struct rtnl_class *class)
00199 {
00200         struct nl_msg *msg;
00201         int err;
00202 
00203         if ((err = rtnl_class_build_delete_request(class, &msg)) < 0)
00204                 return err;
00205 
00206         err = nl_send_auto_complete(sk, msg);
00207         nlmsg_free(msg);
00208         if (err < 0)
00209                 return err;
00210 
00211         return wait_for_ack(sk);
00212 }
00213 
00214 /** @} */
00215 
00216 /**
00217  * @name Cache Management
00218  * @{
00219  */
00220 
00221 /**
00222  * Build a class cache including all classes attached to the specified interface
00223  * @arg sk              Netlink socket.
00224  * @arg ifindex         interface index of the link the classes are
00225  *                      attached to.
00226  *
00227  * Allocates a new cache, initializes it properly and updates it to
00228  * include all classes attached to the specified interface.
00229  *
00230  * @return The cache or NULL if an error has occured.
00231  */
00232 int rtnl_class_alloc_cache(struct nl_sock *sk, int ifindex,
00233                            struct nl_cache **result)
00234 {
00235         struct nl_cache * cache;
00236         int err;
00237         
00238         cache = nl_cache_alloc(&rtnl_class_ops);
00239         if (!cache)
00240                 return -NLE_NOMEM;
00241 
00242         cache->c_iarg1 = ifindex;
00243         
00244         if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
00245                 nl_cache_free(cache);
00246                 return err;
00247         }
00248 
00249         *result = cache;
00250         return 0;
00251 }
00252 
00253 /**
00254  * Look up class by its handle in the provided cache
00255  * @arg cache           class cache
00256  * @arg ifindex         interface the class is attached to
00257  * @arg handle          class handle
00258  * @return pointer to class inside the cache or NULL if no match was found.
00259  */
00260 struct rtnl_class *rtnl_class_get(struct nl_cache *cache, int ifindex,
00261                                                                   uint32_t handle)
00262 {
00263         struct rtnl_class *class;
00264         
00265         if (cache->c_ops != &rtnl_class_ops)
00266                 return NULL;
00267 
00268         nl_list_for_each_entry(class, &cache->c_items, ce_list) {
00269                 if (class->c_handle == handle && class->c_ifindex == ifindex) {
00270                         nl_object_get((struct nl_object *) class);
00271                         return class;
00272                 }
00273         }
00274         return NULL;
00275 }
00276 
00277 /** @} */
00278 
00279 static struct nl_cache_ops rtnl_class_ops = {
00280         .co_name                = "route/class",
00281         .co_hdrsize             = sizeof(struct tcmsg),
00282         .co_msgtypes            = {
00283                                         { RTM_NEWTCLASS, NL_ACT_NEW, "new" },
00284                                         { RTM_DELTCLASS, NL_ACT_DEL, "del" },
00285                                         { RTM_GETTCLASS, NL_ACT_GET, "get" },
00286                                         END_OF_MSGTYPES_LIST,
00287                                   },
00288         .co_protocol            = NETLINK_ROUTE,
00289         .co_request_update      = &class_request_update,
00290         .co_msg_parser          = &class_msg_parser,
00291         .co_obj_ops             = &class_obj_ops,
00292 };
00293 
00294 static void __init class_init(void)
00295 {
00296         nl_cache_mngt_register(&rtnl_class_ops);
00297 }
00298 
00299 static void __exit class_exit(void)
00300 {
00301         nl_cache_mngt_unregister(&rtnl_class_ops);
00302 }
00303 
00304 /** @} */