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