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