libnl 1.1
|
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 /** @} */