1/* 2 * lib/route/class.c Queueing Classes 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation version 2.1 7 * of the License. 8 * 9 * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> 10 */ 11 12/** 13 * @ingroup tc 14 * @defgroup class Queueing Classes 15 * @{ 16 */ 17 18#include <netlink-local.h> 19#include <netlink-tc.h> 20#include <netlink/netlink.h> 21#include <netlink/route/tc.h> 22#include <netlink/route/class.h> 23#include <netlink/route/class-modules.h> 24#include <netlink/route/qdisc.h> 25#include <netlink/route/classifier.h> 26#include <netlink/utils.h> 27 28static struct nl_cache_ops rtnl_class_ops; 29 30static int class_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, 31 struct nlmsghdr *n, struct nl_parser_param *pp) 32{ 33 int err; 34 struct rtnl_class *class; 35 struct rtnl_class_ops *cops; 36 37 class = rtnl_class_alloc(); 38 if (!class) { 39 err = -NLE_NOMEM; 40 goto errout; 41 } 42 class->ce_msgtype = n->nlmsg_type; 43 44 err = tca_msg_parser(n, (struct rtnl_tca *) class); 45 if (err < 0) 46 goto errout_free; 47 48 cops = rtnl_class_lookup_ops(class); 49 if (cops && cops->co_msg_parser) { 50 err = cops->co_msg_parser(class); 51 if (err < 0) 52 goto errout_free; 53 } 54 55 err = pp->pp_cb((struct nl_object *) class, pp); 56errout_free: 57 rtnl_class_put(class); 58errout: 59 return err; 60} 61 62static int class_request_update(struct nl_cache *cache, struct nl_sock *sk) 63{ 64 struct tcmsg tchdr = { 65 .tcm_family = AF_UNSPEC, 66 .tcm_ifindex = cache->c_iarg1, 67 }; 68 69 return nl_send_simple(sk, RTM_GETTCLASS, NLM_F_DUMP, &tchdr, 70 sizeof(tchdr)); 71} 72 73/** 74 * @name Addition/Modification 75 * @{ 76 */ 77 78static int class_build(struct rtnl_class *class, int type, int flags, 79 struct nl_msg **result) 80{ 81 struct rtnl_class_ops *cops; 82 int err; 83 84 err = tca_build_msg((struct rtnl_tca *) class, type, flags, result); 85 if (err < 0) 86 return err; 87 88 cops = rtnl_class_lookup_ops(class); 89 if (cops && cops->co_get_opts) { 90 struct nl_msg *opts; 91 92 opts = cops->co_get_opts(class); 93 if (opts) { 94 err = nla_put_nested(*result, TCA_OPTIONS, opts); 95 nlmsg_free(opts); 96 if (err < 0) 97 goto errout; 98 } 99 } 100 101 return 0; 102errout: 103 nlmsg_free(*result); 104 return err; 105} 106 107/** 108 * Build a netlink message to add a new class 109 * @arg class class to add 110 * @arg flags additional netlink message flags 111 * @arg result Pointer to store resulting message. 112 * 113 * Builds a new netlink message requesting an addition of a class. 114 * The netlink message header isn't fully equipped with all relevant 115 * fields and must be sent out via nl_send_auto_complete() or 116 * supplemented as needed. 117 * 118 * Common message flags 119 * - NLM_F_REPLACE - replace possibly existing classes 120 * 121 * @return 0 on success or a negative error code. 122 */ 123int rtnl_class_build_add_request(struct rtnl_class *class, int flags, 124 struct nl_msg **result) 125{ 126 return class_build(class, RTM_NEWTCLASS, NLM_F_CREATE | flags, result); 127} 128 129/** 130 * Add a new class 131 * @arg sk Netlink socket. 132 * @arg class class to delete 133 * @arg flags additional netlink message flags 134 * 135 * Builds a netlink message by calling rtnl_qdisc_build_add_request(), 136 * sends the request to the kernel and waits for the next ACK to be 137 * received and thus blocks until the request has been processed. 138 * 139 * Common message flags 140 * - NLM_F_REPLACE - replace possibly existing classes 141 * 142 * @return 0 on success or a negative error code 143 */ 144int rtnl_class_add(struct nl_sock *sk, struct rtnl_class *class, int flags) 145{ 146 struct nl_msg *msg; 147 int err; 148 149 if ((err = rtnl_class_build_add_request(class, flags, &msg)) < 0) 150 return err; 151 152 err = nl_send_auto_complete(sk, msg); 153 nlmsg_free(msg); 154 if (err < 0) 155 return err; 156 157 return wait_for_ack(sk); 158} 159 160int rtnl_class_build_delete_request(struct rtnl_class *class, 161 struct nl_msg **result) 162{ 163 struct nl_msg *msg; 164 struct tcmsg tchdr; 165 int required = TCA_ATTR_IFINDEX | TCA_ATTR_PARENT; 166 167 if ((class->ce_mask & required) != required) 168 BUG(); 169 170 msg = nlmsg_alloc_simple(RTM_DELTCLASS, 0); 171 if (!msg) 172 return -NLE_NOMEM; 173 174 tchdr.tcm_family = AF_UNSPEC; 175 tchdr.tcm_handle = class->c_handle; 176 tchdr.tcm_parent = class->c_parent; 177 tchdr.tcm_ifindex = class->c_ifindex; 178 if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0) { 179 nlmsg_free(msg); 180 return -NLE_MSGSIZE; 181 } 182 183 *result = msg; 184 return 0; 185} 186 187/** 188 * Delete a class 189 * @arg sk Netlink socket. 190 * @arg class class to delete 191 * 192 * Builds a netlink message by calling rtnl_class_build_delete_request(), 193 * sends the request to the kernel and waits for the ACK to be 194 * received and thus blocks until the request has been processed. 195 * 196 * @return 0 on success or a negative error code 197 */ 198int rtnl_class_delete(struct nl_sock *sk, struct rtnl_class *class) 199{ 200 struct nl_msg *msg; 201 int err; 202 203 if ((err = rtnl_class_build_delete_request(class, &msg)) < 0) 204 return err; 205 206 err = nl_send_auto_complete(sk, msg); 207 nlmsg_free(msg); 208 if (err < 0) 209 return err; 210 211 return wait_for_ack(sk); 212} 213 214/** @} */ 215 216/** 217 * @name Cache Management 218 * @{ 219 */ 220 221/** 222 * Build a class cache including all classes attached to the specified interface 223 * @arg sk Netlink socket. 224 * @arg ifindex interface index of the link the classes are 225 * attached to. 226 * 227 * Allocates a new cache, initializes it properly and updates it to 228 * include all classes attached to the specified interface. 229 * 230 * @return The cache or NULL if an error has occured. 231 */ 232int rtnl_class_alloc_cache(struct nl_sock *sk, int ifindex, 233 struct nl_cache **result) 234{ 235 struct nl_cache * cache; 236 int err; 237 238 cache = nl_cache_alloc(&rtnl_class_ops); 239 if (!cache) 240 return -NLE_NOMEM; 241 242 cache->c_iarg1 = ifindex; 243 244 if (sk && (err = nl_cache_refill(sk, cache)) < 0) { 245 nl_cache_free(cache); 246 return err; 247 } 248 249 *result = cache; 250 return 0; 251} 252 253/** 254 * Look up class by its handle in the provided cache 255 * @arg cache class cache 256 * @arg ifindex interface the class is attached to 257 * @arg handle class handle 258 * @return pointer to class inside the cache or NULL if no match was found. 259 */ 260struct rtnl_class *rtnl_class_get(struct nl_cache *cache, int ifindex, 261 uint32_t handle) 262{ 263 struct rtnl_class *class; 264 265 if (cache->c_ops != &rtnl_class_ops) 266 return NULL; 267 268 nl_list_for_each_entry(class, &cache->c_items, ce_list) { 269 if (class->c_handle == handle && class->c_ifindex == ifindex) { 270 nl_object_get((struct nl_object *) class); 271 return class; 272 } 273 } 274 return NULL; 275} 276 277/** @} */ 278 279static struct nl_cache_ops rtnl_class_ops = { 280 .co_name = "route/class", 281 .co_hdrsize = sizeof(struct tcmsg), 282 .co_msgtypes = { 283 { RTM_NEWTCLASS, NL_ACT_NEW, "new" }, 284 { RTM_DELTCLASS, NL_ACT_DEL, "del" }, 285 { RTM_GETTCLASS, NL_ACT_GET, "get" }, 286 END_OF_MSGTYPES_LIST, 287 }, 288 .co_protocol = NETLINK_ROUTE, 289 .co_request_update = &class_request_update, 290 .co_msg_parser = &class_msg_parser, 291 .co_obj_ops = &class_obj_ops, 292}; 293 294static void __init class_init(void) 295{ 296 nl_cache_mngt_register(&rtnl_class_ops); 297} 298 299static void __exit class_exit(void) 300{ 301 nl_cache_mngt_unregister(&rtnl_class_ops); 302} 303 304/** @} */ 305