FECs are now inserted in the tree upon creation
[mpls-ldp-portable.git] / ldp / ldp_label_mapping.c
blobba597ce41379befc87421769e7c2473e5e4feeb3
2 /*
3 * Copyright (C) James R. Leu 2000
4 * jleu@mindspring.com
6 * This software is covered under the LGPL, for more
7 * info check out http://www.gnu.org/copyleft/lgpl.html
8 */
10 #include "ldp_struct.h"
11 #include "ldp_session.h"
12 #include "ldp_attr.h"
13 #include "ldp_fec.h"
14 #include "ldp_mesg.h"
15 #include "ldp_notif.h"
16 #include "ldp_entity.h"
17 #include "ldp_inlabel.h"
18 #include "ldp_outlabel.h"
19 #include "ldp_nexthop.h"
20 #include "ldp_global.h"
21 #include "ldp_pdu_setup.h"
22 #include "ldp_label_rel_with.h"
23 #include "ldp_label_mapping.h"
24 #include "ldp_label_request.h"
26 #include "mpls_timer_impl.h"
27 #include "mpls_fib_impl.h"
28 #include "mpls_lock_impl.h"
29 #include "mpls_tree_impl.h"
30 #include "mpls_trace_impl.h"
31 #include "mpls_mm_impl.h"
32 #include "mpls_policy_impl.h"
34 #if MPLS_USE_LSR
35 #include "lsr_cfg.h"
36 #else
37 #include "mpls_mpls_impl.h"
38 #endif
40 mpls_return_enum ldp_label_mapping_with_xc(ldp_global * g, ldp_session * s,
41 ldp_fec * f, ldp_attr ** us_attr, ldp_attr * ds_attr)
43 mpls_return_enum result = MPLS_SUCCESS;
44 mpls_bool propogating = MPLS_BOOL_TRUE;
45 mpls_bool egress = MPLS_BOOL_TRUE;
46 mpls_bool created = MPLS_BOOL_FALSE;
48 MPLS_ASSERT(us_attr);
50 if (!(*us_attr)) {
51 if (!((*us_attr) = ldp_attr_create(&f->info))) {
52 return MPLS_FAILURE;
54 created = MPLS_BOOL_TRUE;
56 if (!ds_attr) {
57 propogating = MPLS_BOOL_FALSE;
58 egress = MPLS_BOOL_TRUE;
61 Prepare_Label_Mapping_Attributes(g, s, &f->info, ds_attr, (*us_attr),
62 propogating, MPLS_BOOL_TRUE, egress);
64 result = ldp_label_mapping_send(g, s, (*us_attr), ds_attr);
65 if (result != MPLS_SUCCESS) {
66 if (created == MPLS_BOOL_TRUE) {
67 ldp_attr_delete(*us_attr);
69 return result;
72 if (created == MPLS_BOOL_TRUE) {
73 result = ldp_attr_insert_upstream2(g, s, (*us_attr), f);
74 if (result != MPLS_SUCCESS) {
75 ldp_attr_delete(*us_attr);
76 return result;
80 if (ds_attr && ds_attr->outlabel && created == MPLS_BOOL_TRUE) {
82 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
83 LDP_TRACE_FLAG_BINDING, "Cross Connect Added\n");
85 result = ldp_inlabel_add_outlabel(g,(*us_attr)->inlabel,ds_attr->outlabel);
86 if (result != MPLS_SUCCESS) {
87 return result;
90 return MPLS_SUCCESS;
93 ldp_session *ldp_get_next_hop_session_for_fec2(ldp_fec * f, ldp_nexthop *nh) {
94 ldp_session *session = NULL;
96 * find the info about the next hop for this FEC
98 if (nh->addr && nh->addr->session_root.count > 0) {
99 session = mpls_link_list_head_data(&nh->addr->session_root);
100 } else if (nh->iff && nh->iff->is_p2p == MPLS_BOOL_TRUE &&
101 &nh->iff->entity) {
102 ldp_adj *adj = MPLS_LIST_HEAD(&nh->iff->entity->adj_root);
103 session = adj ? adj->session : NULL;
105 return session;
108 mpls_return_enum ldp_get_next_hop_session_for_fec(ldp_global * g,
109 mpls_fec * fec, mpls_nexthop *nh, ldp_session ** next_hop_session)
111 ldp_fec *f = NULL;
112 ldp_nexthop *n = NULL;
114 MPLS_ASSERT(next_hop_session);
116 if (!(f = ldp_fec_find(g, fec))) {
117 return MPLS_NO_ROUTE;
120 if (!(n = ldp_fec_nexthop_find(f, nh))) {
121 return MPLS_NO_ROUTE;
124 *next_hop_session = ldp_get_next_hop_session_for_fec2(f,n);
125 return (*next_hop_session) ? MPLS_SUCCESS : MPLS_FAILURE;
128 mpls_return_enum Check_Received_Attributes(ldp_global * g, ldp_session * s,
129 ldp_attr * r_attr, uint16_t type)
131 int count = 0;
132 int i;
134 if (!r_attr->hopCountTlvExists) { /* CRa.1 */
135 goto Check_Received_Attributes_5;
138 if (r_attr->hopCountTlv.hcValue >= s->cfg_hop_count_limit) { /* CRa.2 */
139 LDP_PRINT(g->user_data, "CRa.2\n");
140 goto Check_Received_Attributes_6;
143 if (!r_attr->pathVecTlvExists) { /* CRa.3 */
144 goto Check_Received_Attributes_5;
147 for (i = 0; i < MPLS_MAXHOPSNUMBER; i++) { /* CRa.4 */
148 if (r_attr->pathVecTlv.lsrId[i]) {
149 count++;
150 if (r_attr->pathVecTlv.lsrId[i] == g->lsr_identifier.u.ipv4) {
151 goto Check_Received_Attributes_6;
152 LDP_PRINT(g->user_data, "CRa.4a\n");
154 if (count > s->oper_path_vector_limit) {
155 goto Check_Received_Attributes_6;
156 LDP_PRINT(g->user_data, "CRa.4b\n");
161 Check_Received_Attributes_5:
162 return MPLS_SUCCESS;
164 Check_Received_Attributes_6:
165 if (type != MPLS_LBLMAP_MSGTYPE) {
166 ldp_notif_send(g, s, r_attr, LDP_NOTIF_LOOP_DETECTED); /* CRa.7 */
168 return MPLS_FAILURE; /* CRa.8 */
171 void Prepare_Label_Mapping_Attributes(ldp_global * g, ldp_session * s,
172 mpls_fec * fec, ldp_attr * r_attr, ldp_attr * s_attr, mpls_bool propogating,
173 mpls_bool already, mpls_bool egress)
175 ldp_attr dummy;
176 int i;
178 /* NOTE: PMpA.21 is the end of the procedure (ie return) */
179 /* this function uses goto quite extensivly for a REASON!! */
180 /* Check Appedix A of the LDP draft */
182 LDP_ENTER(g->user_data, "Prepare_Label_Mapping_Attributes");
184 if (!r_attr) {
185 memset(&dummy, 0, sizeof(ldp_attr));
186 mpls_fec2fec_tlv(fec, &dummy.fecTlv, 0);
187 dummy.fecTlvExists = 1;
188 dummy.fecTlv.numberFecElements = 1;
189 r_attr = &dummy;
192 if (!(s->oper_loop_detection == LDP_LOOP_HOPCOUNT ||
193 s->oper_loop_detection == LDP_LOOP_HOPCOUNT_PATHVECTOR ||
194 r_attr->hopCountTlvExists)) { /* PMpA.1 */
195 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
196 return;
199 if (egress) {/* PMpA.2 */
200 /* I'm egress (for now) */
201 s_attr->hopCountTlvExists = 1;
202 s_attr->hopCountTlv.hcValue = 1; /* PMpA.3 */
203 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
204 return;
207 if (!(r_attr->hopCountTlvExists)) { /* PMpA.4 */
208 goto Prepare_Label_Mapping_Attributes_8;
211 if (!(g->ttl_less_domain == MPLS_BOOL_TRUE &&
212 s->cfg_remote_in_ttl_less_domain == MPLS_BOOL_TRUE)) { /* PMpA.5 */
213 goto Prepare_Label_Mapping_Attributes_7;
216 s_attr->hopCountTlvExists = 1;
217 s_attr->hopCountTlv.hcValue = 1; /* PMpA.6 */
218 goto Prepare_Label_Mapping_Attributes_9;
220 Prepare_Label_Mapping_Attributes_7:
221 s_attr->hopCountTlvExists = 1;
222 s_attr->hopCountTlv.hcValue = (r_attr->hopCountTlv.hcValue) ?
223 (r_attr->hopCountTlv.hcValue + 1) : 0;
224 goto Prepare_Label_Mapping_Attributes_9;
226 Prepare_Label_Mapping_Attributes_8:
227 s_attr->hopCountTlvExists = 1;
228 s_attr->hopCountTlv.hcValue = 0;
230 Prepare_Label_Mapping_Attributes_9:
231 if (s->oper_loop_detection == LDP_LOOP_NONE) {
232 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
233 return;
236 if (r_attr->pathVecTlvExists) { /* PMpA.10 */
237 goto Prepare_Label_Mapping_Attributes_19;
240 if (propogating == MPLS_BOOL_FALSE) { /* PMpA.11 */
241 goto Prepare_Label_Mapping_Attributes_20;
244 if (g->label_merge != MPLS_BOOL_TRUE) { /* PMpA.12 */
245 goto Prepare_Label_Mapping_Attributes_14;
248 if (already == MPLS_BOOL_FALSE) { /* PMpA.13 */
249 goto Prepare_Label_Mapping_Attributes_20;
252 Prepare_Label_Mapping_Attributes_14:
253 if (!r_attr->hopCountTlvExists) {
254 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
255 return;
258 if (r_attr->hopCountTlv.hcValue == 0) { /* PMpA.15 */
259 goto Prepare_Label_Mapping_Attributes_20;
262 if (already == MPLS_BOOL_FALSE) { /* PMpA.16 */
263 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
264 return;
267 /* r_attr contain PrevHopCount _IF_ we had one */
268 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
269 return; /* PMpA.17 */
271 if (r_attr->hopCountTlv.hcValue != 0) { /* PMpA.18 */
272 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
273 return;
276 Prepare_Label_Mapping_Attributes_19:
277 s_attr->pathVecTlvExists = 1;
278 s_attr->pathVecTlv.lsrId[0] = g->lsr_identifier.u.ipv4;
279 for (i = 1; i < (MPLS_MAXHOPSNUMBER - 1); i++) {
280 if (r_attr->pathVecTlv.lsrId[i - 1]) {
281 s_attr->pathVecTlv.lsrId[0] = r_attr->pathVecTlv.lsrId[i - 1];
285 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
286 return;
288 Prepare_Label_Mapping_Attributes_20:
289 s_attr->pathVecTlvExists = 1;
290 s_attr->pathVecTlv.lsrId[0] = g->lsr_identifier.u.ipv4;
292 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
293 return;
296 void map2attr(mplsLdpLblMapMsg_t * map, ldp_attr * attr, uint32_t flag)
298 attr->msg_id = map->baseMsg.msgId;
300 if (map->fecTlvExists && flag & LDP_ATTR_FEC) {
301 memcpy(&attr->fecTlv, &map->fecTlv, sizeof(mplsLdpFecTlv_t));
302 attr->fecTlvExists = 1;
304 if (map->genLblTlvExists && flag & LDP_ATTR_LABEL) {
305 memcpy(&attr->genLblTlv, &map->genLblTlv, sizeof(mplsLdpGenLblTlv_t));
306 attr->genLblTlvExists = 1;
307 } else if (map->atmLblTlvExists && flag & LDP_ATTR_LABEL) {
308 memcpy(&attr->atmLblTlv, &map->atmLblTlv, sizeof(mplsLdpAtmLblTlv_t));
309 attr->atmLblTlvExists = 1;
310 } else if (map->frLblTlvExists && flag & LDP_ATTR_LABEL) {
311 memcpy(&attr->frLblTlv, &map->frLblTlv, sizeof(mplsLdpFrLblTlv_t));
312 attr->frLblTlvExists = 1;
314 if (map->hopCountTlvExists && flag & LDP_ATTR_HOPCOUNT) {
315 memcpy(&attr->hopCountTlv, &map->hopCountTlv, sizeof(mplsLdpHopTlv_t));
316 attr->hopCountTlvExists = 1;
318 if (map->pathVecTlvExists && flag & LDP_ATTR_PATH) {
319 memcpy(&attr->pathVecTlv, &map->pathVecTlv, sizeof(mplsLdpPathTlv_t));
320 attr->pathVecTlvExists = 1;
322 if (map->lblMsgIdTlvExists && flag & LDP_ATTR_MSGID) {
323 memcpy(&attr->lblMsgIdTlv, &map->lblMsgIdTlv, sizeof(mplsLdpLblMsgIdTlv_t));
324 attr->lblMsgIdTlvExists = 1;
326 if (map->lspidTlvExists && flag & LDP_ATTR_LSPID) {
327 memcpy(&attr->lspidTlv, &map->lspidTlv, sizeof(mplsLdpLspIdTlv_t));
328 attr->lspidTlvExists = 1;
330 if (map->trafficTlvExists && flag & LDP_ATTR_TRAFFIC) {
331 memcpy(&attr->trafficTlv, &map->trafficTlv, sizeof(mplsLdpTrafficTlv_t));
332 attr->trafficTlvExists = 1;
336 void attr2map(ldp_attr * attr, mplsLdpLblMapMsg_t * map)
338 if (attr->fecTlvExists) {
339 memcpy(&map->fecTlv, &attr->fecTlv, sizeof(mplsLdpFecTlv_t));
340 map->fecTlvExists = 1;
342 if (attr->genLblTlvExists) {
343 memcpy(&map->genLblTlv, &attr->genLblTlv, sizeof(mplsLdpGenLblTlv_t));
344 map->genLblTlvExists = 1;
346 if (attr->atmLblTlvExists) {
347 memcpy(&map->atmLblTlv, &attr->atmLblTlv, sizeof(mplsLdpAtmLblTlv_t));
348 map->atmLblTlvExists = 1;
350 if (attr->frLblTlvExists) {
351 memcpy(&map->frLblTlv, &attr->frLblTlv, sizeof(mplsLdpFrLblTlv_t));
352 map->frLblTlvExists = 1;
354 if (attr->hopCountTlvExists) {
355 memcpy(&map->hopCountTlv, &attr->hopCountTlv, sizeof(mplsLdpHopTlv_t));
356 map->hopCountTlvExists = 1;
358 if (attr->pathVecTlvExists) {
359 memcpy(&map->pathVecTlv, &attr->pathVecTlv, sizeof(mplsLdpPathTlv_t));
360 map->pathVecTlvExists = 1;
362 if (attr->lblMsgIdTlvExists) {
363 memcpy(&map->lblMsgIdTlv, &attr->lblMsgIdTlv, sizeof(mplsLdpLblMsgIdTlv_t));
364 map->lblMsgIdTlvExists = 1;
366 if (attr->lspidTlvExists) {
367 memcpy(&map->lspidTlv, &attr->lspidTlv, sizeof(mplsLdpLspIdTlv_t));
368 map->lspidTlvExists = 1;
370 if (attr->trafficTlvExists) {
371 memcpy(&map->trafficTlv, &attr->trafficTlv, sizeof(mplsLdpTrafficTlv_t));
372 map->trafficTlvExists = 1;
376 void ldp_label_mapping_initial_callback(mpls_timer_handle timer, void *extra,
377 mpls_cfg_handle handle)
379 ldp_session *s = (ldp_session *) extra;
380 ldp_global *g = (ldp_global*)handle;
381 ldp_attr *ds_attr = NULL;
382 ldp_attr *us_attr = NULL;
383 ldp_session *nh_session = NULL;
384 mpls_bool done = MPLS_BOOL_FALSE;
385 ldp_fec *f;
386 ldp_nexthop *nh;
388 LDP_ENTER(g->user_data, "ldp_label_mapping_initial_callback");
390 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_TIMER,
391 "Initial Label Mapping fired: session(%d)\n", s->index);
393 mpls_lock_get(g->global_lock);
395 mpls_timer_stop(g->timer_handle, timer);
397 f = MPLS_LIST_HEAD(&g->fec);
398 while (f) {
399 nh = MPLS_LIST_HEAD(&f->nh_root);
400 while (nh) {
401 switch (f->info.type) {
402 case MPLS_FEC_PREFIX:
403 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
404 LDP_TRACE_FLAG_ROUTE, "Processing prefix FEC: %08x/%d ",
405 f->info.u.prefix.network.u.ipv4, f->info.u.prefix.length);
406 break;
407 case MPLS_FEC_HOST:
408 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
409 LDP_TRACE_FLAG_ROUTE, "Processing host FEC: %08x ",
410 f->info.u.host.u.ipv4);
411 break;
412 case MPLS_FEC_L2CC:
413 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
414 LDP_TRACE_FLAG_ROUTE, "Processingu L2CC FEC: %d %d %d ",
415 f->info.u.l2cc.connection_id, f->info.u.l2cc.group_id,
416 f->info.u.l2cc.type);
417 break;
418 default:
419 MPLS_ASSERT(0);
422 if (nh->info.type & MPLS_NH_IP) {
423 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
424 LDP_TRACE_FLAG_ROUTE, "via %08x\n", nh->addr->address.u.ipv4);
426 if (nh->info.type & MPLS_NH_IF && nh->iff) {
427 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
428 LDP_TRACE_FLAG_ROUTE, "via %p\n", nh->iff->handle);
431 /* are we allowed to export this route from the rib */
432 if (mpls_policy_export_check(g->user_data, &f->info, &nh->info) ==
433 MPLS_BOOL_FALSE) {
434 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
435 LDP_TRACE_FLAG_POLICY, "Rejected by export policy\n");
436 goto ldp_label_mapping_initial_callback_end_nh;
439 /* have we already sent a mapping for this fec to the new session? */
440 if ((us_attr = ldp_attr_find_upstream_state2(g, s, f,
441 LDP_LSP_STATE_MAP_SENT))) {
442 /* no need to sent another mapping */
443 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
444 LDP_TRACE_FLAG_ROUTE, "Already sent this FEC to session %d\n",
445 s->index);
446 goto ldp_label_mapping_initial_callback_end_nh;
449 if (!(nh_session = ldp_get_next_hop_session_for_fec2(f,nh))) {
450 ds_attr = NULL;
451 } else {
452 if (nh_session->index == s->index) {
453 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
454 LDP_TRACE_FLAG_ROUTE, "Nexthop session(%d) == session(%d)\n",
455 nh_session->index, s->index);
456 goto ldp_label_mapping_initial_callback_end_nh;
458 ds_attr = ldp_attr_find_downstream_state2(g, nh_session, f,
459 LDP_LSP_STATE_MAP_RECV);
462 if ((g->label_merge != MPLS_BOOL_TRUE) &&
463 ldp_attr_num_us2ds(ds_attr)) {
464 /* we have a ds label, but can't use it */
465 ds_attr = NULL;
468 us_attr = NULL;
469 if (ds_attr) {
470 /* we can use it, merge on baby */
471 ldp_label_mapping_with_xc(g, s, f, &us_attr, ds_attr);
472 } else {
473 /* we don't have a ds label */
475 /* we will be egress? */
476 if (g->lsp_control_mode == LDP_CONTROL_ORDERED) {
477 if (mpls_policy_egress_check(g->user_data, &f->info,
478 &nh->info) == MPLS_BOOL_TRUE) {
479 ldp_label_mapping_with_xc(g, s, f, &us_attr, NULL);
481 } else {
482 ldp_label_mapping_with_xc(g, s, f, &us_attr, NULL);
485 ldp_label_mapping_initial_callback_end_nh:
486 nh = MPLS_LIST_NEXT(&f->nh_root, nh, _fec);
488 f = MPLS_LIST_NEXT(&g->fec, f, _global);
490 done = MPLS_BOOL_TRUE;
492 if (done == MPLS_BOOL_TRUE) {
493 mpls_timer_delete(g->timer_handle, timer);
494 MPLS_REFCNT_RELEASE(s, ldp_session_delete);
495 s->initial_distribution_timer = (mpls_timer_handle) 0;
496 } else {
497 mpls_timer_start(g->timer_handle, timer, MPLS_TIMER_ONESHOT);
498 /* need to mark the session with where it left off */
501 mpls_lock_release(g->global_lock);
503 LDP_EXIT(g->user_data, "ldp_label_mapping_initial_callback");
506 mpls_return_enum ldp_label_mapping_send(ldp_global * g, ldp_session * s,
507 ldp_attr * us_attr, ldp_attr * ds_attr)
509 ldp_inlabel *in = NULL;
510 ldp_attr *us_temp;
512 LDP_ENTER(g->user_data, "ldp_label_mapping_send");
513 MPLS_ASSERT(us_attr);
515 if ((in = ldp_inlabel_create_complete(g, s, us_attr)) == NULL) { /* SL.1-3 */
516 goto Send_Label_9;
519 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_BINDING,
520 "In Label Added\n");
522 us_attr->state = LDP_LSP_STATE_MAP_SENT;
524 us_attr->msg_id = g->message_identifier;
525 ldp_label_mapping_prepare_msg(s->tx_message, g->message_identifier++,
526 us_attr);
528 if (ldp_mesg_send_tcp(g, s, s->tx_message) != MPLS_SUCCESS) { /* SL.4 */
529 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_SEND, LDP_TRACE_FLAG_ERROR,
530 "Failed sending Label Mapping to %s\n",
531 s->session_name);
532 goto ldp_label_mapping_send_error;
535 ldp_attr_add_us2ds(us_attr, ds_attr);
537 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_SEND, LDP_TRACE_FLAG_LABEL,
538 "Label Mapping Sent to %s for %08x/%d\n",
539 s->session_name,
540 us_attr->fecTlv.fecElArray[0].addressEl.address,
541 us_attr->fecTlv.fecElArray[0].addressEl.preLen);
543 us_attr->state = LDP_LSP_STATE_MAP_SENT; /* SL.6,7 */
545 LDP_EXIT(g->user_data, "ldp_label_mapping_send");
546 return MPLS_SUCCESS; /* SL.8 */
548 Send_Label_9:
549 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_STATE,
550 "No Label Resources\n");
552 while ((us_temp = ldp_attr_find_upstream_state2(g, s, us_attr->fec,
553 LDP_LSP_STATE_REQ_RECV)) != NULL) { /* SL.9 */
554 ldp_notif_send(g, s, us_temp, LDP_NOTIF_NO_LABEL_RESOURCES_AVAILABLE);
555 /* SL.10 */
556 s->no_label_resource_sent = MPLS_BOOL_TRUE; /* SL.12 */
557 us_temp->state = LDP_LSP_STATE_NO_LABEL_RESOURCE_SENT; /* SL.13 */
560 LDP_EXIT(g->user_data, "ldp_label_mapping_send");
562 return MPLS_SUCCESS;
564 ldp_label_mapping_send_error:
566 LDP_EXIT(g->user_data, "ldp_label_mapping_send-error");
567 return MPLS_FAILURE;
570 void ldp_label_mapping_prepare_msg(ldp_mesg * msg, uint32_t msgid,
571 ldp_attr * s_attr)
573 mplsLdpLblMapMsg_t *map = NULL;
574 int i;
576 MPLS_ASSERT(msg);
578 ldp_mesg_prepare(msg, MPLS_LBLMAP_MSGTYPE, msgid);
579 map = &msg->u.map;
581 if (s_attr->fecTlvExists) {
582 /* JLEU: only 1 FEC is allowed!! */
583 map->fecTlvExists = 1;
584 map->baseMsg.msgLength += setupFecTlv(&map->fecTlv);
585 map->baseMsg.msgLength += addFecElem2FecTlv(&map->fecTlv,
586 &s_attr->fecTlv.fecElArray[0]);
588 if (s_attr->genLblTlvExists) {
589 map->genLblTlvExists = 1;
590 map->baseMsg.msgLength += setupGenLblTlv(&map->genLblTlv,
591 s_attr->genLblTlv.label);
593 if (s_attr->atmLblTlvExists) {
594 map->atmLblTlvExists = 1;
595 map->baseMsg.msgLength += setupAtmLblTlv(&map->atmLblTlv, 0, 0,
596 s_attr->atmLblTlv.flags.flags.vpi, s_attr->atmLblTlv.vci);
598 if (s_attr->frLblTlvExists) {
599 map->frLblTlvExists = 1;
600 map->baseMsg.msgLength += setupFrLblTlv(&map->frLblTlv, 0,
601 s_attr->frLblTlv.flags.flags.len, s_attr->frLblTlv.flags.flags.dlci);
603 if (s_attr->hopCountTlvExists) {
604 map->hopCountTlvExists = 1;
605 map->baseMsg.msgLength += setupHopCountTlv(&map->hopCountTlv,
606 s_attr->hopCountTlv.hcValue);
608 if (s_attr->pathVecTlvExists) {
609 map->pathVecTlvExists = 1;
610 map->baseMsg.msgLength += setupPathTlv(&map->pathVecTlv);
611 for (i = 0; i < MPLS_MAXHOPSNUMBER; i++) {
612 if (s_attr->pathVecTlv.lsrId[i]) {
613 map->baseMsg.msgLength += addLsrId2PathTlv(&map->pathVecTlv,
614 s_attr->pathVecTlv.lsrId[i]);
618 #if 0
619 if (s_attr->lblMsgIdTlvExists) {
621 if (s_attr->lspidTlvExists) {
623 if (s_attr->trafficTlvExists) {
625 #endif
628 mpls_return_enum ldp_label_mapping_process(ldp_global * g, ldp_session * s,
629 ldp_adj * a, ldp_entity * e, ldp_attr * r_attr, ldp_fec * f)
631 mpls_return_enum retval = MPLS_SUCCESS;
632 ldp_session *peer = NULL;
633 ldp_attr_list *us_list = NULL;
634 ldp_attr_list *ds_list = NULL;
635 ldp_attr *ds_attr = NULL;
636 ldp_attr *ds_temp = NULL;
637 ldp_attr *us_attr = NULL;
638 ldp_attr *us_temp = NULL;
639 ldp_attr dumb_attr;
640 ldp_nexthop *nh = NULL;
642 ldp_outlabel *out = NULL;
643 mpls_bool requested = MPLS_BOOL_FALSE;
644 ldp_attr *existing = NULL;
645 mpls_bool need_request = MPLS_BOOL_FALSE;
647 LDP_ENTER(g->user_data, "ldp_label_mapping_process");
649 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV, LDP_TRACE_FLAG_LABEL,
650 "Label Mapping Recv from %s for %08x/%d\n",
651 s->session_name,
652 r_attr->fecTlv.fecElArray[0].addressEl.address,
653 r_attr->fecTlv.fecElArray[0].addressEl.preLen);
655 if ((ds_attr = ldp_attr_find_downstream_state2(g, s, f,
656 LDP_LSP_STATE_REQ_SENT)) != NULL) { /* LMp.1 */
657 /* just remove the req from the tree, we will use the r_attr sent to us */
658 ldp_attr_delete_downstream(g, s, ds_attr);
659 requested = MPLS_BOOL_TRUE;
660 } else {
661 requested = MPLS_BOOL_FALSE;
664 ds_attr = r_attr;
665 ds_attr->state = LDP_LSP_STATE_MAP_RECV; /* LMp.2 */
668 * ds_attr is the mapping we will keep and is NOT in the tree, unless
669 * it is an update mapping ...
671 if (Check_Received_Attributes(g, s, ds_attr, MPLS_LBLMAP_MSGTYPE) ==
672 MPLS_SUCCESS) { /* LMp.3 */
673 goto LMp_9;
677 * A loop was detected
679 if ((ds_list = ldp_attr_find_downstream_all2(g, s, f))) {
680 ds_temp = MPLS_LIST_HEAD(ds_list);
682 * check all the labels this session has received from "s" for "fec"
683 * do we have a duplicat?
685 while (ds_temp) {
686 if ((ds_temp->state == LDP_LSP_STATE_MAP_RECV) && /* LMp.4 */
687 ldp_attr_is_equal(ds_temp, ds_attr, LDP_ATTR_LABEL) == /* LMp.5 */
688 MPLS_BOOL_TRUE) {
689 /* remove record of the label and remove it switching */
690 ldp_attr_remove_complete(g, ds_temp, MPLS_BOOL_TRUE); /* LMp.6,7 */
692 * I think this is supposed to be 32 NOT 33, we need to release
693 * it don't we?
695 goto LMp_33;
697 ds_temp = MPLS_LIST_NEXT(ds_list, ds_temp, _fs);
701 LDP_PRINT(g->user_data, "Receive_Label_Map_8: send release");
702 if (ldp_label_release_send(g, s, ds_attr, LDP_NOTIF_LOOP_DETECTED) !=
703 MPLS_SUCCESS) { /* LMp.8 */
704 retval = MPLS_FAILURE;
706 goto LMp_33;
708 LMp_9:
710 * No Loop Detected
712 ds_temp = ldp_attr_find_downstream_state2(g, s, f, LDP_LSP_STATE_MAP_RECV);
713 if (requested == MPLS_BOOL_TRUE ||
714 g->label_merge == MPLS_BOOL_FALSE || !ds_temp) {
715 /* !merging then this is always a new LSP
716 * merging w/o a recv'd mapping is a new LSP
717 * this check comes from Note 6
719 goto LMp_11;
722 /* searching all recv'd attrs for matched mappings,
723 * stop after finding 1st match
725 if ((ds_list = ldp_attr_find_downstream_all2(g, s, f))) {
726 ds_temp = MPLS_LIST_HEAD(ds_list);
727 while (ds_temp) {
728 if (ds_temp->state == LDP_LSP_STATE_MAP_RECV) { /* LMp.9 */
729 if (ldp_attr_is_equal(ds_attr, ds_temp, LDP_ATTR_LABEL) ==
730 MPLS_BOOL_TRUE) { /* LMp.10 */
732 * this mapping matches an existing mapping, but it
733 * could contain updated attributes
735 existing = ds_temp;
736 break;
737 } else {
739 * we have been given another label for the same FEC and we
740 * didn't request it, release it
742 LDP_PRINT(g->user_data, "LMp.10 dup without req\n");
743 goto LMp_32;
746 ds_temp = MPLS_LIST_NEXT(ds_list, ds_temp, _fs);
749 if (existing) {
750 ldp_attr2ldp_attr(ds_attr, existing, LDP_ATTR_HOPCOUNT | LDP_ATTR_PATH |
751 LDP_ATTR_MSGID | LDP_ATTR_LSPID | LDP_ATTR_TRAFFIC);
752 ds_attr = existing;
754 * no need to free ds_attr, since it was not added to the tree it
755 * will be deleted when we exit ldp_label_mapping_process(), see
756 * ldp_state_process().
760 * from this point on.... if this is an updated mapping then ds_attr
761 * is the existing mapping which has now been update, else ds_attr
762 * is the new mapping
765 LMp_11:
767 * existing ONLY has a value for updated label mapping
769 nh = ldp_nexthop_for_fec_session(f,s); /* LMp.11 */
772 * the following departs from the procedure, it allows for filtering
773 * of label mappings
775 * Are we configured to accept and INSTALL this mapping?
777 if (mpls_policy_import_check(g->user_data, &f->info, &nh->info) ==
778 MPLS_BOOL_FALSE) {
780 * policy has rejected it, store it away
782 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV, LDP_TRACE_FLAG_LABEL,
783 "Label Mapping for %08x/%d from %s filtered by import policy\n",
784 r_attr->fecTlv.fecElArray[0].addressEl.address,
785 r_attr->fecTlv.fecElArray[0].addressEl.preLen, s->session_name);
787 if (existing) {
788 ds_attr->filtered = MPLS_BOOL_TRUE;
789 if (ds_attr->outlabel && ds_attr->outlabel->switching == MPLS_BOOL_TRUE) {
790 /* the mapping has been filtered, but the original wasn't? */
791 MPLS_ASSERT(0);
793 } else {
794 ds_attr->filtered = MPLS_BOOL_TRUE;
795 if (ldp_attr_insert_downstream(g, s, ds_attr) != MPLS_SUCCESS) {
796 retval = MPLS_FAILURE;
799 goto LMp_33;
802 if (!nh) { /* LMp.12 */
804 * if we did not find a nh hop for this FEC that corresponded to the
805 * MsgSource then the MsgSource is not a nexthop for the FEC
807 if (g->label_retention_mode == LDP_RETENTION_CONSERVATIVE) { /* LMp.13C */
808 LDP_PRINT(g->user_data, "LMp.13C conservative\n");
809 goto LMp_32;
813 * store it away
815 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV, LDP_TRACE_FLAG_LABEL,
816 "Session %s is not a valid nexthop for %08x/%d\n", s->session_name,
817 r_attr->fecTlv.fecElArray[0].addressEl.address,
818 r_attr->fecTlv.fecElArray[0].addressEl.preLen);
820 if (!existing) {
821 /* LMp.13L */
822 if (ldp_attr_insert_downstream(g, s, ds_attr) != MPLS_SUCCESS) {
823 retval = MPLS_FAILURE;
826 goto LMp_33;
830 * this is slightly different form the procedure, we can still be
831 * transit for a FEC we are not configured to be ingress for.
832 * Either way we only need to do the "install for fwd/switching"
833 * only once. We could arrive here multiple times due to updates,
834 * only install it the first time
836 if ((!existing) || (!existing->outlabel)) {
838 * we haven't installed it yet.
839 * Either new (!existing), or a result of a "Detect FEC Nexthop Change"
840 * and we had this mapping in our database (!existing->outlabel))
843 if (!(out = ldp_outlabel_create_complete(g, s, ds_attr, nh))) {
844 LDP_PRINT(g->user_data, "LMp.15 failure creating outlabel\n");
845 goto LMp_32;
848 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_BINDING,
849 "Out Label Added\n");
853 * are we configured to act as ingress for this FEC?
855 if (mpls_policy_ingress_check(g->user_data, &f->info, &nh->info) ==
856 MPLS_BOOL_TRUE) { /* LMp.14 */
858 * yep, bind the label to the FEC
860 if (ds_attr->ingress != MPLS_BOOL_TRUE) {
861 #if MPLS_USE_LSR
862 lsr_ftn ftn;
863 ftn.outsegment_index = ds_attr->outlabel->info.handle;
864 memcpy(&ftn.fec, &f->info, sizeof(mpls_fec));
865 lsr_cfg_ftn_set2(g->lsr_handle, &ftn, LSR_CFG_ADD|LSR_FTN_CFG_FEC|
866 LSR_FTN_CFG_OUTSEGMENT);
867 #else
868 mpls_mpls_fec2out_add(g->mpls_handle, &f->info, &ds_attr->outlabel->info);
869 #endif
870 ds_attr->ingress = MPLS_BOOL_TRUE;
871 ds_attr->outlabel->merge_count++;
872 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV, LDP_TRACE_FLAG_BINDING,
873 "Acting as ingress for %08x/%d from %s\n",
874 r_attr->fecTlv.fecElArray[0].addressEl.address,
875 r_attr->fecTlv.fecElArray[0].addressEl.preLen, s->session_name);
879 /* create a set of attrs that we will fill and compare against
880 * if this mapping were to be propogate these are the attrs it would have
881 * by comparing what we did sent in the past to these, we con figure out
882 * if we need to send an updated mapping
884 memset(&dumb_attr, 0, sizeof(ldp_attr));
885 mpls_fec2fec_tlv(&f->info, &dumb_attr.fecTlv, 0);
886 dumb_attr.fecTlvExists = 1;
887 dumb_attr.fecTlv.numberFecElements = 1;
890 * by definition (we received a label mapping that will be used) this
891 * LSR is _not_ the egress, so calculate a hop and path based on the
892 * mapping we received. We will compare this with mapping that have
893 * already been sent. If they differ, we will send an updated mapping
895 Prepare_Label_Mapping_Attributes(g, s, &f->info, ds_attr, &dumb_attr,
896 MPLS_BOOL_TRUE, MPLS_BOOL_TRUE, MPLS_BOOL_FALSE);
898 if (!existing) {
900 * this is the first time we've seen this mapping, add it to the database.
901 * all future updates will modify this entry in place
903 /* LMp.16 */
904 if (ldp_attr_insert_downstream(g, s, ds_attr) != MPLS_SUCCESS) {
905 retval = MPLS_FAILURE;
906 goto LMp_33;
910 peer = MPLS_LIST_HEAD(&g->session);
911 while (peer) { /* LMp.17 */
913 if (peer->state != LDP_STATE_OPERATIONAL) {
914 goto next_peer;
918 * it is just as easy to walk the list of all upstream attr for this
919 * peer as it is to the individual check to see if we have sent a
920 * label mapping for this FEC LSP
923 /* LMp.22 - 27 */
924 if ((us_list = ldp_attr_find_upstream_all2(g, peer, f))) { /* LMp.23 */
925 us_temp = MPLS_LIST_HEAD(us_list);
926 while (us_temp) {
928 * if we have sent a label mapping for the FEC and that label mapping
929 * was an done in independent mode or it is part of an existing
930 * recieved label mapping
932 /* LMp.18 */
933 if ((us_temp->state == LDP_LSP_STATE_MAP_SENT) &&
934 ((!existing) || (existing->index == us_temp->ds_attr->index))) {
935 /* are the recieved attrs the same as the ones we've already sent */
936 if (ldp_attr_is_equal(us_temp, &dumb_attr,
937 LDP_ATTR_HOPCOUNT | LDP_ATTR_PATH) != MPLS_BOOL_TRUE) {
938 /* send an updated label mapping */
939 if (ldp_label_mapping_with_xc(g, us_temp->session, f, &us_temp,
940 ds_attr) != MPLS_SUCCESS) { /* LMp.24-26 */
941 retval = MPLS_FAILURE;
942 goto LMp_33;
946 us_temp = MPLS_LIST_NEXT(us_list, us_temp, _fs);
950 if ((peer->oper_distribution_mode == LDP_DISTRIBUTION_UNSOLICITED) &&
951 (g->lsp_control_mode == LDP_CONTROL_ORDERED)) { /* LMp.19 */
954 * if we're not merging and we have multiple ORDERED DU sessions,
955 * we will to start requesting labels after we propogate the mapping to
956 * the first peer
958 if (need_request == MPLS_BOOL_TRUE) {
959 if (ldp_attr_find_downstream_state2(g, peer, f,
960 LDP_LSP_STATE_REQ_SENT) == NULL) {
962 * we don't have a request for FEC to peer outstanding, make one
964 ds_temp = NULL;
965 if (ldp_label_request_for_xc(g, peer, &f->info, NULL, &ds_temp) !=
966 MPLS_SUCCESS) {
967 retval = MPLS_FAILURE;
968 goto LMp_33;
971 } else {
973 * We're in DU more, either we're merging, or we're not merging and
974 * this is the first peer we're propogating this mapping to
976 /* LMp.20-21,30 */
977 us_attr = NULL;
978 if (ldp_label_mapping_with_xc(g, peer, f, &us_attr, ds_attr) !=
979 MPLS_SUCCESS) {
980 retval = MPLS_FAILURE;
981 goto LMp_33;
984 * if we're not merging, we will need to request a label for
985 * the next DU peer
987 if (g->label_merge == MPLS_BOOL_FALSE) {
988 need_request = MPLS_BOOL_TRUE;
993 /* LMp.28 */
994 while ((us_temp = ldp_attr_find_upstream_state2(g, peer, f,
995 LDP_LSP_STATE_REQ_RECV))) {
997 if (peer->oper_distribution_mode == LDP_DISTRIBUTION_UNSOLICITED) {
998 if (need_request == MPLS_BOOL_TRUE) {
999 if (ldp_attr_find_downstream_state2(g, peer, f,
1000 LDP_LSP_STATE_REQ_SENT) == NULL) {
1002 * we don't have a request for FEC to peer outstanding
1004 ds_temp = NULL;
1005 if (ldp_label_request_for_xc(g, peer, &f->info, us_temp,
1006 &ds_temp) != MPLS_SUCCESS) {
1007 retval = MPLS_FAILURE;
1008 goto LMp_33;
1011 } else {
1012 if (ldp_label_mapping_with_xc(g, peer, f, &us_temp,
1013 ds_attr) != MPLS_SUCCESS) {
1014 retval = MPLS_FAILURE;
1015 goto LMp_33;
1018 } else {
1019 if ((us_list = ldp_attr_find_upstream_all2(g, peer, f))) {
1020 us_temp = MPLS_LIST_HEAD(ds_list);
1021 while (us_temp) {
1022 if (us_temp->state == LDP_LSP_STATE_REQ_RECV) {
1023 if (need_request == MPLS_BOOL_TRUE) {
1024 if (ldp_attr_find_downstream_state2(g, peer, f,
1025 LDP_LSP_STATE_REQ_SENT) == NULL) {
1027 * we don't have a request for FEC to peer outstanding
1029 ds_temp = NULL;
1030 if (ldp_label_request_for_xc(g, peer, &f->info, us_temp,
1031 &ds_temp) != MPLS_SUCCESS) {
1032 retval = MPLS_FAILURE;
1033 goto LMp_33;
1036 } else {
1037 if (ldp_label_mapping_with_xc(g, peer, f, &us_temp,
1038 ds_attr) != MPLS_SUCCESS) {
1039 retval = MPLS_FAILURE;
1040 goto LMp_33;
1043 * if we're not merging, we will need to request a label for
1044 * the next DU peer
1046 if (g->label_merge == MPLS_BOOL_FALSE) {
1047 need_request = MPLS_BOOL_TRUE;
1051 us_temp = MPLS_LIST_NEXT(us_list, us_temp, _fs);
1057 next_peer:
1058 peer = MPLS_LIST_NEXT(&g->session, peer, _global);
1061 LMp_33:
1062 LDP_EXIT(g->user_data, "ldp_label_mapping_process");
1063 return retval;
1065 LMp_32:
1066 LDP_PRINT(g->user_data, "Receive_Label_Map_32: send release");
1067 if (ldp_label_release_send(g, s, ds_attr, LDP_NOTIF_NONE) != MPLS_SUCCESS) {
1068 retval = MPLS_FAILURE;
1070 LDP_EXIT(g->user_data, "ldp_label_mapping_process");
1071 return retval;