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