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