libnl 2.0

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