libnl 1.1
lib/fib_lookup/lookup.c
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 /** @} */