libnl 3.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-api.h> 00032 #include <netlink/route/classifier.h> 00033 #include <netlink/route/link.h> 00034 00035 /** @cond SKIP */ 00036 #define CLS_ATTR_PRIO (TCA_ATTR_MAX << 1) 00037 #define CLS_ATTR_PROTOCOL (TCA_ATTR_MAX << 2) 00038 /** @endcond */ 00039 00040 static struct nl_object_ops cls_obj_ops; 00041 static struct nl_cache_ops rtnl_cls_ops; 00042 00043 00044 static int cls_build(struct rtnl_cls *cls, int type, int flags, 00045 struct nl_msg **result) 00046 { 00047 int err, prio, proto; 00048 struct tcmsg *tchdr; 00049 00050 err = rtnl_tc_msg_build(TC_CAST(cls), type, flags, result); 00051 if (err < 0) 00052 return err; 00053 00054 tchdr = nlmsg_data(nlmsg_hdr(*result)); 00055 prio = rtnl_cls_get_prio(cls); 00056 proto = rtnl_cls_get_protocol(cls); 00057 tchdr->tcm_info = TC_H_MAKE(prio << 16, htons(proto)); 00058 00059 return 0; 00060 } 00061 00062 /** 00063 * @name Allocation/Freeing 00064 * @{ 00065 */ 00066 00067 struct rtnl_cls *rtnl_cls_alloc(void) 00068 { 00069 struct rtnl_tc *tc; 00070 00071 tc = TC_CAST(nl_object_alloc(&cls_obj_ops)); 00072 if (tc) 00073 tc->tc_type = RTNL_TC_TYPE_CLS; 00074 00075 return (struct rtnl_cls *) tc; 00076 } 00077 00078 void rtnl_cls_put(struct rtnl_cls *cls) 00079 { 00080 nl_object_put((struct nl_object *) cls); 00081 } 00082 00083 /** @} */ 00084 00085 /** 00086 * @name Attributes 00087 * @{ 00088 */ 00089 00090 void rtnl_cls_set_prio(struct rtnl_cls *cls, uint16_t prio) 00091 { 00092 cls->c_prio = prio; 00093 cls->ce_mask |= CLS_ATTR_PRIO; 00094 } 00095 00096 uint16_t rtnl_cls_get_prio(struct rtnl_cls *cls) 00097 { 00098 if (cls->ce_mask & CLS_ATTR_PRIO) 00099 return cls->c_prio; 00100 else 00101 return 0; 00102 } 00103 00104 void rtnl_cls_set_protocol(struct rtnl_cls *cls, uint16_t protocol) 00105 { 00106 cls->c_protocol = protocol; 00107 cls->ce_mask |= CLS_ATTR_PROTOCOL; 00108 } 00109 00110 uint16_t rtnl_cls_get_protocol(struct rtnl_cls *cls) 00111 { 00112 if (cls->ce_mask & CLS_ATTR_PROTOCOL) 00113 return cls->c_protocol; 00114 else 00115 return ETH_P_ALL; 00116 } 00117 00118 /** @} */ 00119 00120 00121 /** 00122 * @name Classifier Addition/Modification/Deletion 00123 * @{ 00124 */ 00125 00126 /** 00127 * Build a netlink message to add a new classifier 00128 * @arg cls classifier to add 00129 * @arg flags additional netlink message flags 00130 * @arg result Pointer to store resulting message. 00131 * 00132 * Builds a new netlink message requesting an addition of a classifier 00133 * The netlink message header isn't fully equipped with all relevant 00134 * fields and must be sent out via nl_send_auto_complete() or 00135 * supplemented as needed. \a classifier must contain the attributes of 00136 * the new classifier set via \c rtnl_cls_set_* functions. \a opts 00137 * may point to the clsasifier specific options. 00138 * 00139 * @return 0 on success or a negative error code. 00140 */ 00141 int rtnl_cls_build_add_request(struct rtnl_cls *cls, int flags, 00142 struct nl_msg **result) 00143 { 00144 return cls_build(cls, RTM_NEWTFILTER, NLM_F_CREATE | flags, result); 00145 } 00146 00147 /** 00148 * Add a new classifier 00149 * @arg sk Netlink socket. 00150 * @arg cls classifier to add 00151 * @arg flags additional netlink message flags 00152 * 00153 * Builds a netlink message by calling rtnl_cls_build_add_request(), 00154 * sends the request to the kernel and waits for the next ACK to be 00155 * received and thus blocks until the request has been processed. 00156 * 00157 * @return 0 on sucess or a negative error if an error occured. 00158 */ 00159 int rtnl_cls_add(struct nl_sock *sk, struct rtnl_cls *cls, int flags) 00160 { 00161 struct nl_msg *msg; 00162 int err; 00163 00164 if ((err = rtnl_cls_build_add_request(cls, flags, &msg)) < 0) 00165 return err; 00166 00167 err = nl_send_auto_complete(sk, msg); 00168 nlmsg_free(msg); 00169 if (err < 0) 00170 return err; 00171 00172 return nl_wait_for_ack(sk); 00173 } 00174 00175 /** 00176 * Build a netlink message to change classifier attributes 00177 * @arg cls classifier to change 00178 * @arg flags additional netlink message flags 00179 * @arg result Pointer to store resulting message. 00180 * 00181 * Builds a new netlink message requesting a change of a neigh 00182 * attributes. The netlink message header isn't fully equipped with 00183 * all relevant fields and must thus be sent out via nl_send_auto_complete() 00184 * or supplemented as needed. 00185 * 00186 * @return 0 on success or a negative error code. 00187 */ 00188 int rtnl_cls_build_change_request(struct rtnl_cls *cls, int flags, 00189 struct nl_msg **result) 00190 { 00191 return cls_build(cls, RTM_NEWTFILTER, NLM_F_REPLACE | flags, result); 00192 } 00193 00194 /** 00195 * Change a classifier 00196 * @arg sk Netlink socket. 00197 * @arg cls classifier to change 00198 * @arg flags additional netlink message flags 00199 * 00200 * Builds a netlink message by calling rtnl_cls_build_change_request(), 00201 * sends the request to the kernel and waits for the next ACK to be 00202 * received and thus blocks until the request has been processed. 00203 * 00204 * @return 0 on sucess or a negative error if an error occured. 00205 */ 00206 int rtnl_cls_change(struct nl_sock *sk, struct rtnl_cls *cls, int flags) 00207 { 00208 struct nl_msg *msg; 00209 int err; 00210 00211 if ((err = rtnl_cls_build_change_request(cls, flags, &msg)) < 0) 00212 return err; 00213 00214 err = nl_send_auto_complete(sk, msg); 00215 nlmsg_free(msg); 00216 if (err < 0) 00217 return err; 00218 00219 return nl_wait_for_ack(sk); 00220 } 00221 00222 /** 00223 * Build a netlink request message to delete a classifier 00224 * @arg cls classifier to delete 00225 * @arg flags additional netlink message flags 00226 * @arg result Pointer to store resulting message. 00227 * 00228 * Builds a new netlink message requesting a deletion of a classifier. 00229 * The netlink message header isn't fully equipped with all relevant 00230 * fields and must thus be sent out via nl_send_auto_complete() 00231 * or supplemented as needed. 00232 * 00233 * @return 0 on success or a negative error code. 00234 */ 00235 int rtnl_cls_build_delete_request(struct rtnl_cls *cls, int flags, 00236 struct nl_msg **result) 00237 { 00238 return cls_build(cls, RTM_DELTFILTER, flags, result); 00239 } 00240 00241 00242 /** 00243 * Delete a classifier 00244 * @arg sk Netlink socket. 00245 * @arg cls classifier to delete 00246 * @arg flags additional netlink message flags 00247 * 00248 * Builds a netlink message by calling rtnl_cls_build_delete_request(), 00249 * sends the request to the kernel and waits for the next ACK to be 00250 * received and thus blocks until the request has been processed. 00251 * 00252 * @return 0 on sucess or a negative error if an error occured. 00253 */ 00254 int rtnl_cls_delete(struct nl_sock *sk, struct rtnl_cls *cls, int flags) 00255 { 00256 struct nl_msg *msg; 00257 int err; 00258 00259 if ((err = rtnl_cls_build_delete_request(cls, flags, &msg)) < 0) 00260 return err; 00261 00262 err = nl_send_auto_complete(sk, msg); 00263 nlmsg_free(msg); 00264 if (err < 0) 00265 return err; 00266 00267 return nl_wait_for_ack(sk); 00268 } 00269 00270 /** @} */ 00271 00272 /** 00273 * @name Cache Management 00274 * @{ 00275 */ 00276 00277 /** 00278 * Build a classifier cache including all classifiers attached to the 00279 * specified class/qdisc on eht specified interface. 00280 * @arg sk Netlink socket. 00281 * @arg ifindex interface index of the link the classes are 00282 * attached to. 00283 * @arg parent parent qdisc/class 00284 * @arg result Pointer to store resulting cache. 00285 * 00286 * Allocates a new cache, initializes it properly and updates it to 00287 * include all classes attached to the specified interface. 00288 * 00289 * @note The caller is responsible for destroying and freeing the 00290 * cache after using it. 00291 * @return 0 on success or a negative error code. 00292 */ 00293 int rtnl_cls_alloc_cache(struct nl_sock *sk, int ifindex, uint32_t parent, struct nl_cache **result) 00294 { 00295 struct nl_cache * cache; 00296 int err; 00297 00298 if (!(cache = nl_cache_alloc(&rtnl_cls_ops))) 00299 return -NLE_NOMEM; 00300 00301 cache->c_iarg1 = ifindex; 00302 cache->c_iarg2 = parent; 00303 00304 if (sk && (err = nl_cache_refill(sk, cache)) < 0) { 00305 nl_cache_free(cache); 00306 return err; 00307 } 00308 00309 *result = cache; 00310 return 0; 00311 } 00312 00313 /** @} */ 00314 00315 static void cls_dump_line(struct rtnl_tc *tc, struct nl_dump_params *p) 00316 { 00317 struct rtnl_cls *cls = (struct rtnl_cls *) tc; 00318 char buf[32]; 00319 00320 nl_dump(p, " prio %u protocol %s", cls->c_prio, 00321 nl_ether_proto2str(cls->c_protocol, buf, sizeof(buf))); 00322 } 00323 00324 static int cls_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, 00325 struct nlmsghdr *nlh, struct nl_parser_param *pp) 00326 { 00327 struct rtnl_cls *cls; 00328 int err; 00329 00330 if (!(cls = rtnl_cls_alloc())) 00331 return -NLE_NOMEM; 00332 00333 if ((err = rtnl_tc_msg_parse(nlh, TC_CAST(cls))) < 0) 00334 goto errout; 00335 00336 cls->c_prio = TC_H_MAJ(cls->c_info) >> 16; 00337 cls->c_protocol = ntohs(TC_H_MIN(cls->c_info)); 00338 00339 err = pp->pp_cb(OBJ_CAST(cls), pp); 00340 errout: 00341 rtnl_cls_put(cls); 00342 00343 return err; 00344 } 00345 00346 static int cls_request_update(struct nl_cache *cache, struct nl_sock *sk) 00347 { 00348 struct tcmsg tchdr = { 00349 .tcm_family = AF_UNSPEC, 00350 .tcm_ifindex = cache->c_iarg1, 00351 .tcm_parent = cache->c_iarg2, 00352 }; 00353 00354 return nl_send_simple(sk, RTM_GETTFILTER, NLM_F_DUMP, &tchdr, 00355 sizeof(tchdr)); 00356 } 00357 00358 static struct rtnl_tc_type_ops cls_ops = { 00359 .tt_type = RTNL_TC_TYPE_CLS, 00360 .tt_dump_prefix = "cls", 00361 .tt_dump = { 00362 [NL_DUMP_LINE] = cls_dump_line, 00363 }, 00364 }; 00365 00366 static struct nl_cache_ops rtnl_cls_ops = { 00367 .co_name = "route/cls", 00368 .co_hdrsize = sizeof(struct tcmsg), 00369 .co_msgtypes = { 00370 { RTM_NEWTFILTER, NL_ACT_NEW, "new" }, 00371 { RTM_DELTFILTER, NL_ACT_DEL, "del" }, 00372 { RTM_GETTFILTER, NL_ACT_GET, "get" }, 00373 END_OF_MSGTYPES_LIST, 00374 }, 00375 .co_protocol = NETLINK_ROUTE, 00376 .co_request_update = cls_request_update, 00377 .co_msg_parser = cls_msg_parser, 00378 .co_obj_ops = &cls_obj_ops, 00379 }; 00380 00381 static struct nl_object_ops cls_obj_ops = { 00382 .oo_name = "route/cls", 00383 .oo_size = sizeof(struct rtnl_cls), 00384 .oo_free_data = rtnl_tc_free_data, 00385 .oo_clone = rtnl_tc_clone, 00386 .oo_dump = { 00387 [NL_DUMP_LINE] = rtnl_tc_dump_line, 00388 [NL_DUMP_DETAILS] = rtnl_tc_dump_details, 00389 [NL_DUMP_STATS] = rtnl_tc_dump_stats, 00390 }, 00391 .oo_compare = rtnl_tc_compare, 00392 .oo_id_attrs = (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE), 00393 }; 00394 00395 static void __init cls_init(void) 00396 { 00397 rtnl_tc_type_register(&cls_ops); 00398 nl_cache_mngt_register(&rtnl_cls_ops); 00399 } 00400 00401 static void __exit cls_exit(void) 00402 { 00403 nl_cache_mngt_unregister(&rtnl_cls_ops); 00404 rtnl_tc_type_unregister(&cls_ops); 00405 } 00406 00407 /** @} */