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