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