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
00031
00032 struct fib_result_nl {
00033 uint32_t fl_addr;
00034 uint32_t fl_fwmark;
00035 unsigned char fl_tos;
00036 unsigned char fl_scope;
00037 unsigned char tb_id_in;
00038
00039 unsigned char tb_id;
00040 unsigned char prefixlen;
00041 unsigned char nh_sel;
00042 unsigned char type;
00043 unsigned char scope;
00044 int err;
00045 };
00046
00047
00048 static void result_free_data(struct nl_object *obj)
00049 {
00050 struct flnl_result *res = nl_object_priv(obj);
00051
00052 if (res && res->fr_req)
00053 flnl_request_put(res->fr_req);
00054 }
00055
00056 static int result_msg_parser(struct sockaddr_nl *who, struct nlmsghdr *n,
00057 void *arg)
00058 {
00059 struct flnl_result *res;
00060 struct fib_result_nl *fr;
00061 struct nl_parser_param *pp = arg;
00062 struct nl_addr *addr;
00063 int err = -EINVAL;
00064
00065 res = flnl_result_alloc();
00066 if (!res)
00067 goto errout;
00068
00069 res->ce_msgtype = n->nlmsg_type;
00070
00071 res->fr_req = flnl_request_alloc();
00072 if (!res->fr_req)
00073 goto errout;
00074
00075 fr = nlmsg_data(n);
00076 addr = nl_addr_build(AF_INET, &fr->fl_addr, 4);
00077 if (!addr)
00078 goto errout;
00079 err = flnl_request_set_addr(res->fr_req, addr);
00080 nl_addr_put(addr);
00081 if (err < 0)
00082 goto errout;
00083
00084 flnl_request_set_fwmark(res->fr_req, fr->fl_fwmark);
00085 flnl_request_set_tos(res->fr_req, fr->fl_tos);
00086 flnl_request_set_scope(res->fr_req, fr->fl_scope);
00087 flnl_request_set_table(res->fr_req, fr->tb_id_in);
00088
00089 res->fr_table_id = fr->tb_id;
00090 res->fr_prefixlen = fr->prefixlen;
00091 res->fr_nh_sel = fr->nh_sel;
00092 res->fr_type = fr->type;
00093 res->fr_scope = fr->scope;
00094 res->fr_error = fr->err;
00095
00096 err = pp->pp_cb((struct nl_object *) res, pp);
00097 if (err < 0)
00098 goto errout;
00099
00100
00101
00102
00103 return NL_EXIT;
00104
00105 errout:
00106 flnl_result_put(res);
00107 return err;
00108 }
00109
00110 static int result_dump_brief(struct nl_object *obj, struct nl_dump_params *p)
00111 {
00112 struct flnl_result *res = (struct flnl_result *) obj;
00113 char buf[128];
00114 int line = 1;
00115
00116 dp_dump(p, "table %s prefixlen %u next-hop-selector %u\n",
00117 rtnl_route_table2str(res->fr_table_id, buf, sizeof(buf)),
00118 res->fr_prefixlen, res->fr_nh_sel);
00119 dp_dump_line(p, line++, "type %s ",
00120 nl_rtntype2str(res->fr_type, buf, sizeof(buf)));
00121 dp_dump(p, "scope %s error %s (%d)\n",
00122 rtnl_scope2str(res->fr_scope, buf, sizeof(buf)),
00123 strerror(-res->fr_error), res->fr_error);
00124
00125 return line;
00126 }
00127
00128 static int result_dump_full(struct nl_object *obj, struct nl_dump_params *p)
00129 {
00130 return result_dump_brief(obj, p);
00131 }
00132
00133 static int result_filter(struct nl_object *obj, struct nl_object *filter)
00134 {
00135 struct flnl_result *o = (struct flnl_result *) obj;
00136 struct flnl_result *f = (struct flnl_result *) filter;
00137
00138 if (o->fr_req && f->fr_req)
00139 return flnl_request_cmp(o->fr_req, f->fr_req);
00140
00141 return 1;
00142 }
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155 struct flnl_result *flnl_result_alloc(void)
00156 {
00157 return (struct flnl_result *) nl_object_alloc_from_ops(&fib_lookup_ops);
00158 }
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168 struct nl_cache *flnl_result_alloc_cache(void)
00169 {
00170 return nl_cache_alloc_from_ops(&fib_lookup_ops);
00171 }
00172
00173
00174
00175
00176
00177
00178
00179
00180 void flnl_result_put(struct flnl_result *res)
00181 {
00182 nl_object_put((struct nl_object *) res);
00183 }
00184
00185
00186
00187
00188
00189
00190
00191
00192 void flnl_result_free(struct flnl_result *res)
00193 {
00194 nl_object_free((struct nl_object *) res);
00195 }
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221 struct nl_msg *flnl_lookup_build_request(struct flnl_request *req, int flags)
00222 {
00223 struct nl_msg *msg;
00224 struct nl_addr *addr;
00225 uint64_t fwmark;
00226 int tos, scope, table;
00227 struct fib_result_nl fr = {0};
00228
00229 fwmark = flnl_request_get_fwmark(req);
00230 tos = flnl_request_get_tos(req);
00231 scope = flnl_request_get_scope(req);
00232 table = flnl_request_get_table(req);
00233
00234 fr.fl_fwmark = fwmark != UINT_LEAST64_MAX ? fwmark : 0;
00235 fr.fl_tos = tos >= 0 ? tos : 0;
00236 fr.fl_scope = scope >= 0 ? scope : RT_SCOPE_UNIVERSE;
00237 fr.tb_id_in = table >= 0 ? table : RT_TABLE_UNSPEC;
00238
00239 addr = flnl_request_get_addr(req);
00240 if (!addr) {
00241 nl_error(EINVAL, "Request must specify the address");
00242 return NULL;
00243 }
00244
00245 fr.fl_addr = *(uint32_t *) nl_addr_get_binary_addr(addr);
00246
00247 msg = nlmsg_build_simple(0, flags);
00248 if (!msg)
00249 goto errout;
00250
00251 if (nlmsg_append(msg, &fr, sizeof(fr), 1) < 0)
00252 goto errout;
00253
00254 return msg;
00255
00256 errout:
00257 nlmsg_free(msg);
00258 return NULL;
00259 }
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272 int flnl_lookup(struct nl_handle *handle, struct flnl_request *req,
00273 struct nl_cache *cache)
00274 {
00275 struct nl_msg *msg;
00276 int err;
00277
00278 msg = flnl_lookup_build_request(req, 0);
00279 if (!msg)
00280 return nl_errno(ENOMEM);
00281
00282 err = nl_send_auto_complete(handle, msg);
00283 nlmsg_free(msg);
00284 if (err < 0)
00285 return err;
00286
00287 return nl_cache_pickup(handle, cache);
00288 }
00289
00290
00291
00292
00293
00294
00295
00296
00297 int flnl_result_get_table_id(struct flnl_result *res)
00298 {
00299 return res->fr_table_id;
00300 }
00301
00302 int flnl_result_get_prefixlen(struct flnl_result *res)
00303 {
00304 return res->fr_prefixlen;
00305 }
00306
00307 int flnl_result_get_nexthop_sel(struct flnl_result *res)
00308 {
00309 return res->fr_nh_sel;
00310 }
00311
00312 int flnl_result_get_type(struct flnl_result *res)
00313 {
00314 return res->fr_type;
00315 }
00316
00317 int flnl_result_get_scope(struct flnl_result *res)
00318 {
00319 return res->fr_scope;
00320 }
00321
00322 int flnl_result_get_error(struct flnl_result *res)
00323 {
00324 return res->fr_error;
00325 }
00326
00327
00328
00329 static struct nl_cache_ops fib_lookup_ops = {
00330 .co_name = "fib_lookup/fib_lookup",
00331 .co_size = sizeof(struct flnl_result),
00332 .co_hdrsize = sizeof(struct fib_result_nl),
00333 .co_msgtypes = {
00334 { 0, "any" },
00335 { -1, NULL },
00336 },
00337 .co_protocol = NETLINK_FIB_LOOKUP,
00338 .co_msg_parser = result_msg_parser,
00339 .co_free_data = result_free_data,
00340 .co_dump[NL_DUMP_BRIEF] = result_dump_brief,
00341 .co_dump[NL_DUMP_FULL] = result_dump_full,
00342 .co_filter = result_filter,
00343 };
00344
00345 static void __init fib_lookup_init(void)
00346 {
00347 nl_cache_mngt_register(&fib_lookup_ops);
00348 }
00349
00350 static void __exit fib_lookup_exit(void)
00351 {
00352 nl_cache_mngt_unregister(&fib_lookup_ops);
00353 }
00354
00355