From: Vasu Dasari <vdasari@gmail.com>
[mpls-ldp-portable.git] / ldp / ldp_label_mapping.c
blobc74b56bc25ae679e311637821b8f06c6036954cb
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_FALSE;
46 mpls_bool egress_flag = MPLS_BOOL_FALSE;
47 mpls_bool created = MPLS_BOOL_FALSE;
48 ldp_nexthop *nh;
50 MPLS_ASSERT(us_attr);
52 nh = MPLS_LIST_HEAD(&f->nh_root);
53 while (nh) {
54 if (egress_flag == MPLS_BOOL_FALSE) {
55 egress_flag = mpls_policy_egress_check(g->user_data, &f->info, &nh->info);
57 nh = MPLS_LIST_NEXT(&f->nh_root, nh, _fec);
60 if (!(*us_attr)) {
61 if (!((*us_attr) = ldp_attr_create(g, &f->info))) {
62 return MPLS_FAILURE;
64 MPLS_REFCNT_HOLD((*us_attr));
65 created = MPLS_BOOL_TRUE;
67 if ((!ds_attr) && (egress_flag == MPLS_BOOL_TRUE)) {
68 propogating = MPLS_BOOL_FALSE;
69 egress = MPLS_BOOL_TRUE;
72 Prepare_Label_Mapping_Attributes(g, s, &f->info, ds_attr, (*us_attr),
73 propogating, MPLS_BOOL_TRUE, egress);
75 result = ldp_label_mapping_send(g, s, f, (*us_attr), ds_attr);
76 if (result != MPLS_SUCCESS) {
77 if (created == MPLS_BOOL_TRUE) {
78 /* this should result in it being deleted, since we're
79 * the only one who should be holding a ref
81 MPLS_REFCNT_RELEASE2(g, (*us_attr), ldp_attr_delete);
83 return result;
86 if (created == MPLS_BOOL_TRUE) {
87 result = ldp_attr_insert_upstream2(g, s, (*us_attr), f);
88 /* now that it is in the tree (supposedly) we can safely
89 * release our ref, if it is not in the tree, then this should
90 * result in it beig deleted
92 MPLS_REFCNT_RELEASE2(g, (*us_attr), ldp_attr_delete);
93 if (result != MPLS_SUCCESS) {
94 return result;
99 * If we have a downstream mapping (not neccessarily installed) and
100 * the downstream and upstream session are not the same....
102 if (ds_attr && ((*us_attr)->session->index != ds_attr->session->index)) {
103 /* then link the attra */
104 ldp_attr_add_us2ds((*us_attr), ds_attr);
106 /* if we just created the upstream, and we have install the
107 * downstream, then cross connect them */
108 if ((created == MPLS_BOOL_TRUE) && ds_attr->outlabel) {
110 if ((*us_attr)->inlabel->outlabel) {
112 * if we use an existing upstream mapping (in ldp_label_mapping_send())
113 * the inlabel will already be be connected to an outlabel;
115 MPLS_ASSERT((*us_attr)->inlabel->outlabel == ds_attr->outlabel);
116 } else {
117 LDP_TRACE_LOG(g->user_data,MPLS_TRACE_STATE_ALL,LDP_TRACE_FLAG_BINDING,
118 "Cross Connect Added for %08x/%d from %s -> %s\n",
119 f->info.u.prefix.network.u.ipv4, f->info.u.prefix.length,
120 (*us_attr)->session->session_name, ds_attr->session->session_name);
122 result = ldp_inlabel_add_outlabel(g,(*us_attr)->inlabel,
123 ds_attr->outlabel);
124 if (result != MPLS_SUCCESS) {
125 return result;
130 return MPLS_SUCCESS;
133 ldp_session *ldp_get_next_hop_session_for_fec2(ldp_fec * f, ldp_nexthop *nh) {
134 ldp_session *session = NULL;
136 * find the info about the next hop for this FEC
138 if (nh->addr && nh->addr->session) {
139 session = nh->addr->session;
140 } else if (nh->iff && nh->iff->is_p2p == MPLS_BOOL_TRUE &&
141 nh->iff->entity) {
142 ldp_adj *adj = MPLS_LIST_HEAD(&nh->iff->entity->adj_root);
143 session = adj ? adj->session : NULL;
145 return session;
148 mpls_return_enum ldp_get_next_hop_session_for_fec(ldp_global * g,
149 mpls_fec * fec, mpls_nexthop *nh, ldp_session ** next_hop_session)
151 ldp_fec *f = NULL;
152 ldp_nexthop *n = NULL;
154 MPLS_ASSERT(next_hop_session);
156 if (!(f = ldp_fec_find(g, fec))) {
157 return MPLS_NO_ROUTE;
160 if (!(n = ldp_fec_nexthop_find(f, nh))) {
161 return MPLS_NO_ROUTE;
164 *next_hop_session = ldp_get_next_hop_session_for_fec2(f,n);
165 return (*next_hop_session) ? MPLS_SUCCESS : MPLS_FAILURE;
168 mpls_return_enum Check_Received_Attributes(ldp_global * g, ldp_session * s,
169 ldp_attr * r_attr, uint16_t type)
171 int count = 0;
172 int i;
174 if (!r_attr->hopCountTlvExists) { /* CRa.1 */
175 goto Check_Received_Attributes_5;
178 if (r_attr->hopCountTlv.hcValue >= s->cfg_hop_count_limit) { /* CRa.2 */
179 LDP_PRINT(g->user_data, "CRa.2\n");
180 goto Check_Received_Attributes_6;
183 if (!r_attr->pathVecTlvExists) { /* CRa.3 */
184 goto Check_Received_Attributes_5;
187 for (i = 0; i < MPLS_MAXHOPSNUMBER; i++) { /* CRa.4 */
188 if (r_attr->pathVecTlv.lsrId[i]) {
189 count++;
190 if (r_attr->pathVecTlv.lsrId[i] == g->lsr_identifier.u.ipv4) {
191 goto Check_Received_Attributes_6;
192 LDP_PRINT(g->user_data, "CRa.4a\n");
194 if (count > s->oper_path_vector_limit) {
195 goto Check_Received_Attributes_6;
196 LDP_PRINT(g->user_data, "CRa.4b\n");
201 Check_Received_Attributes_5:
202 return MPLS_SUCCESS;
204 Check_Received_Attributes_6:
205 if (type != MPLS_LBLMAP_MSGTYPE) {
206 ldp_notif_send(g, s, r_attr, LDP_NOTIF_LOOP_DETECTED); /* CRa.7 */
208 return MPLS_FAILURE; /* CRa.8 */
211 void Prepare_Label_Mapping_Attributes(ldp_global * g, ldp_session * s,
212 mpls_fec * fec, ldp_attr * r_attr, ldp_attr * s_attr, mpls_bool propogating,
213 mpls_bool already, mpls_bool egress)
215 ldp_attr dummy;
216 int i;
218 /* NOTE: PMpA.21 is the end of the procedure (ie return) */
219 /* this function uses goto quite extensivly for a REASON!! */
220 /* Check Appedix A of the LDP draft */
222 LDP_ENTER(g->user_data, "Prepare_Label_Mapping_Attributes");
224 if (!r_attr) {
225 memset(&dummy, 0, sizeof(ldp_attr));
226 mpls_fec2fec_tlv(fec, &dummy.fecTlv, 0);
227 dummy.fecTlvExists = 1;
228 dummy.fecTlv.numberFecElements = 1;
229 r_attr = &dummy;
232 if (!(s->oper_loop_detection == LDP_LOOP_HOPCOUNT ||
233 s->oper_loop_detection == LDP_LOOP_HOPCOUNT_PATHVECTOR ||
234 r_attr->hopCountTlvExists)) { /* PMpA.1 */
235 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
236 return;
239 if (egress) {/* PMpA.2 */
240 /* I'm egress (for now) */
241 s_attr->hopCountTlvExists = 1;
242 s_attr->hopCountTlv.hcValue = 1; /* PMpA.3 */
243 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
244 return;
247 if (!(r_attr->hopCountTlvExists)) { /* PMpA.4 */
248 goto Prepare_Label_Mapping_Attributes_8;
251 if (!(g->ttl_less_domain == MPLS_BOOL_TRUE &&
252 s->cfg_remote_in_ttl_less_domain == MPLS_BOOL_TRUE)) { /* PMpA.5 */
253 goto Prepare_Label_Mapping_Attributes_7;
256 s_attr->hopCountTlvExists = 1;
257 s_attr->hopCountTlv.hcValue = 1; /* PMpA.6 */
258 goto Prepare_Label_Mapping_Attributes_9;
260 Prepare_Label_Mapping_Attributes_7:
261 s_attr->hopCountTlvExists = 1;
262 s_attr->hopCountTlv.hcValue = (r_attr->hopCountTlv.hcValue) ?
263 (r_attr->hopCountTlv.hcValue + 1) : 0;
264 goto Prepare_Label_Mapping_Attributes_9;
266 Prepare_Label_Mapping_Attributes_8:
267 s_attr->hopCountTlvExists = 1;
268 s_attr->hopCountTlv.hcValue = 0;
270 Prepare_Label_Mapping_Attributes_9:
271 if (s->oper_loop_detection == LDP_LOOP_NONE) {
272 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
273 return;
276 if (r_attr->pathVecTlvExists) { /* PMpA.10 */
277 goto Prepare_Label_Mapping_Attributes_19;
280 if (propogating == MPLS_BOOL_FALSE) { /* PMpA.11 */
281 goto Prepare_Label_Mapping_Attributes_20;
284 if (g->label_merge != MPLS_BOOL_TRUE) { /* PMpA.12 */
285 goto Prepare_Label_Mapping_Attributes_14;
288 if (already == MPLS_BOOL_FALSE) { /* PMpA.13 */
289 goto Prepare_Label_Mapping_Attributes_20;
292 Prepare_Label_Mapping_Attributes_14:
293 if (!r_attr->hopCountTlvExists) {
294 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
295 return;
298 if (r_attr->hopCountTlv.hcValue == 0) { /* PMpA.15 */
299 goto Prepare_Label_Mapping_Attributes_20;
302 if (already == MPLS_BOOL_FALSE) { /* PMpA.16 */
303 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
304 return;
307 /* r_attr contain PrevHopCount _IF_ we had one */
308 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
309 return; /* PMpA.17 */
311 if (r_attr->hopCountTlv.hcValue != 0) { /* PMpA.18 */
312 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
313 return;
316 Prepare_Label_Mapping_Attributes_19:
317 s_attr->pathVecTlvExists = 1;
318 s_attr->pathVecTlv.lsrId[0] = g->lsr_identifier.u.ipv4;
319 for (i = 1; i < (MPLS_MAXHOPSNUMBER - 1); i++) {
320 if (r_attr->pathVecTlv.lsrId[i - 1]) {
321 s_attr->pathVecTlv.lsrId[0] = r_attr->pathVecTlv.lsrId[i - 1];
325 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
326 return;
328 Prepare_Label_Mapping_Attributes_20:
329 s_attr->pathVecTlvExists = 1;
330 s_attr->pathVecTlv.lsrId[0] = g->lsr_identifier.u.ipv4;
332 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
333 return;
336 void map2attr(mplsLdpLblMapMsg_t * map, ldp_attr * attr, uint32_t flag)
338 attr->msg_id = map->baseMsg.msgId;
340 if (map->fecTlvExists && flag & LDP_ATTR_FEC) {
341 memcpy(&attr->fecTlv, &map->fecTlv, sizeof(mplsLdpFecTlv_t));
342 attr->fecTlvExists = 1;
344 if (map->genLblTlvExists && flag & LDP_ATTR_LABEL) {
345 memcpy(&attr->genLblTlv, &map->genLblTlv, sizeof(mplsLdpGenLblTlv_t));
346 attr->genLblTlvExists = 1;
347 } else if (map->atmLblTlvExists && flag & LDP_ATTR_LABEL) {
348 memcpy(&attr->atmLblTlv, &map->atmLblTlv, sizeof(mplsLdpAtmLblTlv_t));
349 attr->atmLblTlvExists = 1;
350 } else if (map->frLblTlvExists && flag & LDP_ATTR_LABEL) {
351 memcpy(&attr->frLblTlv, &map->frLblTlv, sizeof(mplsLdpFrLblTlv_t));
352 attr->frLblTlvExists = 1;
354 if (map->hopCountTlvExists && flag & LDP_ATTR_HOPCOUNT) {
355 memcpy(&attr->hopCountTlv, &map->hopCountTlv, sizeof(mplsLdpHopTlv_t));
356 attr->hopCountTlvExists = 1;
358 if (map->pathVecTlvExists && flag & LDP_ATTR_PATH) {
359 memcpy(&attr->pathVecTlv, &map->pathVecTlv, sizeof(mplsLdpPathTlv_t));
360 attr->pathVecTlvExists = 1;
362 if (map->lblMsgIdTlvExists && flag & LDP_ATTR_MSGID) {
363 memcpy(&attr->lblMsgIdTlv, &map->lblMsgIdTlv, sizeof(mplsLdpLblMsgIdTlv_t));
364 attr->lblMsgIdTlvExists = 1;
366 if (map->lspidTlvExists && flag & LDP_ATTR_LSPID) {
367 memcpy(&attr->lspidTlv, &map->lspidTlv, sizeof(mplsLdpLspIdTlv_t));
368 attr->lspidTlvExists = 1;
370 if (map->trafficTlvExists && flag & LDP_ATTR_TRAFFIC) {
371 memcpy(&attr->trafficTlv, &map->trafficTlv, sizeof(mplsLdpTrafficTlv_t));
372 attr->trafficTlvExists = 1;
376 void attr2map(ldp_attr * attr, mplsLdpLblMapMsg_t * map)
378 if (attr->fecTlvExists) {
379 memcpy(&map->fecTlv, &attr->fecTlv, sizeof(mplsLdpFecTlv_t));
380 map->fecTlvExists = 1;
382 if (attr->genLblTlvExists) {
383 memcpy(&map->genLblTlv, &attr->genLblTlv, sizeof(mplsLdpGenLblTlv_t));
384 map->genLblTlvExists = 1;
386 if (attr->atmLblTlvExists) {
387 memcpy(&map->atmLblTlv, &attr->atmLblTlv, sizeof(mplsLdpAtmLblTlv_t));
388 map->atmLblTlvExists = 1;
390 if (attr->frLblTlvExists) {
391 memcpy(&map->frLblTlv, &attr->frLblTlv, sizeof(mplsLdpFrLblTlv_t));
392 map->frLblTlvExists = 1;
394 if (attr->hopCountTlvExists) {
395 memcpy(&map->hopCountTlv, &attr->hopCountTlv, sizeof(mplsLdpHopTlv_t));
396 map->hopCountTlvExists = 1;
398 if (attr->pathVecTlvExists) {
399 memcpy(&map->pathVecTlv, &attr->pathVecTlv, sizeof(mplsLdpPathTlv_t));
400 map->pathVecTlvExists = 1;
402 if (attr->lblMsgIdTlvExists) {
403 memcpy(&map->lblMsgIdTlv, &attr->lblMsgIdTlv, sizeof(mplsLdpLblMsgIdTlv_t));
404 map->lblMsgIdTlvExists = 1;
406 if (attr->lspidTlvExists) {
407 memcpy(&map->lspidTlv, &attr->lspidTlv, sizeof(mplsLdpLspIdTlv_t));
408 map->lspidTlvExists = 1;
410 if (attr->trafficTlvExists) {
411 memcpy(&map->trafficTlv, &attr->trafficTlv, sizeof(mplsLdpTrafficTlv_t));
412 map->trafficTlvExists = 1;
416 void ldp_label_mapping_initial_callback(mpls_timer_handle timer, void *extra,
417 mpls_cfg_handle handle)
419 ldp_session *s = (ldp_session *) extra;
420 ldp_global *g = (ldp_global*)handle;
421 ldp_attr *ds_attr = NULL;
422 ldp_attr *us_attr = NULL;
423 ldp_session *nh_session = NULL;
424 mpls_bool done = MPLS_BOOL_FALSE;
425 ldp_fec *f;
426 ldp_nexthop *nh;
428 LDP_ENTER(g->user_data, "ldp_label_mapping_initial_callback");
430 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_TIMER,
431 "Initial Label Mapping fired: session(%d)\n", s->index);
433 mpls_lock_get(g->global_lock);
435 mpls_timer_stop(g->timer_handle, timer);
437 f = MPLS_LIST_HEAD(&g->fec);
438 while (f) {
439 nh = MPLS_LIST_HEAD(&f->nh_root);
440 while (nh) {
441 switch (f->info.type) {
442 case MPLS_FEC_PREFIX:
443 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
444 LDP_TRACE_FLAG_ROUTE, "Processing prefix FEC: %08x/%d ",
445 f->info.u.prefix.network.u.ipv4, f->info.u.prefix.length);
446 break;
447 case MPLS_FEC_HOST:
448 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
449 LDP_TRACE_FLAG_ROUTE, "Processing host FEC: %08x ",
450 f->info.u.host.u.ipv4);
451 break;
452 case MPLS_FEC_L2CC:
453 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
454 LDP_TRACE_FLAG_ROUTE, "Processingu L2CC FEC: %d %d %d ",
455 f->info.u.l2cc.connection_id, f->info.u.l2cc.group_id,
456 f->info.u.l2cc.type);
457 break;
458 default:
459 MPLS_ASSERT(0);
462 if (nh->info.type & MPLS_NH_IP) {
463 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
464 LDP_TRACE_FLAG_ROUTE, "via %08x\n", nh->addr->address.u.ipv4);
466 if (nh->info.type & MPLS_NH_IF && nh->iff) {
467 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
468 LDP_TRACE_FLAG_ROUTE, "via %p\n", nh->iff->handle);
471 /* are we allowed to export this route from the rib */
472 if (mpls_policy_export_check(g->user_data, &f->info, &nh->info) ==
473 MPLS_BOOL_FALSE) {
474 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
475 LDP_TRACE_FLAG_POLICY, "Rejected by export policy\n");
476 goto ldp_label_mapping_initial_callback_end_nh;
479 /* have we already sent a mapping for this fec to the new session? */
480 if ((us_attr = ldp_attr_find_upstream_state2(g, s, f,
481 LDP_LSP_STATE_MAP_SENT))) {
482 /* no need to sent another mapping */
483 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
484 LDP_TRACE_FLAG_ROUTE, "Already sent this FEC to session %d\n",
485 s->index);
486 goto ldp_label_mapping_initial_callback_end_nh;
489 if (!(nh_session = ldp_get_next_hop_session_for_fec2(f,nh))) {
490 ds_attr = NULL;
491 } else {
492 if (nh_session->index == s->index) {
493 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
494 LDP_TRACE_FLAG_ROUTE, "Nexthop session(%d) == session(%d)\n",
495 nh_session->index, s->index);
496 goto ldp_label_mapping_initial_callback_end_nh;
498 ds_attr = ldp_attr_find_downstream_state2(g, nh_session, f,
499 LDP_LSP_STATE_MAP_RECV);
502 if ((g->label_merge != MPLS_BOOL_TRUE) &&
503 ldp_attr_num_us2ds(ds_attr)) {
504 /* we have a ds label, but can't use it */
505 ds_attr = NULL;
508 us_attr = NULL;
509 if (ds_attr) {
510 /* we can use it, merge on baby */
511 ldp_label_mapping_with_xc(g, s, f, &us_attr, ds_attr);
512 } else {
513 /* we don't have a ds label */
515 /* we will be egress? */
516 if (g->lsp_control_mode == LDP_CONTROL_ORDERED) {
517 if (mpls_policy_egress_check(g->user_data, &f->info,
518 &nh->info) == MPLS_BOOL_TRUE) {
519 ldp_label_mapping_with_xc(g, s, f, &us_attr, NULL);
521 } else {
522 ldp_label_mapping_with_xc(g, s, f, &us_attr, NULL);
525 ldp_label_mapping_initial_callback_end_nh:
526 nh = MPLS_LIST_NEXT(&f->nh_root, nh, _fec);
528 f = MPLS_LIST_NEXT(&g->fec, f, _global);
530 done = MPLS_BOOL_TRUE;
532 if (done == MPLS_BOOL_TRUE) {
533 mpls_timer_delete(g->timer_handle, timer);
534 MPLS_REFCNT_RELEASE(s, ldp_session_delete);
535 s->initial_distribution_timer = (mpls_timer_handle) 0;
536 } else {
537 mpls_timer_start(g->timer_handle, timer, MPLS_TIMER_ONESHOT);
538 /* need to mark the session with where it left off */
541 mpls_lock_release(g->global_lock);
543 LDP_EXIT(g->user_data, "ldp_label_mapping_initial_callback");
546 mpls_return_enum ldp_label_mapping_send(ldp_global * g, ldp_session * s,
547 ldp_fec *f, ldp_attr * us_attr, ldp_attr * ds_attr)
549 ldp_inlabel *in = NULL;
550 ldp_attr *us_temp, *existing = NULL;
552 LDP_ENTER(g->user_data, "ldp_label_mapping_send");
553 MPLS_ASSERT(us_attr);
555 #if 0
557 * before we can enable this, inlabels need to keep track of all of
558 * the attr that link to it. Then when running in DU independent mode we
559 * can correctly attach the us and ds attrs involved when propogating a
560 * new mapping for a FEC we've already distributed labels for
562 existing = ldp_attr_find_upstream_map_in_labelspace(f, s->cfg_label_space);
563 #endif
565 if (existing) {
566 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_BINDING,
567 "Using an existing label\n");
568 in = existing->inlabel;
569 ldp_attr_add_inlabel(g, us_attr, in);
570 } else {
571 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_BINDING,
572 "Generating a label\n");
573 in = ldp_inlabel_create_complete(g, s, us_attr);
576 if (!in) { /* SL.1-3 */
577 goto Send_Label_9;
580 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_BINDING,
581 "In Label Added\n");
583 us_attr->state = LDP_LSP_STATE_MAP_SENT;
585 us_attr->msg_id = g->message_identifier;
586 ldp_label_mapping_prepare_msg(s->tx_message, g->message_identifier++,
587 us_attr);
589 if (ldp_mesg_send_tcp(g, s, s->tx_message) != MPLS_SUCCESS) { /* SL.4 */
590 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_SEND, LDP_TRACE_FLAG_ERROR,
591 "Failed sending Label Mapping to %s\n",
592 s->session_name);
593 goto ldp_label_mapping_send_error;
596 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_SEND, LDP_TRACE_FLAG_LABEL,
597 "Label Mapping Sent to %s for %08x/%d\n",
598 s->session_name,
599 us_attr->fecTlv.fecElArray[0].addressEl.address,
600 us_attr->fecTlv.fecElArray[0].addressEl.preLen);
602 us_attr->state = LDP_LSP_STATE_MAP_SENT; /* SL.6,7 */
604 LDP_EXIT(g->user_data, "ldp_label_mapping_send");
605 return MPLS_SUCCESS; /* SL.8 */
607 Send_Label_9:
608 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_STATE,
609 "No Label Resources\n");
611 while ((us_temp = ldp_attr_find_upstream_state2(g, s, us_attr->fec,
612 LDP_LSP_STATE_REQ_RECV)) != NULL) { /* SL.9 */
613 ldp_notif_send(g, s, us_temp, LDP_NOTIF_NO_LABEL_RESOURCES_AVAILABLE);
614 /* SL.10 */
615 s->no_label_resource_sent = MPLS_BOOL_TRUE; /* SL.12 */
616 us_temp->state = LDP_LSP_STATE_NO_LABEL_RESOURCE_SENT; /* SL.13 */
619 LDP_EXIT(g->user_data, "ldp_label_mapping_send");
621 return MPLS_SUCCESS;
623 ldp_label_mapping_send_error:
625 LDP_EXIT(g->user_data, "ldp_label_mapping_send-error");
626 return MPLS_FAILURE;
629 void ldp_label_mapping_prepare_msg(ldp_mesg * msg, uint32_t msgid,
630 ldp_attr * s_attr)
632 mplsLdpLblMapMsg_t *map = NULL;
633 int i;
635 MPLS_ASSERT(msg);
637 ldp_mesg_prepare(msg, MPLS_LBLMAP_MSGTYPE, msgid);
638 map = &msg->u.map;
640 if (s_attr->fecTlvExists) {
641 /* JLEU: only 1 FEC is allowed!! */
642 map->fecTlvExists = 1;
643 map->baseMsg.msgLength += setupFecTlv(&map->fecTlv);
644 map->baseMsg.msgLength += addFecElem2FecTlv(&map->fecTlv,
645 &s_attr->fecTlv.fecElArray[0]);
647 if (s_attr->genLblTlvExists) {
648 map->genLblTlvExists = 1;
649 map->baseMsg.msgLength += setupGenLblTlv(&map->genLblTlv,
650 s_attr->genLblTlv.label);
652 if (s_attr->atmLblTlvExists) {
653 map->atmLblTlvExists = 1;
654 map->baseMsg.msgLength += setupAtmLblTlv(&map->atmLblTlv, 0, 0,
655 s_attr->atmLblTlv.flags.flags.vpi, s_attr->atmLblTlv.vci);
657 if (s_attr->frLblTlvExists) {
658 map->frLblTlvExists = 1;
659 map->baseMsg.msgLength += setupFrLblTlv(&map->frLblTlv, 0,
660 s_attr->frLblTlv.flags.flags.len, s_attr->frLblTlv.flags.flags.dlci);
662 if (s_attr->hopCountTlvExists) {
663 map->hopCountTlvExists = 1;
664 map->baseMsg.msgLength += setupHopCountTlv(&map->hopCountTlv,
665 s_attr->hopCountTlv.hcValue);
667 if (s_attr->pathVecTlvExists) {
668 map->pathVecTlvExists = 1;
669 map->baseMsg.msgLength += setupPathTlv(&map->pathVecTlv);
670 for (i = 0; i < MPLS_MAXHOPSNUMBER; i++) {
671 if (s_attr->pathVecTlv.lsrId[i]) {
672 map->baseMsg.msgLength += addLsrId2PathTlv(&map->pathVecTlv,
673 s_attr->pathVecTlv.lsrId[i]);
677 #if 0
678 if (s_attr->lblMsgIdTlvExists) {
680 if (s_attr->lspidTlvExists) {
682 if (s_attr->trafficTlvExists) {
684 #endif
687 mpls_return_enum ldp_label_mapping_process(ldp_global * g, ldp_session * s,
688 ldp_adj * a, ldp_entity * e, ldp_attr * r_attr, ldp_fec * f)
690 mpls_return_enum retval = MPLS_SUCCESS;
691 ldp_session *peer = NULL;
692 ldp_attr_list *us_list = NULL;
693 ldp_attr_list *ds_list = NULL;
694 ldp_attr *ds_attr = NULL;
695 ldp_attr *ds_temp = NULL;
696 ldp_attr *us_attr = NULL;
697 ldp_attr *us_temp = NULL;
698 ldp_attr dumb_attr;
699 ldp_nexthop *nh = NULL;
701 ldp_outlabel *out = NULL;
702 mpls_bool requested = MPLS_BOOL_FALSE;
703 ldp_attr *existing = NULL;
704 mpls_bool need_request = MPLS_BOOL_FALSE;
706 LDP_ENTER(g->user_data, "ldp_label_mapping_process");
708 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV, LDP_TRACE_FLAG_LABEL,
709 "Label Mapping Recv from %s for %08x/%d\n",
710 s->session_name,
711 r_attr->fecTlv.fecElArray[0].addressEl.address,
712 r_attr->fecTlv.fecElArray[0].addressEl.preLen);
714 if ((ds_attr = ldp_attr_find_downstream_state2(g, s, f,
715 LDP_LSP_STATE_REQ_SENT)) != NULL) { /* LMp.1 */
716 /* just remove the req from the tree, we will use the r_attr sent to us */
717 ldp_attr_delete_downstream(g, s, ds_attr);
718 requested = MPLS_BOOL_TRUE;
719 } else {
720 requested = MPLS_BOOL_FALSE;
723 ds_attr = r_attr;
724 ds_attr->state = LDP_LSP_STATE_MAP_RECV; /* LMp.2 */
727 * ds_attr is the mapping we will keep and is NOT in the tree, unless
728 * it is an update mapping ...
730 if (Check_Received_Attributes(g, s, ds_attr, MPLS_LBLMAP_MSGTYPE) ==
731 MPLS_SUCCESS) { /* LMp.3 */
732 goto LMp_9;
736 * A loop was detected
738 if ((ds_list = ldp_attr_find_downstream_all2(g, s, f))) {
739 ds_temp = MPLS_LIST_HEAD(ds_list);
741 * check all the labels this session has received from "s" for "fec"
742 * do we have a duplicat?
744 while (ds_temp) {
745 if ((ds_temp->state == LDP_LSP_STATE_MAP_RECV) && /* LMp.4 */
746 ldp_attr_is_equal(ds_temp, ds_attr, LDP_ATTR_LABEL) == /* LMp.5 */
747 MPLS_BOOL_TRUE) {
748 /* remove record of the label and remove it switching */
749 ldp_attr_remove_complete(g, ds_temp, MPLS_BOOL_TRUE); /* LMp.6,7 */
751 * I think this is supposed to be 32 NOT 33, we need to release
752 * it don't we?
754 goto LMp_33;
756 ds_temp = MPLS_LIST_NEXT(ds_list, ds_temp, _fs);
760 LDP_PRINT(g->user_data, "Receive_Label_Map_8: send release");
761 if (ldp_label_release_send(g, s, ds_attr, LDP_NOTIF_LOOP_DETECTED) !=
762 MPLS_SUCCESS) { /* LMp.8 */
763 retval = MPLS_FAILURE;
765 goto LMp_33;
767 LMp_9:
769 * No Loop Detected
771 ds_temp = ldp_attr_find_downstream_state2(g, s, f, LDP_LSP_STATE_MAP_RECV);
772 if (requested == MPLS_BOOL_TRUE ||
773 g->label_merge == MPLS_BOOL_FALSE || !ds_temp) {
774 /* !merging then this is always a new LSP
775 * merging w/o a recv'd mapping is a new LSP
776 * this check comes from Note 6
778 goto LMp_11;
781 /* searching all recv'd attrs for matched mappings,
782 * stop after finding 1st match
784 if ((ds_list = ldp_attr_find_downstream_all2(g, s, f))) {
785 ds_temp = MPLS_LIST_HEAD(ds_list);
786 while (ds_temp) {
787 if (ds_temp->state == LDP_LSP_STATE_MAP_RECV) { /* LMp.9 */
788 if (ldp_attr_is_equal(ds_attr, ds_temp, LDP_ATTR_LABEL) ==
789 MPLS_BOOL_TRUE) { /* LMp.10 */
791 * this mapping matches an existing mapping, but it
792 * could contain updated attributes
794 existing = ds_temp;
795 break;
796 } else {
798 * we have been given another label for the same FEC and we
799 * didn't request it, release it
801 LDP_PRINT(g->user_data, "LMp.10 dup without req\n");
802 goto LMp_32;
805 ds_temp = MPLS_LIST_NEXT(ds_list, ds_temp, _fs);
808 if (existing) {
809 ldp_attr2ldp_attr(ds_attr, existing, LDP_ATTR_HOPCOUNT | LDP_ATTR_PATH |
810 LDP_ATTR_MSGID | LDP_ATTR_LSPID | LDP_ATTR_TRAFFIC);
811 ds_attr = existing;
813 * no need to free ds_attr, since it was not added to the tree it
814 * will be deleted when we exit ldp_label_mapping_process(), see
815 * ldp_state_process().
819 * from this point on.... if this is an updated mapping then ds_attr
820 * is the existing mapping which has now been update, else ds_attr
821 * is the new mapping
824 LMp_11:
826 * existing ONLY has a value for updated label mapping
828 nh = ldp_nexthop_for_fec_session(f,s); /* LMp.11 */
831 * the following departs from the procedure, it allows for filtering
832 * of label mappings
834 * Are we configured to accept and INSTALL this mapping?
836 if (mpls_policy_import_check(g->user_data, &f->info, &nh->info) ==
837 MPLS_BOOL_FALSE) {
839 * policy has rejected it, store it away
841 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV, LDP_TRACE_FLAG_LABEL,
842 "Label Mapping for %08x/%d from %s filtered by import policy\n",
843 r_attr->fecTlv.fecElArray[0].addressEl.address,
844 r_attr->fecTlv.fecElArray[0].addressEl.preLen, s->session_name);
846 if (existing) {
847 ds_attr->filtered = MPLS_BOOL_TRUE;
848 if (ds_attr->outlabel && ds_attr->outlabel->switching == MPLS_BOOL_TRUE) {
849 /* the mapping has been filtered, but the original wasn't? */
850 MPLS_ASSERT(0);
852 } else {
853 ds_attr->filtered = MPLS_BOOL_TRUE;
854 if (ldp_attr_insert_downstream(g, s, ds_attr) != MPLS_SUCCESS) {
855 retval = MPLS_FAILURE;
858 goto LMp_33;
861 if (!nh) { /* LMp.12 */
863 * if we did not find a nh hop for this FEC that corresponded to the
864 * MsgSource then the MsgSource is not a nexthop for the FEC
866 if (g->label_retention_mode == LDP_RETENTION_CONSERVATIVE) { /* LMp.13C */
867 LDP_PRINT(g->user_data, "LMp.13C conservative\n");
868 goto LMp_32;
872 * store it away
874 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV, LDP_TRACE_FLAG_LABEL,
875 "Session %s is not a valid nexthop for %08x/%d\n", s->session_name,
876 r_attr->fecTlv.fecElArray[0].addressEl.address,
877 r_attr->fecTlv.fecElArray[0].addressEl.preLen);
879 if (!existing) {
880 /* LMp.13L */
881 if (ldp_attr_insert_downstream(g, s, ds_attr) != MPLS_SUCCESS) {
882 retval = MPLS_FAILURE;
885 goto LMp_33;
889 * this is slightly different form the procedure, we can still be
890 * transit for a FEC we are not configured to be ingress for.
891 * Either way we only need to do the "install for fwd/switching"
892 * only once. We could arrive here multiple times due to updates,
893 * only install it the first time
895 if ((!existing) || (!existing->outlabel)) {
897 * we haven't installed it yet.
898 * Either new (!existing), or a result of a "Detect FEC Nexthop Change"
899 * and we had this mapping in our database (!existing->outlabel))
902 if (!(out = ldp_outlabel_create_complete(g, s, ds_attr, nh))) {
903 LDP_PRINT(g->user_data, "LMp.15 failure creating outlabel\n");
904 goto LMp_32;
907 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_BINDING,
908 "Out Label Added\n");
912 * are we configured to act as ingress for this FEC?
914 if (mpls_policy_ingress_check(g->user_data, &f->info, &nh->info) ==
915 MPLS_BOOL_TRUE) { /* LMp.14 */
917 * yep, bind the label to the FEC
919 if (ds_attr->ingress != MPLS_BOOL_TRUE) {
920 #if MPLS_USE_LSR
921 lsr_ftn ftn;
922 ftn.outsegment_index = ds_attr->outlabel->info.handle;
923 memcpy(&ftn.fec, &f->info, sizeof(mpls_fec));
924 lsr_cfg_ftn_set2(g->lsr_handle, &ftn, LSR_CFG_ADD|LSR_FTN_CFG_FEC|
925 LSR_FTN_CFG_OUTSEGMENT);
926 #else
927 mpls_mpls_fec2out_add(g->mpls_handle, &f->info, &ds_attr->outlabel->info);
928 #endif
929 ds_attr->ingress = MPLS_BOOL_TRUE;
930 ds_attr->outlabel->merge_count++;
931 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV, LDP_TRACE_FLAG_BINDING,
932 "Acting as ingress for %08x/%d from %s\n",
933 r_attr->fecTlv.fecElArray[0].addressEl.address,
934 r_attr->fecTlv.fecElArray[0].addressEl.preLen, s->session_name);
938 /* create a set of attrs that we will fill and compare against
939 * if this mapping were to be propogate these are the attrs it would have
940 * by comparing what we did sent in the past to these, we con figure out
941 * if we need to send an updated mapping
943 memset(&dumb_attr, 0, sizeof(ldp_attr));
944 mpls_fec2fec_tlv(&f->info, &dumb_attr.fecTlv, 0);
945 dumb_attr.fecTlvExists = 1;
946 dumb_attr.fecTlv.numberFecElements = 1;
949 * by definition (we received a label mapping that will be used) this
950 * LSR is _not_ the egress, so calculate a hop and path based on the
951 * mapping we received. We will compare this with mapping that have
952 * already been sent. If they differ, we will send an updated mapping
954 Prepare_Label_Mapping_Attributes(g, s, &f->info, ds_attr, &dumb_attr,
955 MPLS_BOOL_TRUE, MPLS_BOOL_TRUE, MPLS_BOOL_FALSE);
957 if (!existing) {
959 * this is the first time we've seen this mapping, add it to the database.
960 * all future updates will modify this entry in place
962 /* LMp.16 */
963 if (ldp_attr_insert_downstream(g, s, ds_attr) != MPLS_SUCCESS) {
964 retval = MPLS_FAILURE;
965 goto LMp_33;
969 peer = MPLS_LIST_HEAD(&g->session);
970 while (peer) { /* LMp.17 */
972 /* can't send messages to non-operational sessions */
973 if (peer->state != LDP_STATE_OPERATIONAL) {
974 goto next_peer;
978 * don't send the mapping to the session
979 * from which we recv'd the mapping
981 if (peer->index == s->index) {
982 goto next_peer;
986 * it is just as easy to walk the list of all upstream attr for this
987 * peer as it is to the individual check to see if we have sent a
988 * label mapping for this FEC LSP
991 /* LMp.22 - 27 */
992 if ((us_list = ldp_attr_find_upstream_all2(g, peer, f))) {
993 us_temp = MPLS_LIST_HEAD(us_list);
994 while (us_temp) {
996 * if we have sent a label mapping for the FEC and that label mapping
997 * was an done in independent mode or it is part of an LSP created
998 * due as part of an existing received label mapping
1000 /* LMp.18 */
1001 if (us_temp->state == LDP_LSP_STATE_MAP_SENT) {
1003 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV,
1004 LDP_TRACE_FLAG_BINDING, "Already sent mapping for %08x/%d to %s\n",
1005 r_attr->fecTlv.fecElArray[0].addressEl.address,
1006 r_attr->fecTlv.fecElArray[0].addressEl.preLen, peer->session_name);
1008 if ((!existing) || (existing->index == us_temp->ds_attr->index)) {
1010 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV,
1011 LDP_TRACE_FLAG_BINDING, "Part of same LSP\n");
1013 /* LMp.23 */
1014 if (ldp_attr_is_equal(us_temp, &dumb_attr,
1015 LDP_ATTR_HOPCOUNT | LDP_ATTR_PATH) != MPLS_BOOL_TRUE) {
1017 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV,
1018 LDP_TRACE_FLAG_BINDING, "Propogating updated attrs\n");
1020 /* send an updated label mapping */
1021 if (ldp_label_mapping_with_xc(g, us_temp->session, f, &us_temp,
1022 ds_attr) != MPLS_SUCCESS) { /* LMp.24-26 */
1023 retval = MPLS_FAILURE;
1024 goto LMp_33;
1029 us_temp = MPLS_LIST_NEXT(us_list, us_temp, _fs);
1033 if ((peer->oper_distribution_mode == LDP_DISTRIBUTION_UNSOLICITED) &&
1034 (g->lsp_control_mode == LDP_CONTROL_ORDERED)) { /* LMp.19 */
1037 * if we're not merging and we have multiple ORDERED DU sessions,
1038 * we will need to start requesting labels after we propogate the
1039 * mapping to the first peer
1041 if (need_request == MPLS_BOOL_TRUE) {
1042 if (ldp_attr_find_downstream_state2(g, peer, f,
1043 LDP_LSP_STATE_REQ_SENT) == NULL) {
1045 * we don't have a request for FEC to peer outstanding, make one
1047 ds_temp = NULL;
1048 if (ldp_label_request_for_xc(g, peer, &f->info, NULL, &ds_temp) !=
1049 MPLS_SUCCESS) {
1050 retval = MPLS_FAILURE;
1051 goto LMp_33;
1054 } else {
1056 * We're in DU more, either we're merging, or we're not merging and
1057 * this is the first peer we're propogating this mapping to
1059 /* LMp.20-21,30 */
1060 us_attr = NULL;
1061 if (ldp_label_mapping_with_xc(g, peer, f, &us_attr, ds_attr) !=
1062 MPLS_SUCCESS) {
1063 retval = MPLS_FAILURE;
1064 goto LMp_33;
1067 * if we're not merging, we will need to request a label for
1068 * the next DU peer
1070 if (g->label_merge == MPLS_BOOL_FALSE) {
1071 need_request = MPLS_BOOL_TRUE;
1076 /* LMp.28 */
1077 while ((us_temp = ldp_attr_find_upstream_state2(g, peer, f,
1078 LDP_LSP_STATE_REQ_RECV))) {
1080 if (peer->oper_distribution_mode == LDP_DISTRIBUTION_UNSOLICITED) {
1081 if (need_request == MPLS_BOOL_TRUE) {
1082 if (ldp_attr_find_downstream_state2(g, peer, f,
1083 LDP_LSP_STATE_REQ_SENT) == NULL) {
1085 * we don't have a request for FEC to peer outstanding
1087 ds_temp = NULL;
1088 if (ldp_label_request_for_xc(g, peer, &f->info, us_temp,
1089 &ds_temp) != MPLS_SUCCESS) {
1090 retval = MPLS_FAILURE;
1091 goto LMp_33;
1094 } else {
1095 if (ldp_label_mapping_with_xc(g, peer, f, &us_temp,
1096 ds_attr) != MPLS_SUCCESS) {
1097 retval = MPLS_FAILURE;
1098 goto LMp_33;
1101 } else {
1102 if ((us_list = ldp_attr_find_upstream_all2(g, peer, f))) {
1103 us_temp = MPLS_LIST_HEAD(ds_list);
1104 while (us_temp) {
1105 if (us_temp->state == LDP_LSP_STATE_REQ_RECV) {
1106 if (need_request == MPLS_BOOL_TRUE) {
1107 if (ldp_attr_find_downstream_state2(g, peer, f,
1108 LDP_LSP_STATE_REQ_SENT) == NULL) {
1110 * we don't have a request for FEC to peer outstanding
1112 ds_temp = NULL;
1113 if (ldp_label_request_for_xc(g, peer, &f->info, us_temp,
1114 &ds_temp) != MPLS_SUCCESS) {
1115 retval = MPLS_FAILURE;
1116 goto LMp_33;
1119 } else {
1120 if (ldp_label_mapping_with_xc(g, peer, f, &us_temp,
1121 ds_attr) != MPLS_SUCCESS) {
1122 retval = MPLS_FAILURE;
1123 goto LMp_33;
1126 * if we're not merging, we will need to request a label for
1127 * the next DU peer
1129 if (g->label_merge == MPLS_BOOL_FALSE) {
1130 need_request = MPLS_BOOL_TRUE;
1134 us_temp = MPLS_LIST_NEXT(us_list, us_temp, _fs);
1140 next_peer:
1141 peer = MPLS_LIST_NEXT(&g->session, peer, _global);
1144 LMp_33:
1145 LDP_EXIT(g->user_data, "ldp_label_mapping_process");
1146 return retval;
1148 LMp_32:
1149 LDP_PRINT(g->user_data, "Receive_Label_Map_32: send release");
1150 if (ldp_label_release_send(g, s, ds_attr, LDP_NOTIF_NONE) != MPLS_SUCCESS) {
1151 retval = MPLS_FAILURE;
1153 LDP_EXIT(g->user_data, "ldp_label_mapping_process");
1154 return retval;