1 /* NHRP shortcut related functions
2 * Copyright (c) 2014-2015 Timo Teräs
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.
19 #include "nhrp_protocol.h"
21 DEFINE_MTYPE_STATIC(NHRPD
, NHRP_SHORTCUT
, "NHRP shortcut");
23 static struct route_table
*shortcut_rib
[AFI_MAX
];
25 static int nhrp_shortcut_do_purge(struct thread
*t
);
26 static void nhrp_shortcut_delete(struct nhrp_shortcut
*s
);
27 static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut
*s
);
29 static void nhrp_shortcut_check_use(struct nhrp_shortcut
*s
)
31 if (s
->expiring
&& s
->cache
&& s
->cache
->used
) {
32 debugf(NHRP_DEBUG_ROUTE
, "Shortcut %pFX used and expiring",
34 nhrp_shortcut_send_resolution_req(s
);
38 static int nhrp_shortcut_do_expire(struct thread
*t
)
40 struct nhrp_shortcut
*s
= THREAD_ARG(t
);
43 thread_add_timer(master
, nhrp_shortcut_do_purge
, s
, s
->holding_time
/ 3,
46 nhrp_shortcut_check_use(s
);
51 static void nhrp_shortcut_cache_notify(struct notifier_block
*n
,
54 char buf2
[PREFIX_STRLEN
];
56 struct nhrp_shortcut
*s
=
57 container_of(n
, struct nhrp_shortcut
, cache_notifier
);
58 struct nhrp_cache
*c
= s
->cache
;
61 sockunion2str(&c
->remote_addr
, buf2
, sizeof(buf2
));
63 snprintf(buf2
, sizeof(buf2
), "(unspec)");
66 if (!s
->route_installed
) {
67 debugf(NHRP_DEBUG_ROUTE
,
68 "Shortcut: route install %pFX nh %s dev %s",
69 s
->p
, buf2
, c
&& c
->ifp
?
70 c
->ifp
->name
: "<unk>");
72 nhrp_route_announce(1, s
->type
, s
->p
, c
? c
->ifp
: NULL
,
73 c
? &c
->remote_addr
: NULL
, 0);
74 s
->route_installed
= 1;
77 case NOTIFY_CACHE_USED
:
78 nhrp_shortcut_check_use(s
);
80 case NOTIFY_CACHE_DOWN
:
81 case NOTIFY_CACHE_DELETE
:
82 if (s
->route_installed
) {
83 nhrp_route_announce(0, NHRP_CACHE_INVALID
, s
->p
, NULL
,
85 s
->route_installed
= 0;
87 if (cmd
== NOTIFY_CACHE_DELETE
)
88 nhrp_shortcut_delete(s
);
93 static void nhrp_shortcut_update_binding(struct nhrp_shortcut
*s
,
94 enum nhrp_cache_type type
,
95 struct nhrp_cache
*c
, int holding_time
)
100 nhrp_cache_notify_del(s
->cache
, &s
->cache_notifier
);
105 nhrp_cache_notify_add(s
->cache
, &s
->cache_notifier
,
106 nhrp_shortcut_cache_notify
);
107 if (s
->cache
->route_installed
) {
108 /* Force renewal of Zebra announce on prefix
110 s
->route_installed
= 0;
111 debugf(NHRP_DEBUG_ROUTE
,
112 "Shortcut: forcing renewal of zebra announce on prefix change peer %pSU ht %u cur nbma %pSU dev %s",
113 &s
->cache
->remote_addr
, holding_time
,
114 &s
->cache
->cur
.remote_nbma_natoa
,
115 s
->cache
->ifp
->name
);
116 nhrp_shortcut_cache_notify(&s
->cache_notifier
,
120 if (!s
->cache
|| !s
->cache
->route_installed
) {
121 debugf(NHRP_DEBUG_ROUTE
,
122 "Shortcut: notify cache down because cache?%s or ri?%s",
123 s
->cache
? "yes" : "no",
124 s
->cache
? (s
->cache
->route_installed
? "yes"
127 nhrp_shortcut_cache_notify(&s
->cache_notifier
,
131 if (s
->type
== NHRP_CACHE_NEGATIVE
&& !s
->route_installed
) {
132 nhrp_route_announce(1, s
->type
, s
->p
, NULL
, NULL
, 0);
133 s
->route_installed
= 1;
134 } else if (s
->type
== NHRP_CACHE_INVALID
&& s
->route_installed
) {
135 nhrp_route_announce(0, NHRP_CACHE_INVALID
, s
->p
, NULL
, NULL
, 0);
136 s
->route_installed
= 0;
139 THREAD_OFF(s
->t_timer
);
142 s
->holding_time
= holding_time
;
143 thread_add_timer(master
, nhrp_shortcut_do_expire
, s
,
144 2 * holding_time
/ 3, &s
->t_timer
);
148 static void nhrp_shortcut_delete(struct nhrp_shortcut
*s
)
150 struct route_node
*rn
;
151 afi_t afi
= family2afi(PREFIX_FAMILY(s
->p
));
153 THREAD_OFF(s
->t_timer
);
154 nhrp_reqid_free(&nhrp_packet_reqid
, &s
->reqid
);
156 debugf(NHRP_DEBUG_ROUTE
, "Shortcut %pFX purged", s
->p
);
158 nhrp_shortcut_update_binding(s
, NHRP_CACHE_INVALID
, NULL
, 0);
161 rn
= route_node_lookup(shortcut_rib
[afi
], s
->p
);
163 XFREE(MTYPE_NHRP_SHORTCUT
, rn
->info
);
165 route_unlock_node(rn
);
166 route_unlock_node(rn
);
170 static int nhrp_shortcut_do_purge(struct thread
*t
)
172 struct nhrp_shortcut
*s
= THREAD_ARG(t
);
174 nhrp_shortcut_delete(s
);
178 static struct nhrp_shortcut
*nhrp_shortcut_get(struct prefix
*p
)
180 struct nhrp_shortcut
*s
;
181 struct route_node
*rn
;
182 afi_t afi
= family2afi(PREFIX_FAMILY(p
));
184 if (!shortcut_rib
[afi
])
187 rn
= route_node_get(shortcut_rib
[afi
], p
);
189 s
= rn
->info
= XCALLOC(MTYPE_NHRP_SHORTCUT
,
190 sizeof(struct nhrp_shortcut
));
191 s
->type
= NHRP_CACHE_INVALID
;
194 debugf(NHRP_DEBUG_ROUTE
, "Shortcut %pFX created", s
->p
);
197 route_unlock_node(rn
);
202 static void nhrp_shortcut_recv_resolution_rep(struct nhrp_reqid
*reqid
,
205 struct nhrp_packet_parser
*pp
= arg
;
206 struct interface
*ifp
= pp
->ifp
;
207 struct nhrp_interface
*nifp
= ifp
->info
;
208 struct nhrp_shortcut
*s
=
209 container_of(reqid
, struct nhrp_shortcut
, reqid
);
210 struct nhrp_shortcut
*ps
;
211 struct nhrp_extension_header
*ext
;
212 struct nhrp_cie_header
*cie
;
213 struct nhrp_cache
*c
= NULL
;
214 struct nhrp_cache
*c_dst
= NULL
;
215 union sockunion
*proto
, cie_proto
, *nbma
, cie_nbma
, nat_nbma
;
216 struct prefix prefix
, route_prefix
;
218 int holding_time
= pp
->if_ad
->holdtime
;
220 nhrp_reqid_free(&nhrp_packet_reqid
, &s
->reqid
);
221 THREAD_OFF(s
->t_timer
);
222 thread_add_timer(master
, nhrp_shortcut_do_purge
, s
, 1, &s
->t_timer
);
224 if (pp
->hdr
->type
!= NHRP_PACKET_RESOLUTION_REPLY
) {
225 if (pp
->hdr
->type
== NHRP_PACKET_ERROR_INDICATION
226 && pp
->hdr
->u
.error
.code
227 == NHRP_ERROR_PROTOCOL_ADDRESS_UNREACHABLE
) {
228 debugf(NHRP_DEBUG_COMMON
,
229 "Shortcut: Resolution: Protocol address unreachable");
230 nhrp_shortcut_update_binding(s
, NHRP_CACHE_NEGATIVE
,
233 debugf(NHRP_DEBUG_COMMON
,
234 "Shortcut: Resolution failed");
239 /* Minor sanity check */
240 prefix2sockunion(s
->p
, &cie_proto
);
241 if (!sockunion_same(&cie_proto
, &pp
->dst_proto
)) {
242 debugf(NHRP_DEBUG_COMMON
,
243 "Shortcut: Warning dst_proto altered from %pSU to %pSU",
244 &cie_proto
, &pp
->dst_proto
);
248 /* One or more CIEs should be given as reply, we support only one */
249 cie
= nhrp_cie_pull(&pp
->payload
, pp
->hdr
, &cie_nbma
, &cie_proto
);
250 if (!cie
|| cie
->code
!= NHRP_CODE_SUCCESS
) {
251 debugf(NHRP_DEBUG_COMMON
, "Shortcut: CIE code %d",
252 cie
? cie
->code
: -1);
256 proto
= sockunion_family(&cie_proto
) != AF_UNSPEC
? &cie_proto
258 if (cie
->holding_time
)
259 holding_time
= htons(cie
->holding_time
);
262 prefix
.prefixlen
= cie
->prefix_length
;
264 /* Sanity check prefix length */
265 if (prefix
.prefixlen
>= 8 * prefix_blen(&prefix
)
266 || prefix
.prefixlen
== 0) {
267 prefix
.prefixlen
= 8 * prefix_blen(&prefix
);
268 } else if (nhrp_route_address(NULL
, &pp
->dst_proto
, &route_prefix
, NULL
)
269 == NHRP_ROUTE_NBMA_NEXTHOP
) {
270 if (prefix
.prefixlen
< route_prefix
.prefixlen
)
271 prefix
.prefixlen
= route_prefix
.prefixlen
;
274 /* Parse extensions */
275 memset(&nat_nbma
, 0, sizeof(nat_nbma
));
276 while ((ext
= nhrp_ext_pull(&pp
->extensions
, &extpl
)) != NULL
) {
277 switch (htons(ext
->type
) & ~NHRP_EXTENSION_FLAG_COMPULSORY
) {
278 case NHRP_EXTENSION_NAT_ADDRESS
: {
279 struct nhrp_cie_header
*cie_nat
;
282 union sockunion cie_nat_proto
, cie_nat_nbma
;
284 sockunion_family(&cie_nat_proto
) = AF_UNSPEC
;
285 sockunion_family(&cie_nat_nbma
) = AF_UNSPEC
;
286 cie_nat
= nhrp_cie_pull(&extpl
, pp
->hdr
,
289 /* We are interested only in peer CIE */
291 && sockunion_same(&cie_nat_proto
, proto
)) {
292 nat_nbma
= cie_nat_nbma
;
301 /* Update cache entry for the protocol to nbma binding */
302 if (sockunion_family(&nat_nbma
) != AF_UNSPEC
) {
303 debugf(NHRP_DEBUG_COMMON
,
304 "Shortcut: NAT detected (NAT extension) proto %pSU NBMA %pSU claimed-NBMA %pSU",
305 proto
, &nat_nbma
, &cie_nbma
);
308 /* For NHRP resolution reply the cie_nbma in mandatory part is the
309 * address of the actual address of the sender
311 else if (!sockunion_same(&cie_nbma
, &pp
->peer
->vc
->remote
.nbma
)
312 && !nhrp_nhs_match_ip(&pp
->peer
->vc
->remote
.nbma
, nifp
)) {
313 debugf(NHRP_DEBUG_COMMON
,
314 "Shortcut: NAT detected (no NAT Extension) proto %pSU NBMA %pSU claimed-NBMA %pSU",
315 proto
, &pp
->peer
->vc
->remote
.nbma
, &cie_nbma
);
316 nbma
= &pp
->peer
->vc
->remote
.nbma
;
322 debugf(NHRP_DEBUG_COMMON
,
323 "Shortcut: %pFX is at proto %pSU dst_proto %pSU NBMA %pSU cie-holdtime %d",
324 &prefix
, proto
, &pp
->dst_proto
, nbma
,
325 htons(cie
->holding_time
));
327 if (sockunion_family(nbma
)) {
328 c
= nhrp_cache_get(pp
->ifp
, proto
, 1);
330 debugf(NHRP_DEBUG_COMMON
,
331 "Shortcut: cache found, update binding");
332 nhrp_cache_update_binding(c
, NHRP_CACHE_DYNAMIC
,
334 nhrp_peer_get(pp
->ifp
, nbma
),
339 debugf(NHRP_DEBUG_COMMON
,
340 "Shortcut: no cache for proto %pSU", proto
);
343 /* Update cache binding for dst_proto as well */
344 if (sockunion_cmp(proto
, &pp
->dst_proto
)) {
345 c_dst
= nhrp_cache_get(pp
->ifp
, &pp
->dst_proto
, 1);
347 debugf(NHRP_DEBUG_COMMON
,
348 "Shortcut: cache found, update binding");
349 nhrp_cache_update_binding(c_dst
,
352 nhrp_peer_get(pp
->ifp
, nbma
),
357 debugf(NHRP_DEBUG_COMMON
,
358 "Shortcut: no cache for proto %pSU",
364 /* Update shortcut entry for subnet to protocol gw binding */
366 ps
= nhrp_shortcut_get(&prefix
);
369 debugf(NHRP_DEBUG_COMMON
,
370 "Shortcut: calling update_binding");
371 nhrp_shortcut_update_binding(ps
, NHRP_CACHE_DYNAMIC
, c
,
374 debugf(NHRP_DEBUG_COMMON
,
375 "Shortcut: proto diff but no ps");
378 debugf(NHRP_DEBUG_COMMON
,
379 "NO Shortcut because c NULL?%s or same proto?%s",
381 proto
&& pp
&& sockunion_same(proto
, &pp
->dst_proto
)
386 debugf(NHRP_DEBUG_COMMON
, "Shortcut: Resolution reply handled");
389 static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut
*s
)
392 struct nhrp_packet_header
*hdr
;
393 struct interface
*ifp
;
394 struct nhrp_interface
*nifp
;
395 struct nhrp_afi_data
*if_ad
;
396 struct nhrp_peer
*peer
;
397 struct nhrp_cie_header
*cie
;
398 struct nhrp_extension_header
*ext
;
400 if (nhrp_route_address(NULL
, &s
->addr
, NULL
, &peer
)
401 != NHRP_ROUTE_NBMA_NEXTHOP
)
404 if (s
->type
== NHRP_CACHE_INVALID
|| s
->type
== NHRP_CACHE_NEGATIVE
)
405 s
->type
= NHRP_CACHE_INCOMPLETE
;
411 zb
= zbuf_alloc(1500);
412 hdr
= nhrp_packet_push(
413 zb
, NHRP_PACKET_RESOLUTION_REQUEST
, &nifp
->nbma
,
414 &nifp
->afi
[family2afi(sockunion_family(&s
->addr
))].addr
,
417 htonl(nhrp_reqid_alloc(&nhrp_packet_reqid
, &s
->reqid
,
418 nhrp_shortcut_recv_resolution_rep
));
419 hdr
->flags
= htons(NHRP_FLAG_RESOLUTION_SOURCE_IS_ROUTER
420 | NHRP_FLAG_RESOLUTION_AUTHORATIVE
421 | NHRP_FLAG_RESOLUTION_SOURCE_STABLE
);
423 /* RFC2332 - One or zero CIEs, if CIE is present contains:
424 * - Prefix length: widest acceptable prefix we accept (if U set, 0xff)
425 * - MTU: MTU of the source station
426 * - Holding Time: Max time to cache the source information
428 /* FIXME: push CIE for each local protocol address */
429 cie
= nhrp_cie_push(zb
, NHRP_CODE_SUCCESS
, NULL
, NULL
);
430 if_ad
= &nifp
->afi
[family2afi(sockunion_family(&s
->addr
))];
431 cie
->prefix_length
= (if_ad
->flags
& NHRP_IFF_REG_NO_UNIQUE
)
432 ? 8 * sockunion_get_addrlen(&s
->addr
)
434 cie
->holding_time
= htons(if_ad
->holdtime
);
435 cie
->mtu
= htons(if_ad
->mtu
);
436 debugf(NHRP_DEBUG_COMMON
,
437 "Shortcut res_req: set cie ht to %u and mtu to %u. shortcut ht is %u",
438 ntohs(cie
->holding_time
), ntohs(cie
->mtu
), s
->holding_time
);
440 nhrp_ext_request(zb
, hdr
, ifp
);
442 /* Cisco NAT detection extension */
443 hdr
->flags
|= htons(NHRP_FLAG_RESOLUTION_NAT
);
444 ext
= nhrp_ext_push(zb
, hdr
, NHRP_EXTENSION_NAT_ADDRESS
);
445 if (sockunion_family(&nifp
->nat_nbma
) != AF_UNSPEC
) {
446 cie
= nhrp_cie_push(zb
, NHRP_CODE_SUCCESS
, &nifp
->nat_nbma
,
448 cie
->prefix_length
= 8 * sockunion_get_addrlen(&if_ad
->addr
);
449 cie
->mtu
= htons(if_ad
->mtu
);
450 nhrp_ext_complete(zb
, ext
);
453 nhrp_packet_complete(zb
, hdr
);
455 nhrp_peer_send(peer
, zb
);
456 nhrp_peer_unref(peer
);
460 void nhrp_shortcut_initiate(union sockunion
*addr
)
463 struct nhrp_shortcut
*s
;
465 if (!sockunion2hostprefix(addr
, &p
))
468 s
= nhrp_shortcut_get(&p
);
469 if (s
&& s
->type
!= NHRP_CACHE_INCOMPLETE
) {
471 THREAD_OFF(s
->t_timer
);
472 thread_add_timer(master
, nhrp_shortcut_do_purge
, s
, 30,
474 nhrp_shortcut_send_resolution_req(s
);
478 void nhrp_shortcut_init(void)
480 shortcut_rib
[AFI_IP
] = route_table_init();
481 shortcut_rib
[AFI_IP6
] = route_table_init();
484 void nhrp_shortcut_terminate(void)
486 route_table_finish(shortcut_rib
[AFI_IP
]);
487 route_table_finish(shortcut_rib
[AFI_IP6
]);
490 void nhrp_shortcut_foreach(afi_t afi
,
491 void (*cb
)(struct nhrp_shortcut
*, void *),
494 struct route_table
*rt
= shortcut_rib
[afi
];
495 struct route_node
*rn
;
496 route_table_iter_t iter
;
501 route_table_iter_init(&iter
, rt
);
502 while ((rn
= route_table_iter_next(&iter
)) != NULL
) {
506 route_table_iter_cleanup(&iter
);
510 const struct prefix
*p
;
514 void nhrp_shortcut_purge(struct nhrp_shortcut
*s
, int force
)
516 THREAD_OFF(s
->t_timer
);
517 nhrp_reqid_free(&nhrp_packet_reqid
, &s
->reqid
);
520 /* Immediate purge on route with draw or pending shortcut */
521 thread_add_timer_msec(master
, nhrp_shortcut_do_purge
, s
, 5,
524 /* Soft expire - force immediate renewal, but purge
525 * in few seconds to make sure stale route is not
526 * used too long. In practice most purges are caused
527 * by hub bgp change, but target usually stays same.
528 * This allows to keep nhrp route up, and to not
529 * cause temporary rerouting via hubs causing latency
531 thread_add_timer_msec(master
, nhrp_shortcut_do_purge
, s
, 3000,
534 nhrp_shortcut_check_use(s
);
538 static void nhrp_shortcut_purge_prefix(struct nhrp_shortcut
*s
, void *ctx
)
540 struct purge_ctx
*pctx
= ctx
;
542 if (prefix_match(pctx
->p
, s
->p
))
543 nhrp_shortcut_purge(s
, pctx
->deleted
|| !s
->cache
);
546 void nhrp_shortcut_prefix_change(const struct prefix
*p
, int deleted
)
548 struct purge_ctx pctx
= {
549 .p
= p
, .deleted
= deleted
,
551 nhrp_shortcut_foreach(family2afi(PREFIX_FAMILY(p
)),
552 nhrp_shortcut_purge_prefix
, &pctx
);