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