123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349 |
- /*
- * lib/fib_lookup/lookup.c FIB Lookup
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation version 2.1
- * of the License.
- *
- * Copyright (c) 2003-2012 Thomas Graf <tgraf@suug.ch>
- */
- /**
- * @ingroup rtnl
- * @defgroup fib_lookup FIB Lookup
- * @brief
- * @{
- */
- #include <netlink-private/netlink.h>
- #include <netlink/netlink.h>
- #include <netlink/attr.h>
- #include <netlink/utils.h>
- #include <netlink/object.h>
- #include <netlink/route/rtnl.h>
- #include <netlink/route/route.h>
- #include <netlink/fib_lookup/request.h>
- #include <netlink/fib_lookup/lookup.h>
- /** @cond SKIP */
- static struct nl_cache_ops fib_lookup_ops;
- static struct nl_object_ops result_obj_ops;
- /* not exported so far */
- struct fib_result_nl {
- uint32_t fl_addr; /* To be looked up*/
- uint32_t fl_fwmark;
- unsigned char fl_tos;
- unsigned char fl_scope;
- unsigned char tb_id_in;
- unsigned char tb_id; /* Results */
- unsigned char prefixlen;
- unsigned char nh_sel;
- unsigned char type;
- unsigned char scope;
- int err;
- };
- /** @endcond */
- static void result_free_data(struct nl_object *obj)
- {
- struct flnl_result *res = nl_object_priv(obj);
- if (res && res->fr_req)
- nl_object_put(OBJ_CAST(res->fr_req));
- }
- static int result_clone(struct nl_object *_dst, struct nl_object *_src)
- {
- struct flnl_result *dst = nl_object_priv(_dst);
- struct flnl_result *src = nl_object_priv(_src);
- if (src->fr_req)
- if (!(dst->fr_req = (struct flnl_request *)
- nl_object_clone(OBJ_CAST(src->fr_req))))
- return -NLE_NOMEM;
-
- return 0;
- }
- static int result_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
- struct nlmsghdr *n, struct nl_parser_param *pp)
- {
- struct flnl_result *res;
- struct fib_result_nl *fr;
- struct nl_addr *addr;
- int err = -NLE_INVAL;
- res = flnl_result_alloc();
- if (!res)
- goto errout;
- res->ce_msgtype = n->nlmsg_type;
- res->fr_req = flnl_request_alloc();
- if (!res->fr_req)
- goto errout;
- fr = nlmsg_data(n);
- addr = nl_addr_build(AF_INET, &fr->fl_addr, 4);
- if (!addr)
- goto errout;
- err = flnl_request_set_addr(res->fr_req, addr);
- nl_addr_put(addr);
- if (err < 0)
- goto errout;
- flnl_request_set_fwmark(res->fr_req, fr->fl_fwmark);
- flnl_request_set_tos(res->fr_req, fr->fl_tos);
- flnl_request_set_scope(res->fr_req, fr->fl_scope);
- flnl_request_set_table(res->fr_req, fr->tb_id_in);
- res->fr_table_id = fr->tb_id;
- res->fr_prefixlen = fr->prefixlen;
- res->fr_nh_sel = fr->nh_sel;
- res->fr_type = fr->type;
- res->fr_scope = fr->scope;
- res->fr_error = fr->err;
- err = pp->pp_cb((struct nl_object *) res, pp);
- if (err < 0)
- goto errout;
- /* REAL HACK, fib_lookup doesn't support ACK nor does it
- * send a DONE message, enforce end of message stream
- * after just the first message */
- err = NL_STOP;
- errout:
- flnl_result_put(res);
- return err;
- }
- static void result_dump_line(struct nl_object *obj, struct nl_dump_params *p)
- {
- struct flnl_result *res = (struct flnl_result *) obj;
- char buf[256];
- nl_dump_line(p, "table %s prefixlen %u next-hop-selector %u\n",
- rtnl_route_table2str(res->fr_table_id, buf, sizeof(buf)),
- res->fr_prefixlen, res->fr_nh_sel);
- nl_dump_line(p, "type %s ",
- nl_rtntype2str(res->fr_type, buf, sizeof(buf)));
- nl_dump(p, "scope %s error %s (%d)\n",
- rtnl_scope2str(res->fr_scope, buf, sizeof(buf)),
- strerror_r(-res->fr_error, buf, sizeof(buf)), res->fr_error);
- }
- static void result_dump_details(struct nl_object *obj, struct nl_dump_params *p)
- {
- result_dump_line(obj, p);
- }
- static int result_compare(struct nl_object *_a, struct nl_object *_b,
- uint32_t attrs, int flags)
- {
- return 0;
- }
- /**
- * @name Allocation/Freeing
- * @{
- */
- struct flnl_result *flnl_result_alloc(void)
- {
- return (struct flnl_result *) nl_object_alloc(&result_obj_ops);
- }
- void flnl_result_put(struct flnl_result *res)
- {
- nl_object_put((struct nl_object *) res);
- }
- /** @} */
- /**
- * @name Cache Management
- * @{
- */
- /**
- * Allocate lookup result cache.
- *
- * Allocates a new lookup result cache and initializes it properly.
- *
- * @note Free the memory after usage using nl_cache_destroy_and_free().
- * @return Newly allocated cache or NULL if an error occured.
- */
- struct nl_cache *flnl_result_alloc_cache(void)
- {
- return nl_cache_alloc(&fib_lookup_ops);
- }
- /** @} */
- /**
- * @name Lookup
- * @{
- */
- /**
- * Builds a netlink request message to do a lookup
- * @arg req Requested match.
- * @arg flags additional netlink message flags
- * @arg result Result pointer
- *
- * Builds a new netlink message requesting a change of link attributes.
- * The netlink message header isn't fully equipped with all relevant
- * fields and must be sent out via nl_send_auto_complete() or
- * supplemented as needed.
- * \a old must point to a link currently configured in the kernel
- * and \a tmpl must contain the attributes to be changed set via
- * \c rtnl_link_set_* functions.
- *
- * @return 0 on success or a negative error code.
- */
- int flnl_lookup_build_request(struct flnl_request *req, int flags,
- struct nl_msg **result)
- {
- struct nl_msg *msg;
- struct nl_addr *addr;
- uint64_t fwmark;
- int tos, scope, table;
- struct fib_result_nl fr = {0};
- fwmark = flnl_request_get_fwmark(req);
- tos = flnl_request_get_tos(req);
- scope = flnl_request_get_scope(req);
- table = flnl_request_get_table(req);
- fr.fl_fwmark = fwmark != UINT_LEAST64_MAX ? fwmark : 0;
- fr.fl_tos = tos >= 0 ? tos : 0;
- fr.fl_scope = scope >= 0 ? scope : RT_SCOPE_UNIVERSE;
- fr.tb_id_in = table >= 0 ? table : RT_TABLE_UNSPEC;
- addr = flnl_request_get_addr(req);
- if (!addr)
- return -NLE_MISSING_ATTR;
- fr.fl_addr = *(uint32_t *) nl_addr_get_binary_addr(addr);
- msg = nlmsg_alloc_simple(0, flags);
- if (!msg)
- return -NLE_NOMEM;
- if (nlmsg_append(msg, &fr, sizeof(fr), NLMSG_ALIGNTO) < 0)
- goto errout;
- *result = msg;
- return 0;
- errout:
- nlmsg_free(msg);
- return -NLE_MSGSIZE;
- }
- /**
- * Perform FIB Lookup
- * @arg sk Netlink socket.
- * @arg req Lookup request object.
- * @arg cache Cache for result.
- *
- * Builds a netlink message to request a FIB lookup, waits for the
- * reply and adds the result to the specified cache.
- *
- * @return 0 on success or a negative error code.
- */
- int flnl_lookup(struct nl_sock *sk, struct flnl_request *req,
- struct nl_cache *cache)
- {
- struct nl_msg *msg;
- int err;
- if ((err = flnl_lookup_build_request(req, 0, &msg)) < 0)
- return err;
- err = nl_send_auto_complete(sk, msg);
- nlmsg_free(msg);
- if (err < 0)
- return err;
- return nl_cache_pickup(sk, cache);
- }
- /** @} */
- /**
- * @name Attribute Access
- * @{
- */
- int flnl_result_get_table_id(struct flnl_result *res)
- {
- return res->fr_table_id;
- }
- int flnl_result_get_prefixlen(struct flnl_result *res)
- {
- return res->fr_prefixlen;
- }
- int flnl_result_get_nexthop_sel(struct flnl_result *res)
- {
- return res->fr_nh_sel;
- }
- int flnl_result_get_type(struct flnl_result *res)
- {
- return res->fr_type;
- }
- int flnl_result_get_scope(struct flnl_result *res)
- {
- return res->fr_scope;
- }
- int flnl_result_get_error(struct flnl_result *res)
- {
- return res->fr_error;
- }
- /** @} */
- static struct nl_object_ops result_obj_ops = {
- .oo_name = "fib_lookup/result",
- .oo_size = sizeof(struct flnl_result),
- .oo_free_data = result_free_data,
- .oo_clone = result_clone,
- .oo_dump = {
- [NL_DUMP_LINE] = result_dump_line,
- [NL_DUMP_DETAILS] = result_dump_details,
- },
- .oo_compare = result_compare,
- };
- static struct nl_cache_ops fib_lookup_ops = {
- .co_name = "fib_lookup/fib_lookup",
- .co_hdrsize = sizeof(struct fib_result_nl),
- .co_msgtypes = {
- { 0, NL_ACT_UNSPEC, "any" },
- END_OF_MSGTYPES_LIST,
- },
- .co_protocol = NETLINK_FIB_LOOKUP,
- .co_msg_parser = result_msg_parser,
- .co_obj_ops = &result_obj_ops,
- };
- static void __init fib_lookup_init(void)
- {
- nl_cache_mngt_register(&fib_lookup_ops);
- }
- static void __exit fib_lookup_exit(void)
- {
- nl_cache_mngt_unregister(&fib_lookup_ops);
- }
- /** @} */
|