]> git.proxmox.com Git - mirror_frr.git/blob - nhrpd/nhrp_nhs.c
doc: Add `show ipv6 rpf X:X::X:X` command to docs
[mirror_frr.git] / nhrpd / nhrp_nhs.c
1 /* NHRP NHC nexthop server functions (registration)
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
10 #include "zebra.h"
11 #include "zbuf.h"
12 #include "memory.h"
13 #include "thread.h"
14 #include "nhrpd.h"
15 #include "nhrp_protocol.h"
16
17 DEFINE_MTYPE_STATIC(NHRPD, NHRP_NHS, "NHRP next hop server");
18 DEFINE_MTYPE_STATIC(NHRPD, NHRP_REGISTRATION, "NHRP registration entries");
19
20 static void nhrp_nhs_resolve(struct thread *t);
21 static void nhrp_reg_send_req(struct thread *t);
22
23 static void nhrp_reg_reply(struct nhrp_reqid *reqid, void *arg)
24 {
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;
33 struct nhrp_cache *c;
34 struct zbuf extpl;
35 union sockunion cie_nbma, cie_nbma_nhs, cie_proto, cie_proto_nhs,
36 *proto;
37 int ok = 0, holdtime;
38 unsigned short mtu = 0;
39
40 nhrp_reqid_free(&nhrp_packet_reqid, &r->reqid);
41
42 if (p->hdr->type != NHRP_PACKET_REGISTRATION_REPLY) {
43 debugf(NHRP_DEBUG_COMMON, "NHS: Registration failed");
44 return;
45 }
46
47 debugf(NHRP_DEBUG_COMMON, "NHS: Reg.reply received");
48
49 ok = 1;
50 while ((cie = nhrp_cie_pull(&p->payload, p->hdr, &cie_nbma, &cie_proto))
51 != NULL) {
52 proto = sockunion_family(&cie_proto) != AF_UNSPEC
53 ? &cie_proto
54 : &p->src_proto;
55 debugf(NHRP_DEBUG_COMMON, "NHS: CIE registration: %pSU: %d",
56 proto, cie->code);
57 if (!((cie->code == NHRP_CODE_SUCCESS)
58 || (cie->code == NHRP_CODE_ADMINISTRATIVELY_PROHIBITED
59 && nhs->hub)))
60 ok = 0;
61 mtu = ntohs(cie->mtu);
62 debugf(NHRP_DEBUG_COMMON, "NHS: CIE MTU: %d", mtu);
63 }
64
65 if (!ok)
66 return;
67
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,
77 &cie_proto)) {
78 nifp->nat_nbma = cie_nbma;
79 debugf(NHRP_DEBUG_IF,
80 "%s: NAT detected, real NBMA address: %pSU",
81 ifp->name, &nifp->nbma);
82 }
83 break;
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,
87 &cie_proto_nhs);
88 break;
89 }
90 }
91
92 /* Success - schedule next registration, and route NHS */
93 r->timeout = 2;
94 holdtime = nifp->afi[nhs->afi].holdtime;
95 THREAD_OFF(r->t_register);
96
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,
100 &r->t_register);
101
102 r->proto_addr = p->dst_proto;
103 c = nhrp_cache_get(ifp, &p->dst_proto, 1);
104 if (c)
105 nhrp_cache_update_binding(c, NHRP_CACHE_NHS, holdtime,
106 nhrp_peer_ref(r->peer), mtu, NULL,
107 &cie_nbma_nhs);
108 }
109
110 static void nhrp_reg_timeout(struct thread *t)
111 {
112 struct nhrp_registration *r = THREAD_ARG(t);
113 struct nhrp_cache *c;
114
115
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);
119 if (c)
120 nhrp_cache_update_binding(c, NHRP_CACHE_NHS, -1, NULL,
121 0, NULL, NULL);
122 sockunion_family(&r->proto_addr) = AF_UNSPEC;
123 }
124
125 r->timeout <<= 1;
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
130 */
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;
137 }
138 r->timeout = 2;
139 }
140 thread_add_timer_msec(master, nhrp_reg_send_req, r, 10, &r->t_register);
141 }
142
143 static void nhrp_reg_peer_notify(struct notifier_block *n, unsigned long cmd)
144 {
145 struct nhrp_registration *r =
146 container_of(n, struct nhrp_registration, peer_notifier);
147
148 switch (cmd) {
149 case NOTIFY_PEER_UP:
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,
157 &r->t_register);
158 break;
159 }
160 }
161
162 static void nhrp_reg_send_req(struct thread *t)
163 {
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;
170 struct zbuf *zb;
171 struct nhrp_packet_header *hdr;
172 struct nhrp_extension_header *ext;
173 struct nhrp_cie_header *cie;
174
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,
179 &r->t_register);
180 return;
181 }
182
183 thread_add_timer(master, nhrp_reg_timeout, r, r->timeout,
184 &r->t_register);
185
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;
190
191 debugf(NHRP_DEBUG_COMMON, "NHS: Register %pSU -> %pSU (timeout %d)",
192 &if_ad->addr, dst_proto, r->timeout);
193
194 /* No protocol address configured for tunnel interface */
195 if (sockunion_family(&if_ad->addr) == AF_UNSPEC)
196 return;
197
198 zb = zbuf_alloc(1400);
199 hdr = nhrp_packet_push(zb, NHRP_PACKET_REGISTRATION_REQUEST,
200 &nifp->nbma, &if_ad->addr, dst_proto);
201 hdr->hop_count = 1;
202 if (!(if_ad->flags & NHRP_IFF_REG_NO_UNIQUE))
203 hdr->flags |= htons(NHRP_FLAG_REGISTRATION_UNIQUE);
204
205 hdr->u.request_id = htonl(nhrp_reqid_alloc(&nhrp_packet_reqid,
206 &r->reqid, nhrp_reg_reply));
207
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)
213 : 0xff;
214 cie->holding_time = htons(if_ad->holdtime);
215 cie->mtu = htons(if_ad->mtu);
216
217 nhrp_ext_request(zb, hdr, ifp);
218
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;
224 } else {
225 /* cisco magic: If NHS is not known then use all 0s as
226 * client protocol address in NAT Extension header
227 */
228 memset(&nhs_proto, 0, sizeof(nhs_proto));
229 sockunion_family(&nhs_proto) = afi2family(nhs->afi);
230 }
231
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,
236 &nhs_proto);
237 cie->prefix_length = 8 * sockunion_get_addrlen(&if_ad->addr);
238 cie->mtu = htons(if_ad->mtu);
239 nhrp_ext_complete(zb, ext);
240
241 nhrp_packet_complete(zb, hdr);
242 nhrp_peer_send(r->peer, zb);
243 zbuf_free(zb);
244 }
245
246 static void nhrp_reg_delete(struct nhrp_registration *r)
247 {
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);
253 }
254
255 static struct nhrp_registration *
256 nhrp_reg_by_nbma(struct nhrp_nhs *nhs, const union sockunion *nbma_addr)
257 {
258 struct nhrp_registration *r;
259
260 frr_each (nhrp_reglist, &nhs->reglist_head, r)
261 if (sockunion_same(&r->peer->vc->remote.nbma, nbma_addr))
262 return r;
263 return NULL;
264 }
265
266 static void nhrp_nhs_resolve_cb(struct resolver_query *q, const char *errstr,
267 int n, union sockunion *addrs)
268 {
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;
272 int i;
273
274 if (n < 0) {
275 /* Failed, retry in a moment */
276 thread_add_timer(master, nhrp_nhs_resolve, nhs, 5,
277 &nhs->t_resolve);
278 return;
279 }
280
281 thread_add_timer(master, nhrp_nhs_resolve, nhs, 2 * 60 * 60,
282 &nhs->t_resolve);
283
284 frr_each (nhrp_reglist, &nhs->reglist_head, reg)
285 reg->mark = 1;
286
287 nhs->hub = 0;
288 for (i = 0; i < n; i++) {
289 if (sockunion_same(&addrs[i], &nifp->nbma)) {
290 nhs->hub = 1;
291 continue;
292 }
293
294 reg = nhrp_reg_by_nbma(nhs, &addrs[i]);
295 if (reg) {
296 reg->mark = 0;
297 continue;
298 }
299
300 reg = XCALLOC(MTYPE_NHRP_REGISTRATION, sizeof(*reg));
301 reg->peer = nhrp_peer_get(nhs->ifp, &addrs[i]);
302 reg->nhs = nhs;
303 reg->timeout = 1;
304 nhrp_reglist_add_tail(&nhs->reglist_head, reg);
305 nhrp_peer_notify_add(reg->peer, &reg->peer_notifier,
306 nhrp_reg_peer_notify);
307 thread_add_timer_msec(master, nhrp_reg_send_req, reg, 50,
308 &reg->t_register);
309 }
310
311 frr_each_safe (nhrp_reglist, &nhs->reglist_head, reg)
312 if (reg->mark)
313 nhrp_reg_delete(reg);
314 }
315
316 static void nhrp_nhs_resolve(struct thread *t)
317 {
318 struct nhrp_nhs *nhs = THREAD_ARG(t);
319
320 resolver_resolve(&nhs->dns_resolve, AF_INET, VRF_DEFAULT,
321 nhs->nbma_fqdn, nhrp_nhs_resolve_cb);
322 }
323
324 int nhrp_nhs_add(struct interface *ifp, afi_t afi, union sockunion *proto_addr,
325 const char *nbma_fqdn)
326 {
327 struct nhrp_interface *nifp = ifp->info;
328 struct nhrp_nhs *nhs;
329
330 if (sockunion_family(proto_addr) != AF_UNSPEC
331 && sockunion_family(proto_addr) != afi2family(afi))
332 return NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH;
333
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;
339
340 if (strcmp(nhs->nbma_fqdn, nbma_fqdn) == 0)
341 return NHRP_ERR_ENTRY_EXISTS;
342 }
343
344 nhs = XMALLOC(MTYPE_NHRP_NHS, sizeof(struct nhrp_nhs));
345
346 *nhs = (struct nhrp_nhs){
347 .afi = afi,
348 .ifp = ifp,
349 .proto_addr = *proto_addr,
350 .nbma_fqdn = strdup(nbma_fqdn),
351 .reglist_head = INIT_DLIST(nhs->reglist_head),
352 };
353 nhrp_nhslist_add_tail(&nifp->afi[afi].nhslist_head, nhs);
354 thread_add_timer_msec(master, nhrp_nhs_resolve, nhs, 1000,
355 &nhs->t_resolve);
356
357 return NHRP_OK;
358 }
359
360 int nhrp_nhs_del(struct interface *ifp, afi_t afi, union sockunion *proto_addr,
361 const char *nbma_fqdn)
362 {
363 struct nhrp_interface *nifp = ifp->info;
364 struct nhrp_nhs *nhs;
365 int ret = NHRP_ERR_ENTRY_NOT_FOUND;
366
367 if (sockunion_family(proto_addr) != AF_UNSPEC
368 && sockunion_family(proto_addr) != afi2family(afi))
369 return NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH;
370
371 frr_each_safe (nhrp_nhslist, &nifp->afi[afi].nhslist_head, nhs) {
372 if (!sockunion_same(&nhs->proto_addr, proto_addr))
373 continue;
374 if (strcmp(nhs->nbma_fqdn, nbma_fqdn) != 0)
375 continue;
376
377 nhrp_nhs_free(nifp, afi, nhs);
378 ret = NHRP_OK;
379 }
380
381 return ret;
382 }
383
384 int nhrp_nhs_free(struct nhrp_interface *nifp, afi_t afi, struct nhrp_nhs *nhs)
385 {
386 struct nhrp_registration *r;
387
388 frr_each_safe (nhrp_reglist, &nhs->reglist_head, r)
389 nhrp_reg_delete(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);
394 return 0;
395 }
396
397 void nhrp_nhs_interface_del(struct interface *ifp)
398 {
399 struct nhrp_interface *nifp = ifp->info;
400 struct nhrp_nhs *nhs;
401 afi_t afi;
402
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));
406
407 frr_each_safe (nhrp_nhslist, &nifp->afi[afi].nhslist_head, nhs)
408 nhrp_nhs_free(nifp, afi, nhs);
409 }
410 }
411
412 void nhrp_nhs_terminate(void)
413 {
414 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
415 struct interface *ifp;
416 struct nhrp_interface *nifp;
417 struct nhrp_nhs *nhs;
418 afi_t afi;
419
420 FOR_ALL_INTERFACES (vrf, ifp) {
421 nifp = ifp->info;
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);
426 }
427 }
428 }
429
430 void nhrp_nhs_foreach(struct interface *ifp, afi_t afi,
431 void (*cb)(struct nhrp_nhs *, struct nhrp_registration *,
432 void *),
433 void *ctx)
434 {
435 struct nhrp_interface *nifp = ifp->info;
436 struct nhrp_nhs *nhs;
437 struct nhrp_registration *reg;
438
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)
442 cb(nhs, reg, ctx);
443 } else
444 cb(nhs, 0, ctx);
445 }
446 }
447
448 int nhrp_nhs_match_ip(union sockunion *in_ip, struct nhrp_interface *nifp)
449 {
450 int i;
451 struct nhrp_nhs *nhs;
452 struct nhrp_registration *reg;
453
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))
457 continue;
458
459 frr_each (nhrp_reglist, &nhs->reglist_head, reg) {
460 if (!sockunion_cmp(in_ip,
461 &reg->peer->vc->remote.nbma))
462 return 1;
463 }
464 }
465 }
466 return 0;
467 }