ldp_peer.c revision 1.1 1 /* $NetBSD: ldp_peer.c,v 1.1 2010/12/08 07:20:14 kefren 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 <netmpls/mpls.h>
36 #include <arpa/inet.h>
37
38 #include <stdlib.h>
39 #include <strings.h>
40 #include <stdio.h>
41 #include <unistd.h>
42 #include <errno.h>
43 #include "socketops.h"
44 #include "ldp_errors.h"
45 #include "ldp.h"
46 #include "tlv_stack.h"
47 #include "mpls_interface.h"
48 #include "notifications.h"
49 #include "ldp_peer.h"
50
51 struct in_addr *myaddresses;
52
53 void
54 ldp_peer_init(void)
55 {
56 SLIST_INIT(&ldp_peer_head);
57 myaddresses = NULL;
58 }
59
60 /*
61 * soc should be > 1 if there is already a TCP socket for this else we'll
62 * initiate a new one
63 */
64 struct ldp_peer *
65 ldp_peer_new(struct in_addr * ldp_id, struct in_addr * a,
66 struct in_addr * tradd, uint16_t holdtime, int soc)
67 {
68 struct ldp_peer *p;
69 int s = soc;
70 struct sockaddr_in sa;
71
72 if (s < 1) {
73 s = socket(PF_INET, SOCK_STREAM, 0);
74 memset(&sa, 0, sizeof(sa));
75 sa.sin_len = sizeof(sa);
76 sa.sin_family = AF_INET;
77
78 if (tradd)
79 memcpy(&sa.sin_addr, tradd,
80 sizeof(struct in_addr));
81 else
82 memcpy(&sa.sin_addr, a,
83 sizeof(struct in_addr));
84 sa.sin_port = htons(LDP_PORT);
85
86 set_ttl(s);
87 }
88
89 /* Set the peer in CONNECTING/CONNECTED state */
90 p = (struct ldp_peer *) malloc(sizeof(struct ldp_peer));
91
92 if (!p) {
93 fatalp("ldp_peer_new: malloc problem\n");
94 return NULL;
95 }
96
97 memset(p, 0, sizeof(struct ldp_peer));
98 SLIST_INSERT_HEAD(&ldp_peer_head, p, peers);
99 memcpy(&p->address, a, sizeof(struct in_addr));
100 memcpy(&p->ldp_id, ldp_id, sizeof(struct in_addr));
101 if (tradd)
102 memcpy(&p->transport_address, tradd,
103 sizeof(struct in_addr));
104 else
105 memcpy(&p->transport_address, a,
106 sizeof(struct in_addr));
107 p->holdtime = holdtime > LDP_HOLDTIME ? holdtime : LDP_HOLDTIME;
108 p->socket = s;
109 if (soc < 1) {
110 p->state = LDP_PEER_CONNECTING;
111 p->master = 1;
112 } else {
113 p->state = LDP_PEER_CONNECTED;
114 p->master = 0;
115 set_ttl(p->socket);
116 }
117 SLIST_INIT(&p->ldp_peer_address_head);
118 SLIST_INIT(&p->label_mapping_head);
119 p->timeout = p->holdtime;
120
121 /* And connect to peer */
122 if (soc < 1)
123 if (connect(s, (struct sockaddr *) & sa, sizeof(sa)) == -1) {
124 if (errno == EINTR) {
125 return p; /* We take care of this in
126 * big_loop */
127 }
128 warnp("connect to %s failed: %s\n",
129 inet_ntoa(sa.sin_addr), strerror(errno));
130 ldp_peer_holddown(p);
131 return NULL;
132 }
133 p->state = LDP_PEER_CONNECTED;
134 return p;
135 }
136
137 void
138 ldp_peer_holddown(struct ldp_peer * p)
139 {
140 if (!p)
141 return;
142 if (p->state == LDP_PEER_ESTABLISHED)
143 mpls_delete_ldp_peer(p);
144 p->state = LDP_PEER_HOLDDOWN;
145 p->timeout = LDP_HOLDTIME;
146 shutdown(p->socket, SHUT_RDWR);
147 ldp_peer_delete_all_mappings(p);
148 del_all_ifaddr(p);
149 fatalp("LDP Neighbour %s is DOWN\n", inet_ntoa(p->ldp_id));
150 }
151
152 void
153 ldp_peer_holddown_all()
154 {
155 struct ldp_peer *p;
156
157 SLIST_FOREACH(p, &ldp_peer_head, peers) {
158 if ((p->state == LDP_PEER_ESTABLISHED) ||
159 (p->state == LDP_PEER_CONNECTED))
160 send_notification(p, get_message_id(), NOTIF_SHUTDOWN);
161 ldp_peer_holddown(p);
162 }
163 }
164
165 void
166 ldp_peer_delete(struct ldp_peer * p)
167 {
168
169 if (!p)
170 return;
171
172 SLIST_REMOVE(&ldp_peer_head, p, ldp_peer, peers);
173 close(p->socket);
174 warnp("LDP Neighbor %s holddown timer expired\n", inet_ntoa(p->ldp_id));
175 free(p);
176 }
177
178 struct ldp_peer *
179 get_ldp_peer(struct in_addr * a)
180 {
181 struct ldp_peer *p;
182
183 SLIST_FOREACH(p, &ldp_peer_head, peers) {
184 if (!memcmp((void *) a, (void *) &p->ldp_id,
185 sizeof(struct in_addr)))
186 return p;
187 if (!memcmp((void *) a, (void *) &p->address,
188 sizeof(struct in_addr)))
189 return p;
190 if (check_ifaddr(p, a))
191 return p;
192 }
193 return NULL;
194 }
195
196 struct ldp_peer *
197 get_ldp_peer_by_socket(int s)
198 {
199 struct ldp_peer *p;
200
201 SLIST_FOREACH(p, &ldp_peer_head, peers)
202 if (p->socket == s)
203 return p;
204 return NULL;
205 }
206
207 /*
208 * Adds address list bounded to a specific peer
209 * Returns the number of addresses inserted successfuly
210 */
211 int
212 add_ifaddresses(struct ldp_peer * p, struct al_tlv * a)
213 {
214 int i, c, n;
215 struct in_addr *ia;
216
217 /*
218 * Check if tlv is Address type, if it's correct size (at least one
219 * address) and if it's IPv4
220 */
221
222 if ((ntohs(a->type) != TLV_ADDRESS_LIST) ||
223 (ntohs(a->length) < sizeof(a->af) + sizeof(struct in_addr)) ||
224 (ntohs(a->af) != LDP_AF_INET))
225 return 0;
226
227 /* Number of addresses to insert */
228 n = (ntohs(a->length) - sizeof(a->af)) / sizeof(struct in_addr);
229
230 debugp("Trying to add %d addresses to peer %s ... \n", n,
231 inet_ntoa(p->ldp_id));
232
233 for (ia = (struct in_addr *) & a->address, c = 0, i = 0; i < n; i++) {
234 if (add_ifaddr(p, &ia[i]) == LDP_E_OK)
235 c++;
236 }
237
238 debugp("Added %d addresses\n", c);
239
240 return c;
241 }
242
243 int
244 del_ifaddresses(struct ldp_peer * p, struct al_tlv * a)
245 {
246 int i, c, n;
247 struct in_addr *ia;
248
249 /*
250 * Check if tlv is Address type, if it's correct size (at least one
251 * address) and if it's IPv4
252 */
253
254 if (ntohs(a->type) != TLV_ADDRESS_LIST ||
255 ntohs(a->length) > sizeof(a->af) + sizeof(struct in_addr) ||
256 ntohs(a->af) != LDP_AF_INET)
257 return -1;
258
259 n = (ntohs(a->length) - sizeof(a->af)) / sizeof(struct in_addr);
260
261 debugp("Trying to delete %d addresses from peer %s ... \n", n,
262 inet_ntoa(p->ldp_id));
263
264 for (ia = (struct in_addr *) & a[1], c = 0, i = 0; i < n; i++) {
265 if (del_ifaddr(p, &ia[i]) == LDP_E_OK)
266 c++;
267 }
268
269 debugp("Deleted %d addresses\n", c);
270
271 return c;
272 }
273
274
275 /* Adds a _SINGLE_ address to a specific peer */
276 int
277 add_ifaddr(struct ldp_peer * p, struct in_addr * a)
278 {
279 struct ldp_peer_address *lpa;
280
281 /* Is it already there ? */
282 if (check_ifaddr(p, a))
283 return LDP_E_ALREADY_DONE;
284
285 lpa = (struct ldp_peer_address*)malloc(sizeof(struct ldp_peer_address));
286
287 if (!lpa) {
288 fatalp("add_ifaddr: malloc problem\n");
289 return LDP_E_MEMORY;
290 }
291
292 memset(lpa, 0, sizeof(struct ldp_peer_address));
293
294 memcpy(&lpa->address, a, sizeof(struct in_addr));
295
296 SLIST_INSERT_HEAD(&p->ldp_peer_address_head, lpa, addresses);
297 return LDP_E_OK;
298 }
299
300 /* Deletes an address bounded to a specific peer */
301 int
302 del_ifaddr(struct ldp_peer * p, struct in_addr * a)
303 {
304 struct ldp_peer_address *wp;
305
306 wp = check_ifaddr(p, a);
307 if (!wp)
308 return LDP_E_NOENT;
309
310 SLIST_REMOVE(&p->ldp_peer_address_head, wp, ldp_peer_address,
311 addresses);
312 free(wp);
313 return LDP_E_OK;
314 }
315
316 /* Checks if an address is already bounded */
317 struct ldp_peer_address *
318 check_ifaddr(struct ldp_peer * p, struct in_addr * a)
319 {
320 struct ldp_peer_address *wp;
321
322 SLIST_FOREACH(wp, &p->ldp_peer_address_head, addresses)
323 if (memcmp(a, &wp->address, sizeof(struct in_addr)) == 0)
324 return wp;
325 return NULL;
326 }
327
328 void
329 del_all_ifaddr(struct ldp_peer * p)
330 {
331 struct ldp_peer_address *wp;
332
333 while (!SLIST_EMPTY(&p->ldp_peer_address_head)) {
334 wp = SLIST_FIRST(&p->ldp_peer_address_head);
335 SLIST_REMOVE_HEAD(&p->ldp_peer_address_head, addresses);
336 free(wp);
337 }
338 }
339
340 void
341 print_bounded_addresses(struct ldp_peer * p)
342 {
343 struct ldp_peer_address *wp;
344 char abuf[512];
345
346 snprintf(abuf, sizeof(abuf), "Addresses bounded to peer %s: ",
347 inet_ntoa(p->address));
348 SLIST_FOREACH(wp, &p->ldp_peer_address_head, addresses) {
349 strncat(abuf, inet_ntoa(wp->address), sizeof(abuf) -1);
350 strncat(abuf, " ", sizeof(abuf) -1);
351 }
352 warnp("%s\n", abuf);
353 }
354
355 void
356 add_my_if_addrs(struct in_addr * a, int count)
357 {
358 myaddresses = (struct in_addr *) malloc((count + 1) *
359 (sizeof(struct in_addr)));
360
361 if (!myaddresses) {
362 fatalp("add_my_if_addrs: malloc problem\n");
363 return;
364 }
365 memcpy(myaddresses, a, count * sizeof(struct in_addr));
366 myaddresses[count].s_addr = 0;
367 }
368
369 /* Adds a label and a prefix to a specific peer */
370 int
371 ldp_peer_add_mapping(struct ldp_peer * p, struct in_addr * a, int prefix,
372 int label)
373 {
374 struct label_mapping *lma;
375
376 if (!p)
377 return -1;
378 if (ldp_peer_get_lm(p, a, prefix))
379 return LDP_E_ALREADY_DONE;
380
381 lma = (struct label_mapping *) malloc(sizeof(struct label_mapping));
382
383 if (!lma) {
384 fatalp("ldp_peer_add_mapping: malloc problem\n");
385 return LDP_E_MEMORY;
386 }
387
388 memcpy(&lma->address, a, sizeof(struct in_addr));
389 lma->prefix = prefix;
390 lma->label = label;
391
392 SLIST_INSERT_HEAD(&p->label_mapping_head, lma, mappings);
393
394 return LDP_E_OK;
395 }
396
397 int
398 ldp_peer_delete_mapping(struct ldp_peer * p, struct in_addr * a, int prefix)
399 {
400 struct label_mapping *lma;
401
402 if (!a)
403 return ldp_peer_delete_all_mappings(p);
404
405 lma = ldp_peer_get_lm(p, a, prefix);
406 if (!lma)
407 return LDP_E_NOENT;
408
409 SLIST_REMOVE(&p->label_mapping_head, lma, label_mapping, mappings);
410 free(lma);
411
412 return LDP_E_OK;
413 }
414
415 struct label_mapping *
416 ldp_peer_get_lm(struct ldp_peer * p, struct in_addr * a, int prefix)
417 {
418 struct label_mapping *rv;
419
420 if (!p)
421 return NULL;
422
423 SLIST_FOREACH(rv, &p->label_mapping_head, mappings)
424 if ((rv->prefix == prefix) && (!memcmp(a, &rv->address,
425 sizeof(struct in_addr))))
426 break;
427
428 return rv;
429
430 }
431
432 int
433 ldp_peer_delete_all_mappings(struct ldp_peer * p)
434 {
435 struct label_mapping *lma;
436
437 while(!SLIST_EMPTY(&p->label_mapping_head)) {
438 lma = SLIST_FIRST(&p->label_mapping_head);
439 SLIST_REMOVE_HEAD(&p->label_mapping_head, mappings);
440 free(lma);
441 }
442
443 return LDP_E_OK;
444 }
445
446 /* returns a mapping and its peer */
447 struct peer_map *
448 ldp_test_mapping(struct in_addr * a, int prefix, struct in_addr * gate)
449 {
450 struct ldp_peer *lpeer;
451 struct peer_map *rv = NULL;
452 struct label_mapping *lm = NULL;
453
454 /* Checks if it's LPDID, else checks if it's an interface */
455
456 lpeer = get_ldp_peer(gate);
457 if (!lpeer) {
458 debugp("Gateway %s is not an LDP peer\n", inet_ntoa(*gate));
459 return NULL;
460 }
461 if (lpeer->state != LDP_PEER_ESTABLISHED) {
462 warnp("ldp_test_mapping: peer is down ?!\n");
463 return NULL;
464 }
465 lm = ldp_peer_get_lm(lpeer, a, prefix);
466
467 if (!lm) {
468 debugp("Cannot match that prefix to the specified peer\n");
469 return NULL;
470 }
471 rv = (struct peer_map *) malloc(sizeof(struct peer_map));
472
473 if (!rv) {
474 fatalp("ldp_test_mapping: malloc problem\n");
475 return NULL;
476 }
477
478 rv->lm = lm;
479 rv->peer = lpeer;
480
481 return rv;
482 }
483
484 /* Name from state */
485 const char * ldp_state_to_name(int state)
486 {
487 switch(state) {
488 case LDP_PEER_CONNECTING:
489 return "CONNECTING";
490 case LDP_PEER_CONNECTED:
491 return "CONNECTED";
492 case LDP_PEER_ESTABLISHED:
493 return "ESTABLISHED";
494 case LDP_PEER_HOLDDOWN:
495 return "HOLDDOWN";
496 }
497 return "UNKNOWN";
498 }
499