Home | History | Annotate | Line # | Download | only in ldpd
ldp_peer.c revision 1.3.6.2
      1 /* $NetBSD: ldp_peer.c,v 1.3.6.2 2014/05/22 11:43:05 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 <assert.h>
     40 #include <errno.h>
     41 #include <fcntl.h>
     42 #include <stdlib.h>
     43 #include <strings.h>
     44 #include <stddef.h>
     45 #include <stdio.h>
     46 #include <unistd.h>
     47 
     48 #include "conffile.h"
     49 #include "socketops.h"
     50 #include "ldp_errors.h"
     51 #include "ldp.h"
     52 #include "tlv_stack.h"
     53 #include "mpls_interface.h"
     54 #include "notifications.h"
     55 #include "ldp_peer.h"
     56 
     57 extern int ldp_holddown_time;
     58 
     59 static struct label_mapping *ldp_peer_get_lm(struct ldp_peer *,
     60     const struct sockaddr *, uint);
     61 
     62 static int mappings_compare(void *, const void *, const void *);
     63 static rb_tree_ops_t mappings_tree_ops = {
     64 	.rbto_compare_nodes = mappings_compare,
     65 	.rbto_compare_key = mappings_compare,
     66 	.rbto_node_offset = offsetof(struct label_mapping, mappings_node),
     67 	.rbto_context = NULL
     68 };
     69 
     70 void
     71 ldp_peer_init(void)
     72 {
     73 	SLIST_INIT(&ldp_peer_head);
     74 }
     75 
     76 int
     77 sockaddr_cmp(const struct sockaddr *a, const struct sockaddr *b)
     78 {
     79 	if (a == NULL || b == NULL || a->sa_len != b->sa_len ||
     80 	    a->sa_family != b->sa_family)
     81 		return -1;
     82 	return memcmp(a, b, a->sa_len);
     83 }
     84 
     85 static int
     86 mappings_compare(void *context, const void *node1, const void *node2)
     87 {
     88 	const struct label_mapping *l1 = node1, *l2 = node2;
     89 	int ret;
     90 
     91 	if (__predict_false(l1->address.sa.sa_family !=
     92 	    l2->address.sa.sa_family))
     93 		return l1->address.sa.sa_family > l2->address.sa.sa_family ?
     94 		    1 : -1;
     95 
     96 	assert(l1->address.sa.sa_len == l2->address.sa.sa_len);
     97 	if ((ret = memcmp(&l1->address.sa, &l2->address.sa, l1->address.sa.sa_len)) != 0)
     98 		return ret;
     99 
    100 	if (__predict_false(l1->prefix != l2->prefix))
    101 		return l1->prefix > l2->prefix ? 1 : -1;
    102 
    103 	return 0;
    104 }
    105 
    106 /*
    107  * soc should be > 1 if there is already a TCP socket for this else we'll
    108  * initiate a new one
    109  */
    110 struct ldp_peer *
    111 ldp_peer_new(const struct in_addr * ldp_id, const struct sockaddr * padd,
    112 	     const struct sockaddr * tradd, uint16_t holdtime, int soc)
    113 {
    114 	struct ldp_peer *p;
    115 	int s = soc, sopts;
    116 	union sockunion connecting_su;
    117 	struct conf_neighbour *cn;
    118 
    119 	assert(tradd == NULL || tradd->sa_family == padd->sa_family);
    120 
    121 	if (soc < 1) {
    122 		s = socket(PF_INET, SOCK_STREAM, 0);
    123 		if (s < 0) {
    124 			fatalp("ldp_peer_new: cannot create socket\n");
    125 			return NULL;
    126 		}
    127 		if (tradd != NULL) {
    128 			assert(tradd->sa_len <= sizeof(connecting_su));
    129 			memcpy(&connecting_su, tradd, tradd->sa_len);
    130 		} else {
    131 			assert(padd->sa_len <= sizeof(connecting_su));
    132 			memcpy(&connecting_su, padd, padd->sa_len);
    133 		}
    134 
    135 		assert(connecting_su.sa.sa_family == AF_INET ||
    136 		    connecting_su.sa.sa_family == AF_INET6);
    137 
    138 		if (connecting_su.sa.sa_family == AF_INET)
    139 			connecting_su.sin.sin_port = htons(LDP_PORT);
    140 		else
    141 			connecting_su.sin6.sin6_port = htons(LDP_PORT);
    142 
    143 		set_ttl(s);
    144 	}
    145 
    146 	/* MD5 authentication needed ? */
    147 	SLIST_FOREACH(cn, &conei_head, neilist)
    148 		if (cn->authenticate != 0 &&
    149 		    ldp_id->s_addr == cn->address.s_addr) {
    150 			if (setsockopt(s, IPPROTO_TCP, TCP_MD5SIG, &(int){1},
    151 			    sizeof(int)) != 0)
    152 				fatalp("setsockopt TCP_MD5SIG: %s\n",
    153 				    strerror(errno));
    154 			break;
    155 		}
    156 
    157 	/* Set the peer in CONNECTING/CONNECTED state */
    158 	p = calloc(1, sizeof(*p));
    159 
    160 	if (!p) {
    161 		fatalp("ldp_peer_new: calloc problem\n");
    162 		return NULL;
    163 	}
    164 
    165 	SLIST_INSERT_HEAD(&ldp_peer_head, p, peers);
    166 	p->address = (struct sockaddr *)malloc(padd->sa_len);
    167 	memcpy(p->address, padd, padd->sa_len);
    168 	memcpy(&p->ldp_id, ldp_id, sizeof(struct in_addr));
    169 	if (tradd != NULL) {
    170 		p->transport_address = (struct sockaddr *)malloc(tradd->sa_len);
    171 		memcpy(p->transport_address, tradd, tradd->sa_len);
    172 	} else {
    173 		p->transport_address = (struct sockaddr *)malloc(padd->sa_len);
    174 		memcpy(p->transport_address, padd, padd->sa_len);
    175 	}
    176 	p->holdtime=holdtime > ldp_holddown_time ? holdtime : ldp_holddown_time;
    177 	p->socket = s;
    178 	if (soc < 1) {
    179 		p->state = LDP_PEER_CONNECTING;
    180 		p->master = 1;
    181 	} else {
    182 		p->state = LDP_PEER_CONNECTED;
    183 		p->master = 0;
    184 		set_ttl(p->socket);
    185 	}
    186 	SLIST_INIT(&p->ldp_peer_address_head);
    187 	rb_tree_init(&p->label_mapping_tree, &mappings_tree_ops);
    188 	p->timeout = p->holdtime;
    189 
    190 	sopts = fcntl(p->socket, F_GETFL);
    191 	if (sopts >= 0) {
    192 		sopts |= O_NONBLOCK;
    193 		fcntl(p->socket, F_SETFL, &sopts);
    194 	}
    195 
    196 	/* And connect to peer */
    197 	if (soc < 1 &&
    198 	    connect(s, &connecting_su.sa, connecting_su.sa.sa_len) == -1) {
    199 		if (errno == EINTR || errno == EINPROGRESS)
    200 			/* We take care of this in big_loop */
    201 			return p;
    202 		warnp("connect to %s failed: %s\n",
    203 		    satos(&connecting_su.sa), strerror(errno));
    204 		ldp_peer_holddown(p);
    205 		return NULL;
    206 	}
    207 	p->state = LDP_PEER_CONNECTED;
    208 	return p;
    209 }
    210 
    211 void
    212 ldp_peer_holddown(struct ldp_peer * p)
    213 {
    214 
    215 	if (!p || p->state == LDP_PEER_HOLDDOWN)
    216 		return;
    217 	if (p->state == LDP_PEER_ESTABLISHED) {
    218 		p->state = LDP_PEER_HOLDDOWN;
    219 		mpls_delete_ldp_peer(p);
    220 	} else
    221 		p->state = LDP_PEER_HOLDDOWN;
    222 	p->timeout = p->holdtime;
    223 	shutdown(p->socket, SHUT_RDWR);
    224 	ldp_peer_delete_all_mappings(p);
    225 	del_all_ifaddr(p);
    226 	fatalp("LDP Neighbour %s is DOWN\n", inet_ntoa(p->ldp_id));
    227 }
    228 
    229 void
    230 ldp_peer_holddown_all()
    231 {
    232 	struct ldp_peer *p;
    233 
    234 	SLIST_FOREACH(p, &ldp_peer_head, peers) {
    235 		if ((p->state == LDP_PEER_ESTABLISHED) ||
    236 		    (p->state == LDP_PEER_CONNECTED))
    237 			send_notification(p, get_message_id(),
    238 			    NOTIF_FATAL | NOTIF_SHUTDOWN);
    239 		ldp_peer_holddown(p);
    240 	}
    241 }
    242 
    243 void
    244 ldp_peer_delete(struct ldp_peer * p)
    245 {
    246 
    247 	if (!p)
    248 		return;
    249 
    250 	SLIST_REMOVE(&ldp_peer_head, p, ldp_peer, peers);
    251 	close(p->socket);
    252 	warnp("LDP Neighbor %s holddown timer expired\n", inet_ntoa(p->ldp_id));
    253 	free(p->address);
    254 	free(p->transport_address);
    255 	free(p);
    256 }
    257 
    258 struct ldp_peer *
    259 get_ldp_peer(const struct sockaddr * a)
    260 {
    261 	struct ldp_peer *p;
    262 	const struct sockaddr_in *a_inet = (const struct sockaddr_in *)a;
    263 
    264 	SLIST_FOREACH(p, &ldp_peer_head, peers) {
    265 		if (a->sa_family == AF_INET &&
    266 		    memcmp((const void *) &a_inet->sin_addr,
    267 		      (const void *) &p->ldp_id,
    268 		      sizeof(struct in_addr)) == 0)
    269 			return p;
    270 		if (sockaddr_cmp(a, p->address) == 0 ||
    271 		    sockaddr_cmp(a, p->transport_address) == 0 ||
    272 		    check_ifaddr(p, a))
    273 			return p;
    274 	}
    275 	return NULL;
    276 }
    277 
    278 struct ldp_peer *
    279 get_ldp_peer_by_id(const struct in_addr *a)
    280 {
    281 	struct ldp_peer *p;
    282 
    283 	SLIST_FOREACH(p, &ldp_peer_head, peers)
    284 		if (memcmp((const void*)a,
    285 		    (const void*)&p->ldp_id, sizeof(*a)) == 0)
    286 			return p;
    287 	return NULL;
    288 }
    289 
    290 struct ldp_peer *
    291 get_ldp_peer_by_socket(int s)
    292 {
    293 	struct ldp_peer *p;
    294 
    295 	SLIST_FOREACH(p, &ldp_peer_head, peers)
    296 		if (p->socket == s)
    297 			return p;
    298 	return NULL;
    299 }
    300 
    301 /*
    302  * Adds address list bounded to a specific peer
    303  * Returns the number of addresses inserted successfuly
    304  */
    305 int
    306 add_ifaddresses(struct ldp_peer * p, const struct al_tlv * a)
    307 {
    308 	int             i, c, n;
    309 	const struct in_addr *ia;
    310 	struct sockaddr_in	ipa;
    311 
    312 	memset(&ipa, 0, sizeof(ipa));
    313 	ipa.sin_len = sizeof(ipa);
    314 	ipa.sin_family = AF_INET;
    315 	/*
    316 	 * Check if tlv is Address type, if it's correct size (at least one
    317 	 * address) and if it's IPv4
    318 	 */
    319 
    320 	if ((ntohs(a->type) != TLV_ADDRESS_LIST) ||
    321 	    (ntohs(a->length) < sizeof(a->af) + sizeof(struct in_addr)) ||
    322 	    (ntohs(a->af) != LDP_AF_INET))
    323 		return 0;
    324 
    325 	/* Number of addresses to insert */
    326 	n = (ntohs(a->length) - sizeof(a->af)) / sizeof(struct in_addr);
    327 
    328 	debugp("Trying to add %d addresses to peer %s ... \n", n,
    329 	    inet_ntoa(p->ldp_id));
    330 
    331 	for (ia = (const struct in_addr *) & a->address,c = 0,i = 0; i<n; i++) {
    332 		memcpy(&ipa.sin_addr, &ia[i], sizeof(ipa.sin_addr));
    333 		if (add_ifaddr(p, (struct sockaddr *)&ipa) == LDP_E_OK)
    334 			c++;
    335 	}
    336 
    337 	debugp("Added %d addresses\n", c);
    338 
    339 	return c;
    340 }
    341 
    342 int
    343 del_ifaddresses(struct ldp_peer * p, const struct al_tlv * a)
    344 {
    345 	int             i, c, n;
    346 	const struct in_addr *ia;
    347 	struct sockaddr_in	ipa;
    348 
    349 	memset(&ipa, 0, sizeof(ipa));
    350 	ipa.sin_len = sizeof(ipa);
    351 	ipa.sin_family = AF_INET;
    352 	/*
    353 	 * Check if tlv is Address type, if it's correct size (at least one
    354 	 * address) and if it's IPv4
    355 	 */
    356 
    357 	if (ntohs(a->type) != TLV_ADDRESS_LIST ||
    358 	    ntohs(a->length) > sizeof(a->af) + sizeof(struct in_addr) ||
    359 	    ntohs(a->af) != LDP_AF_INET)
    360 		return -1;
    361 
    362 	n = (ntohs(a->length) - sizeof(a->af)) / sizeof(struct in_addr);
    363 
    364 	debugp("Trying to delete %d addresses from peer %s ... \n", n,
    365 	    inet_ntoa(p->ldp_id));
    366 
    367 	for (ia = (const struct in_addr *) & a[1], c = 0, i = 0; i < n; i++) {
    368 		memcpy(&ipa.sin_addr, &ia[i], sizeof(ipa.sin_addr));
    369 		if (del_ifaddr(p, (struct sockaddr *)&ipa) == LDP_E_OK)
    370 			c++;
    371 	}
    372 
    373 	debugp("Deleted %d addresses\n", c);
    374 
    375 	return c;
    376 }
    377 
    378 
    379 /* Adds a _SINGLE_ INET address to a specific peer */
    380 int
    381 add_ifaddr(struct ldp_peer * p, const struct sockaddr * a)
    382 {
    383 	struct ldp_peer_address *lpa;
    384 
    385 	/* Is it already there ? */
    386 	if (check_ifaddr(p, a))
    387 		return LDP_E_ALREADY_DONE;
    388 
    389 	lpa = calloc(1, sizeof(*lpa));
    390 
    391 	if (!lpa) {
    392 		fatalp("add_ifaddr: malloc problem\n");
    393 		return LDP_E_MEMORY;
    394 	}
    395 
    396 	assert(a->sa_len <= sizeof(union sockunion));
    397 
    398 	memcpy(&lpa->address.sa, a, a->sa_len);
    399 
    400 	SLIST_INSERT_HEAD(&p->ldp_peer_address_head, lpa, addresses);
    401 	return LDP_E_OK;
    402 }
    403 
    404 /* Deletes an address bounded to a specific peer */
    405 int
    406 del_ifaddr(struct ldp_peer * p, const struct sockaddr * a)
    407 {
    408 	struct ldp_peer_address *wp;
    409 
    410 	wp = check_ifaddr(p, a);
    411 	if (!wp)
    412 		return LDP_E_NOENT;
    413 
    414 	SLIST_REMOVE(&p->ldp_peer_address_head, wp, ldp_peer_address,
    415 	    addresses);
    416 	free(wp);
    417 	return LDP_E_OK;
    418 }
    419 
    420 /* Checks if an address is already bounded */
    421 struct ldp_peer_address *
    422 check_ifaddr(const struct ldp_peer * p, const struct sockaddr * a)
    423 {
    424 	struct ldp_peer_address *wp;
    425 
    426 	SLIST_FOREACH(wp, &p->ldp_peer_address_head, addresses)
    427 		if (sockaddr_cmp(a, &wp->address.sa) == 0)
    428 			return wp;
    429 	return NULL;
    430 }
    431 
    432 void
    433 del_all_ifaddr(struct ldp_peer * p)
    434 {
    435 	struct ldp_peer_address *wp;
    436 
    437 	while (!SLIST_EMPTY(&p->ldp_peer_address_head)) {
    438 		wp = SLIST_FIRST(&p->ldp_peer_address_head);
    439 		SLIST_REMOVE_HEAD(&p->ldp_peer_address_head, addresses);
    440 		free(wp);
    441 	}
    442 }
    443 
    444 void
    445 print_bounded_addresses(const struct ldp_peer * p)
    446 {
    447 	struct ldp_peer_address *wp;
    448 	char abuf[512];
    449 
    450 	snprintf(abuf, sizeof(abuf), "Addresses bounded to peer %s: ",
    451 	    satos(p->address));
    452 	SLIST_FOREACH(wp, &p->ldp_peer_address_head, addresses) {
    453 		strncat(abuf, satos(&wp->address.sa),
    454 			sizeof(abuf) -1);
    455 		strncat(abuf, " ", sizeof(abuf) -1);
    456 	}
    457 	warnp("%s\n", abuf);
    458 }
    459 
    460 /* Adds a label and a prefix to a specific peer */
    461 int
    462 ldp_peer_add_mapping(struct ldp_peer * p, const struct sockaddr * a,
    463     int prefix, int label)
    464 {
    465 	struct label_mapping *lma;
    466 
    467 	if (!p)
    468 		return -1;
    469 	if ((lma = ldp_peer_get_lm(p, a, prefix)) != NULL) {
    470 		/* Change the current label */
    471 		lma->label = label;
    472 		return LDP_E_OK;
    473 	}
    474 
    475 	lma = malloc(sizeof(*lma));
    476 
    477 	if (!lma) {
    478 		fatalp("ldp_peer_add_mapping: malloc problem\n");
    479 		return LDP_E_MEMORY;
    480 	}
    481 
    482 	memcpy(&lma->address, a, a->sa_len);
    483 	lma->prefix = prefix;
    484 	lma->label = label;
    485 
    486 	rb_tree_insert_node(&p->label_mapping_tree, lma);
    487 
    488 	return LDP_E_OK;
    489 }
    490 
    491 int
    492 ldp_peer_delete_mapping(struct ldp_peer * p, const struct sockaddr * a,
    493     int prefix)
    494 {
    495 	struct label_mapping *lma;
    496 
    497 	if (a == NULL || (lma = ldp_peer_get_lm(p, a, prefix)) == NULL)
    498 		return LDP_E_NOENT;
    499 
    500 	rb_tree_remove_node(&p->label_mapping_tree, lma);
    501 	free(lma);
    502 
    503 	return LDP_E_OK;
    504 }
    505 
    506 static struct label_mapping *
    507 ldp_peer_get_lm(struct ldp_peer * p, const struct sockaddr * a,
    508     uint prefix)
    509 {
    510 	struct label_mapping rv;
    511 
    512 	assert(a->sa_len <= sizeof(union sockunion));
    513 
    514 	memset(&rv, 0, sizeof(rv));
    515 	memcpy(&rv.address.sa, a, a->sa_len);
    516 	rv.prefix = prefix;
    517 
    518 	return rb_tree_find_node(&p->label_mapping_tree, &rv);
    519 }
    520 
    521 void
    522 ldp_peer_delete_all_mappings(struct ldp_peer * p)
    523 {
    524 	struct label_mapping *lma;
    525 
    526 	while((lma = RB_TREE_MIN(&p->label_mapping_tree)) != NULL) {
    527 		rb_tree_remove_node(&p->label_mapping_tree, lma);
    528 		free(lma);
    529 	}
    530 }
    531 
    532 /* returns a mapping and its peer */
    533 struct peer_map *
    534 ldp_test_mapping(const struct sockaddr * a, int prefix,
    535     const struct sockaddr * gate)
    536 {
    537 	struct ldp_peer *lpeer;
    538 	struct peer_map *rv = NULL;
    539 	struct label_mapping *lm = NULL;
    540 
    541 	/* Checks if it's LPDID, else checks if it's an interface */
    542 
    543 	lpeer = get_ldp_peer(gate);
    544 	if (!lpeer) {
    545 		debugp("ldp_test_mapping: Gateway is not an LDP peer\n");
    546 		return NULL;
    547 	}
    548 	if (lpeer->state != LDP_PEER_ESTABLISHED) {
    549 		fatalp("ldp_test_mapping: peer is down ?!\n");
    550 		return NULL;
    551 	}
    552 	lm = ldp_peer_get_lm(lpeer, a, prefix);
    553 
    554 	if (!lm) {
    555 		debugp("Cannot match prefix %s/%d to the specified peer\n",
    556 		    satos(a), prefix);
    557 		return NULL;
    558 	}
    559 	rv = malloc(sizeof(*rv));
    560 
    561 	if (!rv) {
    562 		fatalp("ldp_test_mapping: malloc problem\n");
    563 		return NULL;
    564 	}
    565 
    566 	rv->lm = lm;
    567 	rv->peer = lpeer;
    568 
    569 	return rv;
    570 }
    571 
    572 struct label_mapping * ldp_peer_lm_right(struct ldp_peer *p,
    573     struct label_mapping * map)
    574 {
    575 	if (map == NULL)
    576 		return RB_TREE_MIN(&p->label_mapping_tree);
    577 	else
    578 		return rb_tree_iterate(&p->label_mapping_tree, map,
    579 		    RB_DIR_RIGHT);
    580 }
    581 
    582 /* Name from state */
    583 const char * ldp_state_to_name(int state)
    584 {
    585 	switch(state) {
    586 		case LDP_PEER_CONNECTING:
    587 			return "CONNECTING";
    588 		case LDP_PEER_CONNECTED:
    589 			return "CONNECTED";
    590 		case LDP_PEER_ESTABLISHED:
    591 			return "ESTABLISHED";
    592 		case LDP_PEER_HOLDDOWN:
    593 			return "HOLDDOWN";
    594 	}
    595 	return "UNKNOWN";
    596 }
    597