Home | History | Annotate | Download | only in fib_lookup
      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 (at) 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 /** @} */
    350