]> git.proxmox.com Git - mirror_frr.git/blame - nhrpd/nhrp_nhs.c
nhrpd: Make comments clearer, fix style issues
[mirror_frr.git] / nhrpd / nhrp_nhs.c
CommitLineData
2fb975da
TT
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
819dc8bb
DL
17DEFINE_MTYPE_STATIC(NHRPD, NHRP_NHS, "NHRP next hop server")
18DEFINE_MTYPE_STATIC(NHRPD, NHRP_REGISTRATION, "NHRP registration entries")
19
2fb975da 20static int nhrp_nhs_resolve(struct thread *t);
2fb975da
TT
21static int nhrp_reg_send_req(struct thread *t);
22
23static void nhrp_reg_reply(struct nhrp_reqid *reqid, void *arg)
24{
25 struct nhrp_packet_parser *p = arg;
996c9314
LB
26 struct nhrp_registration *r =
27 container_of(reqid, struct nhrp_registration, reqid);
2fb975da
TT
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_proto, *proto;
2fb975da 36 int ok = 0, holdtime;
659fde26 37 unsigned short mtu = 0;
2fb975da
TT
38
39 nhrp_reqid_free(&nhrp_packet_reqid, &r->reqid);
40
41 if (p->hdr->type != NHRP_PACKET_REGISTRATION_REPLY) {
42 debugf(NHRP_DEBUG_COMMON, "NHS: Registration failed");
43 return;
44 }
45
46 debugf(NHRP_DEBUG_COMMON, "NHS: Reg.reply received");
47
48 ok = 1;
996c9314
LB
49 while ((cie = nhrp_cie_pull(&p->payload, p->hdr, &cie_nbma, &cie_proto))
50 != NULL) {
51 proto = sockunion_family(&cie_proto) != AF_UNSPEC
52 ? &cie_proto
53 : &p->src_proto;
b6c48481
DS
54 debugf(NHRP_DEBUG_COMMON, "NHS: CIE registration: %pSU: %d",
55 proto, cie->code);
996c9314
LB
56 if (!((cie->code == NHRP_CODE_SUCCESS)
57 || (cie->code == NHRP_CODE_ADMINISTRATIVELY_PROHIBITED
58 && nhs->hub)))
2fb975da 59 ok = 0;
659fde26
GG
60 mtu = ntohs(cie->mtu);
61 debugf(NHRP_DEBUG_COMMON, "NHS: CIE MTU: %d", mtu);
2fb975da
TT
62 }
63
64 if (!ok)
65 return;
66
67 /* Parse extensions */
68 sockunion_family(&nifp->nat_nbma) = AF_UNSPEC;
69 while ((ext = nhrp_ext_pull(&p->extensions, &extpl)) != NULL) {
70 switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) {
71 case NHRP_EXTENSION_NAT_ADDRESS:
72 /* NHS adds second CIE if NAT is detected */
996c9314
LB
73 if (nhrp_cie_pull(&extpl, p->hdr, &cie_nbma, &cie_proto)
74 && nhrp_cie_pull(&extpl, p->hdr, &cie_nbma,
75 &cie_proto)) {
2fb975da 76 nifp->nat_nbma = cie_nbma;
996c9314 77 debugf(NHRP_DEBUG_IF,
b6c48481
DS
78 "%s: NAT detected, real NBMA address: %pSU",
79 ifp->name, &nifp->nbma);
2fb975da
TT
80 }
81 break;
82 }
83 }
84
85 /* Success - schedule next registration, and route NHS */
86 r->timeout = 2;
87 holdtime = nifp->afi[nhs->afi].holdtime;
88 THREAD_OFF(r->t_register);
89
90 /* RFC 2332 5.2.3 - Registration is recommend to be renewed
91 * every one third of holdtime */
ffa2c898
QY
92 thread_add_timer(master, nhrp_reg_send_req, r, holdtime / 3,
93 &r->t_register);
2fb975da
TT
94
95 r->proto_addr = p->dst_proto;
96 c = nhrp_cache_get(ifp, &p->dst_proto, 1);
996c9314
LB
97 if (c)
98 nhrp_cache_update_binding(c, NHRP_CACHE_NHS, holdtime,
659fde26 99 nhrp_peer_ref(r->peer), mtu, NULL);
2fb975da
TT
100}
101
102static int nhrp_reg_timeout(struct thread *t)
103{
104 struct nhrp_registration *r = THREAD_ARG(t);
105 struct nhrp_cache *c;
106
107 r->t_register = NULL;
108
109 if (r->timeout >= 16 && sockunion_family(&r->proto_addr) != AF_UNSPEC) {
110 nhrp_reqid_free(&nhrp_packet_reqid, &r->reqid);
111 c = nhrp_cache_get(r->nhs->ifp, &r->proto_addr, 0);
996c9314
LB
112 if (c)
113 nhrp_cache_update_binding(c, NHRP_CACHE_NHS, -1, NULL,
114 0, NULL);
2fb975da
TT
115 sockunion_family(&r->proto_addr) = AF_UNSPEC;
116 }
117
118 r->timeout <<= 1;
74e5ba3a
RD
119 if (r->timeout > 64) {
120 /* If registration fails repeatedly, this may be because the
121 * IPSec connection is not working. Close the connection so it
122 * can be re-established correctly
123 */
124 if (r->peer && r->peer->vc && r->peer->vc->ike_uniqueid) {
125 debugf(NHRP_DEBUG_COMMON,
126 "Terminating IPSec Connection for %d\n",
127 r->peer->vc->ike_uniqueid);
083bbfae
GG
128 vici_terminate_vc_by_ike_id(r->peer->vc->ike_uniqueid);
129 r->peer->vc->ike_uniqueid = 0;
4cbaf956 130 }
996c9314 131 r->timeout = 2;
4cbaf956 132 }
996c9314 133 thread_add_timer_msec(master, nhrp_reg_send_req, r, 10, &r->t_register);
2fb975da
TT
134
135 return 0;
136}
137
138static void nhrp_reg_peer_notify(struct notifier_block *n, unsigned long cmd)
139{
996c9314
LB
140 struct nhrp_registration *r =
141 container_of(n, struct nhrp_registration, peer_notifier);
2fb975da
TT
142
143 switch (cmd) {
144 case NOTIFY_PEER_UP:
145 case NOTIFY_PEER_DOWN:
146 case NOTIFY_PEER_IFCONFIG_CHANGED:
147 case NOTIFY_PEER_MTU_CHANGED:
b6c48481
DS
148 debugf(NHRP_DEBUG_COMMON, "NHS: Flush timer for %pSU",
149 &r->peer->vc->remote.nbma);
50478845 150 THREAD_OFF(r->t_register);
ffa2c898
QY
151 thread_add_timer_msec(master, nhrp_reg_send_req, r, 10,
152 &r->t_register);
2fb975da
TT
153 break;
154 }
155}
156
157static int nhrp_reg_send_req(struct thread *t)
158{
159 struct nhrp_registration *r = THREAD_ARG(t);
160 struct nhrp_nhs *nhs = r->nhs;
161 char buf1[SU_ADDRSTRLEN], buf2[SU_ADDRSTRLEN];
162 struct interface *ifp = nhs->ifp;
163 struct nhrp_interface *nifp = ifp->info;
164 struct nhrp_afi_data *if_ad = &nifp->afi[nhs->afi];
165 union sockunion *dst_proto;
166 struct zbuf *zb;
167 struct nhrp_packet_header *hdr;
168 struct nhrp_extension_header *ext;
169 struct nhrp_cie_header *cie;
170
171 r->t_register = NULL;
172 if (!nhrp_peer_check(r->peer, 2)) {
b6c48481
DS
173 debugf(NHRP_DEBUG_COMMON, "NHS: Waiting link for %pSU",
174 &r->peer->vc->remote.nbma);
ffa2c898
QY
175 thread_add_timer(master, nhrp_reg_send_req, r, 120,
176 &r->t_register);
2fb975da
TT
177 return 0;
178 }
179
ffa2c898
QY
180 thread_add_timer(master, nhrp_reg_timeout, r, r->timeout,
181 &r->t_register);
2fb975da
TT
182
183 /* RFC2332 5.2.3 NHC uses it's own address as dst if NHS is unknown */
184 dst_proto = &nhs->proto_addr;
185 if (sockunion_family(dst_proto) == AF_UNSPEC)
186 dst_proto = &if_ad->addr;
187
188 sockunion2str(&if_ad->addr, buf1, sizeof(buf1));
189 sockunion2str(dst_proto, buf2, sizeof(buf2));
996c9314
LB
190 debugf(NHRP_DEBUG_COMMON, "NHS: Register %s -> %s (timeout %d)", buf1,
191 buf2, r->timeout);
2fb975da
TT
192
193 /* No protocol address configured for tunnel interface */
194 if (sockunion_family(&if_ad->addr) == AF_UNSPEC)
195 return 0;
196
197 zb = zbuf_alloc(1400);
996c9314
LB
198 hdr = nhrp_packet_push(zb, NHRP_PACKET_REGISTRATION_REQUEST,
199 &nifp->nbma, &if_ad->addr, dst_proto);
ef9329ac 200 hdr->hop_count = 1;
2fb975da
TT
201 if (!(if_ad->flags & NHRP_IFF_REG_NO_UNIQUE))
202 hdr->flags |= htons(NHRP_FLAG_REGISTRATION_UNIQUE);
203
996c9314
LB
204 hdr->u.request_id = htonl(nhrp_reqid_alloc(&nhrp_packet_reqid,
205 &r->reqid, nhrp_reg_reply));
2fb975da
TT
206
207 /* FIXME: push CIE for each local protocol address */
208 cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, NULL, NULL);
f7f9a377
AL
209 /* RFC2332 5.2.1 if unique is set then prefix length must be 0xff */
210 cie->prefix_length = (if_ad->flags & NHRP_IFF_REG_NO_UNIQUE) ? 8 * sockunion_get_addrlen(dst_proto) : 0xff;
2fb975da
TT
211 cie->holding_time = htons(if_ad->holdtime);
212 cie->mtu = htons(if_ad->mtu);
213
214 nhrp_ext_request(zb, hdr, ifp);
215
216 /* Cisco NAT detection extension */
217 hdr->flags |= htons(NHRP_FLAG_REGISTRATION_NAT);
218 ext = nhrp_ext_push(zb, hdr, NHRP_EXTENSION_NAT_ADDRESS);
219 cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, &nifp->nbma, &if_ad->addr);
55fd6ee9 220 cie->prefix_length = 8 * sockunion_get_addrlen(&if_ad->addr);
2fb975da
TT
221 nhrp_ext_complete(zb, ext);
222
223 nhrp_packet_complete(zb, hdr);
224 nhrp_peer_send(r->peer, zb);
225 zbuf_free(zb);
226
227 return 0;
228}
229
230static void nhrp_reg_delete(struct nhrp_registration *r)
231{
232 nhrp_peer_notify_del(r->peer, &r->peer_notifier);
233 nhrp_peer_unref(r->peer);
234 list_del(&r->reglist_entry);
235 THREAD_OFF(r->t_register);
236 XFREE(MTYPE_NHRP_REGISTRATION, r);
237}
238
996c9314
LB
239static struct nhrp_registration *
240nhrp_reg_by_nbma(struct nhrp_nhs *nhs, const union sockunion *nbma_addr)
2fb975da
TT
241{
242 struct nhrp_registration *r;
243
996c9314
LB
244 list_for_each_entry(
245 r, &nhs->reglist_head,
246 reglist_entry) if (sockunion_same(&r->peer->vc->remote.nbma,
247 nbma_addr)) return r;
2fb975da
TT
248 return NULL;
249}
250
3286ca07
DL
251static void nhrp_nhs_resolve_cb(struct resolver_query *q, const char *errstr,
252 int n, union sockunion *addrs)
2fb975da
TT
253{
254 struct nhrp_nhs *nhs = container_of(q, struct nhrp_nhs, dns_resolve);
255 struct nhrp_interface *nifp = nhs->ifp->info;
256 struct nhrp_registration *reg, *regn;
257 int i;
258
259 nhs->t_resolve = NULL;
260 if (n < 0) {
261 /* Failed, retry in a moment */
ffa2c898
QY
262 thread_add_timer(master, nhrp_nhs_resolve, nhs, 5,
263 &nhs->t_resolve);
2fb975da
TT
264 return;
265 }
266
ffa2c898
QY
267 thread_add_timer(master, nhrp_nhs_resolve, nhs, 2 * 60 * 60,
268 &nhs->t_resolve);
2fb975da 269
996c9314
LB
270 list_for_each_entry(reg, &nhs->reglist_head, reglist_entry) reg->mark =
271 1;
2fb975da
TT
272
273 nhs->hub = 0;
274 for (i = 0; i < n; i++) {
275 if (sockunion_same(&addrs[i], &nifp->nbma)) {
276 nhs->hub = 1;
277 continue;
278 }
279
280 reg = nhrp_reg_by_nbma(nhs, &addrs[i]);
281 if (reg) {
282 reg->mark = 0;
283 continue;
284 }
285
286 reg = XCALLOC(MTYPE_NHRP_REGISTRATION, sizeof(*reg));
287 reg->peer = nhrp_peer_get(nhs->ifp, &addrs[i]);
288 reg->nhs = nhs;
289 reg->timeout = 1;
290 list_init(&reg->reglist_entry);
291 list_add_tail(&reg->reglist_entry, &nhs->reglist_head);
996c9314
LB
292 nhrp_peer_notify_add(reg->peer, &reg->peer_notifier,
293 nhrp_reg_peer_notify);
ffa2c898
QY
294 thread_add_timer_msec(master, nhrp_reg_send_req, reg, 50,
295 &reg->t_register);
2fb975da
TT
296 }
297
996c9314
LB
298 list_for_each_entry_safe(reg, regn, &nhs->reglist_head, reglist_entry)
299 {
2fb975da
TT
300 if (reg->mark)
301 nhrp_reg_delete(reg);
302 }
303}
304
305static int nhrp_nhs_resolve(struct thread *t)
306{
307 struct nhrp_nhs *nhs = THREAD_ARG(t);
308
996c9314
LB
309 resolver_resolve(&nhs->dns_resolve, AF_INET, nhs->nbma_fqdn,
310 nhrp_nhs_resolve_cb);
2fb975da
TT
311
312 return 0;
313}
314
996c9314
LB
315int nhrp_nhs_add(struct interface *ifp, afi_t afi, union sockunion *proto_addr,
316 const char *nbma_fqdn)
2fb975da
TT
317{
318 struct nhrp_interface *nifp = ifp->info;
319 struct nhrp_nhs *nhs;
320
996c9314
LB
321 if (sockunion_family(proto_addr) != AF_UNSPEC
322 && sockunion_family(proto_addr) != afi2family(afi))
2fb975da
TT
323 return NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH;
324
996c9314
LB
325 list_for_each_entry(nhs, &nifp->afi[afi].nhslist_head, nhslist_entry)
326 {
327 if (sockunion_family(&nhs->proto_addr) != AF_UNSPEC
328 && sockunion_family(proto_addr) != AF_UNSPEC
329 && sockunion_same(&nhs->proto_addr, proto_addr))
2fb975da
TT
330 return NHRP_ERR_ENTRY_EXISTS;
331
332 if (strcmp(nhs->nbma_fqdn, nbma_fqdn) == 0)
333 return NHRP_ERR_ENTRY_EXISTS;
334 }
335
336 nhs = XMALLOC(MTYPE_NHRP_NHS, sizeof(struct nhrp_nhs));
2fb975da 337
996c9314 338 *nhs = (struct nhrp_nhs){
2fb975da
TT
339 .afi = afi,
340 .ifp = ifp,
341 .proto_addr = *proto_addr,
342 .nbma_fqdn = strdup(nbma_fqdn),
343 .reglist_head = LIST_INITIALIZER(nhs->reglist_head),
344 };
345 list_add_tail(&nhs->nhslist_entry, &nifp->afi[afi].nhslist_head);
ffa2c898
QY
346 thread_add_timer_msec(master, nhrp_nhs_resolve, nhs, 1000,
347 &nhs->t_resolve);
2fb975da
TT
348
349 return NHRP_OK;
350}
351
996c9314
LB
352int nhrp_nhs_del(struct interface *ifp, afi_t afi, union sockunion *proto_addr,
353 const char *nbma_fqdn)
2fb975da
TT
354{
355 struct nhrp_interface *nifp = ifp->info;
356 struct nhrp_nhs *nhs, *nnhs;
357 int ret = NHRP_ERR_ENTRY_NOT_FOUND;
358
996c9314
LB
359 if (sockunion_family(proto_addr) != AF_UNSPEC
360 && sockunion_family(proto_addr) != afi2family(afi))
2fb975da
TT
361 return NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH;
362
996c9314
LB
363 list_for_each_entry_safe(nhs, nnhs, &nifp->afi[afi].nhslist_head,
364 nhslist_entry)
365 {
2fb975da
TT
366 if (!sockunion_same(&nhs->proto_addr, proto_addr))
367 continue;
368 if (strcmp(nhs->nbma_fqdn, nbma_fqdn) != 0)
369 continue;
370
371 nhrp_nhs_free(nhs);
372 ret = NHRP_OK;
373 }
374
375 return ret;
376}
377
378int nhrp_nhs_free(struct nhrp_nhs *nhs)
379{
380 struct nhrp_registration *r, *rn;
381
382 list_for_each_entry_safe(r, rn, &nhs->reglist_head, reglist_entry)
383 nhrp_reg_delete(r);
384 THREAD_OFF(nhs->t_resolve);
385 list_del(&nhs->nhslist_entry);
996c9314 386 free((void *)nhs->nbma_fqdn);
2fb975da
TT
387 XFREE(MTYPE_NHRP_NHS, nhs);
388 return 0;
389}
390
ee72f0a0
RD
391void nhrp_nhs_interface_del(struct interface *ifp)
392{
393 struct nhrp_interface *nifp = ifp->info;
394 struct nhrp_nhs *nhs, *tmp;
395 afi_t afi;
396
397 for (afi = 0; afi < AFI_MAX; afi++) {
398 debugf(NHRP_DEBUG_COMMON, "Cleaning up nhs entries (%d)",
399 !list_empty(&nifp->afi[afi].nhslist_head));
400
401 list_for_each_entry_safe(nhs, tmp, &nifp->afi[afi].nhslist_head,
402 nhslist_entry)
403 {
404 nhrp_nhs_free(nhs);
405 }
406 }
407}
408
2fb975da
TT
409void nhrp_nhs_terminate(void)
410{
f4e14fdb 411 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
2fb975da
TT
412 struct interface *ifp;
413 struct nhrp_interface *nifp;
414 struct nhrp_nhs *nhs, *tmp;
2fb975da
TT
415 afi_t afi;
416
451fda4f 417 FOR_ALL_INTERFACES (vrf, ifp) {
2fb975da
TT
418 nifp = ifp->info;
419 for (afi = 0; afi < AFI_MAX; afi++) {
996c9314
LB
420 list_for_each_entry_safe(
421 nhs, tmp, &nifp->afi[afi].nhslist_head,
422 nhslist_entry) nhrp_nhs_free(nhs);
2fb975da
TT
423 }
424 }
425}
0ca036b4 426
996c9314
LB
427void nhrp_nhs_foreach(struct interface *ifp, afi_t afi,
428 void (*cb)(struct nhrp_nhs *, struct nhrp_registration *,
429 void *),
430 void *ctx)
0ca036b4
TT
431{
432 struct nhrp_interface *nifp = ifp->info;
433 struct nhrp_nhs *nhs;
434 struct nhrp_registration *reg;
435
996c9314
LB
436 list_for_each_entry(nhs, &nifp->afi[afi].nhslist_head, nhslist_entry)
437 {
0ca036b4 438 if (!list_empty(&nhs->reglist_head)) {
996c9314
LB
439 list_for_each_entry(reg, &nhs->reglist_head,
440 reglist_entry) cb(nhs, reg, ctx);
0ca036b4
TT
441 } else
442 cb(nhs, 0, ctx);
443 }
444}