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/cache.h>
00022 #include <netlink/utils.h>
00023 #include <netlink/data.h>
00024 #include <netlink/route/rtnl.h>
00025 #include <netlink/route/route.h>
00026 #include <netlink/route/link.h>
00027
00028 static struct nl_cache_ops rtnl_route_ops;
00029
00030 static struct nla_policy route_policy[RTA_MAX+1] = {
00031 [RTA_IIF] = { .type = NLA_STRING,
00032 .maxlen = IFNAMSIZ, },
00033 [RTA_OIF] = { .type = NLA_U32 },
00034 [RTA_PRIORITY] = { .type = NLA_U32 },
00035 [RTA_FLOW] = { .type = NLA_U32 },
00036 [RTA_MP_ALGO] = { .type = NLA_U32 },
00037 [RTA_CACHEINFO] = { .minlen = sizeof(struct rta_cacheinfo) },
00038 [RTA_METRICS] = { .type = NLA_NESTED },
00039 [RTA_MULTIPATH] = { .type = NLA_NESTED },
00040 };
00041
00042 static void copy_cacheinfo_into_route(struct rta_cacheinfo *ci,
00043 struct rtnl_route *route)
00044 {
00045 struct rtnl_rtcacheinfo nci = {
00046 .rtci_clntref = ci->rta_clntref,
00047 .rtci_last_use = ci->rta_lastuse,
00048 .rtci_expires = ci->rta_expires,
00049 .rtci_error = ci->rta_error,
00050 .rtci_used = ci->rta_used,
00051 .rtci_id = ci->rta_id,
00052 .rtci_ts = ci->rta_ts,
00053 .rtci_tsage = ci->rta_tsage,
00054 };
00055
00056 rtnl_route_set_cacheinfo(route, &nci);
00057 }
00058
00059 static int route_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
00060 struct nlmsghdr *nlh, struct nl_parser_param *pp)
00061 {
00062 struct rtmsg *rtm;
00063 struct rtnl_route *route;
00064 struct nlattr *tb[RTA_MAX + 1];
00065 struct nl_addr *src = NULL, *dst = NULL, *addr;
00066 int err;
00067
00068 route = rtnl_route_alloc();
00069 if (!route) {
00070 err = nl_errno(ENOMEM);
00071 goto errout;
00072 }
00073
00074 route->ce_msgtype = nlh->nlmsg_type;
00075
00076 err = nlmsg_parse(nlh, sizeof(struct rtmsg), tb, RTA_MAX,
00077 route_policy);
00078 if (err < 0)
00079 goto errout;
00080
00081 rtm = nlmsg_data(nlh);
00082 rtnl_route_set_family(route, rtm->rtm_family);
00083 rtnl_route_set_tos(route, rtm->rtm_tos);
00084 rtnl_route_set_table(route, rtm->rtm_table);
00085 rtnl_route_set_type(route, rtm->rtm_type);
00086 rtnl_route_set_scope(route, rtm->rtm_scope);
00087 rtnl_route_set_protocol(route, rtm->rtm_protocol);
00088 rtnl_route_set_flags(route, rtm->rtm_flags);
00089
00090 if (tb[RTA_DST]) {
00091 dst = nla_get_addr(tb[RTA_DST], rtm->rtm_family);
00092 if (dst == NULL)
00093 goto errout_errno;
00094 } else {
00095 dst = nl_addr_alloc(0);
00096 nl_addr_set_family(dst, rtm->rtm_family);
00097 }
00098
00099 nl_addr_set_prefixlen(dst, rtm->rtm_dst_len);
00100 err = rtnl_route_set_dst(route, dst);
00101 if (err < 0)
00102 goto errout;
00103
00104 nl_addr_put(dst);
00105
00106 if (tb[RTA_SRC]) {
00107 src = nla_get_addr(tb[RTA_SRC], rtm->rtm_family);
00108 if (src == NULL)
00109 goto errout_errno;
00110 } else if (rtm->rtm_src_len)
00111 src = nl_addr_alloc(0);
00112
00113 if (src) {
00114 nl_addr_set_prefixlen(src, rtm->rtm_src_len);
00115 rtnl_route_set_src(route, src);
00116 nl_addr_put(src);
00117 }
00118
00119 if (tb[RTA_IIF])
00120 rtnl_route_set_iif(route, nla_get_string(tb[RTA_IIF]));
00121
00122 if (tb[RTA_OIF])
00123 rtnl_route_set_oif(route, nla_get_u32(tb[RTA_OIF]));
00124
00125 if (tb[RTA_GATEWAY]) {
00126 addr = nla_get_addr(tb[RTA_GATEWAY], route->rt_family);
00127 if (addr == NULL)
00128 goto errout_errno;
00129 rtnl_route_set_gateway(route, addr);
00130 nl_addr_put(addr);
00131 }
00132
00133 if (tb[RTA_PRIORITY])
00134 rtnl_route_set_prio(route, nla_get_u32(tb[RTA_PRIORITY]));
00135
00136 if (tb[RTA_PREFSRC]) {
00137 addr = nla_get_addr(tb[RTA_PREFSRC], route->rt_family);
00138 if (addr == NULL)
00139 goto errout_errno;
00140 rtnl_route_set_pref_src(route, addr);
00141 nl_addr_put(addr);
00142 }
00143
00144 if (tb[RTA_METRICS]) {
00145 struct nlattr *mtb[RTAX_MAX + 1];
00146 int i;
00147
00148 err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL);
00149 if (err < 0)
00150 goto errout;
00151
00152 for (i = 1; i <= RTAX_MAX; i++) {
00153 if (mtb[i] && nla_len(mtb[i]) >= sizeof(uint32_t)) {
00154 uint32_t m = nla_get_u32(mtb[i]);
00155 if (rtnl_route_set_metric(route, i, m) < 0)
00156 goto errout_errno;
00157 }
00158 }
00159 }
00160
00161 if (tb[RTA_MULTIPATH]) {
00162 struct rtnl_nexthop *nh;
00163 struct rtnexthop *rtnh = nla_data(tb[RTA_MULTIPATH]);
00164 size_t tlen = nla_len(tb[RTA_MULTIPATH]);
00165
00166 while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) {
00167 nh = rtnl_route_nh_alloc();
00168 if (!nh)
00169 goto errout;
00170
00171 rtnl_route_nh_set_weight(nh, rtnh->rtnh_hops);
00172 rtnl_route_nh_set_ifindex(nh, rtnh->rtnh_ifindex);
00173 rtnl_route_nh_set_flags(nh, rtnh->rtnh_flags);
00174
00175 if (rtnh->rtnh_len > sizeof(*rtnh)) {
00176 struct nlattr *ntb[RTA_MAX + 1];
00177 nla_parse(ntb, RTA_MAX, (struct nlattr *)
00178 RTNH_DATA(rtnh),
00179 rtnh->rtnh_len - sizeof(*rtnh),
00180 route_policy);
00181
00182 if (ntb[RTA_GATEWAY]) {
00183 nh->rtnh_gateway = nla_get_addr(
00184 ntb[RTA_GATEWAY],
00185 route->rt_family);
00186 nh->rtnh_mask = NEXTHOP_HAS_GATEWAY;
00187 }
00188 }
00189
00190 rtnl_route_add_nexthop(route, nh);
00191 tlen -= RTNH_ALIGN(rtnh->rtnh_len);
00192 rtnh = RTNH_NEXT(rtnh);
00193 }
00194 }
00195
00196 if (tb[RTA_FLOW])
00197 rtnl_route_set_realms(route, nla_get_u32(tb[RTA_FLOW]));
00198
00199 if (tb[RTA_CACHEINFO])
00200 copy_cacheinfo_into_route(nla_data(tb[RTA_CACHEINFO]), route);
00201
00202 if (tb[RTA_MP_ALGO])
00203 rtnl_route_set_mp_algo(route, nla_get_u32(tb[RTA_MP_ALGO]));
00204
00205 err = pp->pp_cb((struct nl_object *) route, pp);
00206 if (err < 0)
00207 goto errout;
00208
00209 err = P_ACCEPT;
00210
00211 errout:
00212 rtnl_route_put(route);
00213 return err;
00214
00215 errout_errno:
00216 err = nl_get_errno();
00217 goto errout;
00218 }
00219
00220 static int route_request_update(struct nl_cache *c, struct nl_handle *h)
00221 {
00222 return nl_rtgen_request(h, RTM_GETROUTE, AF_UNSPEC, NLM_F_DUMP);
00223 }
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241 struct nl_cache *rtnl_route_alloc_cache(struct nl_handle *handle)
00242 {
00243 struct nl_cache *cache;
00244
00245 cache = nl_cache_alloc(&rtnl_route_ops);
00246 if (!cache)
00247 return NULL;
00248
00249 if (handle && nl_cache_refill(handle, cache) < 0) {
00250 free(cache);
00251 return NULL;
00252 }
00253
00254 return cache;
00255 }
00256
00257
00258
00259
00260
00261
00262
00263
00264 static struct nl_msg *build_route_msg(struct rtnl_route *tmpl, int cmd,
00265 int flags)
00266 {
00267 struct nl_msg *msg;
00268 struct nl_addr *addr;
00269 int scope, i, oif, nmetrics = 0;
00270 struct nlattr *metrics;
00271 struct rtmsg rtmsg = {
00272 .rtm_family = rtnl_route_get_family(tmpl),
00273 .rtm_dst_len = rtnl_route_get_dst_len(tmpl),
00274 .rtm_src_len = rtnl_route_get_src_len(tmpl),
00275 .rtm_tos = rtnl_route_get_tos(tmpl),
00276 .rtm_table = rtnl_route_get_table(tmpl),
00277 .rtm_type = rtnl_route_get_type(tmpl),
00278 .rtm_protocol = rtnl_route_get_protocol(tmpl),
00279 .rtm_flags = rtnl_route_get_flags(tmpl),
00280 };
00281
00282 if (rtmsg.rtm_family == AF_UNSPEC) {
00283 nl_error(EINVAL, "Cannot build route message, address " \
00284 "family is unknown.");
00285 return NULL;
00286 }
00287
00288 scope = rtnl_route_get_scope(tmpl);
00289 if (scope == RT_SCOPE_NOWHERE) {
00290 if (rtmsg.rtm_type == RTN_LOCAL)
00291 scope = RT_SCOPE_HOST;
00292 else {
00293
00294 scope = RT_SCOPE_LINK;
00295 }
00296 }
00297
00298 rtmsg.rtm_scope = scope;
00299
00300 msg = nlmsg_alloc_simple(cmd, flags);
00301 if (msg == NULL)
00302 return NULL;
00303
00304 if (nlmsg_append(msg, &rtmsg, sizeof(rtmsg), NLMSG_ALIGNTO) < 0)
00305 goto nla_put_failure;
00306
00307 addr = rtnl_route_get_dst(tmpl);
00308 if (addr)
00309 NLA_PUT_ADDR(msg, RTA_DST, addr);
00310
00311 addr = rtnl_route_get_src(tmpl);
00312 if (addr)
00313 NLA_PUT_ADDR(msg, RTA_SRC, addr);
00314
00315 addr = rtnl_route_get_gateway(tmpl);
00316 if (addr)
00317 NLA_PUT_ADDR(msg, RTA_GATEWAY, addr);
00318
00319 addr = rtnl_route_get_pref_src(tmpl);
00320 if (addr)
00321 NLA_PUT_ADDR(msg, RTA_PREFSRC, addr);
00322
00323 NLA_PUT_U32(msg, RTA_PRIORITY, rtnl_route_get_prio(tmpl));
00324
00325 oif = rtnl_route_get_oif(tmpl);
00326 if (oif != RTNL_LINK_NOT_FOUND)
00327 NLA_PUT_U32(msg, RTA_OIF, oif);
00328
00329 for (i = 1; i <= RTAX_MAX; i++)
00330 if (rtnl_route_get_metric(tmpl, i) != UINT_MAX)
00331 nmetrics++;
00332
00333 if (nmetrics > 0) {
00334 unsigned int val;
00335
00336 metrics = nla_nest_start(msg, RTA_METRICS);
00337 if (metrics == NULL)
00338 goto nla_put_failure;
00339
00340 for (i = 1; i <= RTAX_MAX; i++) {
00341 val = rtnl_route_get_metric(tmpl, i);
00342 if (val != UINT_MAX)
00343 NLA_PUT_U32(msg, i, val);
00344 }
00345
00346 nla_nest_end(msg, metrics);
00347 }
00348
00349 #if 0
00350 RTA_IIF,
00351 RTA_MULTIPATH,
00352 RTA_PROTOINFO,
00353 RTA_FLOW,
00354 RTA_CACHEINFO,
00355 RTA_SESSION,
00356 RTA_MP_ALGO,
00357 #endif
00358
00359 return msg;
00360
00361 nla_put_failure:
00362 nlmsg_free(msg);
00363 return NULL;
00364 }
00365
00366 struct nl_msg *rtnl_route_build_add_request(struct rtnl_route *tmpl, int flags)
00367 {
00368 return build_route_msg(tmpl, RTM_NEWROUTE, NLM_F_CREATE | flags);
00369 }
00370
00371 int rtnl_route_add(struct nl_handle *handle, struct rtnl_route *route,
00372 int flags)
00373 {
00374 struct nl_msg *msg;
00375 int err;
00376
00377 msg = rtnl_route_build_add_request(route, flags);
00378 if (!msg)
00379 return nl_get_errno();
00380
00381 err = nl_send_auto_complete(handle, msg);
00382 nlmsg_free(msg);
00383 if (err < 0)
00384 return err;
00385
00386 return nl_wait_for_ack(handle);
00387 }
00388
00389 struct nl_msg *rtnl_route_build_del_request(struct rtnl_route *tmpl, int flags)
00390 {
00391 return build_route_msg(tmpl, RTM_DELROUTE, flags);
00392 }
00393
00394 int rtnl_route_del(struct nl_handle *handle, struct rtnl_route *route,
00395 int flags)
00396 {
00397 struct nl_msg *msg;
00398 int err;
00399
00400 msg = rtnl_route_build_del_request(route, flags);
00401 if (!msg)
00402 return nl_get_errno();
00403
00404 err = nl_send_auto_complete(handle, msg);
00405 nlmsg_free(msg);
00406 if (err < 0)
00407 return err;
00408
00409 return nl_wait_for_ack(handle);
00410 }
00411
00412
00413
00414 static struct nl_af_group route_groups[] = {
00415 { AF_INET, RTNLGRP_IPV4_ROUTE },
00416 { AF_INET6, RTNLGRP_IPV6_ROUTE },
00417 { AF_DECnet, RTNLGRP_DECnet_ROUTE },
00418 { END_OF_GROUP_LIST },
00419 };
00420
00421 static struct nl_cache_ops rtnl_route_ops = {
00422 .co_name = "route/route",
00423 .co_hdrsize = sizeof(struct rtmsg),
00424 .co_msgtypes = {
00425 { RTM_NEWROUTE, NL_ACT_NEW, "new" },
00426 { RTM_DELROUTE, NL_ACT_DEL, "del" },
00427 { RTM_GETROUTE, NL_ACT_GET, "get" },
00428 END_OF_MSGTYPES_LIST,
00429 },
00430 .co_protocol = NETLINK_ROUTE,
00431 .co_groups = route_groups,
00432 .co_request_update = route_request_update,
00433 .co_msg_parser = route_msg_parser,
00434 .co_obj_ops = &route_obj_ops,
00435 };
00436
00437 static void __init route_init(void)
00438 {
00439 nl_cache_mngt_register(&rtnl_route_ops);
00440 }
00441
00442 static void __exit route_exit(void)
00443 {
00444 nl_cache_mngt_unregister(&rtnl_route_ops);
00445 }
00446
00447