lookup.c 7.9 KB

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