Home | History | Annotate | Line # | Download | only in ldpd
      1 /* $NetBSD: tlv_stack.c,v 1.13 2013/07/31 06:58:23 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 <arpa/inet.h>
     33 
     34 #include <netmpls/mpls.h>
     35 
     36 #include <stdio.h>
     37 #include <string.h>
     38 #include <stdlib.h>
     39 
     40 #include "ldp.h"
     41 #include "ldp_errors.h"
     42 #include "ldp_peer.h"
     43 #include "tlv.h"
     44 #include "socketops.h"
     45 #include "pdu.h"
     46 #include "label.h"
     47 #include "mpls_interface.h"
     48 #include "tlv_stack.h"
     49 
     50 static uint8_t ldp_ceil8(int);
     51 
     52 static uint8_t
     53 ldp_ceil8(int x)
     54 {
     55 	if (x % 8 == 0)
     56 		return x / 8;
     57 	return x / 8 + 1;
     58 }
     59 
     60 int
     61 map_label(struct ldp_peer * p, struct fec_tlv * f, struct label_tlv * l)
     62 {
     63 	int n;
     64 	struct prefix_tlv *pref;
     65 	union sockunion socktmp;
     66 	struct label *lbl_check;
     67 
     68 	if (ntohs(f->type) != TLV_FEC) {
     69 		debugp("Invalid FEC TLV !\n");
     70 		return LDP_E_BAD_FEC;
     71 	}
     72 	if (ntohs(l->type) != TLV_GENERIC_LABEL) {
     73 		debugp("Invalid LABEL TLV! (0x%.4X)\n", ntohs(l->type));
     74 		return LDP_E_BAD_LABEL;
     75 	}
     76 	/*
     77 	 * Actually address field length is given only in length field in
     78 	 * bits !
     79 	 */
     80 
     81 	n = ntohs(f->length);
     82 	if (!n)
     83 		return LDP_E_BAD_FEC;
     84 
     85 	debugp("Label %u for:\n", ntohl(l->label));
     86 
     87 	pref = (struct prefix_tlv *) (f + 1);
     88 	memset (&socktmp, 0, sizeof(socktmp));
     89 
     90 	/*
     91 	 * Section 3.4.1
     92 	 * Note that this version of LDP supports the use of multiple FEC
     93 	 * Elements per FEC for the Label Mapping message only.  The use of
     94 	 * multiple FEC Elements in other messages is not permitted in this
     95 	 * version, and is a subject for future study.
     96 	 */
     97 
     98 	for (; n > 0; pref = (struct prefix_tlv *) ((unsigned char *) pref +
     99 			ldp_ceil8(pref->prelen) + TLV_TYPE_LENGTH)) {
    100 		n -= ldp_ceil8(pref->prelen) + TLV_TYPE_LENGTH;
    101 		if (ntohs(pref->af) == LDP_AF_INET) {
    102 			socktmp.sa.sa_family = AF_INET;
    103 			socktmp.sa.sa_len = sizeof(socktmp.sin);
    104 		} else if (ntohs(pref->af) == LDP_AF_INET6) {
    105 			socktmp.sa.sa_family = AF_INET6;
    106 			socktmp.sa.sa_len = sizeof(socktmp.sin6);
    107 		} else {
    108 			warnp("BAD ADDRESS FAMILY (%d) ! (prefix type %d, "
    109 			    "length %d)\n", ntohs(pref->af), pref->type,
    110 			    pref->prelen);
    111 			return LDP_E_BAD_AF;
    112 		}
    113 		switch(pref->type) {
    114 		    case FEC_PREFIX:
    115 		    case FEC_HOST:
    116 			if (socktmp.sa.sa_family == AF_INET)
    117 				memcpy(&socktmp.sin.sin_addr, &pref->prefix,
    118 				    ldp_ceil8(pref->prelen));
    119 			else
    120 				memcpy(&socktmp.sin6.sin6_addr, &pref->prefix,
    121 				    ldp_ceil8(pref->prelen));
    122 			warnp("Prefix/Host add from %s: %s/%d\n",
    123 			    inet_ntoa(p->ldp_id), satos(&socktmp.sa),
    124 			    pref->prelen);
    125 
    126 			ldp_peer_add_mapping(p, &socktmp.sa, pref->prelen,
    127 			    ntohl(l->label));
    128 
    129 			/* Try to change RIB only if label is installed */
    130 			lbl_check = label_get_by_prefix(&socktmp.sa,
    131 			    pref->prelen);
    132 			if (lbl_check != NULL && lbl_check->p == p) {
    133 				lbl_check->label = ntohl(l->label);
    134 				mpls_add_label(lbl_check);
    135 			} else
    136 				warnp("[map_label] lbl check failed: %s\n",
    137 				    lbl_check == NULL ? "(null)" :
    138 				    lbl_check->p == NULL ? "(null peer)" :
    139 				    inet_ntoa(lbl_check->p->ldp_id));
    140 			break;
    141 		    case FEC_WILDCARD:
    142 			fatalp("LDP: Wildcard add from peer %s\n",
    143 			    satos(p->address));
    144 			return LDP_E_BAD_FEC;
    145 		    default:
    146 			fatalp("Unknown FEC type %d\n", pref->type);
    147 			return LDP_E_BAD_FEC;
    148 		}
    149 	}
    150 
    151 	return LDP_E_OK;
    152 }
    153 
    154 int
    155 withdraw_label(struct ldp_peer * p, struct fec_tlv * f)
    156 {
    157 	int             n;
    158 	struct prefix_tlv *pref;
    159 	union sockunion socktmp;
    160 	struct label *lab;
    161 
    162 	if (ntohs(f->type) != TLV_FEC) {
    163 		debugp("Invalid FEC TLV !\n");
    164 		return LDP_E_BAD_FEC;
    165 	}
    166 	n = ntohs(f->length);
    167 	if (!n)
    168 		return LDP_E_BAD_FEC;
    169 
    170 	pref = (struct prefix_tlv *) & f[1];
    171 
    172 	memset(&socktmp, 0, sizeof(socktmp));
    173 	if (ntohs(pref->af) == LDP_AF_INET) {
    174 		socktmp.sa.sa_family = AF_INET;
    175 		socktmp.sa.sa_len = sizeof(socktmp.sin);
    176 	} else if (ntohs(pref->af) != LDP_AF_INET6) {
    177 		socktmp.sa.sa_family = AF_INET6;
    178 		socktmp.sa.sa_len = sizeof(socktmp.sin6);
    179 	} else {
    180 		warnp("WITHDRAW: Bad AF (%d)! (prefix type %d, length %d)\n",
    181 		    ntohs(pref->af), pref->type, pref->prelen);
    182 		return LDP_E_BAD_AF;
    183 	}
    184 	switch(pref->type) {
    185 	    case FEC_PREFIX:
    186 	    case FEC_HOST:
    187 		if (socktmp.sa.sa_family == AF_INET)
    188 			memcpy(&socktmp.sin.sin_addr, &pref->prefix,
    189 			    ldp_ceil8(pref->prelen));
    190 		else
    191 			memcpy(&socktmp.sin6.sin6_addr, &pref->prefix,
    192 			    ldp_ceil8(pref->prelen));
    193 		debugp("Prefix/Host withdraw: %s/%d\n", satos(&socktmp.sa),
    194 		    pref->prelen);
    195 
    196 		/* Delete mapping */
    197 		ldp_peer_delete_mapping(p, &socktmp.sa, pref->prelen);
    198 
    199 		/* Get label, see if we're pointing to this peer
    200 		 * if so, send withdraw, reattach IP route and announce
    201 		 * POP Label
    202 		 */
    203 		lab = label_get_by_prefix(&socktmp.sa, pref->prelen);
    204 		if (lab && lab->p == p) {
    205 			label_reattach_route(lab, REATT_INET_CHANGE);
    206 			announce_label_change(lab); /* binding has changed */
    207 		}
    208 		break;
    209 	    case FEC_WILDCARD:
    210 		fatalp("LDP neighbour %s: Wildcard withdraw !!!\n",
    211 		    satos(p->address));
    212 		ldp_peer_delete_all_mappings(p);
    213 		label_reattach_all_peer_labels(p, REATT_INET_CHANGE);
    214 		break;
    215 	    default:
    216 		fatalp("Unknown FEC type %d\n", pref->type);
    217 		return LDP_E_BAD_FEC;
    218 	}
    219 
    220 	return LDP_E_OK;
    221 }
    222 
    223 
    224 /*
    225  * In case of label withdraw, reuse the same buffer to send label release
    226  * Simply replace type and message id
    227  */
    228 void
    229 prepare_release(struct tlv * v)
    230 {
    231 	struct label_map_tlv *t;
    232 
    233 	t = (struct label_map_tlv *) v;
    234 
    235 	t->type = htons(LDP_LABEL_RELEASE);
    236 	t->messageid = htonl(get_message_id());
    237 }
    238 
    239 /* Sends a label mapping */
    240 void
    241 send_label_tlv(const struct ldp_peer * peer, const struct sockaddr * addr,
    242     uint8_t prefixlen, uint32_t label, const struct label_request_tlv *lrt)
    243 {
    244 	struct label_map_tlv *lmt;
    245 	struct fec_tlv *fec;
    246 	struct prefix_tlv *p;
    247 	struct label_tlv *l;
    248 
    249 	debugp("SENDING LABEL TLV %s TO %s\n", satos(addr),
    250 	    inet_ntoa(peer->ldp_id));
    251 
    252 	/*
    253 	 * Ok, so we have label map tlv that contains fec tlvs and label tlv
    254 	 * but fec tlv contains prefix or host tlvs and prefix or host tlvs
    255 	 * contains the network. After that we may have optional parameters
    256 	 * Got it ?
    257 	 */
    258 
    259 	lmt = calloc(1,
    260 		sizeof(struct label_map_tlv) +
    261 		sizeof(struct fec_tlv) +
    262 		sizeof(struct prefix_tlv) - sizeof(struct in_addr) +
    263 			ldp_ceil8(prefixlen) +
    264 		sizeof(struct label_tlv) +
    265 	 /* Label request optional parameter  */
    266 	 	(lrt != NULL ? sizeof(struct label_request_tlv) : 0) );
    267 
    268 	if (!lmt) {
    269 		fatalp("send_label_tlv: calloc problem\n");
    270 		return;
    271 	}
    272 
    273 	lmt->type = htons(LDP_LABEL_MAPPING);
    274 	lmt->length = htons(sizeof(struct label_map_tlv) - TLV_TYPE_LENGTH
    275 	    + sizeof(struct fec_tlv)
    276 	    + sizeof(struct prefix_tlv) - sizeof(struct in_addr) +
    277 		ldp_ceil8(prefixlen)
    278 	    + sizeof(struct label_tlv) +
    279 	    + (lrt != NULL ? sizeof(struct label_request_tlv) : 0));
    280 	lmt->messageid = htonl(get_message_id());
    281 
    282 	/* FEC TLV */
    283 	fec = (struct fec_tlv *) & lmt[1];
    284 	fec->type = htons(TLV_FEC);
    285 	fec->length = htons(sizeof(struct prefix_tlv) - sizeof(struct in_addr) +
    286 		ldp_ceil8(prefixlen));
    287 
    288 	/* Now let's do the even a dirtier job: PREFIX TLV */
    289 	p = (struct prefix_tlv *) & fec[1];
    290 	/*
    291 	 * RFC5036 obsoletes FEC_HOST
    292 	 *
    293 	 * if (prefixlen == 32) p->type = FEC_HOST; else
    294 	 */
    295 	p->type = FEC_PREFIX;
    296 	p->af = htons(LDP_AF_INET);
    297 	p->prelen = prefixlen;
    298 	memcpy(&p->prefix, & ((const struct sockaddr_in*)addr)->sin_addr,
    299 	    ldp_ceil8(prefixlen));
    300 
    301 	/* LABEL TLV */
    302 	l = (struct label_tlv *) ((unsigned char *) p +
    303 		sizeof(struct prefix_tlv) - sizeof(struct in_addr) +
    304 		ldp_ceil8(prefixlen));
    305 	l->type = htons(TLV_GENERIC_LABEL);
    306 	l->length = htons(sizeof(l->label));
    307 	l->label = htonl(label);
    308 
    309 	/* Label request optional parameter */
    310 	if (lrt)
    311 		memcpy(((char*)l) + TLV_TYPE_LENGTH + ntohs(l->length),
    312 			lrt, htons(lrt->length) + TLV_TYPE_LENGTH);
    313 
    314 	/* Wow, seems we're ready */
    315 	send_tlv(peer, (struct tlv *) lmt);
    316 	free(lmt);
    317 }
    318 
    319 void
    320 send_label_tlv_to_all(const struct sockaddr * addr, uint8_t prefixlen,
    321     uint32_t label)
    322 {
    323 	struct ldp_peer *p;
    324 	SLIST_FOREACH(p, &ldp_peer_head, peers)
    325 		if (p->state == LDP_PEER_ESTABLISHED)
    326 			send_label_tlv(p, addr, prefixlen, label, NULL);
    327 }
    328 
    329 /*
    330  * Send all local labels to a peer
    331  */
    332 void
    333 send_all_bindings(const struct ldp_peer * peer)
    334 {
    335 	struct label *l = NULL;
    336 
    337 	while((l = label_get_right(l)) != NULL)
    338 	   send_label_tlv(peer, &l->so_dest.sa,
    339 		from_union_to_cidr(&l->so_pref), l->binding, NULL);
    340 
    341 }
    342 
    343 /* Sends a label WITHDRAW */
    344 void
    345 send_withdraw_tlv(const struct ldp_peer * peer, const struct sockaddr * addr,
    346     uint8_t prefixlen)
    347 {
    348 	struct label_map_tlv *lmt;
    349 	struct fec_tlv *fec;
    350 	struct prefix_tlv *p;
    351 
    352 	/*
    353 	 * Ok, so we have label map tlv that contains fec tlvs but fec tlv
    354 	 * contains prefix or host tlvs and prefix or host tlvs contains the
    355 	 * network. Yes, we don't have to announce label here
    356 	 */
    357 
    358 	lmt = malloc(sizeof(struct label_map_tlv)
    359 	      + sizeof(struct fec_tlv)
    360 	      + sizeof(struct prefix_tlv) - sizeof(struct in_addr) +
    361 			ldp_ceil8(prefixlen));
    362 
    363 	if (!lmt) {
    364 		fatalp("send_withdraw_tlv: malloc problem\n");
    365 		return;
    366 		}
    367 
    368 	lmt->type = htons(LDP_LABEL_WITHDRAW);
    369 	lmt->length = htons(sizeof(struct label_map_tlv) - TLV_TYPE_LENGTH
    370 	    + sizeof(struct fec_tlv)
    371 	    + sizeof(struct prefix_tlv) - sizeof(struct in_addr) +
    372 		ldp_ceil8(prefixlen));
    373 	lmt->messageid = htonl(get_message_id());
    374 
    375 	/* FEC TLV */
    376 	fec = (struct fec_tlv *) & lmt[1];
    377 	fec->type = htons(TLV_FEC);
    378 	fec->length = htons(sizeof(struct fec_tlv) - TLV_TYPE_LENGTH
    379 	    + sizeof(struct prefix_tlv) - sizeof(struct in_addr) +
    380 		ldp_ceil8(prefixlen));
    381 
    382 	/* Now the even dirtier job: PREFIX TLV */
    383 	p = (struct prefix_tlv *) & fec[1];
    384 	/*
    385 	 * RFC5036 obsoletes FEC_HOST
    386 	 *
    387 	 * if (prefixlen == 32) p->type = FEC_HOST; else
    388 	 */
    389 	p->type = FEC_PREFIX;
    390 	p->af = htons(LDP_AF_INET);
    391 	p->prelen = prefixlen;
    392 	memcpy(&p->prefix, addr, ldp_ceil8(prefixlen));
    393 
    394 	/* Wow, seems we're ready */
    395 	send_tlv(peer, (struct tlv *) lmt);
    396 	free(lmt);
    397 }
    398 
    399 void
    400 send_withdraw_tlv_to_all(const struct sockaddr * addr, uint8_t prefixlen)
    401 {
    402 	struct ldp_peer *p;
    403 	SLIST_FOREACH(p, &ldp_peer_head, peers)
    404 		if (p->state == LDP_PEER_ESTABLISHED)
    405 			send_withdraw_tlv(p, addr, prefixlen);
    406 }
    407 
    408 int
    409 request_respond(const struct ldp_peer *p, const struct label_map_tlv *lmt,
    410     const struct fec_tlv *fec)
    411 {
    412 	const struct prefix_tlv *pref;
    413 	union sockunion socktmp;
    414 	struct label *lab;
    415 	struct label_request_tlv lrm;
    416 
    417 	if (ntohs(fec->type) != TLV_FEC || fec->length == 0) {
    418 		debugp("Invalid FEC TLV !\n");
    419 		return LDP_E_BAD_FEC;
    420 	}
    421 	pref = (const struct prefix_tlv *) (fec + 1);
    422 
    423 	memset(&socktmp, 0, sizeof(socktmp));
    424 	if (ntohs(pref->af) == LDP_AF_INET) {
    425 		socktmp.sa.sa_family = AF_INET;
    426 		socktmp.sa.sa_len = sizeof(socktmp.sin);
    427 	} else if (ntohs(pref->af) == LDP_AF_INET6) {
    428 		socktmp.sa.sa_family = AF_INET6;
    429 		socktmp.sa.sa_len = sizeof(socktmp.sin6);
    430 	} else {
    431 		debugp("request_respond: Bad address family\n");
    432 		return LDP_E_BAD_AF;
    433 	}
    434 
    435 	switch (pref->type) {
    436 		case FEC_PREFIX:
    437 		case FEC_HOST:
    438 
    439 		if (socktmp.sa.sa_family == AF_INET)
    440 			memcpy(&socktmp.sin.sin_addr, &pref->prefix,
    441 			    ldp_ceil8(pref->prelen));
    442 		else /* AF_INET6 */
    443 			memcpy(&socktmp.sin6.sin6_addr, &pref->prefix,
    444 			    ldp_ceil8(pref->prelen));
    445 		debugp("Prefix/Host request: %s/%d\n", satos(&socktmp.sa),
    446 			pref->prelen);
    447 
    448 		lab = label_get_by_prefix(&socktmp.sa, pref->prelen);
    449 		if (!lab)
    450 			return LDP_E_NO_SUCH_ROUTE;
    451 		lrm.type = htons(TLV_LABEL_REQUEST);
    452 		/* XXX - use sizeof */
    453 		lrm.length = htons(socktmp.sa.sa_family == AF_INET ? 4 : 16);
    454 		lrm.messageid = lmt->messageid;
    455 		send_label_tlv(p, &socktmp.sa, pref->prelen, lab->binding,
    456 		    &lrm);
    457 		break;
    458 
    459 		case FEC_WILDCARD:
    460 		/*
    461 		 * Section 3.4.1
    462 		 * To be used only in the Label Withdraw and Label Release
    463 		 */
    464 		/* Fallthrough */
    465 		default:
    466 
    467 		fatalp("Invalid FEC type\n");
    468 		return LDP_E_BAD_FEC;
    469 	}
    470 	return LDP_E_OK;
    471 }
    472