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.
18 DEFINE_MTYPE_STATIC(NHRPD
, NHRP_CACHE
, "NHRP cache entry");
19 DEFINE_MTYPE_STATIC(NHRPD
, NHRP_CACHE_CONFIG
, "NHRP cache config entry");
21 unsigned long nhrp_cache_counts
[NHRP_CACHE_NUM_TYPES
];
23 const char *const nhrp_cache_type_str
[] = {
24 [NHRP_CACHE_INVALID
] = "invalid",
25 [NHRP_CACHE_INCOMPLETE
] = "incomplete",
26 [NHRP_CACHE_NEGATIVE
] = "negative",
27 [NHRP_CACHE_CACHED
] = "cached",
28 [NHRP_CACHE_DYNAMIC
] = "dynamic",
29 [NHRP_CACHE_NHS
] = "nhs",
30 [NHRP_CACHE_STATIC
] = "static",
31 [NHRP_CACHE_LOCAL
] = "local",
34 static unsigned int nhrp_cache_protocol_key(const void *peer_data
)
36 const struct nhrp_cache
*p
= peer_data
;
37 return sockunion_hash(&p
->remote_addr
);
40 static bool nhrp_cache_protocol_cmp(const void *cache_data
,
43 const struct nhrp_cache
*a
= cache_data
;
44 const struct nhrp_cache
*b
= key_data
;
46 return sockunion_same(&a
->remote_addr
, &b
->remote_addr
);
49 static void *nhrp_cache_alloc(void *data
)
51 struct nhrp_cache
*p
, *key
= data
;
53 p
= XMALLOC(MTYPE_NHRP_CACHE
, sizeof(struct nhrp_cache
));
55 *p
= (struct nhrp_cache
){
56 .cur
.type
= NHRP_CACHE_INVALID
,
57 .new.type
= NHRP_CACHE_INVALID
,
58 .remote_addr
= key
->remote_addr
,
61 NOTIFIER_LIST_INITIALIZER(&p
->notifier_list
),
63 nhrp_cache_counts
[p
->cur
.type
]++;
68 static void nhrp_cache_free(struct nhrp_cache
*c
)
70 struct nhrp_interface
*nifp
= c
->ifp
->info
;
72 debugf(NHRP_DEBUG_COMMON
, "Deleting cache entry");
73 nhrp_cache_counts
[c
->cur
.type
]--;
74 notifier_call(&c
->notifier_list
, NOTIFY_CACHE_DELETE
);
75 assert(!notifier_active(&c
->notifier_list
));
76 hash_release(nifp
->cache_hash
, c
);
77 THREAD_OFF(c
->t_timeout
);
78 THREAD_OFF(c
->t_auth
);
79 XFREE(MTYPE_NHRP_CACHE
, c
);
82 static unsigned int nhrp_cache_config_protocol_key(const void *peer_data
)
84 const struct nhrp_cache_config
*p
= peer_data
;
85 return sockunion_hash(&p
->remote_addr
);
88 static bool nhrp_cache_config_protocol_cmp(const void *cache_data
,
91 const struct nhrp_cache_config
*a
= cache_data
;
92 const struct nhrp_cache_config
*b
= key_data
;
94 if (!sockunion_same(&a
->remote_addr
, &b
->remote_addr
))
101 static void *nhrp_cache_config_alloc(void *data
)
103 struct nhrp_cache_config
*p
, *key
= data
;
105 p
= XCALLOC(MTYPE_NHRP_CACHE_CONFIG
, sizeof(struct nhrp_cache_config
));
107 *p
= (struct nhrp_cache_config
){
108 .remote_addr
= key
->remote_addr
,
114 void nhrp_cache_config_free(struct nhrp_cache_config
*c
)
116 struct nhrp_interface
*nifp
= c
->ifp
->info
;
118 hash_release(nifp
->cache_config_hash
, c
);
119 XFREE(MTYPE_NHRP_CACHE_CONFIG
, c
);
122 struct nhrp_cache_config
*nhrp_cache_config_get(struct interface
*ifp
,
123 union sockunion
*remote_addr
,
126 struct nhrp_interface
*nifp
= ifp
->info
;
127 struct nhrp_cache_config key
;
129 if (!nifp
->cache_config_hash
) {
130 nifp
->cache_config_hash
=
131 hash_create(nhrp_cache_config_protocol_key
,
132 nhrp_cache_config_protocol_cmp
,
133 "NHRP Config Cache");
134 if (!nifp
->cache_config_hash
)
137 key
.remote_addr
= *remote_addr
;
140 return hash_get(nifp
->cache_config_hash
, &key
,
141 create
? nhrp_cache_config_alloc
: NULL
);
144 static void do_nhrp_cache_free(struct hash_bucket
*hb
,
145 void *arg
__attribute__((__unused__
)))
147 struct nhrp_cache
*c
= hb
->data
;
152 static void do_nhrp_cache_config_free(struct hash_bucket
*hb
,
153 void *arg
__attribute__((__unused__
)))
155 struct nhrp_cache_config
*cc
= hb
->data
;
157 nhrp_cache_config_free(cc
);
160 void nhrp_cache_interface_del(struct interface
*ifp
)
162 struct nhrp_interface
*nifp
= ifp
->info
;
164 debugf(NHRP_DEBUG_COMMON
, "Cleaning up undeleted cache entries (%lu)",
165 nifp
->cache_hash
? nifp
->cache_hash
->count
: 0);
167 if (nifp
->cache_hash
) {
168 hash_iterate(nifp
->cache_hash
, do_nhrp_cache_free
, NULL
);
169 hash_free(nifp
->cache_hash
);
172 if (nifp
->cache_config_hash
) {
173 hash_iterate(nifp
->cache_config_hash
, do_nhrp_cache_config_free
,
175 hash_free(nifp
->cache_config_hash
);
179 struct nhrp_cache
*nhrp_cache_get(struct interface
*ifp
,
180 union sockunion
*remote_addr
, int create
)
182 struct nhrp_interface
*nifp
= ifp
->info
;
183 struct nhrp_cache key
;
185 if (!nifp
->cache_hash
) {
187 hash_create(nhrp_cache_protocol_key
,
188 nhrp_cache_protocol_cmp
, "NHRP Cache");
189 if (!nifp
->cache_hash
)
193 key
.remote_addr
= *remote_addr
;
196 return hash_get(nifp
->cache_hash
, &key
,
197 create
? nhrp_cache_alloc
: NULL
);
200 static void nhrp_cache_do_free(struct thread
*t
)
202 struct nhrp_cache
*c
= THREAD_ARG(t
);
208 static void nhrp_cache_do_timeout(struct thread
*t
)
210 struct nhrp_cache
*c
= THREAD_ARG(t
);
213 if (c
->cur
.type
!= NHRP_CACHE_INVALID
)
214 nhrp_cache_update_binding(c
, c
->cur
.type
, -1, NULL
, 0, NULL
,
218 static void nhrp_cache_update_route(struct nhrp_cache
*c
)
221 struct nhrp_peer
*p
= c
->cur
.peer
;
222 struct nhrp_interface
*nifp
;
224 if (!sockunion2hostprefix(&c
->remote_addr
, &pfx
))
227 if (p
&& nhrp_peer_check(p
, 1)) {
228 if (sockunion_family(&c
->cur
.remote_nbma_natoa
) != AF_UNSPEC
) {
229 /* remote_nbma_natoa is already set. Therefore, binding
230 * should be updated to this value and not vc's remote
233 debugf(NHRP_DEBUG_COMMON
,
234 "cache (remote_nbma_natoa set): Update binding for %pSU dev %s from (deleted) peer.vc.nbma %pSU to %pSU",
235 &c
->remote_addr
, p
->ifp
->name
,
236 &p
->vc
->remote
.nbma
, &c
->cur
.remote_nbma_natoa
);
238 netlink_update_binding(p
->ifp
, &c
->remote_addr
,
239 &c
->cur
.remote_nbma_natoa
);
241 /* update binding to peer->vc->remote->nbma */
242 debugf(NHRP_DEBUG_COMMON
,
243 "cache (remote_nbma_natoa unspec): Update binding for %pSU dev %s from (deleted) to peer.vc.nbma %pSU",
244 &c
->remote_addr
, p
->ifp
->name
,
245 &p
->vc
->remote
.nbma
);
247 netlink_update_binding(p
->ifp
, &c
->remote_addr
,
248 &p
->vc
->remote
.nbma
);
251 nhrp_route_announce(1, c
->cur
.type
, &pfx
, c
->ifp
, NULL
,
253 if (c
->cur
.type
>= NHRP_CACHE_DYNAMIC
) {
254 nhrp_route_update_nhrp(&pfx
, c
->ifp
);
255 c
->nhrp_route_installed
= 1;
256 } else if (c
->nhrp_route_installed
) {
257 nhrp_route_update_nhrp(&pfx
, NULL
);
258 c
->nhrp_route_installed
= 0;
260 if (!c
->route_installed
) {
261 notifier_call(&c
->notifier_list
, NOTIFY_CACHE_UP
);
262 c
->route_installed
= 1;
265 /* debug the reason for peer check fail */
268 debugf(NHRP_DEBUG_COMMON
,
269 "cache (peer check failed: online?%d requested?%d ipsec?%d)",
270 p
->online
, p
->requested
,
271 nifp
->ipsec_profile
? 1 : 0);
273 debugf(NHRP_DEBUG_COMMON
,
274 "cache (peer check failed: no p)");
276 if (c
->nhrp_route_installed
) {
277 nhrp_route_update_nhrp(&pfx
, NULL
);
278 c
->nhrp_route_installed
= 0;
280 if (c
->route_installed
) {
281 assert(sockunion2hostprefix(&c
->remote_addr
, &pfx
));
282 notifier_call(&c
->notifier_list
, NOTIFY_CACHE_DOWN
);
283 nhrp_route_announce(0, c
->cur
.type
, &pfx
, NULL
, NULL
,
285 c
->route_installed
= 0;
290 static void nhrp_cache_peer_notifier(struct notifier_block
*n
,
293 struct nhrp_cache
*c
=
294 container_of(n
, struct nhrp_cache
, peer_notifier
);
298 nhrp_cache_update_route(c
);
300 case NOTIFY_PEER_DOWN
:
301 case NOTIFY_PEER_IFCONFIG_CHANGED
:
302 notifier_call(&c
->notifier_list
, NOTIFY_CACHE_DOWN
);
303 nhrp_cache_update_binding(c
, c
->cur
.type
, -1, NULL
, 0, NULL
,
306 case NOTIFY_PEER_NBMA_CHANGING
:
307 if (c
->cur
.type
== NHRP_CACHE_DYNAMIC
)
308 c
->cur
.peer
->vc
->abort_migration
= 1;
313 static void nhrp_cache_reset_new(struct nhrp_cache
*c
)
315 THREAD_OFF(c
->t_auth
);
316 if (notifier_list_anywhere(&c
->newpeer_notifier
))
317 nhrp_peer_notify_del(c
->new.peer
, &c
->newpeer_notifier
);
318 nhrp_peer_unref(c
->new.peer
);
319 memset(&c
->new, 0, sizeof(c
->new));
320 c
->new.type
= NHRP_CACHE_INVALID
;
323 static void nhrp_cache_update_timers(struct nhrp_cache
*c
)
325 THREAD_OFF(c
->t_timeout
);
327 switch (c
->cur
.type
) {
328 case NHRP_CACHE_INVALID
:
330 thread_add_timer_msec(master
, nhrp_cache_do_free
, c
, 10,
333 case NHRP_CACHE_INCOMPLETE
:
334 case NHRP_CACHE_NEGATIVE
:
335 case NHRP_CACHE_CACHED
:
336 case NHRP_CACHE_DYNAMIC
:
338 case NHRP_CACHE_STATIC
:
339 case NHRP_CACHE_LOCAL
:
340 case NHRP_CACHE_NUM_TYPES
:
342 thread_add_timer(master
, nhrp_cache_do_timeout
, c
,
343 c
->cur
.expires
- monotime(NULL
),
349 static void nhrp_cache_authorize_binding(struct nhrp_reqid
*r
, void *arg
)
351 struct nhrp_cache
*c
= container_of(r
, struct nhrp_cache
, eventid
);
352 char buf
[3][SU_ADDRSTRLEN
];
354 debugf(NHRP_DEBUG_COMMON
, "cache: %s %pSU: %s", c
->ifp
->name
,
355 &c
->remote_addr
, (const char *)arg
);
357 nhrp_reqid_free(&nhrp_event_reqid
, r
);
359 if (arg
&& strcmp(arg
, "accept") == 0) {
361 netlink_update_binding(c
->cur
.peer
->ifp
,
362 &c
->remote_addr
, NULL
);
363 nhrp_peer_notify_del(c
->cur
.peer
, &c
->peer_notifier
);
364 nhrp_peer_unref(c
->cur
.peer
);
366 nhrp_cache_counts
[c
->cur
.type
]--;
367 nhrp_cache_counts
[c
->new.type
]++;
369 c
->cur
.peer
= nhrp_peer_ref(c
->cur
.peer
);
370 nhrp_cache_reset_new(c
);
372 nhrp_peer_notify_add(c
->cur
.peer
, &c
->peer_notifier
,
373 nhrp_cache_peer_notifier
);
375 if (sockunion_family(&c
->cur
.remote_nbma_natoa
) != AF_UNSPEC
) {
376 debugf(NHRP_DEBUG_COMMON
,
377 "cache: update binding for %pSU dev %s from (deleted) peer.vc.nbma %s to %pSU",
378 &c
->remote_addr
, c
->ifp
->name
,
379 (c
->cur
.peer
? sockunion2str(
380 &c
->cur
.peer
->vc
->remote
.nbma
, buf
[1],
383 &c
->cur
.remote_nbma_natoa
);
386 netlink_update_binding(
387 c
->cur
.peer
->ifp
, &c
->remote_addr
,
388 &c
->cur
.remote_nbma_natoa
);
391 nhrp_cache_update_route(c
);
392 notifier_call(&c
->notifier_list
, NOTIFY_CACHE_BINDING_CHANGE
);
394 nhrp_cache_reset_new(c
);
397 nhrp_cache_update_timers(c
);
400 static void nhrp_cache_do_auth_timeout(struct thread
*t
)
402 struct nhrp_cache
*c
= THREAD_ARG(t
);
404 nhrp_cache_authorize_binding(&c
->eventid
, (void *)"timeout");
407 static void nhrp_cache_newpeer_notifier(struct notifier_block
*n
,
410 struct nhrp_cache
*c
=
411 container_of(n
, struct nhrp_cache
, newpeer_notifier
);
415 if (nhrp_peer_check(c
->new.peer
, 1)) {
416 evmgr_notify("authorize-binding", c
,
417 nhrp_cache_authorize_binding
);
418 thread_add_timer(master
, nhrp_cache_do_auth_timeout
, c
,
422 case NOTIFY_PEER_DOWN
:
423 case NOTIFY_PEER_IFCONFIG_CHANGED
:
424 nhrp_cache_reset_new(c
);
429 int nhrp_cache_update_binding(struct nhrp_cache
*c
, enum nhrp_cache_type type
,
430 int holding_time
, struct nhrp_peer
*p
,
431 uint32_t mtu
, union sockunion
*nbma_oa
,
432 union sockunion
*nbma_claimed
)
434 char buf
[2][SU_ADDRSTRLEN
];
436 if (c
->cur
.type
> type
|| c
->new.type
> type
) {
442 switch (sockunion_family(&c
->remote_addr
)) {
444 if (mtu
< 576 || mtu
>= 1500)
446 /* Opennhrp announces nbma mtu, but we use protocol mtu.
447 * This heuristic tries to fix up it. */
449 mtu
= (mtu
& -16) - 80;
456 sockunion2str(&c
->cur
.remote_nbma_natoa
, buf
[0], sizeof(buf
[0]));
458 sockunion2str(nbma_oa
, buf
[1], sizeof(buf
[1]));
460 nhrp_cache_reset_new(c
);
461 if (c
->cur
.type
== type
&& c
->cur
.peer
== p
&& c
->cur
.mtu
== mtu
) {
462 debugf(NHRP_DEBUG_COMMON
,
463 "cache: same type %u, updating expiry and changing nbma addr from %s to %s",
464 type
, buf
[0], nbma_oa
? buf
[1] : "(NULL)");
465 if (holding_time
> 0)
466 c
->cur
.expires
= monotime(NULL
) + holding_time
;
469 c
->cur
.remote_nbma_natoa
= *nbma_oa
;
471 memset(&c
->cur
.remote_nbma_natoa
, 0,
472 sizeof(c
->cur
.remote_nbma_natoa
));
475 c
->cur
.remote_nbma_claimed
= *nbma_claimed
;
477 memset(&c
->cur
.remote_nbma_claimed
, 0,
478 sizeof(c
->cur
.remote_nbma_claimed
));
482 debugf(NHRP_DEBUG_COMMON
,
483 "cache: new type %u/%u, or peer %s, or mtu %u/%u, nbma %s --> %s (map %d)",
484 c
->cur
.type
, type
, (c
->cur
.peer
== p
) ? "same" : "diff",
485 c
->cur
.mtu
, mtu
, buf
[0], nbma_oa
? buf
[1] : "(NULL)",
490 c
->new.holding_time
= holding_time
;
492 c
->new.remote_nbma_natoa
= *nbma_oa
;
495 c
->new.remote_nbma_claimed
= *nbma_claimed
;
497 if (holding_time
> 0)
498 c
->new.expires
= monotime(NULL
) + holding_time
;
499 else if (holding_time
< 0)
500 nhrp_cache_reset_new(c
);
502 if (c
->new.type
== NHRP_CACHE_INVALID
503 || c
->new.type
>= NHRP_CACHE_STATIC
|| c
->map
) {
504 nhrp_cache_authorize_binding(&c
->eventid
,
507 nhrp_peer_notify_add(c
->new.peer
, &c
->newpeer_notifier
,
508 nhrp_cache_newpeer_notifier
);
509 nhrp_cache_newpeer_notifier(&c
->newpeer_notifier
,
511 thread_add_timer(master
, nhrp_cache_do_auth_timeout
, c
,
515 nhrp_cache_update_timers(c
);
520 void nhrp_cache_set_used(struct nhrp_cache
*c
, int used
)
524 notifier_call(&c
->notifier_list
, NOTIFY_CACHE_USED
);
527 struct nhrp_cache_iterator_ctx
{
528 void (*cb
)(struct nhrp_cache
*, void *);
532 struct nhrp_cache_config_iterator_ctx
{
533 void (*cb
)(struct nhrp_cache_config
*, void *);
537 static void nhrp_cache_iterator(struct hash_bucket
*b
, void *ctx
)
539 struct nhrp_cache_iterator_ctx
*ic
= ctx
;
540 ic
->cb(b
->data
, ic
->ctx
);
543 static void nhrp_cache_config_iterator(struct hash_bucket
*b
, void *ctx
)
545 struct nhrp_cache_config_iterator_ctx
*ic
= ctx
;
546 ic
->cb(b
->data
, ic
->ctx
);
549 void nhrp_cache_foreach(struct interface
*ifp
,
550 void (*cb
)(struct nhrp_cache
*, void *), void *ctx
)
552 struct nhrp_interface
*nifp
= ifp
->info
;
553 struct nhrp_cache_iterator_ctx ic
= {
554 .cb
= cb
, .ctx
= ctx
,
557 if (nifp
->cache_hash
)
558 hash_iterate(nifp
->cache_hash
, nhrp_cache_iterator
, &ic
);
561 void nhrp_cache_config_foreach(struct interface
*ifp
,
562 void (*cb
)(struct nhrp_cache_config
*, void *), void *ctx
)
564 struct nhrp_interface
*nifp
= ifp
->info
;
565 struct nhrp_cache_config_iterator_ctx ic
= {
566 .cb
= cb
, .ctx
= ctx
,
569 if (nifp
->cache_config_hash
)
570 hash_iterate(nifp
->cache_config_hash
, nhrp_cache_config_iterator
, &ic
);
573 void nhrp_cache_notify_add(struct nhrp_cache
*c
, struct notifier_block
*n
,
576 notifier_add(n
, &c
->notifier_list
, fn
);
579 void nhrp_cache_notify_del(struct nhrp_cache
*c
, struct notifier_block
*n
)
581 notifier_del(n
, &c
->notifier_list
);