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