libnl  3.2.3
/build/buildd/libnl3-3.2.3/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-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 /** @} */