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