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 int nhrp_nhs_resolve(struct thread
*t
);
21 static int 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
= container_of(reqid
, struct nhrp_registration
, reqid
);
27 struct nhrp_nhs
*nhs
= r
->nhs
;
28 struct interface
*ifp
= nhs
->ifp
;
29 struct nhrp_interface
*nifp
= ifp
->info
;
30 struct nhrp_extension_header
*ext
;
31 struct nhrp_cie_header
*cie
;
34 union sockunion cie_nbma
, cie_proto
, *proto
;
38 nhrp_reqid_free(&nhrp_packet_reqid
, &r
->reqid
);
40 if (p
->hdr
->type
!= NHRP_PACKET_REGISTRATION_REPLY
) {
41 debugf(NHRP_DEBUG_COMMON
, "NHS: Registration failed");
45 debugf(NHRP_DEBUG_COMMON
, "NHS: Reg.reply received");
48 while ((cie
= nhrp_cie_pull(&p
->payload
, p
->hdr
, &cie_nbma
, &cie_proto
)) != NULL
) {
49 proto
= sockunion_family(&cie_proto
) != AF_UNSPEC
? &cie_proto
: &p
->src_proto
;
50 debugf(NHRP_DEBUG_COMMON
, "NHS: CIE registration: %s: %d",
51 sockunion2str(proto
, buf
, sizeof(buf
)),
53 if (!((cie
->code
== NHRP_CODE_SUCCESS
) ||
54 (cie
->code
== NHRP_CODE_ADMINISTRATIVELY_PROHIBITED
&& nhs
->hub
)))
61 /* Parse extensions */
62 sockunion_family(&nifp
->nat_nbma
) = AF_UNSPEC
;
63 while ((ext
= nhrp_ext_pull(&p
->extensions
, &extpl
)) != NULL
) {
64 switch (htons(ext
->type
) & ~NHRP_EXTENSION_FLAG_COMPULSORY
) {
65 case NHRP_EXTENSION_NAT_ADDRESS
:
66 /* NHS adds second CIE if NAT is detected */
67 if (nhrp_cie_pull(&extpl
, p
->hdr
, &cie_nbma
, &cie_proto
) &&
68 nhrp_cie_pull(&extpl
, p
->hdr
, &cie_nbma
, &cie_proto
)) {
69 nifp
->nat_nbma
= cie_nbma
;
70 debugf(NHRP_DEBUG_IF
, "%s: NAT detected, real NBMA address: %s",
71 ifp
->name
, sockunion2str(&nifp
->nbma
, buf
, sizeof(buf
)));
77 /* Success - schedule next registration, and route NHS */
79 holdtime
= nifp
->afi
[nhs
->afi
].holdtime
;
80 THREAD_OFF(r
->t_register
);
82 /* RFC 2332 5.2.3 - Registration is recommend to be renewed
83 * every one third of holdtime */
84 THREAD_TIMER_ON(master
, r
->t_register
, nhrp_reg_send_req
, r
, holdtime
/ 3);
86 r
->proto_addr
= p
->dst_proto
;
87 c
= nhrp_cache_get(ifp
, &p
->dst_proto
, 1);
88 if (c
) nhrp_cache_update_binding(c
, NHRP_CACHE_NHS
, holdtime
, nhrp_peer_ref(r
->peer
), 0, NULL
);
91 static int nhrp_reg_timeout(struct thread
*t
)
93 struct nhrp_registration
*r
= THREAD_ARG(t
);
98 if (r
->timeout
>= 16 && sockunion_family(&r
->proto_addr
) != AF_UNSPEC
) {
99 nhrp_reqid_free(&nhrp_packet_reqid
, &r
->reqid
);
100 c
= nhrp_cache_get(r
->nhs
->ifp
, &r
->proto_addr
, 0);
101 if (c
) nhrp_cache_update_binding(c
, NHRP_CACHE_NHS
, -1, NULL
, 0, NULL
);
102 sockunion_family(&r
->proto_addr
) = AF_UNSPEC
;
106 if (r
->timeout
> 64) r
->timeout
= 2;
107 THREAD_TIMER_MSEC_ON(master
, r
->t_register
, nhrp_reg_send_req
, r
, 10);
112 static void nhrp_reg_peer_notify(struct notifier_block
*n
, unsigned long cmd
)
114 struct nhrp_registration
*r
= container_of(n
, struct nhrp_registration
, peer_notifier
);
115 char buf
[SU_ADDRSTRLEN
];
119 case NOTIFY_PEER_DOWN
:
120 case NOTIFY_PEER_IFCONFIG_CHANGED
:
121 case NOTIFY_PEER_MTU_CHANGED
:
122 debugf(NHRP_DEBUG_COMMON
, "NHS: Flush timer for %s",
123 sockunion2str(&r
->peer
->vc
->remote
.nbma
, buf
, sizeof buf
));
124 THREAD_TIMER_OFF(r
->t_register
);
125 THREAD_TIMER_MSEC_ON(master
, r
->t_register
, nhrp_reg_send_req
, r
, 10);
130 static int nhrp_reg_send_req(struct thread
*t
)
132 struct nhrp_registration
*r
= THREAD_ARG(t
);
133 struct nhrp_nhs
*nhs
= r
->nhs
;
134 char buf1
[SU_ADDRSTRLEN
], buf2
[SU_ADDRSTRLEN
];
135 struct interface
*ifp
= nhs
->ifp
;
136 struct nhrp_interface
*nifp
= ifp
->info
;
137 struct nhrp_afi_data
*if_ad
= &nifp
->afi
[nhs
->afi
];
138 union sockunion
*dst_proto
;
140 struct nhrp_packet_header
*hdr
;
141 struct nhrp_extension_header
*ext
;
142 struct nhrp_cie_header
*cie
;
144 r
->t_register
= NULL
;
145 if (!nhrp_peer_check(r
->peer
, 2)) {
146 debugf(NHRP_DEBUG_COMMON
, "NHS: Waiting link for %s",
147 sockunion2str(&r
->peer
->vc
->remote
.nbma
, buf1
, sizeof buf1
));
148 THREAD_TIMER_ON(master
, r
->t_register
, nhrp_reg_send_req
, r
, 120);
152 THREAD_TIMER_ON(master
, r
->t_register
, nhrp_reg_timeout
, r
, r
->timeout
);
154 /* RFC2332 5.2.3 NHC uses it's own address as dst if NHS is unknown */
155 dst_proto
= &nhs
->proto_addr
;
156 if (sockunion_family(dst_proto
) == AF_UNSPEC
)
157 dst_proto
= &if_ad
->addr
;
159 sockunion2str(&if_ad
->addr
, buf1
, sizeof(buf1
));
160 sockunion2str(dst_proto
, buf2
, sizeof(buf2
));
161 debugf(NHRP_DEBUG_COMMON
, "NHS: Register %s -> %s (timeout %d)", buf1
, buf2
, r
->timeout
);
163 /* No protocol address configured for tunnel interface */
164 if (sockunion_family(&if_ad
->addr
) == AF_UNSPEC
)
167 zb
= zbuf_alloc(1400);
168 hdr
= nhrp_packet_push(zb
, NHRP_PACKET_REGISTRATION_REQUEST
, &nifp
->nbma
, &if_ad
->addr
, dst_proto
);
170 if (!(if_ad
->flags
& NHRP_IFF_REG_NO_UNIQUE
))
171 hdr
->flags
|= htons(NHRP_FLAG_REGISTRATION_UNIQUE
);
173 hdr
->u
.request_id
= htonl(nhrp_reqid_alloc(&nhrp_packet_reqid
, &r
->reqid
, nhrp_reg_reply
));
175 /* FIXME: push CIE for each local protocol address */
176 cie
= nhrp_cie_push(zb
, NHRP_CODE_SUCCESS
, NULL
, NULL
);
177 cie
->prefix_length
= 0xff;
178 cie
->holding_time
= htons(if_ad
->holdtime
);
179 cie
->mtu
= htons(if_ad
->mtu
);
181 nhrp_ext_request(zb
, hdr
, ifp
);
183 /* Cisco NAT detection extension */
184 hdr
->flags
|= htons(NHRP_FLAG_REGISTRATION_NAT
);
185 ext
= nhrp_ext_push(zb
, hdr
, NHRP_EXTENSION_NAT_ADDRESS
);
186 cie
= nhrp_cie_push(zb
, NHRP_CODE_SUCCESS
, &nifp
->nbma
, &if_ad
->addr
);
187 cie
->prefix_length
= 8 * sockunion_get_addrlen(&nifp
->nbma
);
188 nhrp_ext_complete(zb
, ext
);
190 nhrp_packet_complete(zb
, hdr
);
191 nhrp_peer_send(r
->peer
, zb
);
197 static void nhrp_reg_delete(struct nhrp_registration
*r
)
199 nhrp_peer_notify_del(r
->peer
, &r
->peer_notifier
);
200 nhrp_peer_unref(r
->peer
);
201 list_del(&r
->reglist_entry
);
202 THREAD_OFF(r
->t_register
);
203 XFREE(MTYPE_NHRP_REGISTRATION
, r
);
206 static struct nhrp_registration
*nhrp_reg_by_nbma(struct nhrp_nhs
*nhs
, const union sockunion
*nbma_addr
)
208 struct nhrp_registration
*r
;
210 list_for_each_entry(r
, &nhs
->reglist_head
, reglist_entry
)
211 if (sockunion_same(&r
->peer
->vc
->remote
.nbma
, nbma_addr
))
216 static void nhrp_nhs_resolve_cb(struct resolver_query
*q
, int n
, union sockunion
*addrs
)
218 struct nhrp_nhs
*nhs
= container_of(q
, struct nhrp_nhs
, dns_resolve
);
219 struct nhrp_interface
*nifp
= nhs
->ifp
->info
;
220 struct nhrp_registration
*reg
, *regn
;
223 nhs
->t_resolve
= NULL
;
225 /* Failed, retry in a moment */
226 THREAD_TIMER_ON(master
, nhs
->t_resolve
, nhrp_nhs_resolve
, nhs
, 5);
230 THREAD_TIMER_ON(master
, nhs
->t_resolve
, nhrp_nhs_resolve
, nhs
, 2*60*60);
232 list_for_each_entry(reg
, &nhs
->reglist_head
, reglist_entry
)
236 for (i
= 0; i
< n
; i
++) {
237 if (sockunion_same(&addrs
[i
], &nifp
->nbma
)) {
242 reg
= nhrp_reg_by_nbma(nhs
, &addrs
[i
]);
248 reg
= XCALLOC(MTYPE_NHRP_REGISTRATION
, sizeof(*reg
));
249 reg
->peer
= nhrp_peer_get(nhs
->ifp
, &addrs
[i
]);
252 list_init(®
->reglist_entry
);
253 list_add_tail(®
->reglist_entry
, &nhs
->reglist_head
);
254 nhrp_peer_notify_add(reg
->peer
, ®
->peer_notifier
, nhrp_reg_peer_notify
);
255 THREAD_TIMER_MSEC_ON(master
, reg
->t_register
, nhrp_reg_send_req
, reg
, 50);
258 list_for_each_entry_safe(reg
, regn
, &nhs
->reglist_head
, reglist_entry
) {
260 nhrp_reg_delete(reg
);
264 static int nhrp_nhs_resolve(struct thread
*t
)
266 struct nhrp_nhs
*nhs
= THREAD_ARG(t
);
268 resolver_resolve(&nhs
->dns_resolve
, AF_INET
, nhs
->nbma_fqdn
, nhrp_nhs_resolve_cb
);
273 int nhrp_nhs_add(struct interface
*ifp
, afi_t afi
, union sockunion
*proto_addr
, const char *nbma_fqdn
)
275 struct nhrp_interface
*nifp
= ifp
->info
;
276 struct nhrp_nhs
*nhs
;
278 if (sockunion_family(proto_addr
) != AF_UNSPEC
&&
279 sockunion_family(proto_addr
) != afi2family(afi
))
280 return NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH
;
282 list_for_each_entry(nhs
, &nifp
->afi
[afi
].nhslist_head
, nhslist_entry
) {
283 if (sockunion_family(&nhs
->proto_addr
) != AF_UNSPEC
&&
284 sockunion_family(proto_addr
) != AF_UNSPEC
&&
285 sockunion_same(&nhs
->proto_addr
, proto_addr
))
286 return NHRP_ERR_ENTRY_EXISTS
;
288 if (strcmp(nhs
->nbma_fqdn
, nbma_fqdn
) == 0)
289 return NHRP_ERR_ENTRY_EXISTS
;
292 nhs
= XMALLOC(MTYPE_NHRP_NHS
, sizeof(struct nhrp_nhs
));
293 if (!nhs
) return NHRP_ERR_NO_MEMORY
;
295 *nhs
= (struct nhrp_nhs
) {
298 .proto_addr
= *proto_addr
,
299 .nbma_fqdn
= strdup(nbma_fqdn
),
300 .reglist_head
= LIST_INITIALIZER(nhs
->reglist_head
),
302 list_add_tail(&nhs
->nhslist_entry
, &nifp
->afi
[afi
].nhslist_head
);
303 THREAD_TIMER_MSEC_ON(master
, nhs
->t_resolve
, nhrp_nhs_resolve
, nhs
, 1000);
308 int nhrp_nhs_del(struct interface
*ifp
, afi_t afi
, union sockunion
*proto_addr
, const char *nbma_fqdn
)
310 struct nhrp_interface
*nifp
= ifp
->info
;
311 struct nhrp_nhs
*nhs
, *nnhs
;
312 int ret
= NHRP_ERR_ENTRY_NOT_FOUND
;
314 if (sockunion_family(proto_addr
) != AF_UNSPEC
&&
315 sockunion_family(proto_addr
) != afi2family(afi
))
316 return NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH
;
318 list_for_each_entry_safe(nhs
, nnhs
, &nifp
->afi
[afi
].nhslist_head
, nhslist_entry
) {
319 if (!sockunion_same(&nhs
->proto_addr
, proto_addr
))
321 if (strcmp(nhs
->nbma_fqdn
, nbma_fqdn
) != 0)
331 int nhrp_nhs_free(struct nhrp_nhs
*nhs
)
333 struct nhrp_registration
*r
, *rn
;
335 list_for_each_entry_safe(r
, rn
, &nhs
->reglist_head
, reglist_entry
)
337 THREAD_OFF(nhs
->t_resolve
);
338 list_del(&nhs
->nhslist_entry
);
339 free((void*) nhs
->nbma_fqdn
);
340 XFREE(MTYPE_NHRP_NHS
, nhs
);
344 void nhrp_nhs_terminate(void)
346 struct interface
*ifp
;
347 struct nhrp_interface
*nifp
;
348 struct nhrp_nhs
*nhs
, *tmp
;
349 struct listnode
*node
;
352 for (ALL_LIST_ELEMENTS_RO(vrf_iflist (VRF_DEFAULT
), node
, ifp
)) {
354 for (afi
= 0; afi
< AFI_MAX
; afi
++) {
355 list_for_each_entry_safe(nhs
, tmp
, &nifp
->afi
[afi
].nhslist_head
, nhslist_entry
)
361 void nhrp_nhs_foreach(struct interface
*ifp
, afi_t afi
, void (*cb
)(struct nhrp_nhs
*, struct nhrp_registration
*, void *), void *ctx
)
363 struct nhrp_interface
*nifp
= ifp
->info
;
364 struct nhrp_nhs
*nhs
;
365 struct nhrp_registration
*reg
;
367 list_for_each_entry(nhs
, &nifp
->afi
[afi
].nhslist_head
, nhslist_entry
) {
368 if (!list_empty(&nhs
->reglist_head
)) {
369 list_for_each_entry(reg
, &nhs
->reglist_head
, reglist_entry
)