]> git.proxmox.com Git - mirror_frr.git/blob - nhrpd/nhrp_nhs.c
*: fix source file headers & includes for errcodes
[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 int nhrp_nhs_resolve(struct thread *t);
21 static int 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_proto, *proto;
36 char buf[64];
37 int ok = 0, holdtime;
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;
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;
54 debugf(NHRP_DEBUG_COMMON, "NHS: CIE registration: %s: %d",
55 sockunion2str(proto, buf, sizeof(buf)), cie->code);
56 if (!((cie->code == NHRP_CODE_SUCCESS)
57 || (cie->code == NHRP_CODE_ADMINISTRATIVELY_PROHIBITED
58 && nhs->hub)))
59 ok = 0;
60 }
61
62 if (!ok)
63 return;
64
65 /* Parse extensions */
66 sockunion_family(&nifp->nat_nbma) = AF_UNSPEC;
67 while ((ext = nhrp_ext_pull(&p->extensions, &extpl)) != NULL) {
68 switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) {
69 case NHRP_EXTENSION_NAT_ADDRESS:
70 /* NHS adds second CIE if NAT is detected */
71 if (nhrp_cie_pull(&extpl, p->hdr, &cie_nbma, &cie_proto)
72 && nhrp_cie_pull(&extpl, p->hdr, &cie_nbma,
73 &cie_proto)) {
74 nifp->nat_nbma = cie_nbma;
75 debugf(NHRP_DEBUG_IF,
76 "%s: NAT detected, real NBMA address: %s",
77 ifp->name,
78 sockunion2str(&nifp->nbma, buf,
79 sizeof(buf)));
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 */
92 thread_add_timer(master, nhrp_reg_send_req, r, holdtime / 3,
93 &r->t_register);
94
95 r->proto_addr = p->dst_proto;
96 c = nhrp_cache_get(ifp, &p->dst_proto, 1);
97 if (c)
98 nhrp_cache_update_binding(c, NHRP_CACHE_NHS, holdtime,
99 nhrp_peer_ref(r->peer), 0, NULL);
100 }
101
102 static 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);
112 if (c)
113 nhrp_cache_update_binding(c, NHRP_CACHE_NHS, -1, NULL,
114 0, NULL);
115 sockunion_family(&r->proto_addr) = AF_UNSPEC;
116 }
117
118 r->timeout <<= 1;
119 if (r->timeout > 64)
120 r->timeout = 2;
121 thread_add_timer_msec(master, nhrp_reg_send_req, r, 10, &r->t_register);
122
123 return 0;
124 }
125
126 static void nhrp_reg_peer_notify(struct notifier_block *n, unsigned long cmd)
127 {
128 struct nhrp_registration *r =
129 container_of(n, struct nhrp_registration, peer_notifier);
130 char buf[SU_ADDRSTRLEN];
131
132 switch (cmd) {
133 case NOTIFY_PEER_UP:
134 case NOTIFY_PEER_DOWN:
135 case NOTIFY_PEER_IFCONFIG_CHANGED:
136 case NOTIFY_PEER_MTU_CHANGED:
137 debugf(NHRP_DEBUG_COMMON, "NHS: Flush timer for %s",
138 sockunion2str(&r->peer->vc->remote.nbma, buf,
139 sizeof buf));
140 THREAD_TIMER_OFF(r->t_register);
141 thread_add_timer_msec(master, nhrp_reg_send_req, r, 10,
142 &r->t_register);
143 break;
144 }
145 }
146
147 static int nhrp_reg_send_req(struct thread *t)
148 {
149 struct nhrp_registration *r = THREAD_ARG(t);
150 struct nhrp_nhs *nhs = r->nhs;
151 char buf1[SU_ADDRSTRLEN], buf2[SU_ADDRSTRLEN];
152 struct interface *ifp = nhs->ifp;
153 struct nhrp_interface *nifp = ifp->info;
154 struct nhrp_afi_data *if_ad = &nifp->afi[nhs->afi];
155 union sockunion *dst_proto;
156 struct zbuf *zb;
157 struct nhrp_packet_header *hdr;
158 struct nhrp_extension_header *ext;
159 struct nhrp_cie_header *cie;
160
161 r->t_register = NULL;
162 if (!nhrp_peer_check(r->peer, 2)) {
163 debugf(NHRP_DEBUG_COMMON, "NHS: Waiting link for %s",
164 sockunion2str(&r->peer->vc->remote.nbma, buf1,
165 sizeof buf1));
166 thread_add_timer(master, nhrp_reg_send_req, r, 120,
167 &r->t_register);
168 return 0;
169 }
170
171 thread_add_timer(master, nhrp_reg_timeout, r, r->timeout,
172 &r->t_register);
173
174 /* RFC2332 5.2.3 NHC uses it's own address as dst if NHS is unknown */
175 dst_proto = &nhs->proto_addr;
176 if (sockunion_family(dst_proto) == AF_UNSPEC)
177 dst_proto = &if_ad->addr;
178
179 sockunion2str(&if_ad->addr, buf1, sizeof(buf1));
180 sockunion2str(dst_proto, buf2, sizeof(buf2));
181 debugf(NHRP_DEBUG_COMMON, "NHS: Register %s -> %s (timeout %d)", buf1,
182 buf2, r->timeout);
183
184 /* No protocol address configured for tunnel interface */
185 if (sockunion_family(&if_ad->addr) == AF_UNSPEC)
186 return 0;
187
188 zb = zbuf_alloc(1400);
189 hdr = nhrp_packet_push(zb, NHRP_PACKET_REGISTRATION_REQUEST,
190 &nifp->nbma, &if_ad->addr, dst_proto);
191 hdr->hop_count = 1;
192 if (!(if_ad->flags & NHRP_IFF_REG_NO_UNIQUE))
193 hdr->flags |= htons(NHRP_FLAG_REGISTRATION_UNIQUE);
194
195 hdr->u.request_id = htonl(nhrp_reqid_alloc(&nhrp_packet_reqid,
196 &r->reqid, nhrp_reg_reply));
197
198 /* FIXME: push CIE for each local protocol address */
199 cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, NULL, NULL);
200 cie->prefix_length = 0xff;
201 cie->holding_time = htons(if_ad->holdtime);
202 cie->mtu = htons(if_ad->mtu);
203
204 nhrp_ext_request(zb, hdr, ifp);
205
206 /* Cisco NAT detection extension */
207 hdr->flags |= htons(NHRP_FLAG_REGISTRATION_NAT);
208 ext = nhrp_ext_push(zb, hdr, NHRP_EXTENSION_NAT_ADDRESS);
209 cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, &nifp->nbma, &if_ad->addr);
210 cie->prefix_length = 8 * sockunion_get_addrlen(&if_ad->addr);
211 nhrp_ext_complete(zb, ext);
212
213 nhrp_packet_complete(zb, hdr);
214 nhrp_peer_send(r->peer, zb);
215 zbuf_free(zb);
216
217 return 0;
218 }
219
220 static void nhrp_reg_delete(struct nhrp_registration *r)
221 {
222 nhrp_peer_notify_del(r->peer, &r->peer_notifier);
223 nhrp_peer_unref(r->peer);
224 list_del(&r->reglist_entry);
225 THREAD_OFF(r->t_register);
226 XFREE(MTYPE_NHRP_REGISTRATION, r);
227 }
228
229 static struct nhrp_registration *
230 nhrp_reg_by_nbma(struct nhrp_nhs *nhs, const union sockunion *nbma_addr)
231 {
232 struct nhrp_registration *r;
233
234 list_for_each_entry(
235 r, &nhs->reglist_head,
236 reglist_entry) if (sockunion_same(&r->peer->vc->remote.nbma,
237 nbma_addr)) return r;
238 return NULL;
239 }
240
241 static void nhrp_nhs_resolve_cb(struct resolver_query *q, int n,
242 union sockunion *addrs)
243 {
244 struct nhrp_nhs *nhs = container_of(q, struct nhrp_nhs, dns_resolve);
245 struct nhrp_interface *nifp = nhs->ifp->info;
246 struct nhrp_registration *reg, *regn;
247 int i;
248
249 nhs->t_resolve = NULL;
250 if (n < 0) {
251 /* Failed, retry in a moment */
252 thread_add_timer(master, nhrp_nhs_resolve, nhs, 5,
253 &nhs->t_resolve);
254 return;
255 }
256
257 thread_add_timer(master, nhrp_nhs_resolve, nhs, 2 * 60 * 60,
258 &nhs->t_resolve);
259
260 list_for_each_entry(reg, &nhs->reglist_head, reglist_entry) reg->mark =
261 1;
262
263 nhs->hub = 0;
264 for (i = 0; i < n; i++) {
265 if (sockunion_same(&addrs[i], &nifp->nbma)) {
266 nhs->hub = 1;
267 continue;
268 }
269
270 reg = nhrp_reg_by_nbma(nhs, &addrs[i]);
271 if (reg) {
272 reg->mark = 0;
273 continue;
274 }
275
276 reg = XCALLOC(MTYPE_NHRP_REGISTRATION, sizeof(*reg));
277 reg->peer = nhrp_peer_get(nhs->ifp, &addrs[i]);
278 reg->nhs = nhs;
279 reg->timeout = 1;
280 list_init(&reg->reglist_entry);
281 list_add_tail(&reg->reglist_entry, &nhs->reglist_head);
282 nhrp_peer_notify_add(reg->peer, &reg->peer_notifier,
283 nhrp_reg_peer_notify);
284 thread_add_timer_msec(master, nhrp_reg_send_req, reg, 50,
285 &reg->t_register);
286 }
287
288 list_for_each_entry_safe(reg, regn, &nhs->reglist_head, reglist_entry)
289 {
290 if (reg->mark)
291 nhrp_reg_delete(reg);
292 }
293 }
294
295 static int nhrp_nhs_resolve(struct thread *t)
296 {
297 struct nhrp_nhs *nhs = THREAD_ARG(t);
298
299 resolver_resolve(&nhs->dns_resolve, AF_INET, nhs->nbma_fqdn,
300 nhrp_nhs_resolve_cb);
301
302 return 0;
303 }
304
305 int nhrp_nhs_add(struct interface *ifp, afi_t afi, union sockunion *proto_addr,
306 const char *nbma_fqdn)
307 {
308 struct nhrp_interface *nifp = ifp->info;
309 struct nhrp_nhs *nhs;
310
311 if (sockunion_family(proto_addr) != AF_UNSPEC
312 && sockunion_family(proto_addr) != afi2family(afi))
313 return NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH;
314
315 list_for_each_entry(nhs, &nifp->afi[afi].nhslist_head, nhslist_entry)
316 {
317 if (sockunion_family(&nhs->proto_addr) != AF_UNSPEC
318 && sockunion_family(proto_addr) != AF_UNSPEC
319 && sockunion_same(&nhs->proto_addr, proto_addr))
320 return NHRP_ERR_ENTRY_EXISTS;
321
322 if (strcmp(nhs->nbma_fqdn, nbma_fqdn) == 0)
323 return NHRP_ERR_ENTRY_EXISTS;
324 }
325
326 nhs = XMALLOC(MTYPE_NHRP_NHS, sizeof(struct nhrp_nhs));
327
328 *nhs = (struct nhrp_nhs){
329 .afi = afi,
330 .ifp = ifp,
331 .proto_addr = *proto_addr,
332 .nbma_fqdn = strdup(nbma_fqdn),
333 .reglist_head = LIST_INITIALIZER(nhs->reglist_head),
334 };
335 list_add_tail(&nhs->nhslist_entry, &nifp->afi[afi].nhslist_head);
336 thread_add_timer_msec(master, nhrp_nhs_resolve, nhs, 1000,
337 &nhs->t_resolve);
338
339 return NHRP_OK;
340 }
341
342 int nhrp_nhs_del(struct interface *ifp, afi_t afi, union sockunion *proto_addr,
343 const char *nbma_fqdn)
344 {
345 struct nhrp_interface *nifp = ifp->info;
346 struct nhrp_nhs *nhs, *nnhs;
347 int ret = NHRP_ERR_ENTRY_NOT_FOUND;
348
349 if (sockunion_family(proto_addr) != AF_UNSPEC
350 && sockunion_family(proto_addr) != afi2family(afi))
351 return NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH;
352
353 list_for_each_entry_safe(nhs, nnhs, &nifp->afi[afi].nhslist_head,
354 nhslist_entry)
355 {
356 if (!sockunion_same(&nhs->proto_addr, proto_addr))
357 continue;
358 if (strcmp(nhs->nbma_fqdn, nbma_fqdn) != 0)
359 continue;
360
361 nhrp_nhs_free(nhs);
362 ret = NHRP_OK;
363 }
364
365 return ret;
366 }
367
368 int nhrp_nhs_free(struct nhrp_nhs *nhs)
369 {
370 struct nhrp_registration *r, *rn;
371
372 list_for_each_entry_safe(r, rn, &nhs->reglist_head, reglist_entry)
373 nhrp_reg_delete(r);
374 THREAD_OFF(nhs->t_resolve);
375 list_del(&nhs->nhslist_entry);
376 free((void *)nhs->nbma_fqdn);
377 XFREE(MTYPE_NHRP_NHS, nhs);
378 return 0;
379 }
380
381 void nhrp_nhs_terminate(void)
382 {
383 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
384 struct interface *ifp;
385 struct nhrp_interface *nifp;
386 struct nhrp_nhs *nhs, *tmp;
387 afi_t afi;
388
389 FOR_ALL_INTERFACES (vrf, ifp) {
390 nifp = ifp->info;
391 for (afi = 0; afi < AFI_MAX; afi++) {
392 list_for_each_entry_safe(
393 nhs, tmp, &nifp->afi[afi].nhslist_head,
394 nhslist_entry) nhrp_nhs_free(nhs);
395 }
396 }
397 }
398
399 void nhrp_nhs_foreach(struct interface *ifp, afi_t afi,
400 void (*cb)(struct nhrp_nhs *, struct nhrp_registration *,
401 void *),
402 void *ctx)
403 {
404 struct nhrp_interface *nifp = ifp->info;
405 struct nhrp_nhs *nhs;
406 struct nhrp_registration *reg;
407
408 list_for_each_entry(nhs, &nifp->afi[afi].nhslist_head, nhslist_entry)
409 {
410 if (!list_empty(&nhs->reglist_head)) {
411 list_for_each_entry(reg, &nhs->reglist_head,
412 reglist_entry) cb(nhs, reg, ctx);
413 } else
414 cb(nhs, 0, ctx);
415 }
416 }