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