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