libnl 1.1
lib/route/classifier.c
00001 /*
00002  * lib/route/classifier.c       Classifier
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 cls Classifiers
00015  *
00016  * @par Classifier Identification
00017  * - protocol
00018  * - priority
00019  * - parent
00020  * - interface
00021  * - kind
00022  * - handle
00023  * 
00024  * @{
00025  */
00026 
00027 #include <netlink-local.h>
00028 #include <netlink-tc.h>
00029 #include <netlink/netlink.h>
00030 #include <netlink/utils.h>
00031 #include <netlink/route/tc.h>
00032 #include <netlink/route/classifier.h>
00033 #include <netlink/route/classifier-modules.h>
00034 #include <netlink/route/link.h>
00035 
00036 static struct nl_cache_ops rtnl_cls_ops;
00037 
00038 static int cls_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
00039                           struct nlmsghdr *nlh, struct nl_parser_param *pp)
00040 {
00041         int err;
00042         struct rtnl_cls *cls;
00043         struct rtnl_cls_ops *cops;
00044 
00045         cls = rtnl_cls_alloc();
00046         if (!cls) {
00047                 err = nl_errno(ENOMEM);
00048                 goto errout;
00049         }
00050         cls->ce_msgtype = nlh->nlmsg_type;
00051 
00052         err = tca_msg_parser(nlh, (struct rtnl_tca *) cls);
00053         if (err < 0)
00054                 goto errout_free;
00055 
00056         cls->c_prio = TC_H_MAJ(cls->c_info) >> 16;
00057         cls->c_protocol = ntohs(TC_H_MIN(cls->c_info));
00058 
00059         cops = rtnl_cls_lookup_ops(cls);
00060         if (cops && cops->co_msg_parser) {
00061                 err = cops->co_msg_parser(cls);
00062                 if (err < 0)
00063                         goto errout_free;
00064         }
00065 
00066         err = pp->pp_cb((struct nl_object *) cls, pp);
00067         if (err < 0)
00068                 goto errout_free;
00069 
00070         err = P_ACCEPT;
00071 
00072 errout_free:
00073         rtnl_cls_put(cls);
00074 errout:
00075         return err;
00076 }
00077 
00078 static int cls_request_update(struct nl_cache *cache, struct nl_handle *handle)
00079 {
00080         struct tcmsg tchdr = {
00081                 .tcm_family = AF_UNSPEC,
00082                 .tcm_ifindex = cache->c_iarg1,
00083                 .tcm_parent = cache->c_iarg2,
00084         };
00085 
00086         return nl_send_simple(handle, RTM_GETTFILTER, NLM_F_DUMP, &tchdr,
00087                               sizeof(tchdr));
00088 }
00089 
00090 
00091 static struct nl_msg *cls_build(struct rtnl_cls *cls, int type, int flags)
00092 {
00093         struct nl_msg *msg;
00094         struct rtnl_cls_ops *cops;
00095         int err, prio, proto;
00096         struct tcmsg *tchdr;
00097 
00098         msg = tca_build_msg((struct rtnl_tca *) cls, type, flags);
00099         if (!msg)
00100                 goto errout;
00101 
00102         tchdr = nlmsg_data(nlmsg_hdr(msg));
00103         prio = rtnl_cls_get_prio(cls);
00104         proto = rtnl_cls_get_protocol(cls);
00105         tchdr->tcm_info = TC_H_MAKE(prio << 16, htons(proto)),
00106 
00107         cops = rtnl_cls_lookup_ops(cls);
00108         if (cops && cops->co_get_opts) {
00109                 struct nl_msg *opts;
00110                 
00111                 opts = cops->co_get_opts(cls);
00112                 if (opts) {
00113                         err = nla_put_nested(msg, TCA_OPTIONS, opts);
00114                         nlmsg_free(opts);
00115                         if (err < 0)
00116                                 goto errout;
00117                 }
00118         }
00119 
00120         return msg;
00121 errout:
00122         nlmsg_free(msg);
00123         return NULL;
00124 }
00125 
00126 /**
00127  * @name Classifier Addition/Modification/Deletion
00128  * @{
00129  */
00130 
00131 /**
00132  * Build a netlink message to add a new classifier
00133  * @arg cls             classifier to add
00134  * @arg flags           additional netlink message flags
00135  *
00136  * Builds a new netlink message requesting an addition of a classifier
00137  * The netlink message header isn't fully equipped with all relevant
00138  * fields and must be sent out via nl_send_auto_complete() or
00139  * supplemented as needed. \a classifier must contain the attributes of
00140  * the new classifier set via \c rtnl_cls_set_* functions. \a opts
00141  * may point to the clsasifier specific options.
00142  *
00143  * @return New netlink message
00144  */
00145 struct nl_msg * rtnl_cls_build_add_request(struct rtnl_cls *cls, int flags)
00146 {
00147         return cls_build(cls, RTM_NEWTFILTER, NLM_F_CREATE | flags);
00148 }
00149 
00150 /**
00151  * Add a new classifier
00152  * @arg handle          netlink handle
00153  * @arg cls             classifier to add
00154  * @arg flags           additional netlink message flags
00155  *
00156  * Builds a netlink message by calling rtnl_cls_build_add_request(),
00157  * sends the request to the kernel and waits for the next ACK to be
00158  * received and thus blocks until the request has been processed.
00159  *
00160  * @return 0 on sucess or a negative error if an error occured.
00161  */
00162 int rtnl_cls_add(struct nl_handle *handle, struct rtnl_cls *cls, int flags)
00163 {
00164         int err;
00165         struct nl_msg *msg;
00166         
00167         msg = rtnl_cls_build_add_request(cls, flags);
00168         if (!msg)
00169                 return nl_errno(ENOMEM);
00170         
00171         err = nl_send_auto_complete(handle, msg);
00172         if (err < 0)
00173                 return err;
00174 
00175         nlmsg_free(msg);
00176         return nl_wait_for_ack(handle);
00177 }
00178 
00179 /**
00180  * Build a netlink message to change classifier attributes
00181  * @arg cls             classifier to change
00182  * @arg flags           additional netlink message flags
00183  *
00184  * Builds a new netlink message requesting a change of a neigh
00185  * attributes. The netlink message header isn't fully equipped with
00186  * all relevant fields and must thus be sent out via nl_send_auto_complete()
00187  * or supplemented as needed.
00188  *
00189  * @return The netlink message
00190  */
00191 struct nl_msg *rtnl_cls_build_change_request(struct rtnl_cls *cls, int flags)
00192 {
00193         return cls_build(cls, RTM_NEWTFILTER, NLM_F_REPLACE | flags);
00194 }
00195 
00196 /**
00197  * Change a classifier
00198  * @arg handle          netlink handle
00199  * @arg cls             classifier to change
00200  * @arg flags           additional netlink message flags
00201  *
00202  * Builds a netlink message by calling rtnl_cls_build_change_request(),
00203  * sends the request to the kernel and waits for the next ACK to be
00204  * received and thus blocks until the request has been processed.
00205  *
00206  * @return 0 on sucess or a negative error if an error occured.
00207  */
00208 int rtnl_cls_change(struct nl_handle *handle, struct rtnl_cls *cls,
00209                     int flags)
00210 {
00211         int err;
00212         struct nl_msg *msg;
00213         
00214         msg = rtnl_cls_build_change_request(cls, flags);
00215         if (!msg)
00216                 return nl_errno(ENOMEM);
00217         
00218         err = nl_send_auto_complete(handle, msg);
00219         if (err < 0)
00220                 return err;
00221 
00222         nlmsg_free(msg);
00223         return nl_wait_for_ack(handle);
00224 }
00225 
00226 /**
00227  * Build a netlink request message to delete a classifier
00228  * @arg cls             classifier to delete
00229  * @arg flags           additional netlink message flags
00230  *
00231  * Builds a new netlink message requesting a deletion of a classifier.
00232  * The netlink message header isn't fully equipped with all relevant
00233  * fields and must thus be sent out via nl_send_auto_complete()
00234  * or supplemented as needed.
00235  *
00236  * @return New netlink message
00237  */
00238 struct nl_msg *rtnl_cls_build_delete_request(struct rtnl_cls *cls, int flags)
00239 {
00240         return cls_build(cls, RTM_DELTFILTER, flags);
00241 }
00242 
00243 
00244 /**
00245  * Delete a classifier
00246  * @arg handle          netlink handle
00247  * @arg cls             classifier to delete
00248  * @arg flags           additional netlink message flags
00249  *
00250  * Builds a netlink message by calling rtnl_cls_build_delete_request(),
00251  * sends the request to the kernel and waits for the next ACK to be
00252  * received and thus blocks until the request has been processed.
00253  *
00254  * @return 0 on sucess or a negative error if an error occured.
00255  */
00256 int rtnl_cls_delete(struct nl_handle *handle, struct rtnl_cls *cls, int flags)
00257 {
00258         int err;
00259         struct nl_msg *msg;
00260         
00261         msg = rtnl_cls_build_delete_request(cls, flags);
00262         if (!msg)
00263                 return nl_errno(ENOMEM);
00264         
00265         err = nl_send_auto_complete(handle, msg);
00266         if (err < 0)
00267                 return err;
00268 
00269         nlmsg_free(msg);
00270         return nl_wait_for_ack(handle);
00271 }
00272 
00273 /** @} */
00274 
00275 /**
00276  * @name Cache Management
00277  * @{
00278  */
00279 
00280 /**
00281  * Build a classifier cache including all classifiers attached to the
00282  * specified class/qdisc on eht specified interface.
00283  * @arg handle          netlink handle
00284  * @arg ifindex         interface index of the link the classes are
00285  *                      attached to.
00286  * @arg parent          parent qdisc/class
00287  *
00288  * Allocates a new cache, initializes it properly and updates it to
00289  * include all classes attached to the specified interface.
00290  *
00291  * @note The caller is responsible for destroying and freeing the
00292  *       cache after using it.
00293  * @return The cache or NULL if an error has occured.
00294  */
00295 struct nl_cache *rtnl_cls_alloc_cache(struct nl_handle *handle,
00296                                       int ifindex, uint32_t parent)
00297 {
00298         struct nl_cache * cache;
00299         
00300         cache = nl_cache_alloc(&rtnl_cls_ops);
00301         if (cache == NULL)
00302                 return NULL;
00303 
00304         cache->c_iarg1 = ifindex;
00305         cache->c_iarg2 = parent;
00306         
00307         if (handle && nl_cache_refill(handle, cache) < 0) {
00308                 nl_cache_free(cache);
00309                 return NULL;
00310         }
00311 
00312         return cache;
00313 }
00314 
00315 /** @} */
00316 
00317 static struct nl_cache_ops rtnl_cls_ops = {
00318         .co_name                = "route/cls",
00319         .co_hdrsize             = sizeof(struct tcmsg),
00320         .co_msgtypes            = {
00321                                         { RTM_NEWTFILTER, NL_ACT_NEW, "new" },
00322                                         { RTM_DELTFILTER, NL_ACT_DEL, "del" },
00323                                         { RTM_GETTFILTER, NL_ACT_GET, "get" },
00324                                         END_OF_MSGTYPES_LIST,
00325                                   },
00326         .co_protocol            = NETLINK_ROUTE,
00327         .co_request_update      = cls_request_update,
00328         .co_msg_parser          = cls_msg_parser,
00329         .co_obj_ops             = &cls_obj_ops,
00330 };
00331 
00332 static void __init cls_init(void)
00333 {
00334         nl_cache_mngt_register(&rtnl_cls_ops);
00335 }
00336 
00337 static void __exit cls_exit(void)
00338 {
00339         nl_cache_mngt_unregister(&rtnl_cls_ops);
00340 }
00341 
00342 /** @} */