source: src/router/quagga/nhrpd/nhrp_nhs.c @ 31640

Last change on this file since 31640 was 31640, checked in by brainslayer, 4 months ago

update quagga

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