In the case of a route being and there is not an alternate
[mpls-ldp-portable.git] / ldp / ldp_label_mapping.c
bloba8fecdd9274a1ce1e9ff582e9ad8c6adff092339
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, f, (*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;
81 * If we have a downstream mapping (not neccessarily installed) and
82 * the downstream and upstream session are not the same....
84 if (ds_attr && ((*us_attr)->session->index != ds_attr->session->index)) {
85 /* then link the attra */
86 ldp_attr_add_us2ds((*us_attr), ds_attr);
88 /* if we just created the upstream, and we have install the
89 * downstream, then cross connect them */
90 if ((created == MPLS_BOOL_TRUE) && ds_attr->outlabel) {
92 if ((*us_attr)->inlabel->outlabel) {
94 * if we use an existing upstream mapping (in ldp_label_mapping_send())
95 * the inlabel will already be be connected to an outlabel;
97 MPLS_ASSERT((*us_attr)->inlabel->outlabel == ds_attr->outlabel);
98 } else {
99 LDP_TRACE_LOG(g->user_data,MPLS_TRACE_STATE_ALL,LDP_TRACE_FLAG_BINDING,
100 "Cross Connect Added for %08x/%d from %s -> %s\n",
101 f->info.u.prefix.network.u.ipv4, f->info.u.prefix.length,
102 (*us_attr)->session->session_name, ds_attr->session->session_name);
104 result = ldp_inlabel_add_outlabel(g,(*us_attr)->inlabel,
105 ds_attr->outlabel);
106 if (result != MPLS_SUCCESS) {
107 return result;
112 return MPLS_SUCCESS;
115 ldp_session *ldp_get_next_hop_session_for_fec2(ldp_fec * f, ldp_nexthop *nh) {
116 ldp_session *session = NULL;
118 * find the info about the next hop for this FEC
120 if (nh->addr && nh->addr->session_root.count > 0) {
121 session = mpls_link_list_head_data(&nh->addr->session_root);
122 } else if (nh->iff && nh->iff->is_p2p == MPLS_BOOL_TRUE &&
123 &nh->iff->entity) {
124 ldp_adj *adj = MPLS_LIST_HEAD(&nh->iff->entity->adj_root);
125 session = adj ? adj->session : NULL;
127 return session;
130 mpls_return_enum ldp_get_next_hop_session_for_fec(ldp_global * g,
131 mpls_fec * fec, mpls_nexthop *nh, ldp_session ** next_hop_session)
133 ldp_fec *f = NULL;
134 ldp_nexthop *n = NULL;
136 MPLS_ASSERT(next_hop_session);
138 if (!(f = ldp_fec_find(g, fec))) {
139 return MPLS_NO_ROUTE;
142 if (!(n = ldp_fec_nexthop_find(f, nh))) {
143 return MPLS_NO_ROUTE;
146 *next_hop_session = ldp_get_next_hop_session_for_fec2(f,n);
147 return (*next_hop_session) ? MPLS_SUCCESS : MPLS_FAILURE;
150 mpls_return_enum Check_Received_Attributes(ldp_global * g, ldp_session * s,
151 ldp_attr * r_attr, uint16_t type)
153 int count = 0;
154 int i;
156 if (!r_attr->hopCountTlvExists) { /* CRa.1 */
157 goto Check_Received_Attributes_5;
160 if (r_attr->hopCountTlv.hcValue >= s->cfg_hop_count_limit) { /* CRa.2 */
161 LDP_PRINT(g->user_data, "CRa.2\n");
162 goto Check_Received_Attributes_6;
165 if (!r_attr->pathVecTlvExists) { /* CRa.3 */
166 goto Check_Received_Attributes_5;
169 for (i = 0; i < MPLS_MAXHOPSNUMBER; i++) { /* CRa.4 */
170 if (r_attr->pathVecTlv.lsrId[i]) {
171 count++;
172 if (r_attr->pathVecTlv.lsrId[i] == g->lsr_identifier.u.ipv4) {
173 goto Check_Received_Attributes_6;
174 LDP_PRINT(g->user_data, "CRa.4a\n");
176 if (count > s->oper_path_vector_limit) {
177 goto Check_Received_Attributes_6;
178 LDP_PRINT(g->user_data, "CRa.4b\n");
183 Check_Received_Attributes_5:
184 return MPLS_SUCCESS;
186 Check_Received_Attributes_6:
187 if (type != MPLS_LBLMAP_MSGTYPE) {
188 ldp_notif_send(g, s, r_attr, LDP_NOTIF_LOOP_DETECTED); /* CRa.7 */
190 return MPLS_FAILURE; /* CRa.8 */
193 void Prepare_Label_Mapping_Attributes(ldp_global * g, ldp_session * s,
194 mpls_fec * fec, ldp_attr * r_attr, ldp_attr * s_attr, mpls_bool propogating,
195 mpls_bool already, mpls_bool egress)
197 ldp_attr dummy;
198 int i;
200 /* NOTE: PMpA.21 is the end of the procedure (ie return) */
201 /* this function uses goto quite extensivly for a REASON!! */
202 /* Check Appedix A of the LDP draft */
204 LDP_ENTER(g->user_data, "Prepare_Label_Mapping_Attributes");
206 if (!r_attr) {
207 memset(&dummy, 0, sizeof(ldp_attr));
208 mpls_fec2fec_tlv(fec, &dummy.fecTlv, 0);
209 dummy.fecTlvExists = 1;
210 dummy.fecTlv.numberFecElements = 1;
211 r_attr = &dummy;
214 if (!(s->oper_loop_detection == LDP_LOOP_HOPCOUNT ||
215 s->oper_loop_detection == LDP_LOOP_HOPCOUNT_PATHVECTOR ||
216 r_attr->hopCountTlvExists)) { /* PMpA.1 */
217 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
218 return;
221 if (egress) {/* PMpA.2 */
222 /* I'm egress (for now) */
223 s_attr->hopCountTlvExists = 1;
224 s_attr->hopCountTlv.hcValue = 1; /* PMpA.3 */
225 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
226 return;
229 if (!(r_attr->hopCountTlvExists)) { /* PMpA.4 */
230 goto Prepare_Label_Mapping_Attributes_8;
233 if (!(g->ttl_less_domain == MPLS_BOOL_TRUE &&
234 s->cfg_remote_in_ttl_less_domain == MPLS_BOOL_TRUE)) { /* PMpA.5 */
235 goto Prepare_Label_Mapping_Attributes_7;
238 s_attr->hopCountTlvExists = 1;
239 s_attr->hopCountTlv.hcValue = 1; /* PMpA.6 */
240 goto Prepare_Label_Mapping_Attributes_9;
242 Prepare_Label_Mapping_Attributes_7:
243 s_attr->hopCountTlvExists = 1;
244 s_attr->hopCountTlv.hcValue = (r_attr->hopCountTlv.hcValue) ?
245 (r_attr->hopCountTlv.hcValue + 1) : 0;
246 goto Prepare_Label_Mapping_Attributes_9;
248 Prepare_Label_Mapping_Attributes_8:
249 s_attr->hopCountTlvExists = 1;
250 s_attr->hopCountTlv.hcValue = 0;
252 Prepare_Label_Mapping_Attributes_9:
253 if (s->oper_loop_detection == LDP_LOOP_NONE) {
254 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
255 return;
258 if (r_attr->pathVecTlvExists) { /* PMpA.10 */
259 goto Prepare_Label_Mapping_Attributes_19;
262 if (propogating == MPLS_BOOL_FALSE) { /* PMpA.11 */
263 goto Prepare_Label_Mapping_Attributes_20;
266 if (g->label_merge != MPLS_BOOL_TRUE) { /* PMpA.12 */
267 goto Prepare_Label_Mapping_Attributes_14;
270 if (already == MPLS_BOOL_FALSE) { /* PMpA.13 */
271 goto Prepare_Label_Mapping_Attributes_20;
274 Prepare_Label_Mapping_Attributes_14:
275 if (!r_attr->hopCountTlvExists) {
276 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
277 return;
280 if (r_attr->hopCountTlv.hcValue == 0) { /* PMpA.15 */
281 goto Prepare_Label_Mapping_Attributes_20;
284 if (already == MPLS_BOOL_FALSE) { /* PMpA.16 */
285 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
286 return;
289 /* r_attr contain PrevHopCount _IF_ we had one */
290 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
291 return; /* PMpA.17 */
293 if (r_attr->hopCountTlv.hcValue != 0) { /* PMpA.18 */
294 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
295 return;
298 Prepare_Label_Mapping_Attributes_19:
299 s_attr->pathVecTlvExists = 1;
300 s_attr->pathVecTlv.lsrId[0] = g->lsr_identifier.u.ipv4;
301 for (i = 1; i < (MPLS_MAXHOPSNUMBER - 1); i++) {
302 if (r_attr->pathVecTlv.lsrId[i - 1]) {
303 s_attr->pathVecTlv.lsrId[0] = r_attr->pathVecTlv.lsrId[i - 1];
307 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
308 return;
310 Prepare_Label_Mapping_Attributes_20:
311 s_attr->pathVecTlvExists = 1;
312 s_attr->pathVecTlv.lsrId[0] = g->lsr_identifier.u.ipv4;
314 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
315 return;
318 void map2attr(mplsLdpLblMapMsg_t * map, ldp_attr * attr, uint32_t flag)
320 attr->msg_id = map->baseMsg.msgId;
322 if (map->fecTlvExists && flag & LDP_ATTR_FEC) {
323 memcpy(&attr->fecTlv, &map->fecTlv, sizeof(mplsLdpFecTlv_t));
324 attr->fecTlvExists = 1;
326 if (map->genLblTlvExists && flag & LDP_ATTR_LABEL) {
327 memcpy(&attr->genLblTlv, &map->genLblTlv, sizeof(mplsLdpGenLblTlv_t));
328 attr->genLblTlvExists = 1;
329 } else if (map->atmLblTlvExists && flag & LDP_ATTR_LABEL) {
330 memcpy(&attr->atmLblTlv, &map->atmLblTlv, sizeof(mplsLdpAtmLblTlv_t));
331 attr->atmLblTlvExists = 1;
332 } else if (map->frLblTlvExists && flag & LDP_ATTR_LABEL) {
333 memcpy(&attr->frLblTlv, &map->frLblTlv, sizeof(mplsLdpFrLblTlv_t));
334 attr->frLblTlvExists = 1;
336 if (map->hopCountTlvExists && flag & LDP_ATTR_HOPCOUNT) {
337 memcpy(&attr->hopCountTlv, &map->hopCountTlv, sizeof(mplsLdpHopTlv_t));
338 attr->hopCountTlvExists = 1;
340 if (map->pathVecTlvExists && flag & LDP_ATTR_PATH) {
341 memcpy(&attr->pathVecTlv, &map->pathVecTlv, sizeof(mplsLdpPathTlv_t));
342 attr->pathVecTlvExists = 1;
344 if (map->lblMsgIdTlvExists && flag & LDP_ATTR_MSGID) {
345 memcpy(&attr->lblMsgIdTlv, &map->lblMsgIdTlv, sizeof(mplsLdpLblMsgIdTlv_t));
346 attr->lblMsgIdTlvExists = 1;
348 if (map->lspidTlvExists && flag & LDP_ATTR_LSPID) {
349 memcpy(&attr->lspidTlv, &map->lspidTlv, sizeof(mplsLdpLspIdTlv_t));
350 attr->lspidTlvExists = 1;
352 if (map->trafficTlvExists && flag & LDP_ATTR_TRAFFIC) {
353 memcpy(&attr->trafficTlv, &map->trafficTlv, sizeof(mplsLdpTrafficTlv_t));
354 attr->trafficTlvExists = 1;
358 void attr2map(ldp_attr * attr, mplsLdpLblMapMsg_t * map)
360 if (attr->fecTlvExists) {
361 memcpy(&map->fecTlv, &attr->fecTlv, sizeof(mplsLdpFecTlv_t));
362 map->fecTlvExists = 1;
364 if (attr->genLblTlvExists) {
365 memcpy(&map->genLblTlv, &attr->genLblTlv, sizeof(mplsLdpGenLblTlv_t));
366 map->genLblTlvExists = 1;
368 if (attr->atmLblTlvExists) {
369 memcpy(&map->atmLblTlv, &attr->atmLblTlv, sizeof(mplsLdpAtmLblTlv_t));
370 map->atmLblTlvExists = 1;
372 if (attr->frLblTlvExists) {
373 memcpy(&map->frLblTlv, &attr->frLblTlv, sizeof(mplsLdpFrLblTlv_t));
374 map->frLblTlvExists = 1;
376 if (attr->hopCountTlvExists) {
377 memcpy(&map->hopCountTlv, &attr->hopCountTlv, sizeof(mplsLdpHopTlv_t));
378 map->hopCountTlvExists = 1;
380 if (attr->pathVecTlvExists) {
381 memcpy(&map->pathVecTlv, &attr->pathVecTlv, sizeof(mplsLdpPathTlv_t));
382 map->pathVecTlvExists = 1;
384 if (attr->lblMsgIdTlvExists) {
385 memcpy(&map->lblMsgIdTlv, &attr->lblMsgIdTlv, sizeof(mplsLdpLblMsgIdTlv_t));
386 map->lblMsgIdTlvExists = 1;
388 if (attr->lspidTlvExists) {
389 memcpy(&map->lspidTlv, &attr->lspidTlv, sizeof(mplsLdpLspIdTlv_t));
390 map->lspidTlvExists = 1;
392 if (attr->trafficTlvExists) {
393 memcpy(&map->trafficTlv, &attr->trafficTlv, sizeof(mplsLdpTrafficTlv_t));
394 map->trafficTlvExists = 1;
398 void ldp_label_mapping_initial_callback(mpls_timer_handle timer, void *extra,
399 mpls_cfg_handle handle)
401 ldp_session *s = (ldp_session *) extra;
402 ldp_global *g = (ldp_global*)handle;
403 ldp_attr *ds_attr = NULL;
404 ldp_attr *us_attr = NULL;
405 ldp_session *nh_session = NULL;
406 mpls_bool done = MPLS_BOOL_FALSE;
407 ldp_fec *f;
408 ldp_nexthop *nh;
410 LDP_ENTER(g->user_data, "ldp_label_mapping_initial_callback");
412 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_TIMER,
413 "Initial Label Mapping fired: session(%d)\n", s->index);
415 mpls_lock_get(g->global_lock);
417 mpls_timer_stop(g->timer_handle, timer);
419 f = MPLS_LIST_HEAD(&g->fec);
420 while (f) {
421 nh = MPLS_LIST_HEAD(&f->nh_root);
422 while (nh) {
423 switch (f->info.type) {
424 case MPLS_FEC_PREFIX:
425 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
426 LDP_TRACE_FLAG_ROUTE, "Processing prefix FEC: %08x/%d ",
427 f->info.u.prefix.network.u.ipv4, f->info.u.prefix.length);
428 break;
429 case MPLS_FEC_HOST:
430 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
431 LDP_TRACE_FLAG_ROUTE, "Processing host FEC: %08x ",
432 f->info.u.host.u.ipv4);
433 break;
434 case MPLS_FEC_L2CC:
435 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
436 LDP_TRACE_FLAG_ROUTE, "Processingu L2CC FEC: %d %d %d ",
437 f->info.u.l2cc.connection_id, f->info.u.l2cc.group_id,
438 f->info.u.l2cc.type);
439 break;
440 default:
441 MPLS_ASSERT(0);
444 if (nh->info.type & MPLS_NH_IP) {
445 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
446 LDP_TRACE_FLAG_ROUTE, "via %08x\n", nh->addr->address.u.ipv4);
448 if (nh->info.type & MPLS_NH_IF && nh->iff) {
449 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
450 LDP_TRACE_FLAG_ROUTE, "via %p\n", nh->iff->handle);
453 /* are we allowed to export this route from the rib */
454 if (mpls_policy_export_check(g->user_data, &f->info, &nh->info) ==
455 MPLS_BOOL_FALSE) {
456 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
457 LDP_TRACE_FLAG_POLICY, "Rejected by export policy\n");
458 goto ldp_label_mapping_initial_callback_end_nh;
461 /* have we already sent a mapping for this fec to the new session? */
462 if ((us_attr = ldp_attr_find_upstream_state2(g, s, f,
463 LDP_LSP_STATE_MAP_SENT))) {
464 /* no need to sent another mapping */
465 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
466 LDP_TRACE_FLAG_ROUTE, "Already sent this FEC to session %d\n",
467 s->index);
468 goto ldp_label_mapping_initial_callback_end_nh;
471 if (!(nh_session = ldp_get_next_hop_session_for_fec2(f,nh))) {
472 ds_attr = NULL;
473 } else {
474 if (nh_session->index == s->index) {
475 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
476 LDP_TRACE_FLAG_ROUTE, "Nexthop session(%d) == session(%d)\n",
477 nh_session->index, s->index);
478 goto ldp_label_mapping_initial_callback_end_nh;
480 ds_attr = ldp_attr_find_downstream_state2(g, nh_session, f,
481 LDP_LSP_STATE_MAP_RECV);
484 if ((g->label_merge != MPLS_BOOL_TRUE) &&
485 ldp_attr_num_us2ds(ds_attr)) {
486 /* we have a ds label, but can't use it */
487 ds_attr = NULL;
490 us_attr = NULL;
491 if (ds_attr) {
492 /* we can use it, merge on baby */
493 ldp_label_mapping_with_xc(g, s, f, &us_attr, ds_attr);
494 } else {
495 /* we don't have a ds label */
497 /* we will be egress? */
498 if (g->lsp_control_mode == LDP_CONTROL_ORDERED) {
499 if (mpls_policy_egress_check(g->user_data, &f->info,
500 &nh->info) == MPLS_BOOL_TRUE) {
501 ldp_label_mapping_with_xc(g, s, f, &us_attr, NULL);
503 } else {
504 ldp_label_mapping_with_xc(g, s, f, &us_attr, NULL);
507 ldp_label_mapping_initial_callback_end_nh:
508 nh = MPLS_LIST_NEXT(&f->nh_root, nh, _fec);
510 f = MPLS_LIST_NEXT(&g->fec, f, _global);
512 done = MPLS_BOOL_TRUE;
514 if (done == MPLS_BOOL_TRUE) {
515 mpls_timer_delete(g->timer_handle, timer);
516 MPLS_REFCNT_RELEASE(s, ldp_session_delete);
517 s->initial_distribution_timer = (mpls_timer_handle) 0;
518 } else {
519 mpls_timer_start(g->timer_handle, timer, MPLS_TIMER_ONESHOT);
520 /* need to mark the session with where it left off */
523 mpls_lock_release(g->global_lock);
525 LDP_EXIT(g->user_data, "ldp_label_mapping_initial_callback");
528 mpls_return_enum ldp_label_mapping_send(ldp_global * g, ldp_session * s,
529 ldp_fec *f, ldp_attr * us_attr, ldp_attr * ds_attr)
531 ldp_inlabel *in = NULL;
532 ldp_attr *us_temp, *existing = NULL;
534 LDP_ENTER(g->user_data, "ldp_label_mapping_send");
535 MPLS_ASSERT(us_attr);
537 #if 0
539 * before we can enable this, inlabels need to keep track of all of
540 * the attr that link to it. Then when running in DU independent mode we
541 * can correctly attach the us and ds attrs involved when propogating a
542 * new mapping for a FEC we've already distributed labels for
544 existing = ldp_attr_find_upstream_map_in_labelspace(f, s->cfg_label_space);
545 #endif
547 if (existing) {
548 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_BINDING,
549 "Using an existing label\n");
550 in = existing->inlabel;
551 ldp_attr_add_inlabel(us_attr, in);
552 } else {
553 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_BINDING,
554 "Generating a label\n");
555 in = ldp_inlabel_create_complete(g, s, us_attr);
558 if (!in) { /* SL.1-3 */
559 goto Send_Label_9;
562 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_BINDING,
563 "In Label Added\n");
565 us_attr->state = LDP_LSP_STATE_MAP_SENT;
567 us_attr->msg_id = g->message_identifier;
568 ldp_label_mapping_prepare_msg(s->tx_message, g->message_identifier++,
569 us_attr);
571 if (ldp_mesg_send_tcp(g, s, s->tx_message) != MPLS_SUCCESS) { /* SL.4 */
572 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_SEND, LDP_TRACE_FLAG_ERROR,
573 "Failed sending Label Mapping to %s\n",
574 s->session_name);
575 goto ldp_label_mapping_send_error;
578 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_SEND, LDP_TRACE_FLAG_LABEL,
579 "Label Mapping Sent to %s for %08x/%d\n",
580 s->session_name,
581 us_attr->fecTlv.fecElArray[0].addressEl.address,
582 us_attr->fecTlv.fecElArray[0].addressEl.preLen);
584 us_attr->state = LDP_LSP_STATE_MAP_SENT; /* SL.6,7 */
586 LDP_EXIT(g->user_data, "ldp_label_mapping_send");
587 return MPLS_SUCCESS; /* SL.8 */
589 Send_Label_9:
590 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_STATE,
591 "No Label Resources\n");
593 while ((us_temp = ldp_attr_find_upstream_state2(g, s, us_attr->fec,
594 LDP_LSP_STATE_REQ_RECV)) != NULL) { /* SL.9 */
595 ldp_notif_send(g, s, us_temp, LDP_NOTIF_NO_LABEL_RESOURCES_AVAILABLE);
596 /* SL.10 */
597 s->no_label_resource_sent = MPLS_BOOL_TRUE; /* SL.12 */
598 us_temp->state = LDP_LSP_STATE_NO_LABEL_RESOURCE_SENT; /* SL.13 */
601 LDP_EXIT(g->user_data, "ldp_label_mapping_send");
603 return MPLS_SUCCESS;
605 ldp_label_mapping_send_error:
607 LDP_EXIT(g->user_data, "ldp_label_mapping_send-error");
608 return MPLS_FAILURE;
611 void ldp_label_mapping_prepare_msg(ldp_mesg * msg, uint32_t msgid,
612 ldp_attr * s_attr)
614 mplsLdpLblMapMsg_t *map = NULL;
615 int i;
617 MPLS_ASSERT(msg);
619 ldp_mesg_prepare(msg, MPLS_LBLMAP_MSGTYPE, msgid);
620 map = &msg->u.map;
622 if (s_attr->fecTlvExists) {
623 /* JLEU: only 1 FEC is allowed!! */
624 map->fecTlvExists = 1;
625 map->baseMsg.msgLength += setupFecTlv(&map->fecTlv);
626 map->baseMsg.msgLength += addFecElem2FecTlv(&map->fecTlv,
627 &s_attr->fecTlv.fecElArray[0]);
629 if (s_attr->genLblTlvExists) {
630 map->genLblTlvExists = 1;
631 map->baseMsg.msgLength += setupGenLblTlv(&map->genLblTlv,
632 s_attr->genLblTlv.label);
634 if (s_attr->atmLblTlvExists) {
635 map->atmLblTlvExists = 1;
636 map->baseMsg.msgLength += setupAtmLblTlv(&map->atmLblTlv, 0, 0,
637 s_attr->atmLblTlv.flags.flags.vpi, s_attr->atmLblTlv.vci);
639 if (s_attr->frLblTlvExists) {
640 map->frLblTlvExists = 1;
641 map->baseMsg.msgLength += setupFrLblTlv(&map->frLblTlv, 0,
642 s_attr->frLblTlv.flags.flags.len, s_attr->frLblTlv.flags.flags.dlci);
644 if (s_attr->hopCountTlvExists) {
645 map->hopCountTlvExists = 1;
646 map->baseMsg.msgLength += setupHopCountTlv(&map->hopCountTlv,
647 s_attr->hopCountTlv.hcValue);
649 if (s_attr->pathVecTlvExists) {
650 map->pathVecTlvExists = 1;
651 map->baseMsg.msgLength += setupPathTlv(&map->pathVecTlv);
652 for (i = 0; i < MPLS_MAXHOPSNUMBER; i++) {
653 if (s_attr->pathVecTlv.lsrId[i]) {
654 map->baseMsg.msgLength += addLsrId2PathTlv(&map->pathVecTlv,
655 s_attr->pathVecTlv.lsrId[i]);
659 #if 0
660 if (s_attr->lblMsgIdTlvExists) {
662 if (s_attr->lspidTlvExists) {
664 if (s_attr->trafficTlvExists) {
666 #endif
669 mpls_return_enum ldp_label_mapping_process(ldp_global * g, ldp_session * s,
670 ldp_adj * a, ldp_entity * e, ldp_attr * r_attr, ldp_fec * f)
672 mpls_return_enum retval = MPLS_SUCCESS;
673 ldp_session *peer = NULL;
674 ldp_attr_list *us_list = NULL;
675 ldp_attr_list *ds_list = NULL;
676 ldp_attr *ds_attr = NULL;
677 ldp_attr *ds_temp = NULL;
678 ldp_attr *us_attr = NULL;
679 ldp_attr *us_temp = NULL;
680 ldp_attr dumb_attr;
681 ldp_nexthop *nh = NULL;
683 ldp_outlabel *out = NULL;
684 mpls_bool requested = MPLS_BOOL_FALSE;
685 ldp_attr *existing = NULL;
686 mpls_bool need_request = MPLS_BOOL_FALSE;
688 LDP_ENTER(g->user_data, "ldp_label_mapping_process");
690 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV, LDP_TRACE_FLAG_LABEL,
691 "Label Mapping Recv from %s for %08x/%d\n",
692 s->session_name,
693 r_attr->fecTlv.fecElArray[0].addressEl.address,
694 r_attr->fecTlv.fecElArray[0].addressEl.preLen);
696 if ((ds_attr = ldp_attr_find_downstream_state2(g, s, f,
697 LDP_LSP_STATE_REQ_SENT)) != NULL) { /* LMp.1 */
698 /* just remove the req from the tree, we will use the r_attr sent to us */
699 ldp_attr_delete_downstream(g, s, ds_attr);
700 requested = MPLS_BOOL_TRUE;
701 } else {
702 requested = MPLS_BOOL_FALSE;
705 ds_attr = r_attr;
706 ds_attr->state = LDP_LSP_STATE_MAP_RECV; /* LMp.2 */
709 * ds_attr is the mapping we will keep and is NOT in the tree, unless
710 * it is an update mapping ...
712 if (Check_Received_Attributes(g, s, ds_attr, MPLS_LBLMAP_MSGTYPE) ==
713 MPLS_SUCCESS) { /* LMp.3 */
714 goto LMp_9;
718 * A loop was detected
720 if ((ds_list = ldp_attr_find_downstream_all2(g, s, f))) {
721 ds_temp = MPLS_LIST_HEAD(ds_list);
723 * check all the labels this session has received from "s" for "fec"
724 * do we have a duplicat?
726 while (ds_temp) {
727 if ((ds_temp->state == LDP_LSP_STATE_MAP_RECV) && /* LMp.4 */
728 ldp_attr_is_equal(ds_temp, ds_attr, LDP_ATTR_LABEL) == /* LMp.5 */
729 MPLS_BOOL_TRUE) {
730 /* remove record of the label and remove it switching */
731 ldp_attr_remove_complete(g, ds_temp, MPLS_BOOL_TRUE); /* LMp.6,7 */
733 * I think this is supposed to be 32 NOT 33, we need to release
734 * it don't we?
736 goto LMp_33;
738 ds_temp = MPLS_LIST_NEXT(ds_list, ds_temp, _fs);
742 LDP_PRINT(g->user_data, "Receive_Label_Map_8: send release");
743 if (ldp_label_release_send(g, s, ds_attr, LDP_NOTIF_LOOP_DETECTED) !=
744 MPLS_SUCCESS) { /* LMp.8 */
745 retval = MPLS_FAILURE;
747 goto LMp_33;
749 LMp_9:
751 * No Loop Detected
753 ds_temp = ldp_attr_find_downstream_state2(g, s, f, LDP_LSP_STATE_MAP_RECV);
754 if (requested == MPLS_BOOL_TRUE ||
755 g->label_merge == MPLS_BOOL_FALSE || !ds_temp) {
756 /* !merging then this is always a new LSP
757 * merging w/o a recv'd mapping is a new LSP
758 * this check comes from Note 6
760 goto LMp_11;
763 /* searching all recv'd attrs for matched mappings,
764 * stop after finding 1st match
766 if ((ds_list = ldp_attr_find_downstream_all2(g, s, f))) {
767 ds_temp = MPLS_LIST_HEAD(ds_list);
768 while (ds_temp) {
769 if (ds_temp->state == LDP_LSP_STATE_MAP_RECV) { /* LMp.9 */
770 if (ldp_attr_is_equal(ds_attr, ds_temp, LDP_ATTR_LABEL) ==
771 MPLS_BOOL_TRUE) { /* LMp.10 */
773 * this mapping matches an existing mapping, but it
774 * could contain updated attributes
776 existing = ds_temp;
777 break;
778 } else {
780 * we have been given another label for the same FEC and we
781 * didn't request it, release it
783 LDP_PRINT(g->user_data, "LMp.10 dup without req\n");
784 goto LMp_32;
787 ds_temp = MPLS_LIST_NEXT(ds_list, ds_temp, _fs);
790 if (existing) {
791 ldp_attr2ldp_attr(ds_attr, existing, LDP_ATTR_HOPCOUNT | LDP_ATTR_PATH |
792 LDP_ATTR_MSGID | LDP_ATTR_LSPID | LDP_ATTR_TRAFFIC);
793 ds_attr = existing;
795 * no need to free ds_attr, since it was not added to the tree it
796 * will be deleted when we exit ldp_label_mapping_process(), see
797 * ldp_state_process().
801 * from this point on.... if this is an updated mapping then ds_attr
802 * is the existing mapping which has now been update, else ds_attr
803 * is the new mapping
806 LMp_11:
808 * existing ONLY has a value for updated label mapping
810 nh = ldp_nexthop_for_fec_session(f,s); /* LMp.11 */
813 * the following departs from the procedure, it allows for filtering
814 * of label mappings
816 * Are we configured to accept and INSTALL this mapping?
818 if (mpls_policy_import_check(g->user_data, &f->info, &nh->info) ==
819 MPLS_BOOL_FALSE) {
821 * policy has rejected it, store it away
823 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV, LDP_TRACE_FLAG_LABEL,
824 "Label Mapping for %08x/%d from %s filtered by import policy\n",
825 r_attr->fecTlv.fecElArray[0].addressEl.address,
826 r_attr->fecTlv.fecElArray[0].addressEl.preLen, s->session_name);
828 if (existing) {
829 ds_attr->filtered = MPLS_BOOL_TRUE;
830 if (ds_attr->outlabel && ds_attr->outlabel->switching == MPLS_BOOL_TRUE) {
831 /* the mapping has been filtered, but the original wasn't? */
832 MPLS_ASSERT(0);
834 } else {
835 ds_attr->filtered = MPLS_BOOL_TRUE;
836 if (ldp_attr_insert_downstream(g, s, ds_attr) != MPLS_SUCCESS) {
837 retval = MPLS_FAILURE;
840 goto LMp_33;
843 if (!nh) { /* LMp.12 */
845 * if we did not find a nh hop for this FEC that corresponded to the
846 * MsgSource then the MsgSource is not a nexthop for the FEC
848 if (g->label_retention_mode == LDP_RETENTION_CONSERVATIVE) { /* LMp.13C */
849 LDP_PRINT(g->user_data, "LMp.13C conservative\n");
850 goto LMp_32;
854 * store it away
856 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV, LDP_TRACE_FLAG_LABEL,
857 "Session %s is not a valid nexthop for %08x/%d\n", s->session_name,
858 r_attr->fecTlv.fecElArray[0].addressEl.address,
859 r_attr->fecTlv.fecElArray[0].addressEl.preLen);
861 if (!existing) {
862 /* LMp.13L */
863 if (ldp_attr_insert_downstream(g, s, ds_attr) != MPLS_SUCCESS) {
864 retval = MPLS_FAILURE;
867 goto LMp_33;
871 * this is slightly different form the procedure, we can still be
872 * transit for a FEC we are not configured to be ingress for.
873 * Either way we only need to do the "install for fwd/switching"
874 * only once. We could arrive here multiple times due to updates,
875 * only install it the first time
877 if ((!existing) || (!existing->outlabel)) {
879 * we haven't installed it yet.
880 * Either new (!existing), or a result of a "Detect FEC Nexthop Change"
881 * and we had this mapping in our database (!existing->outlabel))
884 if (!(out = ldp_outlabel_create_complete(g, s, ds_attr, nh))) {
885 LDP_PRINT(g->user_data, "LMp.15 failure creating outlabel\n");
886 goto LMp_32;
889 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_BINDING,
890 "Out Label Added\n");
894 * are we configured to act as ingress for this FEC?
896 if (mpls_policy_ingress_check(g->user_data, &f->info, &nh->info) ==
897 MPLS_BOOL_TRUE) { /* LMp.14 */
899 * yep, bind the label to the FEC
901 if (ds_attr->ingress != MPLS_BOOL_TRUE) {
902 #if MPLS_USE_LSR
903 lsr_ftn ftn;
904 ftn.outsegment_index = ds_attr->outlabel->info.handle;
905 memcpy(&ftn.fec, &f->info, sizeof(mpls_fec));
906 lsr_cfg_ftn_set2(g->lsr_handle, &ftn, LSR_CFG_ADD|LSR_FTN_CFG_FEC|
907 LSR_FTN_CFG_OUTSEGMENT);
908 #else
909 mpls_mpls_fec2out_add(g->mpls_handle, &f->info, &ds_attr->outlabel->info);
910 #endif
911 ds_attr->ingress = MPLS_BOOL_TRUE;
912 ds_attr->outlabel->merge_count++;
913 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV, LDP_TRACE_FLAG_BINDING,
914 "Acting as ingress for %08x/%d from %s\n",
915 r_attr->fecTlv.fecElArray[0].addressEl.address,
916 r_attr->fecTlv.fecElArray[0].addressEl.preLen, s->session_name);
920 /* create a set of attrs that we will fill and compare against
921 * if this mapping were to be propogate these are the attrs it would have
922 * by comparing what we did sent in the past to these, we con figure out
923 * if we need to send an updated mapping
925 memset(&dumb_attr, 0, sizeof(ldp_attr));
926 mpls_fec2fec_tlv(&f->info, &dumb_attr.fecTlv, 0);
927 dumb_attr.fecTlvExists = 1;
928 dumb_attr.fecTlv.numberFecElements = 1;
931 * by definition (we received a label mapping that will be used) this
932 * LSR is _not_ the egress, so calculate a hop and path based on the
933 * mapping we received. We will compare this with mapping that have
934 * already been sent. If they differ, we will send an updated mapping
936 Prepare_Label_Mapping_Attributes(g, s, &f->info, ds_attr, &dumb_attr,
937 MPLS_BOOL_TRUE, MPLS_BOOL_TRUE, MPLS_BOOL_FALSE);
939 if (!existing) {
941 * this is the first time we've seen this mapping, add it to the database.
942 * all future updates will modify this entry in place
944 /* LMp.16 */
945 if (ldp_attr_insert_downstream(g, s, ds_attr) != MPLS_SUCCESS) {
946 retval = MPLS_FAILURE;
947 goto LMp_33;
951 peer = MPLS_LIST_HEAD(&g->session);
952 while (peer) { /* LMp.17 */
954 if (peer->state != LDP_STATE_OPERATIONAL) {
955 goto next_peer;
959 * it is just as easy to walk the list of all upstream attr for this
960 * peer as it is to the individual check to see if we have sent a
961 * label mapping for this FEC LSP
964 // #error this whole section is f ed
966 /* LMp.22 - 27 */
967 if ((us_list = ldp_attr_find_upstream_all2(g, peer, f))) { /* LMp.23 */
968 us_temp = MPLS_LIST_HEAD(us_list);
969 while (us_temp) {
971 * if we have sent a label mapping for the FEC and that label mapping
972 * was an done in independent mode or it is part of an LSP created
973 * due as part of an existing received label mapping
975 /* LMp.18 */
976 if (us_temp->state == LDP_LSP_STATE_MAP_SENT) {
977 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV,
978 LDP_TRACE_FLAG_BINDING, "Already sent mapping for %08x/%d to %s\n",
979 r_attr->fecTlv.fecElArray[0].addressEl.address,
980 r_attr->fecTlv.fecElArray[0].addressEl.preLen, peer->session_name);
981 if ((!existing) || (existing->index == us_temp->ds_attr->index)) {
982 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV,
983 LDP_TRACE_FLAG_BINDING, "Part of same LSP\n");
984 /* are the received attrs the same as the ones we've already sent */
985 if (ldp_attr_is_equal(us_temp, &dumb_attr,
986 LDP_ATTR_HOPCOUNT | LDP_ATTR_PATH) != MPLS_BOOL_TRUE) {
987 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV,
988 LDP_TRACE_FLAG_BINDING, "Propogating updated attrs\n");
989 /* send an updated label mapping */
990 if (ldp_label_mapping_with_xc(g, us_temp->session, f, &us_temp,
991 ds_attr) != MPLS_SUCCESS) { /* LMp.24-26 */
992 retval = MPLS_FAILURE;
993 goto LMp_33;
998 us_temp = MPLS_LIST_NEXT(us_list, us_temp, _fs);
1002 if ((peer->oper_distribution_mode == LDP_DISTRIBUTION_UNSOLICITED) &&
1003 (g->lsp_control_mode == LDP_CONTROL_ORDERED)) { /* LMp.19 */
1006 * if we're not merging and we have multiple ORDERED DU sessions,
1007 * we will to start requesting labels after we propogate the mapping to
1008 * the first peer
1010 if (need_request == MPLS_BOOL_TRUE) {
1011 if (ldp_attr_find_downstream_state2(g, peer, f,
1012 LDP_LSP_STATE_REQ_SENT) == NULL) {
1014 * we don't have a request for FEC to peer outstanding, make one
1016 ds_temp = NULL;
1017 if (ldp_label_request_for_xc(g, peer, &f->info, NULL, &ds_temp) !=
1018 MPLS_SUCCESS) {
1019 retval = MPLS_FAILURE;
1020 goto LMp_33;
1023 } else {
1025 * We're in DU more, either we're merging, or we're not merging and
1026 * this is the first peer we're propogating this mapping to
1028 /* LMp.20-21,30 */
1029 us_attr = NULL;
1030 if (ldp_label_mapping_with_xc(g, peer, f, &us_attr, ds_attr) !=
1031 MPLS_SUCCESS) {
1032 retval = MPLS_FAILURE;
1033 goto LMp_33;
1036 * if we're not merging, we will need to request a label for
1037 * the next DU peer
1039 if (g->label_merge == MPLS_BOOL_FALSE) {
1040 need_request = MPLS_BOOL_TRUE;
1045 /* LMp.28 */
1046 while ((us_temp = ldp_attr_find_upstream_state2(g, peer, f,
1047 LDP_LSP_STATE_REQ_RECV))) {
1049 if (peer->oper_distribution_mode == LDP_DISTRIBUTION_UNSOLICITED) {
1050 if (need_request == MPLS_BOOL_TRUE) {
1051 if (ldp_attr_find_downstream_state2(g, peer, f,
1052 LDP_LSP_STATE_REQ_SENT) == NULL) {
1054 * we don't have a request for FEC to peer outstanding
1056 ds_temp = NULL;
1057 if (ldp_label_request_for_xc(g, peer, &f->info, us_temp,
1058 &ds_temp) != MPLS_SUCCESS) {
1059 retval = MPLS_FAILURE;
1060 goto LMp_33;
1063 } else {
1064 if (ldp_label_mapping_with_xc(g, peer, f, &us_temp,
1065 ds_attr) != MPLS_SUCCESS) {
1066 retval = MPLS_FAILURE;
1067 goto LMp_33;
1070 } else {
1071 if ((us_list = ldp_attr_find_upstream_all2(g, peer, f))) {
1072 us_temp = MPLS_LIST_HEAD(ds_list);
1073 while (us_temp) {
1074 if (us_temp->state == LDP_LSP_STATE_REQ_RECV) {
1075 if (need_request == MPLS_BOOL_TRUE) {
1076 if (ldp_attr_find_downstream_state2(g, peer, f,
1077 LDP_LSP_STATE_REQ_SENT) == NULL) {
1079 * we don't have a request for FEC to peer outstanding
1081 ds_temp = NULL;
1082 if (ldp_label_request_for_xc(g, peer, &f->info, us_temp,
1083 &ds_temp) != MPLS_SUCCESS) {
1084 retval = MPLS_FAILURE;
1085 goto LMp_33;
1088 } else {
1089 if (ldp_label_mapping_with_xc(g, peer, f, &us_temp,
1090 ds_attr) != MPLS_SUCCESS) {
1091 retval = MPLS_FAILURE;
1092 goto LMp_33;
1095 * if we're not merging, we will need to request a label for
1096 * the next DU peer
1098 if (g->label_merge == MPLS_BOOL_FALSE) {
1099 need_request = MPLS_BOOL_TRUE;
1103 us_temp = MPLS_LIST_NEXT(us_list, us_temp, _fs);
1109 next_peer:
1110 peer = MPLS_LIST_NEXT(&g->session, peer, _global);
1113 LMp_33:
1114 LDP_EXIT(g->user_data, "ldp_label_mapping_process");
1115 return retval;
1117 LMp_32:
1118 LDP_PRINT(g->user_data, "Receive_Label_Map_32: send release");
1119 if (ldp_label_release_send(g, s, ds_attr, LDP_NOTIF_NONE) != MPLS_SUCCESS) {
1120 retval = MPLS_FAILURE;
1122 LDP_EXIT(g->user_data, "ldp_label_mapping_process");
1123 return retval;