libnl 2.0
|
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 * 00196 * Builds a new netlink message requesting a change of link attributes. 00197 * The netlink message header isn't fully equipped with all relevant 00198 * fields and must be sent out via nl_send_auto_complete() or 00199 * supplemented as needed. 00200 * \a old must point to a link currently configured in the kernel 00201 * and \a tmpl must contain the attributes to be changed set via 00202 * \c rtnl_link_set_* functions. 00203 * 00204 * @return New netlink message 00205 * @note Not all attributes can be changed, see 00206 * \ref link_changeable "Changeable Attributes" for more details. 00207 */ 00208 int flnl_lookup_build_request(struct flnl_request *req, int flags, 00209 struct nl_msg **result) 00210 { 00211 struct nl_msg *msg; 00212 struct nl_addr *addr; 00213 uint64_t fwmark; 00214 int tos, scope, table; 00215 struct fib_result_nl fr = {0}; 00216 00217 fwmark = flnl_request_get_fwmark(req); 00218 tos = flnl_request_get_tos(req); 00219 scope = flnl_request_get_scope(req); 00220 table = flnl_request_get_table(req); 00221 00222 fr.fl_fwmark = fwmark != UINT_LEAST64_MAX ? fwmark : 0; 00223 fr.fl_tos = tos >= 0 ? tos : 0; 00224 fr.fl_scope = scope >= 0 ? scope : RT_SCOPE_UNIVERSE; 00225 fr.tb_id_in = table >= 0 ? table : RT_TABLE_UNSPEC; 00226 00227 addr = flnl_request_get_addr(req); 00228 if (!addr) 00229 return -NLE_MISSING_ATTR; 00230 00231 fr.fl_addr = *(uint32_t *) nl_addr_get_binary_addr(addr); 00232 00233 msg = nlmsg_alloc_simple(0, flags); 00234 if (!msg) 00235 return -NLE_NOMEM; 00236 00237 if (nlmsg_append(msg, &fr, sizeof(fr), NLMSG_ALIGNTO) < 0) 00238 goto errout; 00239 00240 *result = msg; 00241 return 0; 00242 00243 errout: 00244 nlmsg_free(msg); 00245 return -NLE_MSGSIZE; 00246 } 00247 00248 /** 00249 * Perform FIB Lookup 00250 * @arg sk Netlink socket. 00251 * @arg req Lookup request object. 00252 * @arg cache Cache for result. 00253 * 00254 * Builds a netlink message to request a FIB lookup, waits for the 00255 * reply and adds the result to the specified cache. 00256 * 00257 * @return 0 on success or a negative error code. 00258 */ 00259 int flnl_lookup(struct nl_sock *sk, struct flnl_request *req, 00260 struct nl_cache *cache) 00261 { 00262 struct nl_msg *msg; 00263 int err; 00264 00265 if ((err = flnl_lookup_build_request(req, 0, &msg)) < 0) 00266 return err; 00267 00268 err = nl_send_auto_complete(sk, msg); 00269 nlmsg_free(msg); 00270 if (err < 0) 00271 return err; 00272 00273 return nl_cache_pickup(sk, cache); 00274 } 00275 00276 /** @} */ 00277 00278 /** 00279 * @name Attribute Access 00280 * @{ 00281 */ 00282 00283 int flnl_result_get_table_id(struct flnl_result *res) 00284 { 00285 return res->fr_table_id; 00286 } 00287 00288 int flnl_result_get_prefixlen(struct flnl_result *res) 00289 { 00290 return res->fr_prefixlen; 00291 } 00292 00293 int flnl_result_get_nexthop_sel(struct flnl_result *res) 00294 { 00295 return res->fr_nh_sel; 00296 } 00297 00298 int flnl_result_get_type(struct flnl_result *res) 00299 { 00300 return res->fr_type; 00301 } 00302 00303 int flnl_result_get_scope(struct flnl_result *res) 00304 { 00305 return res->fr_scope; 00306 } 00307 00308 int flnl_result_get_error(struct flnl_result *res) 00309 { 00310 return res->fr_error; 00311 } 00312 00313 /** @} */ 00314 00315 static struct nl_object_ops result_obj_ops = { 00316 .oo_name = "fib_lookup/result", 00317 .oo_size = sizeof(struct flnl_result), 00318 .oo_free_data = result_free_data, 00319 .oo_clone = result_clone, 00320 .oo_dump = { 00321 [NL_DUMP_LINE] = result_dump_line, 00322 [NL_DUMP_DETAILS] = result_dump_details, 00323 }, 00324 .oo_compare = result_compare, 00325 }; 00326 00327 static struct nl_cache_ops fib_lookup_ops = { 00328 .co_name = "fib_lookup/fib_lookup", 00329 .co_hdrsize = sizeof(struct fib_result_nl), 00330 .co_msgtypes = { 00331 { 0, NL_ACT_UNSPEC, "any" }, 00332 END_OF_MSGTYPES_LIST, 00333 }, 00334 .co_protocol = NETLINK_FIB_LOOKUP, 00335 .co_msg_parser = result_msg_parser, 00336 .co_obj_ops = &result_obj_ops, 00337 }; 00338 00339 static void __init fib_lookup_init(void) 00340 { 00341 nl_cache_mngt_register(&fib_lookup_ops); 00342 } 00343 00344 static void __exit fib_lookup_exit(void) 00345 { 00346 nl_cache_mngt_unregister(&fib_lookup_ops); 00347 } 00348 00349 /** @} */