1 /* NHRP NHC nexthop server functions (registration)
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.
15 #include "nhrp_protocol.h"
17 DEFINE_MTYPE_STATIC(NHRPD
, NHRP_NHS
, "NHRP next hop server");
18 DEFINE_MTYPE_STATIC(NHRPD
, NHRP_REGISTRATION
, "NHRP registration entries");
20 static void nhrp_nhs_resolve(struct thread
*t
);
21 static void nhrp_reg_send_req(struct thread
*t
);
23 static void nhrp_reg_reply(struct nhrp_reqid
*reqid
, void *arg
)
25 struct nhrp_packet_parser
*p
= arg
;
26 struct nhrp_registration
*r
=
27 container_of(reqid
, struct nhrp_registration
, reqid
);
28 struct nhrp_nhs
*nhs
= r
->nhs
;
29 struct interface
*ifp
= nhs
->ifp
;
30 struct nhrp_interface
*nifp
= ifp
->info
;
31 struct nhrp_extension_header
*ext
;
32 struct nhrp_cie_header
*cie
;
35 union sockunion cie_nbma
, cie_nbma_nhs
, cie_proto
, cie_proto_nhs
,
38 unsigned short mtu
= 0;
40 nhrp_reqid_free(&nhrp_packet_reqid
, &r
->reqid
);
42 if (p
->hdr
->type
!= NHRP_PACKET_REGISTRATION_REPLY
) {
43 debugf(NHRP_DEBUG_COMMON
, "NHS: Registration failed");
47 debugf(NHRP_DEBUG_COMMON
, "NHS: Reg.reply received");
50 while ((cie
= nhrp_cie_pull(&p
->payload
, p
->hdr
, &cie_nbma
, &cie_proto
))
52 proto
= sockunion_family(&cie_proto
) != AF_UNSPEC
55 debugf(NHRP_DEBUG_COMMON
, "NHS: CIE registration: %pSU: %d",
57 if (!((cie
->code
== NHRP_CODE_SUCCESS
)
58 || (cie
->code
== NHRP_CODE_ADMINISTRATIVELY_PROHIBITED
61 mtu
= ntohs(cie
->mtu
);
62 debugf(NHRP_DEBUG_COMMON
, "NHS: CIE MTU: %d", mtu
);
68 /* Parse extensions */
69 sockunion_family(&nifp
->nat_nbma
) = AF_UNSPEC
;
70 sockunion_family(&cie_nbma_nhs
) = AF_UNSPEC
;
71 while ((ext
= nhrp_ext_pull(&p
->extensions
, &extpl
)) != NULL
) {
72 switch (htons(ext
->type
) & ~NHRP_EXTENSION_FLAG_COMPULSORY
) {
73 case NHRP_EXTENSION_NAT_ADDRESS
:
74 /* NHS adds second CIE if NAT is detected */
75 if (nhrp_cie_pull(&extpl
, p
->hdr
, &cie_nbma
, &cie_proto
)
76 && nhrp_cie_pull(&extpl
, p
->hdr
, &cie_nbma
,
78 nifp
->nat_nbma
= cie_nbma
;
80 "%s: NAT detected, real NBMA address: %pSU",
81 ifp
->name
, &nifp
->nbma
);
84 case NHRP_EXTENSION_RESPONDER_ADDRESS
:
85 /* NHS adds its own record as responder address */
86 nhrp_cie_pull(&extpl
, p
->hdr
, &cie_nbma_nhs
,
92 /* Success - schedule next registration, and route NHS */
94 holdtime
= nifp
->afi
[nhs
->afi
].holdtime
;
95 THREAD_OFF(r
->t_register
);
97 /* RFC 2332 5.2.3 - Registration is recommend to be renewed
98 * every one third of holdtime */
99 thread_add_timer(master
, nhrp_reg_send_req
, r
, holdtime
/ 3,
102 r
->proto_addr
= p
->dst_proto
;
103 c
= nhrp_cache_get(ifp
, &p
->dst_proto
, 1);
105 nhrp_cache_update_binding(c
, NHRP_CACHE_NHS
, holdtime
,
106 nhrp_peer_ref(r
->peer
), mtu
, NULL
,
110 static void nhrp_reg_timeout(struct thread
*t
)
112 struct nhrp_registration
*r
= THREAD_ARG(t
);
113 struct nhrp_cache
*c
;
116 if (r
->timeout
>= 16 && sockunion_family(&r
->proto_addr
) != AF_UNSPEC
) {
117 nhrp_reqid_free(&nhrp_packet_reqid
, &r
->reqid
);
118 c
= nhrp_cache_get(r
->nhs
->ifp
, &r
->proto_addr
, 0);
120 nhrp_cache_update_binding(c
, NHRP_CACHE_NHS
, -1, NULL
,
122 sockunion_family(&r
->proto_addr
) = AF_UNSPEC
;
126 if (r
->timeout
> 64) {
127 /* If registration fails repeatedly, this may be because the
128 * IPSec connection is not working. Close the connection so it
129 * can be re-established correctly
131 if (r
->peer
&& r
->peer
->vc
&& r
->peer
->vc
->ike_uniqueid
) {
132 debugf(NHRP_DEBUG_COMMON
,
133 "Terminating IPSec Connection for %d",
134 r
->peer
->vc
->ike_uniqueid
);
135 vici_terminate_vc_by_ike_id(r
->peer
->vc
->ike_uniqueid
);
136 r
->peer
->vc
->ike_uniqueid
= 0;
140 thread_add_timer_msec(master
, nhrp_reg_send_req
, r
, 10, &r
->t_register
);
143 static void nhrp_reg_peer_notify(struct notifier_block
*n
, unsigned long cmd
)
145 struct nhrp_registration
*r
=
146 container_of(n
, struct nhrp_registration
, peer_notifier
);
150 case NOTIFY_PEER_DOWN
:
151 case NOTIFY_PEER_IFCONFIG_CHANGED
:
152 case NOTIFY_PEER_MTU_CHANGED
:
153 debugf(NHRP_DEBUG_COMMON
, "NHS: Flush timer for %pSU",
154 &r
->peer
->vc
->remote
.nbma
);
155 THREAD_OFF(r
->t_register
);
156 thread_add_timer_msec(master
, nhrp_reg_send_req
, r
, 10,
162 static void nhrp_reg_send_req(struct thread
*t
)
164 struct nhrp_registration
*r
= THREAD_ARG(t
);
165 struct nhrp_nhs
*nhs
= r
->nhs
;
166 struct interface
*ifp
= nhs
->ifp
;
167 struct nhrp_interface
*nifp
= ifp
->info
;
168 struct nhrp_afi_data
*if_ad
= &nifp
->afi
[nhs
->afi
];
169 union sockunion
*dst_proto
, nhs_proto
;
171 struct nhrp_packet_header
*hdr
;
172 struct nhrp_extension_header
*ext
;
173 struct nhrp_cie_header
*cie
;
175 if (!nhrp_peer_check(r
->peer
, 2)) {
176 debugf(NHRP_DEBUG_COMMON
, "NHS: Waiting link for %pSU",
177 &r
->peer
->vc
->remote
.nbma
);
178 thread_add_timer(master
, nhrp_reg_send_req
, r
, 120,
183 thread_add_timer(master
, nhrp_reg_timeout
, r
, r
->timeout
,
186 /* RFC2332 5.2.3 NHC uses it's own address as dst if NHS is unknown */
187 dst_proto
= &nhs
->proto_addr
;
188 if (sockunion_family(dst_proto
) == AF_UNSPEC
)
189 dst_proto
= &if_ad
->addr
;
191 debugf(NHRP_DEBUG_COMMON
, "NHS: Register %pSU -> %pSU (timeout %d)",
192 &if_ad
->addr
, dst_proto
, r
->timeout
);
194 /* No protocol address configured for tunnel interface */
195 if (sockunion_family(&if_ad
->addr
) == AF_UNSPEC
)
198 zb
= zbuf_alloc(1400);
199 hdr
= nhrp_packet_push(zb
, NHRP_PACKET_REGISTRATION_REQUEST
,
200 &nifp
->nbma
, &if_ad
->addr
, dst_proto
);
202 if (!(if_ad
->flags
& NHRP_IFF_REG_NO_UNIQUE
))
203 hdr
->flags
|= htons(NHRP_FLAG_REGISTRATION_UNIQUE
);
205 hdr
->u
.request_id
= htonl(nhrp_reqid_alloc(&nhrp_packet_reqid
,
206 &r
->reqid
, nhrp_reg_reply
));
208 /* FIXME: push CIE for each local protocol address */
209 cie
= nhrp_cie_push(zb
, NHRP_CODE_SUCCESS
, NULL
, NULL
);
210 /* RFC2332 5.2.1 if unique is set then prefix length must be 0xff */
211 cie
->prefix_length
= (if_ad
->flags
& NHRP_IFF_REG_NO_UNIQUE
)
212 ? 8 * sockunion_get_addrlen(dst_proto
)
214 cie
->holding_time
= htons(if_ad
->holdtime
);
215 cie
->mtu
= htons(if_ad
->mtu
);
217 nhrp_ext_request(zb
, hdr
, ifp
);
219 /* Cisco NAT detection extension */
220 if (sockunion_family(&r
->proto_addr
) != AF_UNSPEC
) {
221 nhs_proto
= r
->proto_addr
;
222 } else if (sockunion_family(&nhs
->proto_addr
) != AF_UNSPEC
) {
223 nhs_proto
= nhs
->proto_addr
;
225 /* cisco magic: If NHS is not known then use all 0s as
226 * client protocol address in NAT Extension header
228 memset(&nhs_proto
, 0, sizeof(nhs_proto
));
229 sockunion_family(&nhs_proto
) = afi2family(nhs
->afi
);
232 hdr
->flags
|= htons(NHRP_FLAG_REGISTRATION_NAT
);
233 ext
= nhrp_ext_push(zb
, hdr
, NHRP_EXTENSION_NAT_ADDRESS
);
234 /* push NHS details */
235 cie
= nhrp_cie_push(zb
, NHRP_CODE_SUCCESS
, &r
->peer
->vc
->remote
.nbma
,
237 cie
->prefix_length
= 8 * sockunion_get_addrlen(&if_ad
->addr
);
238 cie
->mtu
= htons(if_ad
->mtu
);
239 nhrp_ext_complete(zb
, ext
);
241 nhrp_packet_complete(zb
, hdr
);
242 nhrp_peer_send(r
->peer
, zb
);
246 static void nhrp_reg_delete(struct nhrp_registration
*r
)
248 nhrp_peer_notify_del(r
->peer
, &r
->peer_notifier
);
249 nhrp_peer_unref(r
->peer
);
250 nhrp_reglist_del(&r
->nhs
->reglist_head
, r
);
251 THREAD_OFF(r
->t_register
);
252 XFREE(MTYPE_NHRP_REGISTRATION
, r
);
255 static struct nhrp_registration
*
256 nhrp_reg_by_nbma(struct nhrp_nhs
*nhs
, const union sockunion
*nbma_addr
)
258 struct nhrp_registration
*r
;
260 frr_each (nhrp_reglist
, &nhs
->reglist_head
, r
)
261 if (sockunion_same(&r
->peer
->vc
->remote
.nbma
, nbma_addr
))
266 static void nhrp_nhs_resolve_cb(struct resolver_query
*q
, const char *errstr
,
267 int n
, union sockunion
*addrs
)
269 struct nhrp_nhs
*nhs
= container_of(q
, struct nhrp_nhs
, dns_resolve
);
270 struct nhrp_interface
*nifp
= nhs
->ifp
->info
;
271 struct nhrp_registration
*reg
;
275 /* Failed, retry in a moment */
276 thread_add_timer(master
, nhrp_nhs_resolve
, nhs
, 5,
281 thread_add_timer(master
, nhrp_nhs_resolve
, nhs
, 2 * 60 * 60,
284 frr_each (nhrp_reglist
, &nhs
->reglist_head
, reg
)
288 for (i
= 0; i
< n
; i
++) {
289 if (sockunion_same(&addrs
[i
], &nifp
->nbma
)) {
294 reg
= nhrp_reg_by_nbma(nhs
, &addrs
[i
]);
300 reg
= XCALLOC(MTYPE_NHRP_REGISTRATION
, sizeof(*reg
));
301 reg
->peer
= nhrp_peer_get(nhs
->ifp
, &addrs
[i
]);
304 nhrp_reglist_add_tail(&nhs
->reglist_head
, reg
);
305 nhrp_peer_notify_add(reg
->peer
, ®
->peer_notifier
,
306 nhrp_reg_peer_notify
);
307 thread_add_timer_msec(master
, nhrp_reg_send_req
, reg
, 50,
311 frr_each_safe (nhrp_reglist
, &nhs
->reglist_head
, reg
)
313 nhrp_reg_delete(reg
);
316 static void nhrp_nhs_resolve(struct thread
*t
)
318 struct nhrp_nhs
*nhs
= THREAD_ARG(t
);
320 resolver_resolve(&nhs
->dns_resolve
, AF_INET
, VRF_DEFAULT
,
321 nhs
->nbma_fqdn
, nhrp_nhs_resolve_cb
);
324 int nhrp_nhs_add(struct interface
*ifp
, afi_t afi
, union sockunion
*proto_addr
,
325 const char *nbma_fqdn
)
327 struct nhrp_interface
*nifp
= ifp
->info
;
328 struct nhrp_nhs
*nhs
;
330 if (sockunion_family(proto_addr
) != AF_UNSPEC
331 && sockunion_family(proto_addr
) != afi2family(afi
))
332 return NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH
;
334 frr_each (nhrp_nhslist
, &nifp
->afi
[afi
].nhslist_head
, nhs
) {
335 if (sockunion_family(&nhs
->proto_addr
) != AF_UNSPEC
336 && sockunion_family(proto_addr
) != AF_UNSPEC
337 && sockunion_same(&nhs
->proto_addr
, proto_addr
))
338 return NHRP_ERR_ENTRY_EXISTS
;
340 if (strcmp(nhs
->nbma_fqdn
, nbma_fqdn
) == 0)
341 return NHRP_ERR_ENTRY_EXISTS
;
344 nhs
= XMALLOC(MTYPE_NHRP_NHS
, sizeof(struct nhrp_nhs
));
346 *nhs
= (struct nhrp_nhs
){
349 .proto_addr
= *proto_addr
,
350 .nbma_fqdn
= strdup(nbma_fqdn
),
351 .reglist_head
= INIT_DLIST(nhs
->reglist_head
),
353 nhrp_nhslist_add_tail(&nifp
->afi
[afi
].nhslist_head
, nhs
);
354 thread_add_timer_msec(master
, nhrp_nhs_resolve
, nhs
, 1000,
360 int nhrp_nhs_del(struct interface
*ifp
, afi_t afi
, union sockunion
*proto_addr
,
361 const char *nbma_fqdn
)
363 struct nhrp_interface
*nifp
= ifp
->info
;
364 struct nhrp_nhs
*nhs
;
365 int ret
= NHRP_ERR_ENTRY_NOT_FOUND
;
367 if (sockunion_family(proto_addr
) != AF_UNSPEC
368 && sockunion_family(proto_addr
) != afi2family(afi
))
369 return NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH
;
371 frr_each_safe (nhrp_nhslist
, &nifp
->afi
[afi
].nhslist_head
, nhs
) {
372 if (!sockunion_same(&nhs
->proto_addr
, proto_addr
))
374 if (strcmp(nhs
->nbma_fqdn
, nbma_fqdn
) != 0)
377 nhrp_nhs_free(nifp
, afi
, nhs
);
384 int nhrp_nhs_free(struct nhrp_interface
*nifp
, afi_t afi
, struct nhrp_nhs
*nhs
)
386 struct nhrp_registration
*r
;
388 frr_each_safe (nhrp_reglist
, &nhs
->reglist_head
, r
)
390 THREAD_OFF(nhs
->t_resolve
);
391 nhrp_nhslist_del(&nifp
->afi
[afi
].nhslist_head
, nhs
);
392 free((void *)nhs
->nbma_fqdn
);
393 XFREE(MTYPE_NHRP_NHS
, nhs
);
397 void nhrp_nhs_interface_del(struct interface
*ifp
)
399 struct nhrp_interface
*nifp
= ifp
->info
;
400 struct nhrp_nhs
*nhs
;
403 for (afi
= 0; afi
< AFI_MAX
; afi
++) {
404 debugf(NHRP_DEBUG_COMMON
, "Cleaning up nhs entries (%zu)",
405 nhrp_nhslist_count(&nifp
->afi
[afi
].nhslist_head
));
407 frr_each_safe (nhrp_nhslist
, &nifp
->afi
[afi
].nhslist_head
, nhs
)
408 nhrp_nhs_free(nifp
, afi
, nhs
);
412 void nhrp_nhs_terminate(void)
414 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
415 struct interface
*ifp
;
416 struct nhrp_interface
*nifp
;
417 struct nhrp_nhs
*nhs
;
420 FOR_ALL_INTERFACES (vrf
, ifp
) {
422 for (afi
= 0; afi
< AFI_MAX
; afi
++) {
423 frr_each_safe (nhrp_nhslist
,
424 &nifp
->afi
[afi
].nhslist_head
, nhs
)
425 nhrp_nhs_free(nifp
, afi
, nhs
);
430 void nhrp_nhs_foreach(struct interface
*ifp
, afi_t afi
,
431 void (*cb
)(struct nhrp_nhs
*, struct nhrp_registration
*,
435 struct nhrp_interface
*nifp
= ifp
->info
;
436 struct nhrp_nhs
*nhs
;
437 struct nhrp_registration
*reg
;
439 frr_each (nhrp_nhslist
, &nifp
->afi
[afi
].nhslist_head
, nhs
) {
440 if (nhrp_reglist_count(&nhs
->reglist_head
)) {
441 frr_each (nhrp_reglist
, &nhs
->reglist_head
, reg
)
448 int nhrp_nhs_match_ip(union sockunion
*in_ip
, struct nhrp_interface
*nifp
)
451 struct nhrp_nhs
*nhs
;
452 struct nhrp_registration
*reg
;
454 for (i
= 0; i
< AFI_MAX
; i
++) {
455 frr_each (nhrp_nhslist
, &nifp
->afi
[i
].nhslist_head
, nhs
) {
456 if (!nhrp_reglist_count(&nhs
->reglist_head
))
459 frr_each (nhrp_reglist
, &nhs
->reglist_head
, reg
) {
460 if (!sockunion_cmp(in_ip
,
461 ®
->peer
->vc
->remote
.nbma
))