xref: /aosp_15_r20/external/libnl/lib/fib_lookup/lookup.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * Copyright (c) 2003-2012 Thomas Graf <[email protected]>
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 */
29 struct 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 
42 static struct nl_cache_ops fib_lookup_ops;
43 static struct nl_object_ops result_obj_ops;
44 
45 /* not exported so far */
46 struct 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 
result_free_data(struct nl_object * obj)62 static 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 
result_clone(struct nl_object * _dst,struct nl_object * _src)70 static 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 
result_msg_parser(struct nl_cache_ops * ops,struct sockaddr_nl * who,struct nlmsghdr * n,struct nl_parser_param * pp)85 static 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 
133 errout:
134 	flnl_result_put(res);
135 	return err;
136 }
137 
result_dump_line(struct nl_object * obj,struct nl_dump_params * p)138 static 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 
result_dump_details(struct nl_object * obj,struct nl_dump_params * p)153 static void result_dump_details(struct nl_object *obj, struct nl_dump_params *p)
154 {
155 	result_dump_line(obj, p);
156 }
157 
result_compare(struct nl_object * _a,struct nl_object * _b,uint64_t attrs,int flags)158 static 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 
flnl_result_alloc(void)169 struct flnl_result *flnl_result_alloc(void)
170 {
171 	return (struct flnl_result *) nl_object_alloc(&result_obj_ops);
172 }
173 
flnl_result_put(struct flnl_result * res)174 void 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  */
flnl_result_alloc_cache(void)194 struct 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  */
flnl_lookup_build_request(struct flnl_request * req,int flags,struct nl_msg ** result)222 int 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 
257 errout:
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  */
flnl_lookup(struct nl_sock * sk,struct flnl_request * req,struct nl_cache * cache)273 int 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 
flnl_result_get_table_id(struct flnl_result * res)297 int flnl_result_get_table_id(struct flnl_result *res)
298 {
299 	return res->fr_table_id;
300 }
301 
flnl_result_get_prefixlen(struct flnl_result * res)302 int flnl_result_get_prefixlen(struct flnl_result *res)
303 {
304 	return res->fr_prefixlen;
305 }
306 
flnl_result_get_nexthop_sel(struct flnl_result * res)307 int flnl_result_get_nexthop_sel(struct flnl_result *res)
308 {
309 	return res->fr_nh_sel;
310 }
311 
flnl_result_get_type(struct flnl_result * res)312 int flnl_result_get_type(struct flnl_result *res)
313 {
314 	return res->fr_type;
315 }
316 
flnl_result_get_scope(struct flnl_result * res)317 int flnl_result_get_scope(struct flnl_result *res)
318 {
319 	return res->fr_scope;
320 }
321 
flnl_result_get_error(struct flnl_result * res)322 int flnl_result_get_error(struct flnl_result *res)
323 {
324 	return res->fr_error;
325 }
326 
327 /** @} */
328 
329 static 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 
341 static 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 
fib_lookup_init(void)353 static void _nl_init fib_lookup_init(void)
354 {
355 	nl_cache_mngt_register(&fib_lookup_ops);
356 }
357 
fib_lookup_exit(void)358 static void _nl_exit fib_lookup_exit(void)
359 {
360 	nl_cache_mngt_unregister(&fib_lookup_ops);
361 }
362 
363 /** @} */
364