• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
25 static struct nl_cache_ops fib_lookup_ops;
26 static struct nl_object_ops result_obj_ops;
27 
28 /* not exported so far */
29 struct 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 
result_free_data(struct nl_object * obj)45 static 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 
result_clone(struct nl_object * _dst,struct nl_object * _src)53 static 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 
result_msg_parser(struct nl_cache_ops * ops,struct sockaddr_nl * who,struct nlmsghdr * n,struct nl_parser_param * pp)68 static 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 
116 errout:
117 	flnl_result_put(res);
118 	return err;
119 }
120 
result_dump_line(struct nl_object * obj,struct nl_dump_params * p)121 static 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 
result_dump_details(struct nl_object * obj,struct nl_dump_params * p)136 static void result_dump_details(struct nl_object *obj, struct nl_dump_params *p)
137 {
138 	result_dump_line(obj, p);
139 }
140 
result_compare(struct nl_object * _a,struct nl_object * _b,uint64_t attrs,int flags)141 static 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 
flnl_result_alloc(void)152 struct flnl_result *flnl_result_alloc(void)
153 {
154 	return (struct flnl_result *) nl_object_alloc(&result_obj_ops);
155 }
156 
flnl_result_put(struct flnl_result * res)157 void 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  */
flnl_result_alloc_cache(void)177 struct 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  */
flnl_lookup_build_request(struct flnl_request * req,int flags,struct nl_msg ** result)205 int 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 
240 errout:
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  */
flnl_lookup(struct nl_sock * sk,struct flnl_request * req,struct nl_cache * cache)256 int 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 
flnl_result_get_table_id(struct flnl_result * res)280 int flnl_result_get_table_id(struct flnl_result *res)
281 {
282 	return res->fr_table_id;
283 }
284 
flnl_result_get_prefixlen(struct flnl_result * res)285 int flnl_result_get_prefixlen(struct flnl_result *res)
286 {
287 	return res->fr_prefixlen;
288 }
289 
flnl_result_get_nexthop_sel(struct flnl_result * res)290 int flnl_result_get_nexthop_sel(struct flnl_result *res)
291 {
292 	return res->fr_nh_sel;
293 }
294 
flnl_result_get_type(struct flnl_result * res)295 int flnl_result_get_type(struct flnl_result *res)
296 {
297 	return res->fr_type;
298 }
299 
flnl_result_get_scope(struct flnl_result * res)300 int flnl_result_get_scope(struct flnl_result *res)
301 {
302 	return res->fr_scope;
303 }
304 
flnl_result_get_error(struct flnl_result * res)305 int flnl_result_get_error(struct flnl_result *res)
306 {
307 	return res->fr_error;
308 }
309 
310 /** @} */
311 
312 static 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 
324 static 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 
fib_lookup_init(void)336 static void __init fib_lookup_init(void)
337 {
338 	nl_cache_mngt_register(&fib_lookup_ops);
339 }
340 
fib_lookup_exit(void)341 static void __exit fib_lookup_exit(void)
342 {
343 	nl_cache_mngt_unregister(&fib_lookup_ops);
344 }
345 
346 /** @} */
347