Tizen 2.1 base
[platform/upstream/libnl2.git] / lib / fib_lookup / lookup.c
1 /*
2  * lib/fib_lookup/lookup.c      FIB Lookup
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  * @defgroup fib_lookup FIB Lookup
14  * @brief
15  * @{
16  */
17
18 #include <netlink-local.h>
19 #include <netlink/netlink.h>
20 #include <netlink/attr.h>
21 #include <netlink/utils.h>
22 #include <netlink/object.h>
23 #include <netlink/route/rtnl.h>
24 #include <netlink/route/route.h>
25 #include <netlink/fib_lookup/request.h>
26 #include <netlink/fib_lookup/lookup.h>
27
28 /** @cond SKIP */
29 static struct nl_cache_ops fib_lookup_ops;
30 static struct nl_object_ops result_obj_ops;
31
32 /* not exported so far */
33 struct fib_result_nl {
34         uint32_t        fl_addr;   /* To be looked up*/ 
35         uint32_t        fl_fwmark; 
36         unsigned char   fl_tos;
37         unsigned char   fl_scope;
38         unsigned char   tb_id_in;
39
40         unsigned char   tb_id;      /* Results */
41         unsigned char   prefixlen;
42         unsigned char   nh_sel;
43         unsigned char   type;
44         unsigned char   scope;
45         int             err;      
46 };
47 /** @endcond */
48
49 static void result_free_data(struct nl_object *obj)
50 {
51         struct flnl_result *res = nl_object_priv(obj);
52
53         if (res && res->fr_req)
54                 nl_object_put(OBJ_CAST(res->fr_req));
55 }
56
57 static int result_clone(struct nl_object *_dst, struct nl_object *_src)
58 {
59         struct flnl_result *dst = nl_object_priv(_dst);
60         struct flnl_result *src = nl_object_priv(_src);
61
62         if (src->fr_req)
63                 if (!(dst->fr_req = (struct flnl_request *)
64                                 nl_object_clone(OBJ_CAST(src->fr_req))))
65                         return -NLE_NOMEM;
66         
67         return 0;
68 }
69
70 static int result_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
71                              struct nlmsghdr *n, struct nl_parser_param *pp)
72 {
73         struct flnl_result *res;
74         struct fib_result_nl *fr;
75         struct nl_addr *addr;
76         int err = -NLE_INVAL;
77
78         res = flnl_result_alloc();
79         if (!res)
80                 goto errout;
81
82         res->ce_msgtype = n->nlmsg_type;
83
84         res->fr_req = flnl_request_alloc();
85         if (!res->fr_req)
86                 goto errout;
87
88         fr = nlmsg_data(n);
89         addr = nl_addr_build(AF_INET, &fr->fl_addr, 4);
90         if (!addr)
91                 goto errout;
92         err = flnl_request_set_addr(res->fr_req, addr);
93         nl_addr_put(addr);
94         if (err < 0)
95                 goto errout;
96
97         flnl_request_set_fwmark(res->fr_req, fr->fl_fwmark);
98         flnl_request_set_tos(res->fr_req, fr->fl_tos);
99         flnl_request_set_scope(res->fr_req, fr->fl_scope);
100         flnl_request_set_table(res->fr_req, fr->tb_id_in);
101
102         res->fr_table_id = fr->tb_id;
103         res->fr_prefixlen = fr->prefixlen;
104         res->fr_nh_sel = fr->nh_sel;
105         res->fr_type = fr->type;
106         res->fr_scope = fr->scope;
107         res->fr_error = fr->err;
108
109         err = pp->pp_cb((struct nl_object *) res, pp);
110         if (err < 0)
111                 goto errout;
112
113         /* REAL HACK, fib_lookup doesn't support ACK nor does it
114          * send a DONE message, enforce end of message stream
115          * after just the first message */
116         err = NL_STOP;
117
118 errout:
119         flnl_result_put(res);
120         return err;
121 }
122
123 static void result_dump_line(struct nl_object *obj, struct nl_dump_params *p)
124 {
125         struct flnl_result *res = (struct flnl_result *) obj;
126         char buf[128];
127
128         nl_dump_line(p, "table %s prefixlen %u next-hop-selector %u\n",
129                 rtnl_route_table2str(res->fr_table_id, buf, sizeof(buf)),
130                 res->fr_prefixlen, res->fr_nh_sel);
131         nl_dump_line(p, "type %s ",
132                      nl_rtntype2str(res->fr_type, buf, sizeof(buf)));
133         nl_dump(p, "scope %s error %s (%d)\n",
134                 rtnl_scope2str(res->fr_scope, buf, sizeof(buf)),
135                 strerror(-res->fr_error), res->fr_error);
136 }
137
138 static void result_dump_details(struct nl_object *obj, struct nl_dump_params *p)
139 {
140         result_dump_line(obj, p);
141 }
142
143 static int result_compare(struct nl_object *_a, struct nl_object *_b,
144                         uint32_t attrs, int flags)
145 {
146         return 0;
147 }
148
149 /**
150  * @name Allocation/Freeing
151  * @{
152  */
153
154 struct flnl_result *flnl_result_alloc(void)
155 {
156         return (struct flnl_result *) nl_object_alloc(&result_obj_ops);
157 }
158
159 void flnl_result_put(struct flnl_result *res)
160 {
161         nl_object_put((struct nl_object *) res);
162 }
163
164 /** @} */
165
166 /**
167  * @name Cache Management
168  * @{
169  */
170
171 /**
172  * Allocate lookup result cache.
173  *
174  * Allocates a new lookup result cache and initializes it properly.
175  *
176  * @note Free the memory after usage using nl_cache_destroy_and_free().
177  * @return Newly allocated cache or NULL if an error occured.
178  */
179 struct nl_cache *flnl_result_alloc_cache(void)
180 {
181         return nl_cache_alloc(&fib_lookup_ops);
182 }
183
184 /** @} */
185
186 /**
187  * @name Lookup
188  * @{
189  */
190
191 /**
192  * Builds a netlink request message to do a lookup
193  * @arg req             Requested match.
194  * @arg flags           additional netlink message flags
195  *
196  * Builds a new netlink message requesting a change of link attributes.
197  * The netlink message header isn't fully equipped with all relevant
198  * fields and must be sent out via nl_send_auto_complete() or
199  * supplemented as needed.
200  * \a old must point to a link currently configured in the kernel
201  * and \a tmpl must contain the attributes to be changed set via
202  * \c rtnl_link_set_* functions.
203  *
204  * @return New netlink message
205  * @note Not all attributes can be changed, see
206  *       \ref link_changeable "Changeable Attributes" for more details.
207  */
208 int flnl_lookup_build_request(struct flnl_request *req, int flags,
209                               struct nl_msg **result)
210 {
211         struct nl_msg *msg;
212         struct nl_addr *addr;
213         uint64_t fwmark;
214         int tos, scope, table;
215         struct fib_result_nl fr = {0};
216
217         fwmark = flnl_request_get_fwmark(req);
218         tos = flnl_request_get_tos(req);
219         scope = flnl_request_get_scope(req);
220         table = flnl_request_get_table(req);
221
222         fr.fl_fwmark = fwmark != UINT_LEAST64_MAX ? fwmark : 0;
223         fr.fl_tos = tos >= 0 ? tos : 0;
224         fr.fl_scope = scope >= 0 ? scope : RT_SCOPE_UNIVERSE;
225         fr.tb_id_in = table >= 0 ? table : RT_TABLE_UNSPEC;
226
227         addr = flnl_request_get_addr(req);
228         if (!addr)
229                 return -NLE_MISSING_ATTR;
230
231         fr.fl_addr = *(uint32_t *) nl_addr_get_binary_addr(addr);
232
233         msg = nlmsg_alloc_simple(0, flags);
234         if (!msg)
235                 return -NLE_NOMEM;
236
237         if (nlmsg_append(msg, &fr, sizeof(fr), NLMSG_ALIGNTO) < 0)
238                 goto errout;
239
240         *result = msg;
241         return 0;
242
243 errout:
244         nlmsg_free(msg);
245         return -NLE_MSGSIZE;
246 }
247
248 /**
249  * Perform FIB Lookup
250  * @arg sk              Netlink socket.
251  * @arg req             Lookup request object.
252  * @arg cache           Cache for result.
253  *
254  * Builds a netlink message to request a FIB lookup, waits for the
255  * reply and adds the result to the specified cache.
256  *
257  * @return 0 on success or a negative error code.
258  */
259 int flnl_lookup(struct nl_sock *sk, struct flnl_request *req,
260                 struct nl_cache *cache)
261 {
262         struct nl_msg *msg;
263         int err;
264
265         if ((err = flnl_lookup_build_request(req, 0, &msg)) < 0)
266                 return err;
267
268         err = nl_send_auto_complete(sk, msg);
269         nlmsg_free(msg);
270         if (err < 0)
271                 return err;
272
273         return nl_cache_pickup(sk, cache);
274 }
275
276 /** @} */
277
278 /**
279  * @name Attribute Access
280  * @{
281  */
282
283 int flnl_result_get_table_id(struct flnl_result *res)
284 {
285         return res->fr_table_id;
286 }
287
288 int flnl_result_get_prefixlen(struct flnl_result *res)
289 {
290         return res->fr_prefixlen;
291 }
292
293 int flnl_result_get_nexthop_sel(struct flnl_result *res)
294 {
295         return res->fr_nh_sel;
296 }
297
298 int flnl_result_get_type(struct flnl_result *res)
299 {
300         return res->fr_type;
301 }
302
303 int flnl_result_get_scope(struct flnl_result *res)
304 {
305         return res->fr_scope;
306 }
307
308 int flnl_result_get_error(struct flnl_result *res)
309 {
310         return res->fr_error;
311 }
312
313 /** @} */
314
315 static struct nl_object_ops result_obj_ops = {
316         .oo_name                = "fib_lookup/result",
317         .oo_size                = sizeof(struct flnl_result),
318         .oo_free_data           = result_free_data,
319         .oo_clone               = result_clone,
320         .oo_dump = {
321             [NL_DUMP_LINE]      = result_dump_line,
322             [NL_DUMP_DETAILS]   = result_dump_details,
323         },
324         .oo_compare             = result_compare,
325 };
326
327 static struct nl_cache_ops fib_lookup_ops = {
328         .co_name                = "fib_lookup/fib_lookup",
329         .co_hdrsize             = sizeof(struct fib_result_nl),
330         .co_msgtypes            = {
331                                         { 0, NL_ACT_UNSPEC, "any" },
332                                         END_OF_MSGTYPES_LIST,
333                                   },
334         .co_protocol            = NETLINK_FIB_LOOKUP,
335         .co_msg_parser          = result_msg_parser,
336         .co_obj_ops             = &result_obj_ops,
337 };
338
339 static void __init fib_lookup_init(void)
340 {
341         nl_cache_mngt_register(&fib_lookup_ops);
342 }
343
344 static void __exit fib_lookup_exit(void)
345 {
346         nl_cache_mngt_unregister(&fib_lookup_ops);
347 }
348
349 /** @} */