]> git.proxmox.com Git - mirror_frr.git/blame - nhrpd/nhrp_shortcut.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / nhrpd / nhrp_shortcut.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
2fb975da
TT
2/* NHRP shortcut related functions
3 * Copyright (c) 2014-2015 Timo Teräs
2fb975da
TT
4 */
5
b45ac5f5
DL
6#ifdef HAVE_CONFIG_H
7#include "config.h"
8#endif
9
2fb975da
TT
10#include "nhrpd.h"
11#include "table.h"
12#include "memory.h"
13#include "thread.h"
14#include "log.h"
15#include "nhrp_protocol.h"
16
bf8d3d6a 17DEFINE_MTYPE_STATIC(NHRPD, NHRP_SHORTCUT, "NHRP shortcut");
819dc8bb 18
2fb975da
TT
19static struct route_table *shortcut_rib[AFI_MAX];
20
cc9f21da 21static void nhrp_shortcut_do_purge(struct thread *t);
2fb975da
TT
22static void nhrp_shortcut_delete(struct nhrp_shortcut *s);
23static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s);
24
25static void nhrp_shortcut_check_use(struct nhrp_shortcut *s)
26{
2fb975da 27 if (s->expiring && s->cache && s->cache->used) {
2dbe669b
DA
28 debugf(NHRP_DEBUG_ROUTE, "Shortcut %pFX used and expiring",
29 s->p);
2fb975da
TT
30 nhrp_shortcut_send_resolution_req(s);
31 }
32}
33
cc9f21da 34static void nhrp_shortcut_do_expire(struct thread *t)
2fb975da
TT
35{
36 struct nhrp_shortcut *s = THREAD_ARG(t);
37
996c9314
LB
38 thread_add_timer(master, nhrp_shortcut_do_purge, s, s->holding_time / 3,
39 &s->t_timer);
2fb975da
TT
40 s->expiring = 1;
41 nhrp_shortcut_check_use(s);
2fb975da
TT
42}
43
996c9314
LB
44static void nhrp_shortcut_cache_notify(struct notifier_block *n,
45 unsigned long cmd)
2fb975da 46{
996c9314
LB
47 struct nhrp_shortcut *s =
48 container_of(n, struct nhrp_shortcut, cache_notifier);
ef91ff04 49 struct nhrp_cache *c = s->cache;
2fb975da
TT
50
51 switch (cmd) {
52 case NOTIFY_CACHE_UP:
53 if (!s->route_installed) {
912c556b 54 debugf(NHRP_DEBUG_ROUTE,
47e12884
DA
55 "Shortcut: route install %pFX nh %pSU dev %s",
56 s->p, &c->remote_addr,
57 c && c->ifp ? c->ifp->name : "<unk>");
912c556b 58
ef91ff04
PG
59 nhrp_route_announce(1, s->type, s->p, c ? c->ifp : NULL,
60 c ? &c->remote_addr : NULL, 0);
2fb975da
TT
61 s->route_installed = 1;
62 }
63 break;
64 case NOTIFY_CACHE_USED:
65 nhrp_shortcut_check_use(s);
66 break;
67 case NOTIFY_CACHE_DOWN:
68 case NOTIFY_CACHE_DELETE:
69 if (s->route_installed) {
996c9314
LB
70 nhrp_route_announce(0, NHRP_CACHE_INVALID, s->p, NULL,
71 NULL, 0);
2fb975da
TT
72 s->route_installed = 0;
73 }
74 if (cmd == NOTIFY_CACHE_DELETE)
75 nhrp_shortcut_delete(s);
76 break;
77 }
78}
79
996c9314
LB
80static void nhrp_shortcut_update_binding(struct nhrp_shortcut *s,
81 enum nhrp_cache_type type,
82 struct nhrp_cache *c, int holding_time)
2fb975da
TT
83{
84 s->type = type;
85 if (c != s->cache) {
86 if (s->cache) {
87 nhrp_cache_notify_del(s->cache, &s->cache_notifier);
88 s->cache = NULL;
89 }
90 s->cache = c;
91 if (s->cache) {
996c9314
LB
92 nhrp_cache_notify_add(s->cache, &s->cache_notifier,
93 nhrp_shortcut_cache_notify);
2fb975da 94 if (s->cache->route_installed) {
996c9314
LB
95 /* Force renewal of Zebra announce on prefix
96 * change */
2fb975da 97 s->route_installed = 0;
912c556b 98 debugf(NHRP_DEBUG_ROUTE,
b6c48481
DS
99 "Shortcut: forcing renewal of zebra announce on prefix change peer %pSU ht %u cur nbma %pSU dev %s",
100 &s->cache->remote_addr, holding_time,
101 &s->cache->cur.remote_nbma_natoa,
912c556b 102 s->cache->ifp->name);
996c9314
LB
103 nhrp_shortcut_cache_notify(&s->cache_notifier,
104 NOTIFY_CACHE_UP);
2fb975da
TT
105 }
106 }
912c556b
GN
107 if (!s->cache || !s->cache->route_installed) {
108 debugf(NHRP_DEBUG_ROUTE,
5f36c26c 109 "Shortcut: notify cache down because cache?%s or ri?%s",
912c556b
GN
110 s->cache ? "yes" : "no",
111 s->cache ? (s->cache->route_installed ? "yes"
112 : "no")
113 : "n/a");
996c9314
LB
114 nhrp_shortcut_cache_notify(&s->cache_notifier,
115 NOTIFY_CACHE_DOWN);
912c556b 116 }
2fb975da
TT
117 }
118 if (s->type == NHRP_CACHE_NEGATIVE && !s->route_installed) {
119 nhrp_route_announce(1, s->type, s->p, NULL, NULL, 0);
120 s->route_installed = 1;
121 } else if (s->type == NHRP_CACHE_INVALID && s->route_installed) {
122 nhrp_route_announce(0, NHRP_CACHE_INVALID, s->p, NULL, NULL, 0);
123 s->route_installed = 0;
124 }
125
126 THREAD_OFF(s->t_timer);
127 if (holding_time) {
128 s->expiring = 0;
129 s->holding_time = holding_time;
ffa2c898
QY
130 thread_add_timer(master, nhrp_shortcut_do_expire, s,
131 2 * holding_time / 3, &s->t_timer);
2fb975da
TT
132 }
133}
134
135static void nhrp_shortcut_delete(struct nhrp_shortcut *s)
136{
137 struct route_node *rn;
138 afi_t afi = family2afi(PREFIX_FAMILY(s->p));
2fb975da
TT
139
140 THREAD_OFF(s->t_timer);
141 nhrp_reqid_free(&nhrp_packet_reqid, &s->reqid);
142
2dbe669b 143 debugf(NHRP_DEBUG_ROUTE, "Shortcut %pFX purged", s->p);
2fb975da
TT
144
145 nhrp_shortcut_update_binding(s, NHRP_CACHE_INVALID, NULL, 0);
146
147 /* Delete node */
148 rn = route_node_lookup(shortcut_rib[afi], s->p);
149 if (rn) {
150 XFREE(MTYPE_NHRP_SHORTCUT, rn->info);
912c556b 151 rn->info = NULL;
2fb975da
TT
152 route_unlock_node(rn);
153 route_unlock_node(rn);
154 }
155}
156
cc9f21da 157static void nhrp_shortcut_do_purge(struct thread *t)
2fb975da
TT
158{
159 struct nhrp_shortcut *s = THREAD_ARG(t);
160 s->t_timer = NULL;
161 nhrp_shortcut_delete(s);
2fb975da
TT
162}
163
164static struct nhrp_shortcut *nhrp_shortcut_get(struct prefix *p)
165{
166 struct nhrp_shortcut *s;
167 struct route_node *rn;
2fb975da
TT
168 afi_t afi = family2afi(PREFIX_FAMILY(p));
169
170 if (!shortcut_rib[afi])
171 return 0;
172
173 rn = route_node_get(shortcut_rib[afi], p);
174 if (!rn->info) {
996c9314
LB
175 s = rn->info = XCALLOC(MTYPE_NHRP_SHORTCUT,
176 sizeof(struct nhrp_shortcut));
2fb975da
TT
177 s->type = NHRP_CACHE_INVALID;
178 s->p = &rn->p;
179
2dbe669b 180 debugf(NHRP_DEBUG_ROUTE, "Shortcut %pFX created", s->p);
2fb975da
TT
181 } else {
182 s = rn->info;
183 route_unlock_node(rn);
184 }
185 return s;
186}
187
996c9314
LB
188static void nhrp_shortcut_recv_resolution_rep(struct nhrp_reqid *reqid,
189 void *arg)
2fb975da
TT
190{
191 struct nhrp_packet_parser *pp = arg;
bb58f442
GG
192 struct interface *ifp = pp->ifp;
193 struct nhrp_interface *nifp = ifp->info;
996c9314
LB
194 struct nhrp_shortcut *s =
195 container_of(reqid, struct nhrp_shortcut, reqid);
2fb975da
TT
196 struct nhrp_shortcut *ps;
197 struct nhrp_extension_header *ext;
198 struct nhrp_cie_header *cie;
199 struct nhrp_cache *c = NULL;
00683a14 200 struct nhrp_cache *c_dst = NULL;
912c556b 201 union sockunion *proto, cie_proto, *nbma, cie_nbma, nat_nbma;
2fb975da
TT
202 struct prefix prefix, route_prefix;
203 struct zbuf extpl;
2fb975da
TT
204 int holding_time = pp->if_ad->holdtime;
205
206 nhrp_reqid_free(&nhrp_packet_reqid, &s->reqid);
207 THREAD_OFF(s->t_timer);
ffa2c898 208 thread_add_timer(master, nhrp_shortcut_do_purge, s, 1, &s->t_timer);
2fb975da
TT
209
210 if (pp->hdr->type != NHRP_PACKET_RESOLUTION_REPLY) {
996c9314
LB
211 if (pp->hdr->type == NHRP_PACKET_ERROR_INDICATION
212 && pp->hdr->u.error.code
213 == NHRP_ERROR_PROTOCOL_ADDRESS_UNREACHABLE) {
214 debugf(NHRP_DEBUG_COMMON,
215 "Shortcut: Resolution: Protocol address unreachable");
216 nhrp_shortcut_update_binding(s, NHRP_CACHE_NEGATIVE,
217 NULL, holding_time);
2fb975da 218 } else {
996c9314
LB
219 debugf(NHRP_DEBUG_COMMON,
220 "Shortcut: Resolution failed");
2fb975da
TT
221 }
222 return;
223 }
224
2fb975da
TT
225 /* Minor sanity check */
226 prefix2sockunion(s->p, &cie_proto);
227 if (!sockunion_same(&cie_proto, &pp->dst_proto)) {
996c9314 228 debugf(NHRP_DEBUG_COMMON,
b6c48481
DS
229 "Shortcut: Warning dst_proto altered from %pSU to %pSU",
230 &cie_proto, &pp->dst_proto);
231 ;
2fb975da
TT
232 }
233
234 /* One or more CIEs should be given as reply, we support only one */
235 cie = nhrp_cie_pull(&pp->payload, pp->hdr, &cie_nbma, &cie_proto);
236 if (!cie || cie->code != NHRP_CODE_SUCCESS) {
996c9314
LB
237 debugf(NHRP_DEBUG_COMMON, "Shortcut: CIE code %d",
238 cie ? cie->code : -1);
2fb975da
TT
239 return;
240 }
241
996c9314
LB
242 proto = sockunion_family(&cie_proto) != AF_UNSPEC ? &cie_proto
243 : &pp->dst_proto;
2fb975da
TT
244 if (cie->holding_time)
245 holding_time = htons(cie->holding_time);
246
247 prefix = *s->p;
248 prefix.prefixlen = cie->prefix_length;
249
250 /* Sanity check prefix length */
996c9314
LB
251 if (prefix.prefixlen >= 8 * prefix_blen(&prefix)
252 || prefix.prefixlen == 0) {
253 prefix.prefixlen = 8 * prefix_blen(&prefix);
254 } else if (nhrp_route_address(NULL, &pp->dst_proto, &route_prefix, NULL)
255 == NHRP_ROUTE_NBMA_NEXTHOP) {
2fb975da
TT
256 if (prefix.prefixlen < route_prefix.prefixlen)
257 prefix.prefixlen = route_prefix.prefixlen;
258 }
259
9c292647
AL
260 /* Parse extensions */
261 memset(&nat_nbma, 0, sizeof(nat_nbma));
262 while ((ext = nhrp_ext_pull(&pp->extensions, &extpl)) != NULL) {
263 switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) {
264 case NHRP_EXTENSION_NAT_ADDRESS: {
265 struct nhrp_cie_header *cie_nat;
00683a14 266
9c292647
AL
267 do {
268 union sockunion cie_nat_proto, cie_nat_nbma;
00683a14 269
9c292647
AL
270 sockunion_family(&cie_nat_proto) = AF_UNSPEC;
271 sockunion_family(&cie_nat_nbma) = AF_UNSPEC;
611915ae
AL
272 cie_nat = nhrp_cie_pull(&extpl, pp->hdr,
273 &cie_nat_nbma,
274 &cie_nat_proto);
9c292647 275 /* We are interested only in peer CIE */
611915ae
AL
276 if (cie_nat
277 && sockunion_same(&cie_nat_proto, proto)) {
9c292647
AL
278 nat_nbma = cie_nat_nbma;
279 }
280 } while (cie_nat);
281 } break;
282 default:
283 break;
284 }
285 }
2fb975da
TT
286
287 /* Update cache entry for the protocol to nbma binding */
bb58f442 288 if (sockunion_family(&nat_nbma) != AF_UNSPEC) {
611915ae 289 debugf(NHRP_DEBUG_COMMON,
0551aead 290 "Shortcut: NAT detected (NAT extension) proto %pSU NBMA %pSU claimed-NBMA %pSU",
4ddc702a 291 proto, &nat_nbma, &cie_nbma);
2fb975da 292 nbma = &nat_nbma;
611915ae
AL
293 }
294 /* For NHRP resolution reply the cie_nbma in mandatory part is the
00683a14
RD
295 * address of the actual address of the sender
296 */
611915ae
AL
297 else if (!sockunion_same(&cie_nbma, &pp->peer->vc->remote.nbma)
298 && !nhrp_nhs_match_ip(&pp->peer->vc->remote.nbma, nifp)) {
299 debugf(NHRP_DEBUG_COMMON,
0551aead 300 "Shortcut: NAT detected (no NAT Extension) proto %pSU NBMA %pSU claimed-NBMA %pSU",
4ddc702a 301 proto, &pp->peer->vc->remote.nbma, &cie_nbma);
bb58f442
GG
302 nbma = &pp->peer->vc->remote.nbma;
303 nat_nbma = *nbma;
304 } else {
2fb975da 305 nbma = &cie_nbma;
bb58f442
GG
306 }
307
996c9314 308 debugf(NHRP_DEBUG_COMMON,
4ddc702a
RD
309 "Shortcut: %pFX is at proto %pSU dst_proto %pSU NBMA %pSU cie-holdtime %d",
310 &prefix, proto, &pp->dst_proto, nbma,
996c9314 311 htons(cie->holding_time));
912c556b 312
2fb975da
TT
313 if (sockunion_family(nbma)) {
314 c = nhrp_cache_get(pp->ifp, proto, 1);
315 if (c) {
912c556b
GN
316 debugf(NHRP_DEBUG_COMMON,
317 "Shortcut: cache found, update binding");
318 nhrp_cache_update_binding(c, NHRP_CACHE_DYNAMIC,
996c9314
LB
319 holding_time,
320 nhrp_peer_get(pp->ifp, nbma),
00683a14
RD
321 htons(cie->mtu),
322 nbma,
323 &cie_nbma);
912c556b
GN
324 } else {
325 debugf(NHRP_DEBUG_COMMON,
4ddc702a 326 "Shortcut: no cache for proto %pSU", proto);
2fb975da 327 }
ac95bcef
GG
328
329 /* Update cache binding for dst_proto as well */
bb58f442 330 if (sockunion_cmp(proto, &pp->dst_proto)) {
00683a14
RD
331 c_dst = nhrp_cache_get(pp->ifp, &pp->dst_proto, 1);
332 if (c_dst) {
ac95bcef 333 debugf(NHRP_DEBUG_COMMON,
00683a14
RD
334 "Shortcut: cache found, update binding");
335 nhrp_cache_update_binding(c_dst,
336 NHRP_CACHE_DYNAMIC,
ac95bcef
GG
337 holding_time,
338 nhrp_peer_get(pp->ifp, nbma),
00683a14
RD
339 htons(cie->mtu),
340 nbma,
341 &cie_nbma);
ac95bcef
GG
342 } else {
343 debugf(NHRP_DEBUG_COMMON,
4ddc702a
RD
344 "Shortcut: no cache for proto %pSU",
345 &pp->dst_proto);
ac95bcef
GG
346 }
347 }
2fb975da
TT
348 }
349
350 /* Update shortcut entry for subnet to protocol gw binding */
912c556b 351 if (c) {
2fb975da
TT
352 ps = nhrp_shortcut_get(&prefix);
353 if (ps) {
354 ps->addr = s->addr;
912c556b 355 debugf(NHRP_DEBUG_COMMON,
5f36c26c 356 "Shortcut: calling update_binding");
912c556b 357 nhrp_shortcut_update_binding(ps, NHRP_CACHE_DYNAMIC, c,
996c9314 358 holding_time);
912c556b
GN
359 } else {
360 debugf(NHRP_DEBUG_COMMON,
361 "Shortcut: proto diff but no ps");
2fb975da 362 }
912c556b
GN
363 } else {
364 debugf(NHRP_DEBUG_COMMON,
5f36c26c 365 "NO Shortcut because c NULL?%s or same proto?%s",
912c556b
GN
366 c ? "no" : "yes",
367 proto && pp && sockunion_same(proto, &pp->dst_proto)
368 ? "yes"
369 : "no");
2fb975da
TT
370 }
371
372 debugf(NHRP_DEBUG_COMMON, "Shortcut: Resolution reply handled");
373}
374
375static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s)
376{
377 struct zbuf *zb;
378 struct nhrp_packet_header *hdr;
379 struct interface *ifp;
380 struct nhrp_interface *nifp;
47d40757 381 struct nhrp_afi_data *if_ad;
2fb975da 382 struct nhrp_peer *peer;
47d40757 383 struct nhrp_cie_header *cie;
c2cffffb 384 struct nhrp_extension_header *ext;
2fb975da 385
996c9314
LB
386 if (nhrp_route_address(NULL, &s->addr, NULL, &peer)
387 != NHRP_ROUTE_NBMA_NEXTHOP)
2fb975da
TT
388 return;
389
390 if (s->type == NHRP_CACHE_INVALID || s->type == NHRP_CACHE_NEGATIVE)
391 s->type = NHRP_CACHE_INCOMPLETE;
392
393 ifp = peer->ifp;
394 nifp = ifp->info;
395
396 /* Create request */
397 zb = zbuf_alloc(1500);
996c9314
LB
398 hdr = nhrp_packet_push(
399 zb, NHRP_PACKET_RESOLUTION_REQUEST, &nifp->nbma,
400 &nifp->afi[family2afi(sockunion_family(&s->addr))].addr,
401 &s->addr);
402 hdr->u.request_id =
403 htonl(nhrp_reqid_alloc(&nhrp_packet_reqid, &s->reqid,
404 nhrp_shortcut_recv_resolution_rep));
405 hdr->flags = htons(NHRP_FLAG_RESOLUTION_SOURCE_IS_ROUTER
406 | NHRP_FLAG_RESOLUTION_AUTHORATIVE
407 | NHRP_FLAG_RESOLUTION_SOURCE_STABLE);
2fb975da
TT
408
409 /* RFC2332 - One or zero CIEs, if CIE is present contains:
410 * - Prefix length: widest acceptable prefix we accept (if U set, 0xff)
411 * - MTU: MTU of the source station
412 * - Holding Time: Max time to cache the source information
413 * */
47d40757
GN
414 /* FIXME: push CIE for each local protocol address */
415 cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, NULL, NULL);
47d40757 416 if_ad = &nifp->afi[family2afi(sockunion_family(&s->addr))];
32dbbf1a
AL
417 cie->prefix_length = (if_ad->flags & NHRP_IFF_REG_NO_UNIQUE)
418 ? 8 * sockunion_get_addrlen(&s->addr)
419 : 0xff;
47d40757
GN
420 cie->holding_time = htons(if_ad->holdtime);
421 cie->mtu = htons(if_ad->mtu);
422 debugf(NHRP_DEBUG_COMMON,
5f36c26c 423 "Shortcut res_req: set cie ht to %u and mtu to %u. shortcut ht is %u",
47d40757 424 ntohs(cie->holding_time), ntohs(cie->mtu), s->holding_time);
2fb975da
TT
425
426 nhrp_ext_request(zb, hdr, ifp);
427
428 /* Cisco NAT detection extension */
429 hdr->flags |= htons(NHRP_FLAG_RESOLUTION_NAT);
c2cffffb 430 ext = nhrp_ext_push(zb, hdr, NHRP_EXTENSION_NAT_ADDRESS);
611915ae
AL
431 if (sockunion_family(&nifp->nat_nbma) != AF_UNSPEC) {
432 cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, &nifp->nat_nbma,
433 &if_ad->addr);
999a07f0 434 cie->prefix_length = 8 * sockunion_get_addrlen(&if_ad->addr);
1e52c954 435 cie->mtu = htons(if_ad->mtu);
c2cffffb
GG
436 nhrp_ext_complete(zb, ext);
437 }
2fb975da
TT
438
439 nhrp_packet_complete(zb, hdr);
440
441 nhrp_peer_send(peer, zb);
442 nhrp_peer_unref(peer);
443 zbuf_free(zb);
444}
445
446void nhrp_shortcut_initiate(union sockunion *addr)
447{
448 struct prefix p;
449 struct nhrp_shortcut *s;
450
0154d8ce
DS
451 if (!sockunion2hostprefix(addr, &p))
452 return;
453
2fb975da
TT
454 s = nhrp_shortcut_get(&p);
455 if (s && s->type != NHRP_CACHE_INCOMPLETE) {
456 s->addr = *addr;
457 THREAD_OFF(s->t_timer);
ffa2c898
QY
458 thread_add_timer(master, nhrp_shortcut_do_purge, s, 30,
459 &s->t_timer);
2fb975da
TT
460 nhrp_shortcut_send_resolution_req(s);
461 }
462}
463
464void nhrp_shortcut_init(void)
465{
466 shortcut_rib[AFI_IP] = route_table_init();
467 shortcut_rib[AFI_IP6] = route_table_init();
468}
469
470void nhrp_shortcut_terminate(void)
471{
472 route_table_finish(shortcut_rib[AFI_IP]);
473 route_table_finish(shortcut_rib[AFI_IP6]);
474}
475
996c9314
LB
476void nhrp_shortcut_foreach(afi_t afi,
477 void (*cb)(struct nhrp_shortcut *, void *),
478 void *ctx)
2fb975da
TT
479{
480 struct route_table *rt = shortcut_rib[afi];
481 struct route_node *rn;
482 route_table_iter_t iter;
483
996c9314
LB
484 if (!rt)
485 return;
2fb975da
TT
486
487 route_table_iter_init(&iter, rt);
488 while ((rn = route_table_iter_next(&iter)) != NULL) {
996c9314
LB
489 if (rn->info)
490 cb(rn->info, ctx);
2fb975da
TT
491 }
492 route_table_iter_cleanup(&iter);
493}
494
495struct purge_ctx {
496 const struct prefix *p;
497 int deleted;
498};
499
500void nhrp_shortcut_purge(struct nhrp_shortcut *s, int force)
501{
502 THREAD_OFF(s->t_timer);
503 nhrp_reqid_free(&nhrp_packet_reqid, &s->reqid);
504
505 if (force) {
506 /* Immediate purge on route with draw or pending shortcut */
ffa2c898
QY
507 thread_add_timer_msec(master, nhrp_shortcut_do_purge, s, 5,
508 &s->t_timer);
2fb975da
TT
509 } else {
510 /* Soft expire - force immediate renewal, but purge
511 * in few seconds to make sure stale route is not
512 * used too long. In practice most purges are caused
513 * by hub bgp change, but target usually stays same.
514 * This allows to keep nhrp route up, and to not
515 * cause temporary rerouting via hubs causing latency
516 * jitter. */
ffa2c898
QY
517 thread_add_timer_msec(master, nhrp_shortcut_do_purge, s, 3000,
518 &s->t_timer);
2fb975da
TT
519 s->expiring = 1;
520 nhrp_shortcut_check_use(s);
521 }
522}
523
524static void nhrp_shortcut_purge_prefix(struct nhrp_shortcut *s, void *ctx)
525{
526 struct purge_ctx *pctx = ctx;
527
528 if (prefix_match(pctx->p, s->p))
529 nhrp_shortcut_purge(s, pctx->deleted || !s->cache);
530}
531
532void nhrp_shortcut_prefix_change(const struct prefix *p, int deleted)
533{
534 struct purge_ctx pctx = {
996c9314 535 .p = p, .deleted = deleted,
2fb975da 536 };
996c9314
LB
537 nhrp_shortcut_foreach(family2afi(PREFIX_FAMILY(p)),
538 nhrp_shortcut_purge_prefix, &pctx);
2fb975da 539}