Home | History | Annotate | Line # | Download | only in ldpd
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