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