nhrp_shortcut.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /* NHRP shortcut related functions
  2. * Copyright (c) 2014-2015 Timo Teräs
  3. *
  4. * This file is free software: you may copy, redistribute and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 2 of the License, or
  7. * (at your option) any later version.
  8. */
  9. #include "nhrpd.h"
  10. #include "table.h"
  11. #include "memory.h"
  12. #include "thread.h"
  13. #include "log.h"
  14. #include "nhrp_protocol.h"
  15. static struct route_table *shortcut_rib[AFI_MAX];
  16. static int nhrp_shortcut_do_purge(struct thread *t);
  17. static void nhrp_shortcut_delete(struct nhrp_shortcut *s);
  18. static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s);
  19. static void nhrp_shortcut_check_use(struct nhrp_shortcut *s)
  20. {
  21. char buf[PREFIX_STRLEN];
  22. if (s->expiring && s->cache && s->cache->used) {
  23. debugf(NHRP_DEBUG_ROUTE, "Shortcut %s used and expiring",
  24. prefix2str(s->p, buf, sizeof buf));
  25. nhrp_shortcut_send_resolution_req(s);
  26. }
  27. }
  28. static int nhrp_shortcut_do_expire(struct thread *t)
  29. {
  30. struct nhrp_shortcut *s = THREAD_ARG(t);
  31. s->t_timer = NULL;
  32. THREAD_TIMER_ON(master, s->t_timer, nhrp_shortcut_do_purge, s, s->holding_time/3);
  33. s->expiring = 1;
  34. nhrp_shortcut_check_use(s);
  35. return 0;
  36. }
  37. static void nhrp_shortcut_cache_notify(struct notifier_block *n, unsigned long cmd)
  38. {
  39. struct nhrp_shortcut *s = container_of(n, struct nhrp_shortcut, cache_notifier);
  40. switch (cmd) {
  41. case NOTIFY_CACHE_UP:
  42. if (!s->route_installed) {
  43. nhrp_route_announce(1, s->type, s->p, NULL, &s->cache->remote_addr, 0);
  44. s->route_installed = 1;
  45. }
  46. break;
  47. case NOTIFY_CACHE_USED:
  48. nhrp_shortcut_check_use(s);
  49. break;
  50. case NOTIFY_CACHE_DOWN:
  51. case NOTIFY_CACHE_DELETE:
  52. if (s->route_installed) {
  53. nhrp_route_announce(0, NHRP_CACHE_INVALID, s->p, NULL, NULL, 0);
  54. s->route_installed = 0;
  55. }
  56. if (cmd == NOTIFY_CACHE_DELETE)
  57. nhrp_shortcut_delete(s);
  58. break;
  59. }
  60. }
  61. static void nhrp_shortcut_update_binding(struct nhrp_shortcut *s, enum nhrp_cache_type type, struct nhrp_cache *c, int holding_time)
  62. {
  63. s->type = type;
  64. if (c != s->cache) {
  65. if (s->cache) {
  66. nhrp_cache_notify_del(s->cache, &s->cache_notifier);
  67. s->cache = NULL;
  68. }
  69. s->cache = c;
  70. if (s->cache) {
  71. nhrp_cache_notify_add(s->cache, &s->cache_notifier, nhrp_shortcut_cache_notify);
  72. if (s->cache->route_installed) {
  73. /* Force renewal of Zebra announce on prefix change */
  74. s->route_installed = 0;
  75. nhrp_shortcut_cache_notify(&s->cache_notifier, NOTIFY_CACHE_UP);
  76. }
  77. }
  78. if (!s->cache || !s->cache->route_installed)
  79. nhrp_shortcut_cache_notify(&s->cache_notifier, NOTIFY_CACHE_DOWN);
  80. }
  81. if (s->type == NHRP_CACHE_NEGATIVE && !s->route_installed) {
  82. nhrp_route_announce(1, s->type, s->p, NULL, NULL, 0);
  83. s->route_installed = 1;
  84. } else if (s->type == NHRP_CACHE_INVALID && s->route_installed) {
  85. nhrp_route_announce(0, NHRP_CACHE_INVALID, s->p, NULL, NULL, 0);
  86. s->route_installed = 0;
  87. }
  88. THREAD_OFF(s->t_timer);
  89. if (holding_time) {
  90. s->expiring = 0;
  91. s->holding_time = holding_time;
  92. THREAD_TIMER_ON(master, s->t_timer, nhrp_shortcut_do_expire, s, 2*holding_time/3);
  93. }
  94. }
  95. static void nhrp_shortcut_delete(struct nhrp_shortcut *s)
  96. {
  97. struct route_node *rn;
  98. afi_t afi = family2afi(PREFIX_FAMILY(s->p));
  99. char buf[PREFIX_STRLEN];
  100. THREAD_OFF(s->t_timer);
  101. nhrp_reqid_free(&nhrp_packet_reqid, &s->reqid);
  102. debugf(NHRP_DEBUG_ROUTE, "Shortcut %s purged",
  103. prefix2str(s->p, buf, sizeof buf));
  104. nhrp_shortcut_update_binding(s, NHRP_CACHE_INVALID, NULL, 0);
  105. /* Delete node */
  106. rn = route_node_lookup(shortcut_rib[afi], s->p);
  107. if (rn) {
  108. XFREE(MTYPE_NHRP_SHORTCUT, rn->info);
  109. rn->info = NULL;
  110. route_unlock_node(rn);
  111. route_unlock_node(rn);
  112. }
  113. }
  114. static int nhrp_shortcut_do_purge(struct thread *t)
  115. {
  116. struct nhrp_shortcut *s = THREAD_ARG(t);
  117. s->t_timer = NULL;
  118. nhrp_shortcut_delete(s);
  119. return 0;
  120. }
  121. static struct nhrp_shortcut *nhrp_shortcut_get(struct prefix *p)
  122. {
  123. struct nhrp_shortcut *s;
  124. struct route_node *rn;
  125. char buf[PREFIX_STRLEN];
  126. afi_t afi = family2afi(PREFIX_FAMILY(p));
  127. if (!shortcut_rib[afi])
  128. return 0;
  129. rn = route_node_get(shortcut_rib[afi], p);
  130. if (!rn->info) {
  131. s = rn->info = XCALLOC(MTYPE_NHRP_SHORTCUT, sizeof(struct nhrp_shortcut));
  132. s->type = NHRP_CACHE_INVALID;
  133. s->p = &rn->p;
  134. debugf(NHRP_DEBUG_ROUTE, "Shortcut %s created",
  135. prefix2str(s->p, buf, sizeof buf));
  136. } else {
  137. s = rn->info;
  138. route_unlock_node(rn);
  139. }
  140. return s;
  141. }
  142. static void nhrp_shortcut_recv_resolution_rep(struct nhrp_reqid *reqid, void *arg)
  143. {
  144. struct nhrp_packet_parser *pp = arg;
  145. struct nhrp_shortcut *s = container_of(reqid, struct nhrp_shortcut, reqid);
  146. struct nhrp_shortcut *ps;
  147. struct nhrp_extension_header *ext;
  148. struct nhrp_cie_header *cie;
  149. struct nhrp_cache *c = NULL;
  150. union sockunion *proto, cie_proto, *nbma, *nbma_natoa, cie_nbma, nat_nbma;
  151. struct prefix prefix, route_prefix;
  152. struct zbuf extpl;
  153. char bufp[PREFIX_STRLEN], buf[3][SU_ADDRSTRLEN];
  154. int holding_time = pp->if_ad->holdtime;
  155. nhrp_reqid_free(&nhrp_packet_reqid, &s->reqid);
  156. THREAD_OFF(s->t_timer);
  157. THREAD_TIMER_ON(master, s->t_timer, nhrp_shortcut_do_purge, s, 1);
  158. if (pp->hdr->type != NHRP_PACKET_RESOLUTION_REPLY) {
  159. if (pp->hdr->type == NHRP_PACKET_ERROR_INDICATION &&
  160. pp->hdr->u.error.code == NHRP_ERROR_PROTOCOL_ADDRESS_UNREACHABLE) {
  161. debugf(NHRP_DEBUG_COMMON, "Shortcut: Resolution: Protocol address unreachable");
  162. nhrp_shortcut_update_binding(s, NHRP_CACHE_NEGATIVE, NULL, holding_time);
  163. } else {
  164. debugf(NHRP_DEBUG_COMMON, "Shortcut: Resolution failed");
  165. }
  166. return;
  167. }
  168. /* Parse extensions */
  169. memset(&nat_nbma, 0, sizeof nat_nbma);
  170. while ((ext = nhrp_ext_pull(&pp->extensions, &extpl)) != NULL) {
  171. switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) {
  172. case NHRP_EXTENSION_NAT_ADDRESS:
  173. nhrp_cie_pull(&extpl, pp->hdr, &nat_nbma, &cie_proto);
  174. break;
  175. }
  176. }
  177. /* Minor sanity check */
  178. prefix2sockunion(s->p, &cie_proto);
  179. if (!sockunion_same(&cie_proto, &pp->dst_proto)) {
  180. debugf(NHRP_DEBUG_COMMON, "Shortcut: Warning dst_proto altered from %s to %s",
  181. sockunion2str(&cie_proto, buf[0], sizeof buf[0]),
  182. sockunion2str(&pp->dst_proto, buf[1], sizeof buf[1]));
  183. }
  184. /* One or more CIEs should be given as reply, we support only one */
  185. cie = nhrp_cie_pull(&pp->payload, pp->hdr, &cie_nbma, &cie_proto);
  186. if (!cie || cie->code != NHRP_CODE_SUCCESS) {
  187. debugf(NHRP_DEBUG_COMMON, "Shortcut: CIE code %d", cie ? cie->code : -1);
  188. return;
  189. }
  190. proto = sockunion_family(&cie_proto) != AF_UNSPEC ? &cie_proto : &pp->dst_proto;
  191. if (cie->holding_time)
  192. holding_time = htons(cie->holding_time);
  193. prefix = *s->p;
  194. prefix.prefixlen = cie->prefix_length;
  195. /* Sanity check prefix length */
  196. if (prefix.prefixlen >= 8*prefix_blen(&prefix) || prefix.prefixlen == 0) {
  197. prefix.prefixlen = 8*prefix_blen(&prefix);
  198. } else if (nhrp_route_address(NULL, &pp->dst_proto, &route_prefix, NULL) == NHRP_ROUTE_NBMA_NEXTHOP) {
  199. if (prefix.prefixlen < route_prefix.prefixlen)
  200. prefix.prefixlen = route_prefix.prefixlen;
  201. }
  202. debugf(NHRP_DEBUG_COMMON, "Shortcut: %s is at proto %s cie-nbma %s nat-nbma %s cie-holdtime %d",
  203. prefix2str(&prefix, bufp, sizeof bufp),
  204. sockunion2str(proto, buf[0], sizeof buf[0]),
  205. sockunion2str(&cie_nbma, buf[1], sizeof buf[1]),
  206. sockunion2str(&nat_nbma, buf[2], sizeof buf[2]),
  207. htons(cie->holding_time));
  208. /* Update cache entry for the protocol to nbma binding */
  209. if (sockunion_family(&nat_nbma) != AF_UNSPEC) {
  210. nbma = &nat_nbma;
  211. nbma_natoa = &cie_nbma;
  212. } else {
  213. nbma = &cie_nbma;
  214. nbma_natoa = NULL;
  215. }
  216. if (sockunion_family(nbma)) {
  217. c = nhrp_cache_get(pp->ifp, proto, 1);
  218. if (c) {
  219. nhrp_cache_update_binding(
  220. c, NHRP_CACHE_CACHED, holding_time,
  221. nhrp_peer_get(pp->ifp, nbma),
  222. htons(cie->mtu), nbma_natoa);
  223. }
  224. }
  225. /* Update shortcut entry for subnet to protocol gw binding */
  226. if (c && !sockunion_same(proto, &pp->dst_proto)) {
  227. ps = nhrp_shortcut_get(&prefix);
  228. if (ps) {
  229. ps->addr = s->addr;
  230. nhrp_shortcut_update_binding(ps, NHRP_CACHE_CACHED, c, holding_time);
  231. }
  232. }
  233. debugf(NHRP_DEBUG_COMMON, "Shortcut: Resolution reply handled");
  234. }
  235. static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s)
  236. {
  237. struct zbuf *zb;
  238. struct nhrp_packet_header *hdr;
  239. struct interface *ifp;
  240. struct nhrp_interface *nifp;
  241. struct nhrp_peer *peer;
  242. if (nhrp_route_address(NULL, &s->addr, NULL, &peer) != NHRP_ROUTE_NBMA_NEXTHOP)
  243. return;
  244. if (s->type == NHRP_CACHE_INVALID || s->type == NHRP_CACHE_NEGATIVE)
  245. s->type = NHRP_CACHE_INCOMPLETE;
  246. ifp = peer->ifp;
  247. nifp = ifp->info;
  248. /* Create request */
  249. zb = zbuf_alloc(1500);
  250. hdr = nhrp_packet_push(zb, NHRP_PACKET_RESOLUTION_REQUEST,
  251. &nifp->nbma, &nifp->afi[family2afi(sockunion_family(&s->addr))].addr, &s->addr);
  252. hdr->u.request_id = htonl(nhrp_reqid_alloc(&nhrp_packet_reqid, &s->reqid, nhrp_shortcut_recv_resolution_rep));
  253. hdr->flags = htons(NHRP_FLAG_RESOLUTION_SOURCE_IS_ROUTER |
  254. NHRP_FLAG_RESOLUTION_AUTHORATIVE |
  255. NHRP_FLAG_RESOLUTION_SOURCE_STABLE);
  256. /* RFC2332 - One or zero CIEs, if CIE is present contains:
  257. * - Prefix length: widest acceptable prefix we accept (if U set, 0xff)
  258. * - MTU: MTU of the source station
  259. * - Holding Time: Max time to cache the source information
  260. * */
  261. /* FIXME: Send holding time, and MTU */
  262. nhrp_ext_request(zb, hdr, ifp);
  263. /* Cisco NAT detection extension */
  264. hdr->flags |= htons(NHRP_FLAG_RESOLUTION_NAT);
  265. nhrp_ext_push(zb, hdr, NHRP_EXTENSION_NAT_ADDRESS);
  266. nhrp_packet_complete(zb, hdr);
  267. nhrp_peer_send(peer, zb);
  268. nhrp_peer_unref(peer);
  269. zbuf_free(zb);
  270. }
  271. void nhrp_shortcut_initiate(union sockunion *addr)
  272. {
  273. struct prefix p;
  274. struct nhrp_shortcut *s;
  275. sockunion2hostprefix(addr, &p);
  276. s = nhrp_shortcut_get(&p);
  277. if (s && s->type != NHRP_CACHE_INCOMPLETE) {
  278. s->addr = *addr;
  279. THREAD_OFF(s->t_timer);
  280. THREAD_TIMER_ON(master, s->t_timer, nhrp_shortcut_do_purge, s, 30);
  281. nhrp_shortcut_send_resolution_req(s);
  282. }
  283. }
  284. void nhrp_shortcut_init(void)
  285. {
  286. shortcut_rib[AFI_IP] = route_table_init();
  287. shortcut_rib[AFI_IP6] = route_table_init();
  288. }
  289. void nhrp_shortcut_terminate(void)
  290. {
  291. route_table_finish(shortcut_rib[AFI_IP]);
  292. route_table_finish(shortcut_rib[AFI_IP6]);
  293. }
  294. void nhrp_shortcut_foreach(afi_t afi, void (*cb)(struct nhrp_shortcut *, void *), void *ctx)
  295. {
  296. struct route_table *rt = shortcut_rib[afi];
  297. struct route_node *rn;
  298. route_table_iter_t iter;
  299. if (!rt) return;
  300. route_table_iter_init(&iter, rt);
  301. while ((rn = route_table_iter_next(&iter)) != NULL) {
  302. if (rn->info) cb(rn->info, ctx);
  303. }
  304. route_table_iter_cleanup(&iter);
  305. }
  306. struct purge_ctx {
  307. const struct prefix *p;
  308. int deleted;
  309. };
  310. void nhrp_shortcut_purge(struct nhrp_shortcut *s, int force)
  311. {
  312. THREAD_OFF(s->t_timer);
  313. nhrp_reqid_free(&nhrp_packet_reqid, &s->reqid);
  314. if (force) {
  315. /* Immediate purge on route with draw or pending shortcut */
  316. THREAD_TIMER_MSEC_ON(master, s->t_timer, nhrp_shortcut_do_purge, s, 5);
  317. } else {
  318. /* Soft expire - force immediate renewal, but purge
  319. * in few seconds to make sure stale route is not
  320. * used too long. In practice most purges are caused
  321. * by hub bgp change, but target usually stays same.
  322. * This allows to keep nhrp route up, and to not
  323. * cause temporary rerouting via hubs causing latency
  324. * jitter. */
  325. THREAD_TIMER_MSEC_ON(master, s->t_timer, nhrp_shortcut_do_purge, s, 3000);
  326. s->expiring = 1;
  327. nhrp_shortcut_check_use(s);
  328. }
  329. }
  330. static void nhrp_shortcut_purge_prefix(struct nhrp_shortcut *s, void *ctx)
  331. {
  332. struct purge_ctx *pctx = ctx;
  333. if (prefix_match(pctx->p, s->p))
  334. nhrp_shortcut_purge(s, pctx->deleted || !s->cache);
  335. }
  336. void nhrp_shortcut_prefix_change(const struct prefix *p, int deleted)
  337. {
  338. struct purge_ctx pctx = {
  339. .p = p,
  340. .deleted = deleted,
  341. };
  342. nhrp_shortcut_foreach(family2afi(PREFIX_FAMILY(p)), nhrp_shortcut_purge_prefix, &pctx);
  343. }