Home | History | Annotate | Download | only in route
      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 (at) 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 
     28 static struct nl_cache_ops rtnl_class_ops;
     29 
     30 static 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);
     56 errout_free:
     57 	rtnl_class_put(class);
     58 errout:
     59 	return err;
     60 }
     61 
     62 static 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 
     78 static 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;
    102 errout:
    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  */
    123 int 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  */
    144 int 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 int 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  */
    198 int 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  */
    232 int 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  */
    260 struct 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 
    279 static 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 
    294 static void __init class_init(void)
    295 {
    296 	nl_cache_mngt_register(&rtnl_class_ops);
    297 }
    298 
    299 static void __exit class_exit(void)
    300 {
    301 	nl_cache_mngt_unregister(&rtnl_class_ops);
    302 }
    303 
    304 /** @} */
    305