/build/buildd/libnl-1.0~pre6/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 /** @cond SKIP */
00037 #define CLS_ATTR_PRIO           (TCA_ATTR_MAX << 1)
00038 #define CLS_ATTR_PROTOCOL       (TCA_ATTR_MAX << 2)
00039 
00040 static struct nl_cache_ops rtnl_cls_ops;
00041 /** @endcond */
00042 
00043 static struct rtnl_cls_ops *cls_ops_list;
00044 
00045 static struct rtnl_cls_ops * cls_lookup_ops(char *kind)
00046 {
00047         struct rtnl_cls_ops *ops;
00048 
00049         for (ops = cls_ops_list; ops; ops = ops->co_next)
00050                 if (!strcmp(kind, ops->co_kind))
00051                         return ops;
00052 
00053         return NULL;
00054 }
00055 
00056 static inline struct rtnl_cls_ops *cls_ops(struct rtnl_cls *cls)
00057 {
00058         if (!cls->c_ops)
00059                 cls->c_ops = cls_lookup_ops(cls->c_kind);
00060 
00061         return cls->c_ops;
00062 }
00063 
00064 /**
00065  * @name Classifier Module API
00066  * @{
00067  */
00068 
00069 /**
00070  * Register a classifier module
00071  * @arg ops             classifier module operations
00072  */
00073 int rtnl_cls_register(struct rtnl_cls_ops *ops)
00074 {
00075         struct rtnl_cls_ops *o, **op;
00076 
00077         if (!ops->co_kind)
00078                 BUG();
00079 
00080         for (op = &cls_ops_list; (o = *op) != NULL; op = &o->co_next)
00081                 if (!strcasecmp(ops->co_kind, o->co_kind))
00082                         return nl_errno(EEXIST);
00083 
00084         ops->co_next = NULL;
00085         *op = ops;
00086 
00087         return 0;
00088 }
00089 
00090 /**
00091  * Unregister a classifier module
00092  * @arg ops             classifier module operations
00093  */
00094 int rtnl_cls_unregister(struct rtnl_cls_ops *ops)
00095 {
00096         struct rtnl_cls_ops *o, **op;
00097 
00098         for (op = &cls_ops_list; (o = *op) != NULL; op = &o->co_next)
00099                 if (!strcasecmp(ops->co_kind, o->co_kind))
00100                         break;
00101 
00102         if (!o)
00103                 return nl_errno(ENOENT);
00104 
00105         *op = ops->co_next;
00106 
00107         return 0;
00108 }
00109 
00110 /** @} */
00111 
00112 static int cls_msg_parser(struct sockaddr_nl *who, struct nlmsghdr *nlh,
00113                           void *arg)
00114 {
00115         int err;
00116         struct nl_parser_param *pp = arg;
00117         struct rtnl_cls *cls;
00118         struct rtnl_cls_ops *ops;
00119 
00120         cls = rtnl_cls_alloc();
00121         if (!cls) {
00122                 err = nl_errno(ENOMEM);
00123                 goto errout;
00124         }
00125         cls->ce_msgtype = nlh->nlmsg_type;
00126 
00127         err = tca_msg_parser(nlh, (struct rtnl_tca *) cls);
00128         if (err < 0)
00129                 goto errout_free;
00130 
00131         cls->c_prio = TC_H_MAJ(cls->c_info) >> 16;
00132         cls->c_protocol = ntohs(TC_H_MIN(cls->c_info));
00133 
00134         ops = cls_ops(cls);
00135         if (ops && ops->co_msg_parser) {
00136                 err = ops->co_msg_parser(cls);
00137                 if (err < 0)
00138                         goto errout_free;
00139         }
00140 
00141         err = pp->pp_cb((struct nl_object *) cls, pp);
00142         if (err < 0)
00143                 goto errout_free;
00144 
00145         return P_ACCEPT;
00146 
00147 errout_free:
00148         rtnl_cls_put(cls);
00149 errout:
00150         return err;
00151 }
00152 
00153 static int cls_request_update(struct nl_cache *cache, struct nl_handle *handle)
00154 {
00155         struct tcmsg tchdr = {
00156                 .tcm_family = AF_UNSPEC,
00157                 .tcm_ifindex = cache->c_iarg1,
00158                 .tcm_parent = cache->c_iarg2,
00159         };
00160 
00161         return nl_send_simple(handle, RTM_GETTFILTER, NLM_F_DUMP, &tchdr,
00162                               sizeof(tchdr));
00163 }
00164 
00165 
00166 static void cls_free_data(struct nl_object *obj)
00167 {
00168         struct rtnl_cls *cls = (struct rtnl_cls *) obj;
00169         struct rtnl_cls_ops *ops;
00170         
00171         tca_free_data((struct rtnl_tca *) cls);
00172 
00173         ops = cls_ops(cls);
00174         if (ops && ops->co_free_data)
00175                 ops->co_free_data(cls);
00176 }
00177 
00178 static int cls_dump_brief(struct nl_object *obj, struct nl_dump_params *p)
00179 {
00180         char buf[32];
00181         struct rtnl_cls *cls = (struct rtnl_cls *) obj;
00182         struct rtnl_cls_ops *ops;
00183         int line;
00184 
00185         line = tca_dump_brief((struct rtnl_tca *) cls, "cls", p, 0);
00186 
00187         dp_dump(p, " prio %u protocol %s", cls->c_prio,
00188                 nl_ether_proto2str(cls->c_protocol, buf, sizeof(buf)));
00189 
00190         ops = cls_ops(cls);
00191         if (ops && ops->co_dump[NL_DUMP_BRIEF])
00192                 line = ops->co_dump[NL_DUMP_BRIEF](cls, p, line);
00193         dp_dump(p, "\n");
00194 
00195         return line;
00196 }
00197 
00198 static int cls_dump_full(struct nl_object *obj, struct nl_dump_params *p)
00199 {
00200         struct rtnl_cls *cls = (struct rtnl_cls *) obj;
00201         struct rtnl_cls_ops *ops;
00202         int line;
00203 
00204         line = cls_dump_brief(obj, p);
00205         line = tca_dump_full((struct rtnl_tca *) cls, p, line);
00206 
00207         ops = cls_ops(cls);
00208         if (ops && ops->co_dump[NL_DUMP_FULL])
00209                 line = ops->co_dump[NL_DUMP_FULL](cls, p, line);
00210         else
00211                 dp_dump(p, "no options\n");
00212 
00213         return line;
00214 }
00215 
00216 static int cls_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
00217 {
00218         struct rtnl_cls *cls = (struct rtnl_cls *) obj;
00219         struct rtnl_cls_ops *ops;
00220         int line;
00221 
00222         line = cls_dump_full(obj, p);
00223         line = tca_dump_stats((struct rtnl_tca *) cls, p, line);
00224         dp_dump(p, "\n");
00225 
00226         ops = cls_ops(cls);
00227         if (ops && ops->co_dump[NL_DUMP_STATS])
00228                 line = ops->co_dump[NL_DUMP_STATS](cls, p, line);
00229 
00230         return line;
00231 }
00232 
00233 static int cls_filter(struct nl_object *obj, struct nl_object *filter)
00234 {
00235         return tca_filter((struct rtnl_tca *) obj, (struct rtnl_tca *) filter);
00236 }
00237 
00238 static struct nl_msg *cls_build(struct rtnl_cls *cls, int type, int flags)
00239 {
00240         struct nl_msg *msg;
00241         struct rtnl_cls_ops *ops;
00242         int err, prio, proto;
00243         struct tcmsg *tchdr;
00244 
00245         msg = tca_build_msg((struct rtnl_tca *) cls, type, flags);
00246         if (!msg)
00247                 goto errout;
00248 
00249         tchdr = nlmsg_data(nlmsg_hdr(msg));
00250         prio = cls->c_mask & CLS_ATTR_PRIO ? cls->c_prio : 0;
00251         proto = cls->c_mask & CLS_ATTR_PROTOCOL ? cls->c_protocol : ETH_P_ALL;
00252         tchdr->tcm_info = TC_H_MAKE(prio << 16, htons(proto)),
00253 
00254         ops = cls_ops(cls);
00255         if (ops && ops->co_get_opts) {
00256                 struct nl_msg *opts;
00257                 
00258                 opts = ops->co_get_opts(cls);
00259                 if (opts) {
00260                         err = nla_put_nested(msg, TCA_OPTIONS, opts);
00261                         nlmsg_free(opts);
00262                         if (err < 0)
00263                                 goto errout;
00264                 }
00265         }
00266 
00267         return msg;
00268 errout:
00269         nlmsg_free(msg);
00270         return NULL;
00271 }
00272 
00273 /**
00274  * @name Classifier Addition/Modification/Deletion
00275  * @{
00276  */
00277 
00278 /**
00279  * Build a netlink message to add a new classifier
00280  * @arg cls             classifier to add
00281  * @arg flags           additional netlink message flags
00282  *
00283  * Builds a new netlink message requesting an addition of a classifier
00284  * The netlink message header isn't fully equipped with all relevant
00285  * fields and must be sent out via nl_send_auto_complete() or
00286  * supplemented as needed. \a classifier must contain the attributes of
00287  * the new classifier set via \c rtnl_cls_set_* functions. \a opts
00288  * may point to the clsasifier specific options.
00289  *
00290  * @return New netlink message
00291  */
00292 struct nl_msg * rtnl_cls_build_add_request(struct rtnl_cls *cls, int flags)
00293 {
00294         return cls_build(cls, RTM_NEWTFILTER, NLM_F_CREATE | flags);
00295 }
00296 
00297 /**
00298  * Add a new classifier
00299  * @arg handle          netlink handle
00300  * @arg cls             classifier to add
00301  * @arg flags           additional netlink message flags
00302  *
00303  * Builds a netlink message by calling rtnl_cls_build_add_request(),
00304  * sends the request to the kernel and waits for the next ACK to be
00305  * received and thus blocks until the request has been processed.
00306  *
00307  * @return 0 on sucess or a negative error if an error occured.
00308  */
00309 int rtnl_cls_add(struct nl_handle *handle, struct rtnl_cls *cls, int flags)
00310 {
00311         int err;
00312         struct nl_msg *msg;
00313         
00314         msg = rtnl_cls_build_add_request(cls, flags);
00315         if (!msg)
00316                 return nl_errno(ENOMEM);
00317         
00318         err = nl_send_auto_complete(handle, msg);
00319         if (err < 0)
00320                 return err;
00321 
00322         nlmsg_free(msg);
00323         return nl_wait_for_ack(handle);
00324 }
00325 
00326 /**
00327  * Build a netlink message to change classifier attributes
00328  * @arg cls             classifier to change
00329  * @arg flags           additional netlink message flags
00330  *
00331  * Builds a new netlink message requesting a change of a neigh
00332  * attributes. The netlink message header isn't fully equipped with
00333  * all relevant fields and must thus be sent out via nl_send_auto_complete()
00334  * or supplemented as needed.
00335  *
00336  * @return The netlink message
00337  */
00338 struct nl_msg *rtnl_cls_build_change_request(struct rtnl_cls *cls, int flags)
00339 {
00340         return cls_build(cls, RTM_NEWTFILTER, NLM_F_REPLACE | flags);
00341 }
00342 
00343 /**
00344  * Change a classifier
00345  * @arg handle          netlink handle
00346  * @arg cls             classifier to change
00347  * @arg flags           additional netlink message flags
00348  *
00349  * Builds a netlink message by calling rtnl_cls_build_change_request(),
00350  * sends the request to the kernel and waits for the next ACK to be
00351  * received and thus blocks until the request has been processed.
00352  *
00353  * @return 0 on sucess or a negative error if an error occured.
00354  */
00355 int rtnl_cls_change(struct nl_handle *handle, struct rtnl_cls *cls,
00356                     int flags)
00357 {
00358         int err;
00359         struct nl_msg *msg;
00360         
00361         msg = rtnl_cls_build_change_request(cls, flags);
00362         if (!msg)
00363                 return nl_errno(ENOMEM);
00364         
00365         err = nl_send_auto_complete(handle, msg);
00366         if (err < 0)
00367                 return err;
00368 
00369         nlmsg_free(msg);
00370         return nl_wait_for_ack(handle);
00371 }
00372 
00373 /**
00374  * Build a netlink request message to delete a classifier
00375  * @arg cls             classifier to delete
00376  * @arg flags           additional netlink message flags
00377  *
00378  * Builds a new netlink message requesting a deletion of a classifier.
00379  * The netlink message header isn't fully equipped with all relevant
00380  * fields and must thus be sent out via nl_send_auto_complete()
00381  * or supplemented as needed.
00382  *
00383  * @return New netlink message
00384  */
00385 struct nl_msg *rtnl_cls_build_delete_request(struct rtnl_cls *cls, int flags)
00386 {
00387         return cls_build(cls, RTM_DELTFILTER, flags);
00388 }
00389 
00390 
00391 /**
00392  * Delete a classifier
00393  * @arg handle          netlink handle
00394  * @arg cls             classifier to delete
00395  * @arg flags           additional netlink message flags
00396  *
00397  * Builds a netlink message by calling rtnl_cls_build_delete_request(),
00398  * sends the request to the kernel and waits for the next ACK to be
00399  * received and thus blocks until the request has been processed.
00400  *
00401  * @return 0 on sucess or a negative error if an error occured.
00402  */
00403 int rtnl_cls_delete(struct nl_handle *handle, struct rtnl_cls *cls, int flags)
00404 {
00405         int err;
00406         struct nl_msg *msg;
00407         
00408         msg = rtnl_cls_build_delete_request(cls, flags);
00409         if (!msg)
00410                 return nl_errno(ENOMEM);
00411         
00412         err = nl_send_auto_complete(handle, msg);
00413         if (err < 0)
00414                 return err;
00415 
00416         nlmsg_free(msg);
00417         return nl_wait_for_ack(handle);
00418 }
00419 
00420 /** @} */
00421 
00422 /**
00423  * @name General API
00424  * @{
00425  */
00426 
00427 /**
00428  * Allocate a new classifier object
00429  * @return New classifier object
00430  */
00431 struct rtnl_cls *rtnl_cls_alloc(void)
00432 {
00433         return (struct rtnl_cls *) nl_object_alloc_from_ops(&rtnl_cls_ops);
00434 }
00435 
00436 /**
00437  * Give back reference on classifier object.
00438  * @arg cls             Classifier object to be given back.
00439  *
00440  * Decrements the reference counter and frees the object if the
00441  * last reference has been released.
00442  */
00443 void rtnl_cls_put(struct rtnl_cls *cls)
00444 {
00445         nl_object_put((struct nl_object *) cls);
00446 }
00447 
00448 /**
00449  * Free classifier object.
00450  * @arg cls             Classifier object to be freed.
00451  *
00452  * @note Always use rtnl_cls_put() unless you're absolutely sure
00453  *       that no other user may have a reference on this object.
00454  */
00455 void rtnl_cls_free(struct rtnl_cls *cls)
00456 {
00457         nl_object_free((struct nl_object *) cls);
00458 }
00459 
00460 /**
00461  * Build a classifier cache including all classifiers attached to the
00462  * specified class/qdisc on eht specified interface.
00463  * @arg handle          netlink handle
00464  * @arg ifindex         interface index of the link the classes are
00465  *                      attached to.
00466  * @arg parent          parent qdisc/class
00467  *
00468  * Allocates a new cache, initializes it properly and updates it to
00469  * include all classes attached to the specified interface.
00470  *
00471  * @note The caller is responsible for destroying and freeing the
00472  *       cache after using it.
00473  * @return The cache or NULL if an error has occured.
00474  */
00475 struct nl_cache *rtnl_cls_alloc_cache(struct nl_handle *handle,
00476                                       int ifindex, uint32_t parent)
00477 {
00478         struct nl_cache * cache;
00479         
00480         cache = nl_cache_alloc_from_ops(&rtnl_cls_ops);
00481         if (cache == NULL)
00482                 return NULL;
00483 
00484         cache->c_iarg1 = ifindex;
00485         cache->c_iarg2 = parent;
00486         
00487         if (nl_cache_update(handle, cache) < 0) {
00488                 nl_cache_free(cache);
00489                 return NULL;
00490         }
00491 
00492         return cache;
00493 }
00494 
00495 void rtnl_cls_set_ifindex(struct rtnl_cls *f, int ifindex)
00496 {
00497         tca_set_ifindex((struct rtnl_tca *) f, ifindex);
00498 }
00499 
00500 void rtnl_cls_set_handle(struct rtnl_cls *f, uint32_t handle)
00501 {
00502         tca_set_handle((struct rtnl_tca *) f, handle);
00503 }
00504 
00505 void rtnl_cls_set_parent(struct rtnl_cls *f, uint32_t parent)
00506 {
00507         tca_set_parent((struct rtnl_tca *) f, parent);
00508 }
00509 
00510 void rtnl_cls_set_kind(struct rtnl_cls *f, const char *kind)
00511 {
00512         tca_set_kind((struct rtnl_tca *) f, kind);
00513 }
00514 
00515 /**
00516  * Set prioroty of a classifier
00517  * @arg cls             classifier to change
00518  * @arg prio            new priority
00519  */
00520 void rtnl_cls_set_prio(struct rtnl_cls *cls, int prio)
00521 {
00522         cls->c_prio = prio;
00523         cls->c_mask |= CLS_ATTR_PRIO;
00524 }
00525 
00526 /**
00527  * Get priority of a classifier
00528  * @arg cls             classifier
00529  */
00530 int rtnl_cls_get_prio(struct rtnl_cls *cls)
00531 {
00532         if (cls->c_mask & CLS_ATTR_PRIO)
00533                 return cls->c_prio;
00534         else
00535                 return 0;
00536 }
00537 
00538 /**
00539  * Set protocol of a classifier
00540  * @arg cls             classifier to change
00541  * @arg protocol        protocol identifier (ETH_P_xxx) in host byte-order
00542  */
00543 void rtnl_cls_set_protocol(struct rtnl_cls *cls, int protocol)
00544 {
00545         cls->c_protocol = protocol;
00546         cls->c_mask |= CLS_ATTR_PROTOCOL;
00547 }
00548 
00549 /**
00550  * Get protocol of a classifier
00551  * @arg cls             classifier
00552  */
00553 int rtnl_cls_get_protocol(struct rtnl_cls *cls)
00554 {
00555         if (cls->c_mask & CLS_ATTR_PROTOCOL)
00556                 return cls->c_protocol;
00557         else
00558                 return 0;
00559 }
00560 
00561 /** @} */
00562 
00563 static struct nl_cache_ops rtnl_cls_ops = {
00564         .co_name                = "route/cls",
00565         .co_size                = sizeof(struct rtnl_cls),
00566         .co_hdrsize             = sizeof(struct tcmsg),
00567         .co_msgtypes            = {
00568                                         { RTM_NEWTFILTER, "new" },
00569                                         { RTM_DELTFILTER, "delete" },
00570                                         { RTM_GETTFILTER, "get" },
00571                                         { -1, NULL },
00572                                   },
00573         .co_protocol            = NETLINK_ROUTE,
00574         .co_request_update      = cls_request_update,
00575         .co_filter              = cls_filter,
00576         .co_free_data           = cls_free_data,
00577         .co_msg_parser          = cls_msg_parser,
00578         .co_dump[NL_DUMP_BRIEF] = cls_dump_brief,
00579         .co_dump[NL_DUMP_FULL]  = cls_dump_full,
00580         .co_dump[NL_DUMP_STATS] = cls_dump_stats,
00581 };
00582 
00583 static void __init cls_init(void)
00584 {
00585         nl_cache_mngt_register(&rtnl_cls_ops);
00586 }
00587 
00588 static void __exit cls_exit(void)
00589 {
00590         nl_cache_mngt_unregister(&rtnl_cls_ops);
00591 }
00592 
00593 /** @} */

Generated on Fri Apr 27 14:14:07 2007 for libnl by  doxygen 1.5.1