libnl  3.2.3
/build/buildd/libnl3-3.2.3/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-2011 Thomas Graf <tgraf@suug.ch>
00010  */
00011 
00012 /**
00013  * @ingroup tc
00014  * @defgroup cls Classifiers
00015  * @{
00016  */
00017 
00018 #include <netlink-local.h>
00019 #include <netlink-tc.h>
00020 #include <netlink/netlink.h>
00021 #include <netlink/utils.h>
00022 #include <netlink/route/tc-api.h>
00023 #include <netlink/route/classifier.h>
00024 #include <netlink/route/link.h>
00025 
00026 /** @cond SKIP */
00027 #define CLS_ATTR_PRIO           (TCA_ATTR_MAX << 1)
00028 #define CLS_ATTR_PROTOCOL       (TCA_ATTR_MAX << 2)
00029 /** @endcond */
00030 
00031 static struct nl_object_ops cls_obj_ops;
00032 static struct nl_cache_ops rtnl_cls_ops;
00033 
00034 
00035 static int cls_build(struct rtnl_cls *cls, int type, int flags,
00036                      struct nl_msg **result)
00037 {
00038         int err, prio, proto;
00039         struct tcmsg *tchdr;
00040         int required = TCA_ATTR_IFINDEX;
00041 
00042         if ((cls->ce_mask & required) != required) {
00043                 APPBUG("ifindex must be specified");
00044                 return -NLE_MISSING_ATTR;
00045         }
00046 
00047         err = rtnl_tc_msg_build(TC_CAST(cls), type, flags, result);
00048         if (err < 0)
00049                 return err;
00050 
00051         tchdr = nlmsg_data(nlmsg_hdr(*result));
00052         prio = rtnl_cls_get_prio(cls);
00053         proto = rtnl_cls_get_protocol(cls);
00054         tchdr->tcm_info = TC_H_MAKE(prio << 16, htons(proto));
00055 
00056         return 0;
00057 }
00058 
00059 /**
00060  * @name Allocation/Freeing
00061  * @{
00062  */
00063 
00064 struct rtnl_cls *rtnl_cls_alloc(void)
00065 {
00066         struct rtnl_tc *tc;
00067 
00068         tc = TC_CAST(nl_object_alloc(&cls_obj_ops));
00069         if (tc)
00070                 tc->tc_type = RTNL_TC_TYPE_CLS;
00071 
00072         return (struct rtnl_cls *) tc;
00073 }
00074 
00075 void rtnl_cls_put(struct rtnl_cls *cls)
00076 {
00077         nl_object_put((struct nl_object *) cls);
00078 }
00079 
00080 /** @} */
00081 
00082 /**
00083  * @name Attributes
00084  * @{
00085  */
00086 
00087 void rtnl_cls_set_prio(struct rtnl_cls *cls, uint16_t prio)
00088 {
00089         cls->c_prio = prio;
00090         cls->ce_mask |= CLS_ATTR_PRIO;
00091 }
00092 
00093 uint16_t rtnl_cls_get_prio(struct rtnl_cls *cls)
00094 {
00095         if (cls->ce_mask & CLS_ATTR_PRIO)
00096                 return cls->c_prio;
00097         else
00098                 return 0;
00099 }
00100 
00101 void rtnl_cls_set_protocol(struct rtnl_cls *cls, uint16_t protocol)
00102 {
00103         cls->c_protocol = protocol;
00104         cls->ce_mask |= CLS_ATTR_PROTOCOL;
00105 }
00106 
00107 uint16_t rtnl_cls_get_protocol(struct rtnl_cls *cls)
00108 {
00109         if (cls->ce_mask & CLS_ATTR_PROTOCOL)
00110                 return cls->c_protocol;
00111         else
00112                 return ETH_P_ALL;
00113 }
00114 
00115 /** @} */
00116 
00117 
00118 /**
00119  * @name Addition/Modification/Deletion
00120  * @{
00121  */
00122 
00123 /**
00124  * Build a netlink message requesting the addition of a classifier
00125  * @arg cls             Classifier to add 
00126  * @arg flags           Additional netlink message flags
00127  * @arg result          Pointer to store resulting netlink message
00128  *
00129  * The behaviour of this function is identical to rtnl_cls_add() with
00130  * the exception that it will not send the message but return it int the
00131  * provided return pointer instead.
00132  *
00133  * @see rtnl_cls_add()
00134  *
00135  * @return 0 on success or a negative error code.
00136  */
00137 int rtnl_cls_build_add_request(struct rtnl_cls *cls, int flags,
00138                                struct nl_msg **result)
00139 {
00140         if (!(flags & NLM_F_CREATE) && !(cls->ce_mask & CLS_ATTR_PRIO)) {
00141                 APPBUG("prio must be specified if not a new classifier");
00142                 return -NLE_MISSING_ATTR;
00143         }
00144 
00145         return cls_build(cls, RTM_NEWTFILTER, flags, result);
00146 }
00147 
00148 /**
00149  * Add/Update classifier
00150  * @arg sk              Netlink socket
00151  * @arg cls             Classifier to add/update
00152  * @arg flags           Additional netlink message flags
00153  *
00154  * Builds a \c RTM_NEWTFILTER netlink message requesting the addition
00155  * of a new classifier and sends the message to the kernel. The
00156  * configuration of the classifier is derived from the attributes of
00157  * the specified traffic class.
00158  *
00159  * The following flags may be specified:
00160  *  - \c NLM_F_CREATE:  Create classifier if it does not exist,
00161  *                      otherwise -NLE_OBJ_NOTFOUND is returned.
00162  *  - \c NLM_F_EXCL:    Return -NLE_EXISTS if a classifier with
00163  *                      matching handle exists already.
00164  *
00165  * Existing classifiers with matching handles will be updated, unless
00166  * the flag \c NLM_F_EXCL is specified. If no matching classifier
00167  * exists, it will be created if the flag \c NLM_F_CREATE is set,
00168  * otherwise the error -NLE_OBJ_NOTFOUND is returned. 
00169  *
00170  * If the parent qdisc does not support classes, the error
00171  * \c NLE_OPNOTSUPP is returned.
00172  *
00173  * After sending, the function will wait for the ACK or an eventual
00174  * error message to be received and will therefore block until the
00175  * operation has been completed.
00176  *
00177  * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
00178  *       this function to return immediately after sending. In this case,
00179  *       it is the responsibility of the caller to handle any error
00180  *       messages returned.
00181  *
00182  * @return 0 on success or a negative error code.
00183  */
00184 int rtnl_cls_add(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
00185 {
00186         struct nl_msg *msg;
00187         int err;
00188         
00189         if ((err = rtnl_cls_build_add_request(cls, flags, &msg)) < 0)
00190                 return err;
00191 
00192         return nl_send_sync(sk, msg);
00193 }
00194 
00195 /**
00196  * Build a netlink message to change classifier attributes
00197  * @arg cls             classifier to change
00198  * @arg flags           additional netlink message flags
00199  * @arg result          Pointer to store resulting message.
00200  *
00201  * Builds a new netlink message requesting a change of a neigh
00202  * attributes. The netlink message header isn't fully equipped with
00203  * all relevant fields and must thus be sent out via nl_send_auto_complete()
00204  * or supplemented as needed.
00205  *
00206  * @return 0 on success or a negative error code.
00207  */
00208 int rtnl_cls_build_change_request(struct rtnl_cls *cls, int flags,
00209                                   struct nl_msg **result)
00210 {
00211         return cls_build(cls, RTM_NEWTFILTER, NLM_F_REPLACE | flags, result);
00212 }
00213 
00214 /**
00215  * Change a classifier
00216  * @arg sk              Netlink socket.
00217  * @arg cls             classifier to change
00218  * @arg flags           additional netlink message flags
00219  *
00220  * Builds a netlink message by calling rtnl_cls_build_change_request(),
00221  * sends the request to the kernel and waits for the next ACK to be
00222  * received and thus blocks until the request has been processed.
00223  *
00224  * @return 0 on sucess or a negative error if an error occured.
00225  */
00226 int rtnl_cls_change(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
00227 {
00228         struct nl_msg *msg;
00229         int err;
00230         
00231         if ((err = rtnl_cls_build_change_request(cls, flags, &msg)) < 0)
00232                 return err;
00233         
00234         return nl_send_sync(sk, msg);
00235 }
00236 
00237 /**
00238  * Build netlink message requesting the deletion of a classifier
00239  * @arg cls             Classifier to delete
00240  * @arg flags           Additional netlink message flags
00241  * @arg result          Pointer to store resulting netlink message
00242  *
00243  * The behaviour of this function is identical to rtnl_cls_delete() with
00244  * the exception that it will not send the message but return it in the
00245  * provided return pointer instead.
00246  *
00247  * @see rtnl_cls_delete()
00248  *
00249  * @return 0 on success or a negative error code.
00250  */
00251 int rtnl_cls_build_delete_request(struct rtnl_cls *cls, int flags,
00252                                   struct nl_msg **result)
00253 {
00254         int required = CLS_ATTR_PRIO;
00255 
00256         if ((cls->ce_mask & required) != required) {
00257                 APPBUG("prio must be specified");
00258                 return -NLE_MISSING_ATTR;
00259         }
00260 
00261         return cls_build(cls, RTM_DELTFILTER, flags, result);
00262 }
00263 
00264 /**
00265  * Delete classifier
00266  * @arg sk              Netlink socket
00267  * @arg cls             Classifier to delete
00268  * @arg flags           Additional netlink message flags
00269  *
00270  * Builds a \c RTM_DELTFILTER netlink message requesting the deletion
00271  * of a classifier and sends the message to the kernel.
00272  *
00273  * The message is constructed out of the following attributes:
00274  * - \c ifindex (required)
00275  * - \c prio (required)
00276  * - \c protocol (required)
00277  * - \c handle (required)
00278  * - \c parent (optional, if not specified parent equals root-qdisc)
00279  * - \c kind (optional, must match if provided)
00280  *
00281  * All other classifier attributes including all class type specific
00282  * attributes are ignored.
00283  *
00284  * After sending, the function will wait for the ACK or an eventual
00285  * error message to be received and will therefore block until the
00286  * operation has been completed.
00287  *
00288  * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
00289  *       this function to return immediately after sending. In this case,
00290  *       it is the responsibility of the caller to handle any error
00291  *       messages returned.
00292  *
00293  * @return 0 on success or a negative error code.
00294  */
00295 int rtnl_cls_delete(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
00296 {
00297         struct nl_msg *msg;
00298         int err;
00299         
00300         if ((err = rtnl_cls_build_delete_request(cls, flags, &msg)) < 0)
00301                 return err;
00302         
00303         return nl_send_sync(sk, msg);
00304 }
00305 
00306 /** @} */
00307 
00308 /**
00309  * @name Cache Related Functions
00310  * @{
00311  */
00312 
00313 /**
00314  * Allocate a cache and fill it with all configured classifiers
00315  * @arg sk              Netlink socket
00316  * @arg ifindex         Interface index of the network device
00317  * @arg parent          Parent qdisc/traffic class class
00318  * @arg result          Pointer to store the created cache
00319  *
00320  * Allocates a new classifier cache and fills it with a list of all
00321  * configured classifier attached to the specified parent qdisc/traffic
00322  * class on the specified network device. Release the cache with
00323  * nl_cache_free().
00324  *
00325  * @return 0 on success or a negative error code.
00326  */
00327 int rtnl_cls_alloc_cache(struct nl_sock *sk, int ifindex, uint32_t parent,                       struct nl_cache **result)
00328 {
00329         struct nl_cache * cache;
00330         int err;
00331         
00332         if (!(cache = nl_cache_alloc(&rtnl_cls_ops)))
00333                 return -NLE_NOMEM;
00334 
00335         cache->c_iarg1 = ifindex;
00336         cache->c_iarg2 = parent;
00337         
00338         if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
00339                 nl_cache_free(cache);
00340                 return err;
00341         }
00342 
00343         *result = cache;
00344         return 0;
00345 }
00346 
00347 /** @} */
00348 
00349 static void cls_dump_line(struct rtnl_tc *tc, struct nl_dump_params *p)
00350 {
00351         struct rtnl_cls *cls = (struct rtnl_cls *) tc;
00352         char buf[32];
00353 
00354         nl_dump(p, " prio %u protocol %s", cls->c_prio,
00355                 nl_ether_proto2str(cls->c_protocol, buf, sizeof(buf)));
00356 }
00357 
00358 static int cls_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
00359                           struct nlmsghdr *nlh, struct nl_parser_param *pp)
00360 {
00361         struct rtnl_cls *cls;
00362         int err;
00363 
00364         if (!(cls = rtnl_cls_alloc()))
00365                 return -NLE_NOMEM;
00366 
00367         if ((err = rtnl_tc_msg_parse(nlh, TC_CAST(cls))) < 0)
00368                 goto errout;
00369 
00370         cls->c_prio = TC_H_MAJ(cls->c_info) >> 16;
00371         cls->c_protocol = ntohs(TC_H_MIN(cls->c_info));
00372 
00373         err = pp->pp_cb(OBJ_CAST(cls), pp);
00374 errout:
00375         rtnl_cls_put(cls);
00376 
00377         return err;
00378 }
00379 
00380 static int cls_request_update(struct nl_cache *cache, struct nl_sock *sk)
00381 {
00382         struct tcmsg tchdr = {
00383                 .tcm_family = AF_UNSPEC,
00384                 .tcm_ifindex = cache->c_iarg1,
00385                 .tcm_parent = cache->c_iarg2,
00386         };
00387 
00388         return nl_send_simple(sk, RTM_GETTFILTER, NLM_F_DUMP, &tchdr,
00389                               sizeof(tchdr));
00390 }
00391 
00392 static struct rtnl_tc_type_ops cls_ops = {
00393         .tt_type                = RTNL_TC_TYPE_CLS,
00394         .tt_dump_prefix         = "cls",
00395         .tt_dump = {
00396                 [NL_DUMP_LINE]  = cls_dump_line,
00397         },
00398 };
00399 
00400 static struct nl_cache_ops rtnl_cls_ops = {
00401         .co_name                = "route/cls",
00402         .co_hdrsize             = sizeof(struct tcmsg),
00403         .co_msgtypes            = {
00404                                         { RTM_NEWTFILTER, NL_ACT_NEW, "new" },
00405                                         { RTM_DELTFILTER, NL_ACT_DEL, "del" },
00406                                         { RTM_GETTFILTER, NL_ACT_GET, "get" },
00407                                         END_OF_MSGTYPES_LIST,
00408                                   },
00409         .co_protocol            = NETLINK_ROUTE,
00410         .co_request_update      = cls_request_update,
00411         .co_msg_parser          = cls_msg_parser,
00412         .co_obj_ops             = &cls_obj_ops,
00413 };
00414 
00415 static struct nl_object_ops cls_obj_ops = {
00416         .oo_name                = "route/cls",
00417         .oo_size                = sizeof(struct rtnl_cls),
00418         .oo_free_data           = rtnl_tc_free_data,
00419         .oo_clone               = rtnl_tc_clone,
00420         .oo_dump = {
00421             [NL_DUMP_LINE]      = rtnl_tc_dump_line,
00422             [NL_DUMP_DETAILS]   = rtnl_tc_dump_details,
00423             [NL_DUMP_STATS]     = rtnl_tc_dump_stats,
00424         },
00425         .oo_compare             = rtnl_tc_compare,
00426         .oo_id_attrs            = (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE),
00427 };
00428 
00429 static void __init cls_init(void)
00430 {
00431         rtnl_tc_type_register(&cls_ops);
00432         nl_cache_mngt_register(&rtnl_cls_ops);
00433 }
00434 
00435 static void __exit cls_exit(void)
00436 {
00437         nl_cache_mngt_unregister(&rtnl_cls_ops);
00438         rtnl_tc_type_unregister(&cls_ops);
00439 }
00440 
00441 /** @} */