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