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