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