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