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