Tizen 2.1 base
[platform/upstream/libnl2.git] / lib / route / class.c
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
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 /** @} */