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