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