libnl 1.1
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 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 = nl_errno(ENOMEM);
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         if (err < 0)
00057                 goto errout_free;
00058 
00059         err = P_ACCEPT;
00060 
00061 errout_free:
00062         rtnl_class_put(class);
00063 errout:
00064         return err;
00065 }
00066 
00067 static int class_request_update(struct nl_cache *cache,
00068                                 struct nl_handle *handle)
00069 {
00070         struct tcmsg tchdr = {
00071                 .tcm_family = AF_UNSPEC,
00072                 .tcm_ifindex = cache->c_iarg1,
00073         };
00074 
00075         return nl_send_simple(handle, RTM_GETTCLASS, NLM_F_DUMP, &tchdr,
00076                               sizeof(tchdr));
00077 }
00078 
00079 /**
00080  * @name Addition/Modification
00081  * @{
00082  */
00083 
00084 static struct nl_msg *class_build(struct rtnl_class *class, int type, int flags)
00085 {
00086         struct rtnl_class_ops *cops;
00087         struct nl_msg *msg;
00088         int err;
00089 
00090         msg = tca_build_msg((struct rtnl_tca *) class, type, flags);
00091         if (!msg)
00092                 goto errout;
00093 
00094         cops = rtnl_class_lookup_ops(class);
00095         if (cops && cops->co_get_opts) {
00096                 struct nl_msg *opts;
00097                 
00098                 opts = cops->co_get_opts(class);
00099                 if (opts) {
00100                         err = nla_put_nested(msg, TCA_OPTIONS, opts);
00101                         nlmsg_free(opts);
00102                         if (err < 0)
00103                                 goto errout;
00104                 }
00105         }
00106 
00107         return msg;
00108 errout:
00109         nlmsg_free(msg);
00110         return NULL;
00111 }
00112 
00113 /**
00114  * Build a netlink message to add a new class
00115  * @arg class           class to add 
00116  * @arg flags           additional netlink message flags
00117  *
00118  * Builds a new netlink message requesting an addition of a class.
00119  * The netlink message header isn't fully equipped with all relevant
00120  * fields and must be sent out via nl_send_auto_complete() or
00121  * supplemented as needed. 
00122  *
00123  * Common message flags
00124  *   - NLM_F_REPLACE - replace possibly existing classes
00125  *
00126  * @return New netlink message
00127  */
00128 struct nl_msg *rtnl_class_build_add_request(struct rtnl_class *class, int flags)
00129 {
00130         return class_build(class, RTM_NEWTCLASS, NLM_F_CREATE | flags);
00131 }
00132 
00133 /**
00134  * Add a new class
00135  * @arg handle          netlink handle
00136  * @arg class           class to delete
00137  * @arg flags           additional netlink message flags
00138  *
00139  * Builds a netlink message by calling rtnl_qdisc_build_add_request(),
00140  * sends the request to the kernel and waits for the next ACK to be
00141  * received and thus blocks until the request has been processed.
00142  *
00143  * Common message flags
00144  *   - NLM_F_REPLACE - replace possibly existing classes
00145  *
00146  * @return 0 on success or a negative error code
00147  */
00148 int rtnl_class_add(struct nl_handle *handle, struct rtnl_class *class,
00149                    int flags)
00150 {
00151         struct nl_msg *msg;
00152         int err;
00153 
00154         msg = rtnl_class_build_add_request(class, flags);
00155         if (!msg)
00156                 return nl_errno(ENOMEM);
00157 
00158         err = nl_send_auto_complete(handle, msg);
00159         if (err < 0)
00160                 return err;
00161 
00162         nlmsg_free(msg);
00163         return nl_wait_for_ack(handle);
00164 }
00165 
00166 /** @} */
00167 
00168 /**
00169  * @name Cache Management
00170  * @{
00171  */
00172 
00173 /**
00174  * Build a class cache including all classes attached to the specified interface
00175  * @arg handle          netlink handle
00176  * @arg ifindex         interface index of the link the classes are
00177  *                      attached to.
00178  *
00179  * Allocates a new cache, initializes it properly and updates it to
00180  * include all classes attached to the specified interface.
00181  *
00182  * @return The cache or NULL if an error has occured.
00183  */
00184 struct nl_cache * rtnl_class_alloc_cache(struct nl_handle *handle, int ifindex)
00185 {
00186         struct nl_cache * cache;
00187         
00188         cache = nl_cache_alloc(&rtnl_class_ops);
00189         if (!cache)
00190                 return NULL;
00191 
00192         cache->c_iarg1 = ifindex;
00193         
00194         if (handle && nl_cache_refill(handle, cache) < 0) {
00195                 nl_cache_free(cache);
00196                 return NULL;
00197         }
00198 
00199         return cache;
00200 }
00201 
00202 /** @} */
00203 
00204 static struct nl_cache_ops rtnl_class_ops = {
00205         .co_name                = "route/class",
00206         .co_hdrsize             = sizeof(struct tcmsg),
00207         .co_msgtypes            = {
00208                                         { RTM_NEWTCLASS, NL_ACT_NEW, "new" },
00209                                         { RTM_DELTCLASS, NL_ACT_DEL, "del" },
00210                                         { RTM_GETTCLASS, NL_ACT_GET, "get" },
00211                                         END_OF_MSGTYPES_LIST,
00212                                   },
00213         .co_protocol            = NETLINK_ROUTE,
00214         .co_request_update      = &class_request_update,
00215         .co_msg_parser          = &class_msg_parser,
00216         .co_obj_ops             = &class_obj_ops,
00217 };
00218 
00219 static void __init class_init(void)
00220 {
00221         nl_cache_mngt_register(&rtnl_class_ops);
00222 }
00223 
00224 static void __exit class_exit(void)
00225 {
00226         nl_cache_mngt_unregister(&rtnl_class_ops);
00227 }
00228 
00229 /** @} */