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