class.c revision cfcfca070355b246028df60da79813f09ed65755
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 160/** @} */ 161 162/** 163 * @name Cache Management 164 * @{ 165 */ 166 167/** 168 * Build a class cache including all classes attached to the specified interface 169 * @arg sk Netlink socket. 170 * @arg ifindex interface index of the link the classes are 171 * attached to. 172 * 173 * Allocates a new cache, initializes it properly and updates it to 174 * include all classes attached to the specified interface. 175 * 176 * @return The cache or NULL if an error has occured. 177 */ 178int rtnl_class_alloc_cache(struct nl_sock *sk, int ifindex, 179 struct nl_cache **result) 180{ 181 struct nl_cache * cache; 182 int err; 183 184 cache = nl_cache_alloc(&rtnl_class_ops); 185 if (!cache) 186 return -NLE_NOMEM; 187 188 cache->c_iarg1 = ifindex; 189 190 if (sk && (err = nl_cache_refill(sk, cache)) < 0) { 191 nl_cache_free(cache); 192 return err; 193 } 194 195 *result = cache; 196 return 0; 197} 198 199/** @} */ 200 201static struct nl_cache_ops rtnl_class_ops = { 202 .co_name = "route/class", 203 .co_hdrsize = sizeof(struct tcmsg), 204 .co_msgtypes = { 205 { RTM_NEWTCLASS, NL_ACT_NEW, "new" }, 206 { RTM_DELTCLASS, NL_ACT_DEL, "del" }, 207 { RTM_GETTCLASS, NL_ACT_GET, "get" }, 208 END_OF_MSGTYPES_LIST, 209 }, 210 .co_protocol = NETLINK_ROUTE, 211 .co_request_update = &class_request_update, 212 .co_msg_parser = &class_msg_parser, 213 .co_obj_ops = &class_obj_ops, 214}; 215 216static void __init class_init(void) 217{ 218 nl_cache_mngt_register(&rtnl_class_ops); 219} 220 221static void __exit class_exit(void) 222{ 223 nl_cache_mngt_unregister(&rtnl_class_ops); 224} 225 226/** @} */ 227