00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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
00029 static struct nl_cache_ops fib_lookup_ops;
00030 static struct nl_object_ops result_obj_ops;
00031
00032
00033 struct fib_result_nl {
00034 uint32_t fl_addr;
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;
00041 unsigned char prefixlen;
00042 unsigned char nh_sel;
00043 unsigned char type;
00044 unsigned char scope;
00045 int err;
00046 };
00047
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
00114
00115
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
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
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
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
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
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
00250
00251
00252
00253
00254
00255
00256
00257
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
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