libnl 2.0
|
00001 /* 00002 * lib/route/class.c Queueing Classes 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-2008 Thomas Graf <tgraf@suug.ch> 00010 */ 00011 00012 /** 00013 * @ingroup tc 00014 * @defgroup class Queueing Classes 00015 * @{ 00016 */ 00017 00018 #include <netlink-local.h> 00019 #include <netlink-tc.h> 00020 #include <netlink/netlink.h> 00021 #include <netlink/route/tc.h> 00022 #include <netlink/route/class.h> 00023 #include <netlink/route/class-modules.h> 00024 #include <netlink/route/qdisc.h> 00025 #include <netlink/route/classifier.h> 00026 #include <netlink/utils.h> 00027 00028 static struct nl_cache_ops rtnl_class_ops; 00029 00030 static int class_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, 00031 struct nlmsghdr *n, struct nl_parser_param *pp) 00032 { 00033 int err; 00034 struct rtnl_class *class; 00035 struct rtnl_class_ops *cops; 00036 00037 class = rtnl_class_alloc(); 00038 if (!class) { 00039 err = -NLE_NOMEM; 00040 goto errout; 00041 } 00042 class->ce_msgtype = n->nlmsg_type; 00043 00044 err = tca_msg_parser(n, (struct rtnl_tca *) class); 00045 if (err < 0) 00046 goto errout_free; 00047 00048 cops = rtnl_class_lookup_ops(class); 00049 if (cops && cops->co_msg_parser) { 00050 err = cops->co_msg_parser(class); 00051 if (err < 0) 00052 goto errout_free; 00053 } 00054 00055 err = pp->pp_cb((struct nl_object *) class, pp); 00056 errout_free: 00057 rtnl_class_put(class); 00058 errout: 00059 return err; 00060 } 00061 00062 static int class_request_update(struct nl_cache *cache, struct nl_sock *sk) 00063 { 00064 struct tcmsg tchdr = { 00065 .tcm_family = AF_UNSPEC, 00066 .tcm_ifindex = cache->c_iarg1, 00067 }; 00068 00069 return nl_send_simple(sk, RTM_GETTCLASS, NLM_F_DUMP, &tchdr, 00070 sizeof(tchdr)); 00071 } 00072 00073 /** 00074 * @name Addition/Modification 00075 * @{ 00076 */ 00077 00078 static int class_build(struct rtnl_class *class, int type, int flags, 00079 struct nl_msg **result) 00080 { 00081 struct rtnl_class_ops *cops; 00082 int err; 00083 00084 err = tca_build_msg((struct rtnl_tca *) class, type, flags, result); 00085 if (err < 0) 00086 return err; 00087 00088 cops = rtnl_class_lookup_ops(class); 00089 if (cops && cops->co_get_opts) { 00090 struct nl_msg *opts; 00091 00092 opts = cops->co_get_opts(class); 00093 if (opts) { 00094 err = nla_put_nested(*result, TCA_OPTIONS, opts); 00095 nlmsg_free(opts); 00096 if (err < 0) 00097 goto errout; 00098 } 00099 } 00100 00101 return 0; 00102 errout: 00103 nlmsg_free(*result); 00104 return err; 00105 } 00106 00107 /** 00108 * Build a netlink message to add a new class 00109 * @arg class class to add 00110 * @arg flags additional netlink message flags 00111 * @arg result Pointer to store resulting message. 00112 * 00113 * Builds a new netlink message requesting an addition of a class. 00114 * The netlink message header isn't fully equipped with all relevant 00115 * fields and must be sent out via nl_send_auto_complete() or 00116 * supplemented as needed. 00117 * 00118 * Common message flags 00119 * - NLM_F_REPLACE - replace possibly existing classes 00120 * 00121 * @return 0 on success or a negative error code. 00122 */ 00123 int rtnl_class_build_add_request(struct rtnl_class *class, int flags, 00124 struct nl_msg **result) 00125 { 00126 return class_build(class, RTM_NEWTCLASS, NLM_F_CREATE | flags, result); 00127 } 00128 00129 /** 00130 * Add a new class 00131 * @arg sk Netlink socket. 00132 * @arg class class to delete 00133 * @arg flags additional netlink message flags 00134 * 00135 * Builds a netlink message by calling rtnl_qdisc_build_add_request(), 00136 * sends the request to the kernel and waits for the next ACK to be 00137 * received and thus blocks until the request has been processed. 00138 * 00139 * Common message flags 00140 * - NLM_F_REPLACE - replace possibly existing classes 00141 * 00142 * @return 0 on success or a negative error code 00143 */ 00144 int rtnl_class_add(struct nl_sock *sk, struct rtnl_class *class, int flags) 00145 { 00146 struct nl_msg *msg; 00147 int err; 00148 00149 if ((err = rtnl_class_build_add_request(class, flags, &msg)) < 0) 00150 return err; 00151 00152 err = nl_send_auto_complete(sk, msg); 00153 nlmsg_free(msg); 00154 if (err < 0) 00155 return err; 00156 00157 return wait_for_ack(sk); 00158 } 00159 00160 int rtnl_class_build_delete_request(struct rtnl_class *class, 00161 struct nl_msg **result) 00162 { 00163 struct nl_msg *msg; 00164 struct tcmsg tchdr; 00165 int required = TCA_ATTR_IFINDEX | TCA_ATTR_PARENT; 00166 00167 if ((class->ce_mask & required) != required) 00168 BUG(); 00169 00170 msg = nlmsg_alloc_simple(RTM_DELTCLASS, 0); 00171 if (!msg) 00172 return -NLE_NOMEM; 00173 00174 tchdr.tcm_family = AF_UNSPEC; 00175 tchdr.tcm_handle = class->c_handle; 00176 tchdr.tcm_parent = class->c_parent; 00177 tchdr.tcm_ifindex = class->c_ifindex; 00178 if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0) { 00179 nlmsg_free(msg); 00180 return -NLE_MSGSIZE; 00181 } 00182 00183 *result = msg; 00184 return 0; 00185 } 00186 00187 /** 00188 * Delete a class 00189 * @arg sk Netlink socket. 00190 * @arg class class to delete 00191 * 00192 * Builds a netlink message by calling rtnl_class_build_delete_request(), 00193 * sends the request to the kernel and waits for the ACK to be 00194 * received and thus blocks until the request has been processed. 00195 * 00196 * @return 0 on success or a negative error code 00197 */ 00198 int rtnl_class_delete(struct nl_sock *sk, struct rtnl_class *class) 00199 { 00200 struct nl_msg *msg; 00201 int err; 00202 00203 if ((err = rtnl_class_build_delete_request(class, &msg)) < 0) 00204 return err; 00205 00206 err = nl_send_auto_complete(sk, msg); 00207 nlmsg_free(msg); 00208 if (err < 0) 00209 return err; 00210 00211 return wait_for_ack(sk); 00212 } 00213 00214 /** @} */ 00215 00216 /** 00217 * @name Cache Management 00218 * @{ 00219 */ 00220 00221 /** 00222 * Build a class cache including all classes attached to the specified interface 00223 * @arg sk Netlink socket. 00224 * @arg ifindex interface index of the link the classes are 00225 * attached to. 00226 * 00227 * Allocates a new cache, initializes it properly and updates it to 00228 * include all classes attached to the specified interface. 00229 * 00230 * @return The cache or NULL if an error has occured. 00231 */ 00232 int rtnl_class_alloc_cache(struct nl_sock *sk, int ifindex, 00233 struct nl_cache **result) 00234 { 00235 struct nl_cache * cache; 00236 int err; 00237 00238 cache = nl_cache_alloc(&rtnl_class_ops); 00239 if (!cache) 00240 return -NLE_NOMEM; 00241 00242 cache->c_iarg1 = ifindex; 00243 00244 if (sk && (err = nl_cache_refill(sk, cache)) < 0) { 00245 nl_cache_free(cache); 00246 return err; 00247 } 00248 00249 *result = cache; 00250 return 0; 00251 } 00252 00253 /** 00254 * Look up class by its handle in the provided cache 00255 * @arg cache class cache 00256 * @arg ifindex interface the class is attached to 00257 * @arg handle class handle 00258 * @return pointer to class inside the cache or NULL if no match was found. 00259 */ 00260 struct rtnl_class *rtnl_class_get(struct nl_cache *cache, int ifindex, 00261 uint32_t handle) 00262 { 00263 struct rtnl_class *class; 00264 00265 if (cache->c_ops != &rtnl_class_ops) 00266 return NULL; 00267 00268 nl_list_for_each_entry(class, &cache->c_items, ce_list) { 00269 if (class->c_handle == handle && class->c_ifindex == ifindex) { 00270 nl_object_get((struct nl_object *) class); 00271 return class; 00272 } 00273 } 00274 return NULL; 00275 } 00276 00277 /** @} */ 00278 00279 static struct nl_cache_ops rtnl_class_ops = { 00280 .co_name = "route/class", 00281 .co_hdrsize = sizeof(struct tcmsg), 00282 .co_msgtypes = { 00283 { RTM_NEWTCLASS, NL_ACT_NEW, "new" }, 00284 { RTM_DELTCLASS, NL_ACT_DEL, "del" }, 00285 { RTM_GETTCLASS, NL_ACT_GET, "get" }, 00286 END_OF_MSGTYPES_LIST, 00287 }, 00288 .co_protocol = NETLINK_ROUTE, 00289 .co_request_update = &class_request_update, 00290 .co_msg_parser = &class_msg_parser, 00291 .co_obj_ops = &class_obj_ops, 00292 }; 00293 00294 static void __init class_init(void) 00295 { 00296 nl_cache_mngt_register(&rtnl_class_ops); 00297 } 00298 00299 static void __exit class_exit(void) 00300 { 00301 nl_cache_mngt_unregister(&rtnl_class_ops); 00302 } 00303 00304 /** @} */