libnl
3.2.3
|
00001 /* 00002 * lib/fib_lookup/lookup.c FIB Lookup 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation version 2.1 00007 * of the License. 00008 * 00009 * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> 00010 */ 00011 00012 /** 00013 * @defgroup fib_lookup FIB Lookup 00014 * @brief 00015 * @{ 00016 */ 00017 00018 #include <netlink-local.h> 00019 #include <netlink/netlink.h> 00020 #include <netlink/attr.h> 00021 #include <netlink/utils.h> 00022 #include <netlink/object.h> 00023 #include <netlink/route/rtnl.h> 00024 #include <netlink/route/route.h> 00025 #include <netlink/fib_lookup/request.h> 00026 #include <netlink/fib_lookup/lookup.h> 00027 00028 /** @cond SKIP */ 00029 static struct nl_cache_ops fib_lookup_ops; 00030 static struct nl_object_ops result_obj_ops; 00031 00032 /* not exported so far */ 00033 struct fib_result_nl { 00034 uint32_t fl_addr; /* To be looked up*/ 00035 uint32_t fl_fwmark; 00036 unsigned char fl_tos; 00037 unsigned char fl_scope; 00038 unsigned char tb_id_in; 00039 00040 unsigned char tb_id; /* Results */ 00041 unsigned char prefixlen; 00042 unsigned char nh_sel; 00043 unsigned char type; 00044 unsigned char scope; 00045 int err; 00046 }; 00047 /** @endcond */ 00048 00049 static void result_free_data(struct nl_object *obj) 00050 { 00051 struct flnl_result *res = nl_object_priv(obj); 00052 00053 if (res && res->fr_req) 00054 nl_object_put(OBJ_CAST(res->fr_req)); 00055 } 00056 00057 static int result_clone(struct nl_object *_dst, struct nl_object *_src) 00058 { 00059 struct flnl_result *dst = nl_object_priv(_dst); 00060 struct flnl_result *src = nl_object_priv(_src); 00061 00062 if (src->fr_req) 00063 if (!(dst->fr_req = (struct flnl_request *) 00064 nl_object_clone(OBJ_CAST(src->fr_req)))) 00065 return -NLE_NOMEM; 00066 00067 return 0; 00068 } 00069 00070 static int result_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, 00071 struct nlmsghdr *n, struct nl_parser_param *pp) 00072 { 00073 struct flnl_result *res; 00074 struct fib_result_nl *fr; 00075 struct nl_addr *addr; 00076 int err = -NLE_INVAL; 00077 00078 res = flnl_result_alloc(); 00079 if (!res) 00080 goto errout; 00081 00082 res->ce_msgtype = n->nlmsg_type; 00083 00084 res->fr_req = flnl_request_alloc(); 00085 if (!res->fr_req) 00086 goto errout; 00087 00088 fr = nlmsg_data(n); 00089 addr = nl_addr_build(AF_INET, &fr->fl_addr, 4); 00090 if (!addr) 00091 goto errout; 00092 err = flnl_request_set_addr(res->fr_req, addr); 00093 nl_addr_put(addr); 00094 if (err < 0) 00095 goto errout; 00096 00097 flnl_request_set_fwmark(res->fr_req, fr->fl_fwmark); 00098 flnl_request_set_tos(res->fr_req, fr->fl_tos); 00099 flnl_request_set_scope(res->fr_req, fr->fl_scope); 00100 flnl_request_set_table(res->fr_req, fr->tb_id_in); 00101 00102 res->fr_table_id = fr->tb_id; 00103 res->fr_prefixlen = fr->prefixlen; 00104 res->fr_nh_sel = fr->nh_sel; 00105 res->fr_type = fr->type; 00106 res->fr_scope = fr->scope; 00107 res->fr_error = fr->err; 00108 00109 err = pp->pp_cb((struct nl_object *) res, pp); 00110 if (err < 0) 00111 goto errout; 00112 00113 /* REAL HACK, fib_lookup doesn't support ACK nor does it 00114 * send a DONE message, enforce end of message stream 00115 * after just the first message */ 00116 err = NL_STOP; 00117 00118 errout: 00119 flnl_result_put(res); 00120 return err; 00121 } 00122 00123 static void result_dump_line(struct nl_object *obj, struct nl_dump_params *p) 00124 { 00125 struct flnl_result *res = (struct flnl_result *) obj; 00126 char buf[128]; 00127 00128 nl_dump_line(p, "table %s prefixlen %u next-hop-selector %u\n", 00129 rtnl_route_table2str(res->fr_table_id, buf, sizeof(buf)), 00130 res->fr_prefixlen, res->fr_nh_sel); 00131 nl_dump_line(p, "type %s ", 00132 nl_rtntype2str(res->fr_type, buf, sizeof(buf))); 00133 nl_dump(p, "scope %s error %s (%d)\n", 00134 rtnl_scope2str(res->fr_scope, buf, sizeof(buf)), 00135 strerror(-res->fr_error), res->fr_error); 00136 } 00137 00138 static void result_dump_details(struct nl_object *obj, struct nl_dump_params *p) 00139 { 00140 result_dump_line(obj, p); 00141 } 00142 00143 static int result_compare(struct nl_object *_a, struct nl_object *_b, 00144 uint32_t attrs, int flags) 00145 { 00146 return 0; 00147 } 00148 00149 /** 00150 * @name Allocation/Freeing 00151 * @{ 00152 */ 00153 00154 struct flnl_result *flnl_result_alloc(void) 00155 { 00156 return (struct flnl_result *) nl_object_alloc(&result_obj_ops); 00157 } 00158 00159 void flnl_result_put(struct flnl_result *res) 00160 { 00161 nl_object_put((struct nl_object *) res); 00162 } 00163 00164 /** @} */ 00165 00166 /** 00167 * @name Cache Management 00168 * @{ 00169 */ 00170 00171 /** 00172 * Allocate lookup result cache. 00173 * 00174 * Allocates a new lookup result cache and initializes it properly. 00175 * 00176 * @note Free the memory after usage using nl_cache_destroy_and_free(). 00177 * @return Newly allocated cache or NULL if an error occured. 00178 */ 00179 struct nl_cache *flnl_result_alloc_cache(void) 00180 { 00181 return nl_cache_alloc(&fib_lookup_ops); 00182 } 00183 00184 /** @} */ 00185 00186 /** 00187 * @name Lookup 00188 * @{ 00189 */ 00190 00191 /** 00192 * Builds a netlink request message to do a lookup 00193 * @arg req Requested match. 00194 * @arg flags additional netlink message flags 00195 * @arg result Result pointer 00196 * 00197 * Builds a new netlink message requesting a change of link attributes. 00198 * The netlink message header isn't fully equipped with all relevant 00199 * fields and must be sent out via nl_send_auto_complete() or 00200 * supplemented as needed. 00201 * \a old must point to a link currently configured in the kernel 00202 * and \a tmpl must contain the attributes to be changed set via 00203 * \c rtnl_link_set_* functions. 00204 * 00205 * @return 0 on success or a negative error code. 00206 */ 00207 int flnl_lookup_build_request(struct flnl_request *req, int flags, 00208 struct nl_msg **result) 00209 { 00210 struct nl_msg *msg; 00211 struct nl_addr *addr; 00212 uint64_t fwmark; 00213 int tos, scope, table; 00214 struct fib_result_nl fr = {0}; 00215 00216 fwmark = flnl_request_get_fwmark(req); 00217 tos = flnl_request_get_tos(req); 00218 scope = flnl_request_get_scope(req); 00219 table = flnl_request_get_table(req); 00220 00221 fr.fl_fwmark = fwmark != UINT_LEAST64_MAX ? fwmark : 0; 00222 fr.fl_tos = tos >= 0 ? tos : 0; 00223 fr.fl_scope = scope >= 0 ? scope : RT_SCOPE_UNIVERSE; 00224 fr.tb_id_in = table >= 0 ? table : RT_TABLE_UNSPEC; 00225 00226 addr = flnl_request_get_addr(req); 00227 if (!addr) 00228 return -NLE_MISSING_ATTR; 00229 00230 fr.fl_addr = *(uint32_t *) nl_addr_get_binary_addr(addr); 00231 00232 msg = nlmsg_alloc_simple(0, flags); 00233 if (!msg) 00234 return -NLE_NOMEM; 00235 00236 if (nlmsg_append(msg, &fr, sizeof(fr), NLMSG_ALIGNTO) < 0) 00237 goto errout; 00238 00239 *result = msg; 00240 return 0; 00241 00242 errout: 00243 nlmsg_free(msg); 00244 return -NLE_MSGSIZE; 00245 } 00246 00247 /** 00248 * Perform FIB Lookup 00249 * @arg sk Netlink socket. 00250 * @arg req Lookup request object. 00251 * @arg cache Cache for result. 00252 * 00253 * Builds a netlink message to request a FIB lookup, waits for the 00254 * reply and adds the result to the specified cache. 00255 * 00256 * @return 0 on success or a negative error code. 00257 */ 00258 int flnl_lookup(struct nl_sock *sk, struct flnl_request *req, 00259 struct nl_cache *cache) 00260 { 00261 struct nl_msg *msg; 00262 int err; 00263 00264 if ((err = flnl_lookup_build_request(req, 0, &msg)) < 0) 00265 return err; 00266 00267 err = nl_send_auto_complete(sk, msg); 00268 nlmsg_free(msg); 00269 if (err < 0) 00270 return err; 00271 00272 return nl_cache_pickup(sk, cache); 00273 } 00274 00275 /** @} */ 00276 00277 /** 00278 * @name Attribute Access 00279 * @{ 00280 */ 00281 00282 int flnl_result_get_table_id(struct flnl_result *res) 00283 { 00284 return res->fr_table_id; 00285 } 00286 00287 int flnl_result_get_prefixlen(struct flnl_result *res) 00288 { 00289 return res->fr_prefixlen; 00290 } 00291 00292 int flnl_result_get_nexthop_sel(struct flnl_result *res) 00293 { 00294 return res->fr_nh_sel; 00295 } 00296 00297 int flnl_result_get_type(struct flnl_result *res) 00298 { 00299 return res->fr_type; 00300 } 00301 00302 int flnl_result_get_scope(struct flnl_result *res) 00303 { 00304 return res->fr_scope; 00305 } 00306 00307 int flnl_result_get_error(struct flnl_result *res) 00308 { 00309 return res->fr_error; 00310 } 00311 00312 /** @} */ 00313 00314 static struct nl_object_ops result_obj_ops = { 00315 .oo_name = "fib_lookup/result", 00316 .oo_size = sizeof(struct flnl_result), 00317 .oo_free_data = result_free_data, 00318 .oo_clone = result_clone, 00319 .oo_dump = { 00320 [NL_DUMP_LINE] = result_dump_line, 00321 [NL_DUMP_DETAILS] = result_dump_details, 00322 }, 00323 .oo_compare = result_compare, 00324 }; 00325 00326 static struct nl_cache_ops fib_lookup_ops = { 00327 .co_name = "fib_lookup/fib_lookup", 00328 .co_hdrsize = sizeof(struct fib_result_nl), 00329 .co_msgtypes = { 00330 { 0, NL_ACT_UNSPEC, "any" }, 00331 END_OF_MSGTYPES_LIST, 00332 }, 00333 .co_protocol = NETLINK_FIB_LOOKUP, 00334 .co_msg_parser = result_msg_parser, 00335 .co_obj_ops = &result_obj_ops, 00336 }; 00337 00338 static void __init fib_lookup_init(void) 00339 { 00340 nl_cache_mngt_register(&fib_lookup_ops); 00341 } 00342 00343 static void __exit fib_lookup_exit(void) 00344 { 00345 nl_cache_mngt_unregister(&fib_lookup_ops); 00346 } 00347 00348 /** @} */