00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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
00030 static struct nl_cache_ops fib_lookup_ops;
00031 static struct nl_object_ops result_obj_ops;
00032
00033
00034 struct fib_result_nl {
00035 uint32_t fl_addr;
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;
00042 unsigned char prefixlen;
00043 unsigned char nh_sel;
00044 unsigned char type;
00045 unsigned char scope;
00046 int err;
00047 };
00048
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
00115
00116
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
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
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
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
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
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
00254
00255
00256
00257
00258
00259
00260
00261
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
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