This commit was generated by cvs2svn to compensate for changes in r786,
[libnl.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-2006 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
31 /* not exported so far */
32 struct fib_result_nl {
33         uint32_t        fl_addr;   /* To be looked up*/ 
34         uint32_t        fl_fwmark; 
35         unsigned char   fl_tos;
36         unsigned char   fl_scope;
37         unsigned char   tb_id_in;
38
39         unsigned char   tb_id;      /* Results */
40         unsigned char   prefixlen;
41         unsigned char   nh_sel;
42         unsigned char   type;
43         unsigned char   scope;
44         int             err;      
45 };
46 /** @endcond */
47
48 static void result_free_data(struct nl_object *obj)
49 {
50         struct flnl_result *res = nl_object_priv(obj);
51
52         if (res && res->fr_req)
53                 flnl_request_put(res->fr_req);
54 }
55
56 static int result_msg_parser(struct sockaddr_nl *who, struct nlmsghdr *n,
57                              void *arg)
58 {
59         struct flnl_result *res;
60         struct fib_result_nl *fr;
61         struct nl_parser_param *pp = arg;
62         struct nl_addr *addr;
63         int err = -EINVAL;
64
65         res = flnl_result_alloc();
66         if (!res)
67                 goto errout;
68
69         res->ce_msgtype = n->nlmsg_type;
70
71         res->fr_req = flnl_request_alloc();
72         if (!res->fr_req)
73                 goto errout;
74
75         fr = nlmsg_data(n);
76         addr = nl_addr_build(AF_INET, &fr->fl_addr, 4);
77         if (!addr)
78                 goto errout;
79         err = flnl_request_set_addr(res->fr_req, addr);
80         nl_addr_put(addr);
81         if (err < 0)
82                 goto errout;
83
84         flnl_request_set_fwmark(res->fr_req, fr->fl_fwmark);
85         flnl_request_set_tos(res->fr_req, fr->fl_tos);
86         flnl_request_set_scope(res->fr_req, fr->fl_scope);
87         flnl_request_set_table(res->fr_req, fr->tb_id_in);
88
89         res->fr_table_id = fr->tb_id;
90         res->fr_prefixlen = fr->prefixlen;
91         res->fr_nh_sel = fr->nh_sel;
92         res->fr_type = fr->type;
93         res->fr_scope = fr->scope;
94         res->fr_error = fr->err;
95
96         err = pp->pp_cb((struct nl_object *) res, pp);
97         if (err < 0)
98                 goto errout;
99
100         /* REAL HACK, fib_lookup doesn't support ACK nor does it
101          * send a DONE message, enforce end of message stream
102          * after just the first message */
103         return NL_EXIT;
104
105 errout:
106         flnl_result_put(res);
107         return err;
108 }
109
110 static int result_dump_brief(struct nl_object *obj, struct nl_dump_params *p)
111 {
112         struct flnl_result *res = (struct flnl_result *) obj;
113         char buf[128];
114         int line = 1;
115
116         dp_dump(p, "table %s prefixlen %u next-hop-selector %u\n",
117                 rtnl_route_table2str(res->fr_table_id, buf, sizeof(buf)),
118                 res->fr_prefixlen, res->fr_nh_sel);
119         dp_dump_line(p, line++, "type %s ",
120                      nl_rtntype2str(res->fr_type, buf, sizeof(buf)));
121         dp_dump(p, "scope %s error %s (%d)\n",
122                 rtnl_scope2str(res->fr_scope, buf, sizeof(buf)),
123                 strerror(-res->fr_error), res->fr_error);
124
125         return line;
126 }
127
128 static int result_dump_full(struct nl_object *obj, struct nl_dump_params *p)
129 {
130         return result_dump_brief(obj, p);
131 }
132
133 static int result_filter(struct nl_object *obj, struct nl_object *filter)
134 {
135         struct flnl_result *o = (struct flnl_result *) obj;
136         struct flnl_result *f = (struct flnl_result *) filter;
137
138         if (o->fr_req && f->fr_req)
139                 return flnl_request_cmp(o->fr_req, f->fr_req);
140
141         return 1;
142 }
143
144 /**
145  * @name FIB Result Allocation/Freeage
146  * @{
147  */
148
149 /**
150  * Allocate and initialize new lookup result object.
151  * @note Free the memory after usage using flnl_result_put() or
152  *       flnl_result_free().
153  * @return Newly allocated lookup result object or NULL if an error occured.
154  */
155 struct flnl_result *flnl_result_alloc(void)
156 {
157         return (struct flnl_result *) nl_object_alloc_from_ops(&fib_lookup_ops);
158 }
159
160 /**
161  * Allocate lookup result cache.
162  *
163  * Allocates a new lookup result cache and initializes it properly.
164  *
165  * @note Free the memory after usage using nl_cache_destroy_and_free().
166  * @return Newly allocated cache or NULL if an error occured.
167  */
168 struct nl_cache *flnl_result_alloc_cache(void)
169 {
170         return nl_cache_alloc_from_ops(&fib_lookup_ops);
171 }
172
173 /**
174  * Give back reference on lookup result object.
175  * @arg res             lookup result object to be given back.
176  *
177  * Decrements the reference counter and frees the object if the
178  * last reference has been released.
179  */
180 void flnl_result_put(struct flnl_result *res)
181 {
182         nl_object_put((struct nl_object *) res);
183 }
184
185 /**
186  * Free lookup result object.
187  * @arg res             lookup result object to be freed.
188  *
189  * @note Always use flnl_result_put() unless you're absolutely sure
190  *       that no other user may have a reference on this object.
191  */
192 void flnl_result_free(struct flnl_result *res)
193 {
194         nl_object_free((struct nl_object *) res);
195 }
196
197 /** @} */
198
199 /**
200  * @name Lookup
201  * @{
202  */
203
204 /**
205  * Builds a netlink request message to do a lookup
206  * @arg req             Requested match.
207  * @arg flags           additional netlink message flags
208  *
209  * Builds a new netlink message requesting a change of link attributes.
210  * The netlink message header isn't fully equipped with all relevant
211  * fields and must be sent out via nl_send_auto_complete() or
212  * supplemented as needed.
213  * \a old must point to a link currently configured in the kernel
214  * and \a tmpl must contain the attributes to be changed set via
215  * \c rtnl_link_set_* functions.
216  *
217  * @return New netlink message
218  * @note Not all attributes can be changed, see
219  *       \ref link_changeable "Changeable Attributes" for more details.
220  */
221 struct nl_msg *flnl_lookup_build_request(struct flnl_request *req, int flags)
222 {
223         struct nl_msg *msg;
224         struct nl_addr *addr;
225         uint64_t fwmark;
226         int tos, scope, table;
227         struct fib_result_nl fr = {0};
228
229         fwmark = flnl_request_get_fwmark(req);
230         tos = flnl_request_get_tos(req);
231         scope = flnl_request_get_scope(req);
232         table = flnl_request_get_table(req);
233
234         fr.fl_fwmark = fwmark != UINT_LEAST64_MAX ? fwmark : 0;
235         fr.fl_tos = tos >= 0 ? tos : 0;
236         fr.fl_scope = scope >= 0 ? scope : RT_SCOPE_UNIVERSE;
237         fr.tb_id_in = table >= 0 ? table : RT_TABLE_UNSPEC;
238
239         addr = flnl_request_get_addr(req);
240         if (!addr) {
241                 nl_error(EINVAL, "Request must specify the address");
242                 return NULL;
243         }
244
245         fr.fl_addr = *(uint32_t *) nl_addr_get_binary_addr(addr);
246
247         msg = nlmsg_build_simple(0, flags);
248         if (!msg)
249                 goto errout;
250
251         if (nlmsg_append(msg, &fr, sizeof(fr), 1) < 0)
252                 goto errout;
253
254         return msg;
255
256 errout:
257         nlmsg_free(msg);
258         return NULL;
259 }
260
261 /**
262  * Perform FIB Lookup
263  * @arg handle          Netlink handle.
264  * @arg req             Lookup request object.
265  * @arg cache           Cache for result.
266  *
267  * Builds a netlink message to request a FIB lookup, waits for the
268  * reply and adds the result to the specified cache.
269  *
270  * @return 0 on success or a negative error code.
271  */
272 int flnl_lookup(struct nl_handle *handle, struct flnl_request *req,
273                 struct nl_cache *cache)
274 {
275         struct nl_msg *msg;
276         int err;
277
278         msg = flnl_lookup_build_request(req, 0);
279         if (!msg)
280                 return nl_errno(ENOMEM);
281
282         err = nl_send_auto_complete(handle, msg);
283         nlmsg_free(msg);
284         if (err < 0)
285                 return err;
286
287         return nl_cache_pickup(handle, cache);
288 }
289
290 /** @} */
291
292 /**
293  * @name Attribute Access
294  * @{
295  */
296
297 int flnl_result_get_table_id(struct flnl_result *res)
298 {
299         return res->fr_table_id;
300 }
301
302 int flnl_result_get_prefixlen(struct flnl_result *res)
303 {
304         return res->fr_prefixlen;
305 }
306
307 int flnl_result_get_nexthop_sel(struct flnl_result *res)
308 {
309         return res->fr_nh_sel;
310 }
311
312 int flnl_result_get_type(struct flnl_result *res)
313 {
314         return res->fr_type;
315 }
316
317 int flnl_result_get_scope(struct flnl_result *res)
318 {
319         return res->fr_scope;
320 }
321
322 int flnl_result_get_error(struct flnl_result *res)
323 {
324         return res->fr_error;
325 }
326
327 /** @} */
328
329 static struct nl_cache_ops fib_lookup_ops = {
330         .co_name                = "fib_lookup/fib_lookup",
331         .co_size                = sizeof(struct flnl_result),
332         .co_hdrsize             = sizeof(struct fib_result_nl),
333         .co_msgtypes            = {
334                                         { 0, "any" },
335                                         { -1, NULL },
336                                   },
337         .co_protocol            = NETLINK_FIB_LOOKUP,
338         .co_msg_parser          = result_msg_parser,
339         .co_free_data           = result_free_data,
340         .co_dump[NL_DUMP_BRIEF] = result_dump_brief,
341         .co_dump[NL_DUMP_FULL]  = result_dump_full,
342         .co_filter              = result_filter,
343 };
344
345 static void __init fib_lookup_init(void)
346 {
347         nl_cache_mngt_register(&fib_lookup_ops);
348 }
349
350 static void __exit fib_lookup_exit(void)
351 {
352         nl_cache_mngt_unregister(&fib_lookup_ops);
353 }
354
355 /** @} */