route.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. /*
  2. * lib/route/route.c Routes
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation version 2.1
  7. * of the License.
  8. *
  9. * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
  10. */
  11. /**
  12. * @ingroup rtnl
  13. * @defgroup route Routing
  14. * @brief
  15. * @{
  16. */
  17. #include <netlink-local.h>
  18. #include <netlink/netlink.h>
  19. #include <netlink/cache.h>
  20. #include <netlink/utils.h>
  21. #include <netlink/data.h>
  22. #include <netlink/route/rtnl.h>
  23. #include <netlink/route/route.h>
  24. #include <netlink/route/link.h>
  25. static struct nl_cache_ops rtnl_route_ops;
  26. static struct nla_policy route_policy[RTA_MAX+1] = {
  27. [RTA_IIF] = { .type = NLA_STRING,
  28. .maxlen = IFNAMSIZ, },
  29. [RTA_OIF] = { .type = NLA_U32 },
  30. [RTA_PRIORITY] = { .type = NLA_U32 },
  31. [RTA_FLOW] = { .type = NLA_U32 },
  32. [RTA_MP_ALGO] = { .type = NLA_U32 },
  33. [RTA_CACHEINFO] = { .minlen = sizeof(struct rta_cacheinfo) },
  34. [RTA_METRICS] = { .type = NLA_NESTED },
  35. [RTA_MULTIPATH] = { .type = NLA_NESTED },
  36. };
  37. static void copy_cacheinfo_into_route(struct rta_cacheinfo *ci,
  38. struct rtnl_route *route)
  39. {
  40. struct rtnl_rtcacheinfo nci = {
  41. .rtci_clntref = ci->rta_clntref,
  42. .rtci_last_use = ci->rta_lastuse,
  43. .rtci_expires = ci->rta_expires,
  44. .rtci_error = ci->rta_error,
  45. .rtci_used = ci->rta_used,
  46. .rtci_id = ci->rta_id,
  47. .rtci_ts = ci->rta_ts,
  48. .rtci_tsage = ci->rta_tsage,
  49. };
  50. rtnl_route_set_cacheinfo(route, &nci);
  51. }
  52. static int route_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
  53. struct nlmsghdr *nlh, struct nl_parser_param *pp)
  54. {
  55. struct rtmsg *rtm;
  56. struct rtnl_route *route;
  57. struct nlattr *tb[RTA_MAX + 1];
  58. struct nl_addr *src = NULL, *dst = NULL, *addr;
  59. int err;
  60. route = rtnl_route_alloc();
  61. if (!route) {
  62. err = nl_errno(ENOMEM);
  63. goto errout;
  64. }
  65. route->ce_msgtype = nlh->nlmsg_type;
  66. err = nlmsg_parse(nlh, sizeof(struct rtmsg), tb, RTA_MAX,
  67. route_policy);
  68. if (err < 0)
  69. goto errout;
  70. rtm = nlmsg_data(nlh);
  71. rtnl_route_set_family(route, rtm->rtm_family);
  72. rtnl_route_set_tos(route, rtm->rtm_tos);
  73. rtnl_route_set_table(route, rtm->rtm_table);
  74. rtnl_route_set_type(route, rtm->rtm_type);
  75. rtnl_route_set_scope(route, rtm->rtm_scope);
  76. rtnl_route_set_protocol(route, rtm->rtm_protocol);
  77. rtnl_route_set_flags(route, rtm->rtm_flags);
  78. if (tb[RTA_DST]) {
  79. dst = nla_get_addr(tb[RTA_DST], rtm->rtm_family);
  80. if (dst == NULL)
  81. goto errout_errno;
  82. } else {
  83. dst = nl_addr_alloc(0);
  84. nl_addr_set_family(dst, rtm->rtm_family);
  85. }
  86. nl_addr_set_prefixlen(dst, rtm->rtm_dst_len);
  87. err = rtnl_route_set_dst(route, dst);
  88. if (err < 0)
  89. goto errout;
  90. nl_addr_put(dst);
  91. if (tb[RTA_SRC]) {
  92. src = nla_get_addr(tb[RTA_SRC], rtm->rtm_family);
  93. if (src == NULL)
  94. goto errout_errno;
  95. } else if (rtm->rtm_src_len)
  96. src = nl_addr_alloc(0);
  97. if (src) {
  98. nl_addr_set_prefixlen(src, rtm->rtm_src_len);
  99. rtnl_route_set_src(route, src);
  100. nl_addr_put(src);
  101. }
  102. if (tb[RTA_IIF])
  103. rtnl_route_set_iif(route, nla_get_string(tb[RTA_IIF]));
  104. if (tb[RTA_OIF])
  105. rtnl_route_set_oif(route, nla_get_u32(tb[RTA_OIF]));
  106. if (tb[RTA_GATEWAY]) {
  107. addr = nla_get_addr(tb[RTA_GATEWAY], route->rt_family);
  108. if (addr == NULL)
  109. goto errout_errno;
  110. rtnl_route_set_gateway(route, addr);
  111. nl_addr_put(addr);
  112. }
  113. if (tb[RTA_PRIORITY])
  114. rtnl_route_set_prio(route, nla_get_u32(tb[RTA_PRIORITY]));
  115. if (tb[RTA_PREFSRC]) {
  116. addr = nla_get_addr(tb[RTA_PREFSRC], route->rt_family);
  117. if (addr == NULL)
  118. goto errout_errno;
  119. rtnl_route_set_pref_src(route, addr);
  120. nl_addr_put(addr);
  121. }
  122. if (tb[RTA_METRICS]) {
  123. struct nlattr *mtb[RTAX_MAX + 1];
  124. int i;
  125. err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL);
  126. if (err < 0)
  127. goto errout;
  128. for (i = 1; i <= RTAX_MAX; i++) {
  129. if (mtb[i] && nla_len(mtb[i]) >= sizeof(uint32_t)) {
  130. uint32_t m = nla_get_u32(mtb[i]);
  131. if (rtnl_route_set_metric(route, i, m) < 0)
  132. goto errout_errno;
  133. }
  134. }
  135. }
  136. if (tb[RTA_MULTIPATH]) {
  137. struct rtnl_nexthop *nh;
  138. struct rtnexthop *rtnh = nla_data(tb[RTA_MULTIPATH]);
  139. size_t tlen = nla_len(tb[RTA_MULTIPATH]);
  140. while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) {
  141. nh = rtnl_route_nh_alloc();
  142. if (!nh)
  143. goto errout;
  144. rtnl_route_nh_set_weight(nh, rtnh->rtnh_hops);
  145. rtnl_route_nh_set_ifindex(nh, rtnh->rtnh_ifindex);
  146. rtnl_route_nh_set_flags(nh, rtnh->rtnh_flags);
  147. if (rtnh->rtnh_len > sizeof(*rtnh)) {
  148. struct nlattr *ntb[RTA_MAX + 1];
  149. nla_parse(ntb, RTA_MAX, (struct nlattr *)
  150. RTNH_DATA(rtnh),
  151. rtnh->rtnh_len - sizeof(*rtnh),
  152. route_policy);
  153. if (ntb[RTA_GATEWAY]) {
  154. nh->rtnh_gateway = nla_get_addr(
  155. ntb[RTA_GATEWAY],
  156. route->rt_family);
  157. nh->rtnh_mask = NEXTHOP_HAS_GATEWAY;
  158. }
  159. }
  160. rtnl_route_add_nexthop(route, nh);
  161. tlen -= RTNH_ALIGN(rtnh->rtnh_len);
  162. rtnh = RTNH_NEXT(rtnh);
  163. }
  164. }
  165. if (tb[RTA_FLOW])
  166. rtnl_route_set_realms(route, nla_get_u32(tb[RTA_FLOW]));
  167. if (tb[RTA_CACHEINFO])
  168. copy_cacheinfo_into_route(nla_data(tb[RTA_CACHEINFO]), route);
  169. if (tb[RTA_MP_ALGO])
  170. rtnl_route_set_mp_algo(route, nla_get_u32(tb[RTA_MP_ALGO]));
  171. err = pp->pp_cb((struct nl_object *) route, pp);
  172. if (err < 0)
  173. goto errout;
  174. err = P_ACCEPT;
  175. errout:
  176. rtnl_route_put(route);
  177. return err;
  178. errout_errno:
  179. err = nl_get_errno();
  180. goto errout;
  181. }
  182. static int route_request_update(struct nl_cache *c, struct nl_handle *h)
  183. {
  184. return nl_rtgen_request(h, RTM_GETROUTE, AF_UNSPEC, NLM_F_DUMP);
  185. }
  186. /**
  187. * @name Cache Management
  188. * @{
  189. */
  190. /**
  191. * Build a route cache holding all routes currently configured in the kernel
  192. * @arg handle netlink handle
  193. *
  194. * Allocates a new cache, initializes it properly and updates it to
  195. * contain all routes currently configured in the kernel.
  196. *
  197. * @note The caller is responsible for destroying and freeing the
  198. * cache after using it.
  199. * @return The cache or NULL if an error has occured.
  200. */
  201. struct nl_cache *rtnl_route_alloc_cache(struct nl_handle *handle)
  202. {
  203. struct nl_cache *cache;
  204. cache = nl_cache_alloc(&rtnl_route_ops);
  205. if (!cache)
  206. return NULL;
  207. if (handle && nl_cache_refill(handle, cache) < 0) {
  208. free(cache);
  209. return NULL;
  210. }
  211. return cache;
  212. }
  213. /** @} */
  214. /**
  215. * @name Route Addition
  216. * @{
  217. */
  218. static struct nl_msg *build_route_msg(struct rtnl_route *tmpl, int cmd,
  219. int flags)
  220. {
  221. struct nl_msg *msg;
  222. struct nl_addr *addr;
  223. int scope, i, oif, nmetrics = 0;
  224. struct nlattr *metrics;
  225. struct rtmsg rtmsg = {
  226. .rtm_family = rtnl_route_get_family(tmpl),
  227. .rtm_dst_len = rtnl_route_get_dst_len(tmpl),
  228. .rtm_src_len = rtnl_route_get_src_len(tmpl),
  229. .rtm_tos = rtnl_route_get_tos(tmpl),
  230. .rtm_table = rtnl_route_get_table(tmpl),
  231. .rtm_type = rtnl_route_get_type(tmpl),
  232. .rtm_protocol = rtnl_route_get_protocol(tmpl),
  233. .rtm_flags = rtnl_route_get_flags(tmpl),
  234. };
  235. if (rtmsg.rtm_family == AF_UNSPEC) {
  236. nl_error(EINVAL, "Cannot build route message, address " \
  237. "family is unknown.");
  238. return NULL;
  239. }
  240. scope = rtnl_route_get_scope(tmpl);
  241. if (scope == RT_SCOPE_NOWHERE) {
  242. if (rtmsg.rtm_type == RTN_LOCAL)
  243. scope = RT_SCOPE_HOST;
  244. else {
  245. /* XXX Change to UNIVERSE if gw || nexthops */
  246. scope = RT_SCOPE_LINK;
  247. }
  248. }
  249. rtmsg.rtm_scope = scope;
  250. msg = nlmsg_alloc_simple(cmd, flags);
  251. if (msg == NULL)
  252. return NULL;
  253. if (nlmsg_append(msg, &rtmsg, sizeof(rtmsg), NLMSG_ALIGNTO) < 0)
  254. goto nla_put_failure;
  255. addr = rtnl_route_get_dst(tmpl);
  256. if (addr)
  257. NLA_PUT_ADDR(msg, RTA_DST, addr);
  258. addr = rtnl_route_get_src(tmpl);
  259. if (addr)
  260. NLA_PUT_ADDR(msg, RTA_SRC, addr);
  261. addr = rtnl_route_get_gateway(tmpl);
  262. if (addr)
  263. NLA_PUT_ADDR(msg, RTA_GATEWAY, addr);
  264. addr = rtnl_route_get_pref_src(tmpl);
  265. if (addr)
  266. NLA_PUT_ADDR(msg, RTA_PREFSRC, addr);
  267. NLA_PUT_U32(msg, RTA_PRIORITY, rtnl_route_get_prio(tmpl));
  268. oif = rtnl_route_get_oif(tmpl);
  269. if (oif != RTNL_LINK_NOT_FOUND)
  270. NLA_PUT_U32(msg, RTA_OIF, oif);
  271. for (i = 1; i <= RTAX_MAX; i++)
  272. if (rtnl_route_get_metric(tmpl, i) != UINT_MAX)
  273. nmetrics++;
  274. if (nmetrics > 0) {
  275. unsigned int val;
  276. metrics = nla_nest_start(msg, RTA_METRICS);
  277. if (metrics == NULL)
  278. goto nla_put_failure;
  279. for (i = 1; i <= RTAX_MAX; i++) {
  280. val = rtnl_route_get_metric(tmpl, i);
  281. if (val != UINT_MAX)
  282. NLA_PUT_U32(msg, i, val);
  283. }
  284. nla_nest_end(msg, metrics);
  285. }
  286. #if 0
  287. RTA_IIF,
  288. RTA_MULTIPATH,
  289. RTA_PROTOINFO,
  290. RTA_FLOW,
  291. RTA_CACHEINFO,
  292. RTA_SESSION,
  293. RTA_MP_ALGO,
  294. #endif
  295. return msg;
  296. nla_put_failure:
  297. nlmsg_free(msg);
  298. return NULL;
  299. }
  300. struct nl_msg *rtnl_route_build_add_request(struct rtnl_route *tmpl, int flags)
  301. {
  302. return build_route_msg(tmpl, RTM_NEWROUTE, NLM_F_CREATE | flags);
  303. }
  304. int rtnl_route_add(struct nl_handle *handle, struct rtnl_route *route,
  305. int flags)
  306. {
  307. struct nl_msg *msg;
  308. int err;
  309. msg = rtnl_route_build_add_request(route, flags);
  310. if (!msg)
  311. return nl_get_errno();
  312. err = nl_send_auto_complete(handle, msg);
  313. nlmsg_free(msg);
  314. if (err < 0)
  315. return err;
  316. return nl_wait_for_ack(handle);
  317. }
  318. struct nl_msg *rtnl_route_build_del_request(struct rtnl_route *tmpl, int flags)
  319. {
  320. return build_route_msg(tmpl, RTM_DELROUTE, flags);
  321. }
  322. int rtnl_route_del(struct nl_handle *handle, struct rtnl_route *route,
  323. int flags)
  324. {
  325. struct nl_msg *msg;
  326. int err;
  327. msg = rtnl_route_build_del_request(route, flags);
  328. if (!msg)
  329. return nl_get_errno();
  330. err = nl_send_auto_complete(handle, msg);
  331. nlmsg_free(msg);
  332. if (err < 0)
  333. return err;
  334. return nl_wait_for_ack(handle);
  335. }
  336. /** @} */
  337. static struct nl_af_group route_groups[] = {
  338. { AF_INET, RTNLGRP_IPV4_ROUTE },
  339. { AF_INET6, RTNLGRP_IPV6_ROUTE },
  340. { AF_DECnet, RTNLGRP_DECnet_ROUTE },
  341. { END_OF_GROUP_LIST },
  342. };
  343. static struct nl_cache_ops rtnl_route_ops = {
  344. .co_name = "route/route",
  345. .co_hdrsize = sizeof(struct rtmsg),
  346. .co_msgtypes = {
  347. { RTM_NEWROUTE, NL_ACT_NEW, "new" },
  348. { RTM_DELROUTE, NL_ACT_DEL, "del" },
  349. { RTM_GETROUTE, NL_ACT_GET, "get" },
  350. END_OF_MSGTYPES_LIST,
  351. },
  352. .co_protocol = NETLINK_ROUTE,
  353. .co_groups = route_groups,
  354. .co_request_update = route_request_update,
  355. .co_msg_parser = route_msg_parser,
  356. .co_obj_ops = &route_obj_ops,
  357. };
  358. static void __init route_init(void)
  359. {
  360. nl_cache_mngt_register(&rtnl_route_ops);
  361. }
  362. static void __exit route_exit(void)
  363. {
  364. nl_cache_mngt_unregister(&rtnl_route_ops);
  365. }
  366. /** @} */