ldp_peer.c revision 1.3.6.1 1 /* $NetBSD: ldp_peer.c,v 1.3.6.1 2013/01/16 05:34:09 yamt Exp $ */
2
3 /*-
4 * Copyright (c) 2010 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Mihai Chelaru <kefren (at) NetBSD.org>
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <netinet/tcp.h>
36 #include <netmpls/mpls.h>
37 #include <arpa/inet.h>
38
39 #include <stdlib.h>
40 #include <strings.h>
41 #include <stdio.h>
42 #include <unistd.h>
43 #include <errno.h>
44
45 #include "conffile.h"
46 #include "socketops.h"
47 #include "ldp_errors.h"
48 #include "ldp.h"
49 #include "tlv_stack.h"
50 #include "mpls_interface.h"
51 #include "notifications.h"
52 #include "ldp_peer.h"
53
54 extern int ldp_holddown_time;
55
56 struct in_addr *myaddresses;
57
58 void
59 ldp_peer_init(void)
60 {
61 SLIST_INIT(&ldp_peer_head);
62 myaddresses = NULL;
63 }
64
65 /*
66 * soc should be > 1 if there is already a TCP socket for this else we'll
67 * initiate a new one
68 */
69 struct ldp_peer *
70 ldp_peer_new(struct in_addr * ldp_id, struct in_addr * a,
71 struct in_addr * tradd, struct in6_addr * tradd6,
72 uint16_t holdtime, int soc)
73 {
74 struct ldp_peer *p;
75 int s = soc;
76 struct sockaddr_in sa;
77 struct conf_neighbour *cn;
78
79 if (s < 1) {
80 s = socket(PF_INET, SOCK_STREAM, 0);
81 memset(&sa, 0, sizeof(sa));
82 sa.sin_len = sizeof(sa);
83 sa.sin_family = AF_INET;
84
85 if (tradd)
86 memcpy(&sa.sin_addr, tradd,
87 sizeof(struct in_addr));
88 else
89 memcpy(&sa.sin_addr, a,
90 sizeof(struct in_addr));
91 sa.sin_port = htons(LDP_PORT);
92
93 set_ttl(s);
94 }
95
96 /* MD5 authentication needed ? */
97 SLIST_FOREACH(cn, &conei_head, neilist)
98 if (cn->authenticate != 0 && (a->s_addr == cn->address.s_addr ||
99 (tradd && tradd->s_addr == cn->address.s_addr))) {
100 if (setsockopt(s, IPPROTO_TCP, TCP_MD5SIG, &(int){1},
101 sizeof(int)) != 0)
102 fatalp("setsockopt TCP_MD5SIG: %s\n",
103 strerror(errno));
104 break;
105 }
106
107 /* Set the peer in CONNECTING/CONNECTED state */
108 p = calloc(1, sizeof(*p));
109
110 if (!p) {
111 fatalp("ldp_peer_new: calloc problem\n");
112 return NULL;
113 }
114
115 SLIST_INSERT_HEAD(&ldp_peer_head, p, peers);
116 memcpy(&p->address, a, sizeof(struct in_addr));
117 memcpy(&p->ldp_id, ldp_id, sizeof(struct in_addr));
118 if (tradd)
119 memcpy(&p->transport_address, tradd,
120 sizeof(struct in_addr));
121 else
122 memcpy(&p->transport_address, a,
123 sizeof(struct in_addr));
124 p->holdtime = holdtime > ldp_holddown_time ? holdtime : ldp_holddown_time;
125 p->socket = s;
126 if (soc < 1) {
127 p->state = LDP_PEER_CONNECTING;
128 p->master = 1;
129 } else {
130 p->state = LDP_PEER_CONNECTED;
131 p->master = 0;
132 set_ttl(p->socket);
133 }
134 SLIST_INIT(&p->ldp_peer_address_head);
135 SLIST_INIT(&p->label_mapping_head);
136 p->timeout = p->holdtime;
137
138 /* And connect to peer */
139 if (soc < 1)
140 if (connect(s, (struct sockaddr *) & sa, sizeof(sa)) == -1) {
141 if (errno == EINTR) {
142 return p; /* We take care of this in
143 * big_loop */
144 }
145 warnp("connect to %s failed: %s\n",
146 inet_ntoa(sa.sin_addr), strerror(errno));
147 ldp_peer_holddown(p);
148 return NULL;
149 }
150 p->state = LDP_PEER_CONNECTED;
151 return p;
152 }
153
154 void
155 ldp_peer_holddown(struct ldp_peer * p)
156 {
157 if (!p)
158 return;
159 if (p->state == LDP_PEER_ESTABLISHED)
160 mpls_delete_ldp_peer(p);
161 p->state = LDP_PEER_HOLDDOWN;
162 p->timeout = ldp_holddown_time;
163 shutdown(p->socket, SHUT_RDWR);
164 ldp_peer_delete_all_mappings(p);
165 del_all_ifaddr(p);
166 fatalp("LDP Neighbour %s is DOWN\n", inet_ntoa(p->ldp_id));
167 }
168
169 void
170 ldp_peer_holddown_all()
171 {
172 struct ldp_peer *p;
173
174 SLIST_FOREACH(p, &ldp_peer_head, peers) {
175 if ((p->state == LDP_PEER_ESTABLISHED) ||
176 (p->state == LDP_PEER_CONNECTED))
177 send_notification(p, get_message_id(), NOTIF_SHUTDOWN);
178 ldp_peer_holddown(p);
179 }
180 }
181
182 void
183 ldp_peer_delete(struct ldp_peer * p)
184 {
185
186 if (!p)
187 return;
188
189 SLIST_REMOVE(&ldp_peer_head, p, ldp_peer, peers);
190 close(p->socket);
191 warnp("LDP Neighbor %s holddown timer expired\n", inet_ntoa(p->ldp_id));
192 free(p);
193 }
194
195 struct ldp_peer *
196 get_ldp_peer(struct in_addr * a)
197 {
198 struct ldp_peer *p;
199
200 SLIST_FOREACH(p, &ldp_peer_head, peers) {
201 if (!memcmp((void *) a, (void *) &p->ldp_id,
202 sizeof(struct in_addr)))
203 return p;
204 if (!memcmp((void *) a, (void *) &p->address,
205 sizeof(struct in_addr)))
206 return p;
207 if (check_ifaddr(p, a))
208 return p;
209 }
210 return NULL;
211 }
212
213 struct ldp_peer *
214 get_ldp_peer_by_socket(int s)
215 {
216 struct ldp_peer *p;
217
218 SLIST_FOREACH(p, &ldp_peer_head, peers)
219 if (p->socket == s)
220 return p;
221 return NULL;
222 }
223
224 /*
225 * Adds address list bounded to a specific peer
226 * Returns the number of addresses inserted successfuly
227 */
228 int
229 add_ifaddresses(struct ldp_peer * p, struct al_tlv * a)
230 {
231 int i, c, n;
232 struct in_addr *ia;
233
234 /*
235 * Check if tlv is Address type, if it's correct size (at least one
236 * address) and if it's IPv4
237 */
238
239 if ((ntohs(a->type) != TLV_ADDRESS_LIST) ||
240 (ntohs(a->length) < sizeof(a->af) + sizeof(struct in_addr)) ||
241 (ntohs(a->af) != LDP_AF_INET))
242 return 0;
243
244 /* Number of addresses to insert */
245 n = (ntohs(a->length) - sizeof(a->af)) / sizeof(struct in_addr);
246
247 debugp("Trying to add %d addresses to peer %s ... \n", n,
248 inet_ntoa(p->ldp_id));
249
250 for (ia = (struct in_addr *) & a->address, c = 0, i = 0; i < n; i++) {
251 if (add_ifaddr(p, &ia[i]) == LDP_E_OK)
252 c++;
253 }
254
255 debugp("Added %d addresses\n", c);
256
257 return c;
258 }
259
260 int
261 del_ifaddresses(struct ldp_peer * p, struct al_tlv * a)
262 {
263 int i, c, n;
264 struct in_addr *ia;
265
266 /*
267 * Check if tlv is Address type, if it's correct size (at least one
268 * address) and if it's IPv4
269 */
270
271 if (ntohs(a->type) != TLV_ADDRESS_LIST ||
272 ntohs(a->length) > sizeof(a->af) + sizeof(struct in_addr) ||
273 ntohs(a->af) != LDP_AF_INET)
274 return -1;
275
276 n = (ntohs(a->length) - sizeof(a->af)) / sizeof(struct in_addr);
277
278 debugp("Trying to delete %d addresses from peer %s ... \n", n,
279 inet_ntoa(p->ldp_id));
280
281 for (ia = (struct in_addr *) & a[1], c = 0, i = 0; i < n; i++) {
282 if (del_ifaddr(p, &ia[i]) == LDP_E_OK)
283 c++;
284 }
285
286 debugp("Deleted %d addresses\n", c);
287
288 return c;
289 }
290
291
292 /* Adds a _SINGLE_ address to a specific peer */
293 int
294 add_ifaddr(struct ldp_peer * p, struct in_addr * a)
295 {
296 struct ldp_peer_address *lpa;
297
298 /* Is it already there ? */
299 if (check_ifaddr(p, a))
300 return LDP_E_ALREADY_DONE;
301
302 lpa = calloc(1, sizeof(*lpa));
303
304 if (!lpa) {
305 fatalp("add_ifaddr: malloc problem\n");
306 return LDP_E_MEMORY;
307 }
308
309 memcpy(&lpa->address, a, sizeof(struct in_addr));
310
311 SLIST_INSERT_HEAD(&p->ldp_peer_address_head, lpa, addresses);
312 return LDP_E_OK;
313 }
314
315 /* Deletes an address bounded to a specific peer */
316 int
317 del_ifaddr(struct ldp_peer * p, struct in_addr * a)
318 {
319 struct ldp_peer_address *wp;
320
321 wp = check_ifaddr(p, a);
322 if (!wp)
323 return LDP_E_NOENT;
324
325 SLIST_REMOVE(&p->ldp_peer_address_head, wp, ldp_peer_address,
326 addresses);
327 free(wp);
328 return LDP_E_OK;
329 }
330
331 /* Checks if an address is already bounded */
332 struct ldp_peer_address *
333 check_ifaddr(struct ldp_peer * p, struct in_addr * a)
334 {
335 struct ldp_peer_address *wp;
336
337 SLIST_FOREACH(wp, &p->ldp_peer_address_head, addresses)
338 if (memcmp(a, &wp->address, sizeof(struct in_addr)) == 0)
339 return wp;
340 return NULL;
341 }
342
343 void
344 del_all_ifaddr(struct ldp_peer * p)
345 {
346 struct ldp_peer_address *wp;
347
348 while (!SLIST_EMPTY(&p->ldp_peer_address_head)) {
349 wp = SLIST_FIRST(&p->ldp_peer_address_head);
350 SLIST_REMOVE_HEAD(&p->ldp_peer_address_head, addresses);
351 free(wp);
352 }
353 }
354
355 void
356 print_bounded_addresses(struct ldp_peer * p)
357 {
358 struct ldp_peer_address *wp;
359 char abuf[512];
360
361 snprintf(abuf, sizeof(abuf), "Addresses bounded to peer %s: ",
362 inet_ntoa(p->address));
363 SLIST_FOREACH(wp, &p->ldp_peer_address_head, addresses) {
364 strncat(abuf, inet_ntoa(wp->address), sizeof(abuf) -1);
365 strncat(abuf, " ", sizeof(abuf) -1);
366 }
367 warnp("%s\n", abuf);
368 }
369
370 void
371 add_my_if_addrs(struct in_addr * a, int count)
372 {
373 myaddresses = calloc((count + 1), sizeof(*myaddresses));
374
375 if (!myaddresses) {
376 fatalp("add_my_if_addrs: malloc problem\n");
377 return;
378 }
379 memcpy(myaddresses, a, count * sizeof(struct in_addr));
380 myaddresses[count].s_addr = 0;
381 }
382
383 /* Adds a label and a prefix to a specific peer */
384 int
385 ldp_peer_add_mapping(struct ldp_peer * p, struct in_addr * a, int prefix,
386 int label)
387 {
388 struct label_mapping *lma;
389
390 if (!p)
391 return -1;
392 if (ldp_peer_get_lm(p, a, prefix))
393 return LDP_E_ALREADY_DONE;
394
395 lma = malloc(sizeof(*lma));
396
397 if (!lma) {
398 fatalp("ldp_peer_add_mapping: malloc problem\n");
399 return LDP_E_MEMORY;
400 }
401
402 memcpy(&lma->address, a, sizeof(struct in_addr));
403 lma->prefix = prefix;
404 lma->label = label;
405
406 SLIST_INSERT_HEAD(&p->label_mapping_head, lma, mappings);
407
408 return LDP_E_OK;
409 }
410
411 int
412 ldp_peer_delete_mapping(struct ldp_peer * p, struct in_addr * a, int prefix)
413 {
414 struct label_mapping *lma;
415
416 if (!a)
417 return ldp_peer_delete_all_mappings(p);
418
419 lma = ldp_peer_get_lm(p, a, prefix);
420 if (!lma)
421 return LDP_E_NOENT;
422
423 SLIST_REMOVE(&p->label_mapping_head, lma, label_mapping, mappings);
424 free(lma);
425
426 return LDP_E_OK;
427 }
428
429 struct label_mapping *
430 ldp_peer_get_lm(struct ldp_peer * p, struct in_addr * a, int prefix)
431 {
432 struct label_mapping *rv;
433
434 if (!p)
435 return NULL;
436
437 SLIST_FOREACH(rv, &p->label_mapping_head, mappings)
438 if ((rv->prefix == prefix) && (!memcmp(a, &rv->address,
439 sizeof(struct in_addr))))
440 break;
441
442 return rv;
443
444 }
445
446 int
447 ldp_peer_delete_all_mappings(struct ldp_peer * p)
448 {
449 struct label_mapping *lma;
450
451 while(!SLIST_EMPTY(&p->label_mapping_head)) {
452 lma = SLIST_FIRST(&p->label_mapping_head);
453 SLIST_REMOVE_HEAD(&p->label_mapping_head, mappings);
454 free(lma);
455 }
456
457 return LDP_E_OK;
458 }
459
460 /* returns a mapping and its peer */
461 struct peer_map *
462 ldp_test_mapping(struct in_addr * a, int prefix, struct in_addr * gate)
463 {
464 struct ldp_peer *lpeer;
465 struct peer_map *rv = NULL;
466 struct label_mapping *lm = NULL;
467
468 /* Checks if it's LPDID, else checks if it's an interface */
469
470 lpeer = get_ldp_peer(gate);
471 if (!lpeer) {
472 debugp("Gateway %s is not an LDP peer\n", inet_ntoa(*gate));
473 return NULL;
474 }
475 if (lpeer->state != LDP_PEER_ESTABLISHED) {
476 warnp("ldp_test_mapping: peer is down ?!\n");
477 return NULL;
478 }
479 lm = ldp_peer_get_lm(lpeer, a, prefix);
480
481 if (!lm) {
482 debugp("Cannot match that prefix to the specified peer\n");
483 return NULL;
484 }
485 rv = malloc(sizeof(*rv));
486
487 if (!rv) {
488 fatalp("ldp_test_mapping: malloc problem\n");
489 return NULL;
490 }
491
492 rv->lm = lm;
493 rv->peer = lpeer;
494
495 return rv;
496 }
497
498 /* Name from state */
499 const char * ldp_state_to_name(int state)
500 {
501 switch(state) {
502 case LDP_PEER_CONNECTING:
503 return "CONNECTING";
504 case LDP_PEER_CONNECTED:
505 return "CONNECTED";
506 case LDP_PEER_ESTABLISHED:
507 return "ESTABLISHED";
508 case LDP_PEER_HOLDDOWN:
509 return "HOLDDOWN";
510 }
511 return "UNKNOWN";
512 }
513