Convert to a generic FEC handling architecture. Part of this change
[mpls-ldp-portable.git] / ldp / ldp_label_mapping.c
blob8562ee2a6510a8a6409d0acd1df45a7e06e4ebd1
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_global.h"
20 #include "ldp_pdu_setup.h"
21 #include "ldp_label_rel_with.h"
22 #include "ldp_label_mapping.h"
23 #include "ldp_label_request.h"
25 #include "mpls_timer_impl.h"
26 #include "mpls_fib_impl.h"
27 #include "mpls_lock_impl.h"
28 #include "mpls_tree_impl.h"
29 #include "mpls_trace_impl.h"
30 #include "mpls_mm_impl.h"
31 #include "mpls_policy_impl.h"
33 #if MPLS_USE_LSR
34 #include "lsr_cfg.h"
35 #else
36 #include "mpls_mpls_impl.h"
37 #endif
39 mpls_return_enum ldp_label_mapping_with_xc(ldp_global * g, ldp_session * s,
40 ldp_fec * f, ldp_attr ** us_attr, ldp_attr * ds_attr)
42 mpls_return_enum result;
43 mpls_bool propogating = MPLS_BOOL_TRUE;
44 mpls_bool egress = MPLS_BOOL_TRUE;
46 MPLS_ASSERT(us_attr);
48 if (!(*us_attr)) {
49 if (!((*us_attr) = ldp_attr_create(&f->info))) {
50 return MPLS_FAILURE;
53 if (!ds_attr) {
54 propogating = MPLS_BOOL_FALSE;
55 egress = MPLS_BOOL_TRUE;
58 Prepare_Label_Mapping_Attributes(g, s, &f->info, ds_attr, (*us_attr),
59 propogating, MPLS_BOOL_TRUE, egress);
61 if (ldp_attr_insert_upstream2(g, s, (*us_attr), f) != MPLS_SUCCESS) {
62 ldp_attr_delete(*us_attr);
63 return MPLS_FATAL;
66 if (ldp_label_mapping_send(g, s, (*us_attr), ds_attr) != MPLS_SUCCESS) {
67 ldp_attr_delete(*us_attr);
68 return MPLS_FATAL;
71 if (ds_attr && ds_attr->outlabel) {
73 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
74 LDP_TRACE_FLAG_BINDING, "Cross Connect Added\n");
76 result = ldp_inlabel_add_outlabel(g,(*us_attr)->inlabel,ds_attr->outlabel);
77 if (result != MPLS_SUCCESS) {
78 ldp_label_withdraw_send(g, s, (*us_attr), LDP_NOTIF_NONE);
79 return MPLS_FATAL;
82 return MPLS_SUCCESS;
85 ldp_session *ldp_get_session_by_next_hop(ldp_global * g, mpls_nexthop * a,
86 ldp_addr ** next_hop)
88 mpls_fec dest, entry;
89 ldp_addr *addr = NULL;
91 MPLS_ASSERT(next_hop);
93 if (a->type == MPLS_NH_IP) {
94 /* possibly an indirect nexthop */
95 if (!mpls_fib_get_best_route(g->fib_handle, 1, &dest, &entry)) {
96 return NULL;
98 a = &entry.nh;
101 if (a->type & MPLS_NH_IP) {
102 if (mpls_tree_get(g->addr_tree, a->ip.u.ipv4, 32, (void **)&addr) ==
103 MPLS_SUCCESS) {
104 ldp_session *ses = NULL;
106 /* JLEU if there is more then one session that has given this address
107 then we're in trouble, just choose the first for now */
108 if ((ses = (ldp_session*)mpls_link_list_head_data(&addr->session_root))) {
109 *next_hop = addr;
110 return ses;
113 } else if (a->type & MPLS_NH_IF) {
114 ldp_if *iff = ldp_global_find_if_handle(g, a->if_handle);
115 ldp_adj *a;
117 if (iff) {
118 /* JLEU if there is more then one session on this interface
119 then we're in trouble, just choose the first for now */
120 *next_hop = NULL;
121 a = MPLS_LIST_HEAD(&iff->entity->adj_root);
122 return a->session;
124 } else {
125 MPLS_ASSERT(0);
128 return NULL;
131 ldp_session *ldp_get_next_hop_session_for_fec2(ldp_fec * f) {
132 ldp_session *session = NULL;
134 * find the info about the next hop for this FEC
136 if (f->addr && f->addr->session_root.count > 0) {
137 session = mpls_link_list_head_data(&f->addr->session_root);
138 } else if (f->iff && f->iff->is_p2p == MPLS_BOOL_TRUE &&
139 &f->iff->entity) {
140 ldp_adj *adj = MPLS_LIST_HEAD(&f->iff->entity->adj_root);
141 session = adj ? adj->session : NULL;
143 return session;
146 mpls_return_enum ldp_get_next_hop_session_for_fec(ldp_global * g,
147 mpls_fec * fec, ldp_session ** next_hop_session)
149 ldp_fec *f = NULL;
151 MPLS_ASSERT(next_hop_session);
153 if (!(f = ldp_fec_find(g, fec))) {
154 return MPLS_NO_ROUTE;
157 *next_hop_session = ldp_get_next_hop_session_for_fec2(f);
158 return (*next_hop_session) ? MPLS_SUCCESS : MPLS_FAILURE;
161 mpls_return_enum Check_Received_Attributes(ldp_global * g, ldp_session * s,
162 ldp_attr * r_attr, uint16_t type)
164 int count = 0;
165 int i;
167 if (!r_attr->hopCountTlvExists) { /* CRa.1 */
168 goto Check_Received_Attributes_5;
171 if (r_attr->hopCountTlv.hcValue >= s->cfg_hop_count_limit) { /* CRa.2 */
172 LDP_PRINT(g->user_data, "CRa.2\n");
173 goto Check_Received_Attributes_6;
176 if (!r_attr->pathVecTlvExists) { /* CRa.3 */
177 goto Check_Received_Attributes_5;
180 for (i = 0; i < MPLS_MAXHOPSNUMBER; i++) { /* CRa.4 */
181 if (r_attr->pathVecTlv.lsrId[i]) {
182 count++;
183 if (r_attr->pathVecTlv.lsrId[i] == g->lsr_identifier.u.ipv4) {
184 goto Check_Received_Attributes_6;
185 LDP_PRINT(g->user_data, "CRa.4a\n");
187 if (count > s->oper_path_vector_limit) {
188 goto Check_Received_Attributes_6;
189 LDP_PRINT(g->user_data, "CRa.4b\n");
194 Check_Received_Attributes_5:
195 return MPLS_SUCCESS;
197 Check_Received_Attributes_6:
198 if (type != MPLS_LBLMAP_MSGTYPE) {
199 ldp_notif_send(g, s, r_attr, LDP_NOTIF_LOOP_DETECTED); /* CRa.7 */
201 return MPLS_FAILURE; /* CRa.8 */
204 void Prepare_Label_Mapping_Attributes(ldp_global * g, ldp_session * s,
205 mpls_fec * fec, ldp_attr * r_attr, ldp_attr * s_attr, mpls_bool propogating,
206 mpls_bool already, mpls_bool egress)
208 ldp_attr dummy;
209 int i;
211 /* NOTE: PMpA.21 is the end of the procedure (ie return) */
212 /* this function uses goto quite extensivly for a REASON!! */
213 /* Check Appedix A of the LDP draft */
215 LDP_ENTER(g->user_data, "Prepare_Label_Mapping_Attributes");
217 if (!r_attr) {
218 memset(&dummy, 0, sizeof(ldp_attr));
219 mpls_fec2fec_tlv(fec, &dummy.fecTlv, 0);
220 dummy.fecTlvExists = 1;
221 dummy.fecTlv.numberFecElements = 1;
222 r_attr = &dummy;
225 if (!(s->oper_loop_detection == LDP_LOOP_HOPCOUNT ||
226 s->oper_loop_detection == LDP_LOOP_HOPCOUNT_PATHVECTOR ||
227 r_attr->hopCountTlvExists)) { /* PMpA.1 */
228 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
229 return;
232 if (egress) {/* PMpA.2 */
233 /* I'm egress (for now) */
234 s_attr->hopCountTlvExists = 1;
235 s_attr->hopCountTlv.hcValue = 1; /* PMpA.3 */
236 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
237 return;
240 if (!(r_attr->hopCountTlvExists)) { /* PMpA.4 */
241 goto Prepare_Label_Mapping_Attributes_8;
244 if (!(g->ttl_less_domain == MPLS_BOOL_TRUE &&
245 s->cfg_remote_in_ttl_less_domain == MPLS_BOOL_TRUE)) { /* PMpA.5 */
246 goto Prepare_Label_Mapping_Attributes_7;
249 s_attr->hopCountTlvExists = 1;
250 s_attr->hopCountTlv.hcValue = 1; /* PMpA.6 */
251 goto Prepare_Label_Mapping_Attributes_9;
253 Prepare_Label_Mapping_Attributes_7:
254 s_attr->hopCountTlvExists = 1;
255 s_attr->hopCountTlv.hcValue = (r_attr->hopCountTlv.hcValue) ?
256 (r_attr->hopCountTlv.hcValue + 1) : 0;
257 goto Prepare_Label_Mapping_Attributes_9;
259 Prepare_Label_Mapping_Attributes_8:
260 s_attr->hopCountTlvExists = 1;
261 s_attr->hopCountTlv.hcValue = 0;
263 Prepare_Label_Mapping_Attributes_9:
264 if (s->oper_loop_detection == LDP_LOOP_NONE) {
265 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
266 return;
269 if (r_attr->pathVecTlvExists) { /* PMpA.10 */
270 goto Prepare_Label_Mapping_Attributes_19;
273 if (propogating == MPLS_BOOL_FALSE) { /* PMpA.11 */
274 goto Prepare_Label_Mapping_Attributes_20;
277 if (g->label_merge != MPLS_BOOL_TRUE) { /* PMpA.12 */
278 goto Prepare_Label_Mapping_Attributes_14;
281 if (already == MPLS_BOOL_FALSE) { /* PMpA.13 */
282 goto Prepare_Label_Mapping_Attributes_20;
285 Prepare_Label_Mapping_Attributes_14:
286 if (!r_attr->hopCountTlvExists) {
287 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
288 return;
291 if (r_attr->hopCountTlv.hcValue == 0) { /* PMpA.15 */
292 goto Prepare_Label_Mapping_Attributes_20;
295 if (already == MPLS_BOOL_FALSE) { /* PMpA.16 */
296 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
297 return;
300 /* r_attr contain PrevHopCount _IF_ we had one */
301 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
302 return; /* PMpA.17 */
304 if (r_attr->hopCountTlv.hcValue != 0) { /* PMpA.18 */
305 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
306 return;
309 Prepare_Label_Mapping_Attributes_19:
310 s_attr->pathVecTlvExists = 1;
311 s_attr->pathVecTlv.lsrId[0] = g->lsr_identifier.u.ipv4;
312 for (i = 1; i < (MPLS_MAXHOPSNUMBER - 1); i++) {
313 if (r_attr->pathVecTlv.lsrId[i - 1]) {
314 s_attr->pathVecTlv.lsrId[0] = r_attr->pathVecTlv.lsrId[i - 1];
318 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
319 return;
321 Prepare_Label_Mapping_Attributes_20:
322 s_attr->pathVecTlvExists = 1;
323 s_attr->pathVecTlv.lsrId[0] = g->lsr_identifier.u.ipv4;
325 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
326 return;
329 void map2attr(mplsLdpLblMapMsg_t * map, ldp_attr * attr, uint32_t flag)
331 attr->msg_id = map->baseMsg.msgId;
333 if (map->fecTlvExists && flag & LDP_ATTR_FEC) {
334 memcpy(&attr->fecTlv, &map->fecTlv, sizeof(mplsLdpFecTlv_t));
335 attr->fecTlvExists = 1;
337 if (map->genLblTlvExists && flag & LDP_ATTR_LABEL) {
338 memcpy(&attr->genLblTlv, &map->genLblTlv, sizeof(mplsLdpGenLblTlv_t));
339 attr->genLblTlvExists = 1;
340 } else if (map->atmLblTlvExists && flag & LDP_ATTR_LABEL) {
341 memcpy(&attr->atmLblTlv, &map->atmLblTlv, sizeof(mplsLdpAtmLblTlv_t));
342 attr->atmLblTlvExists = 1;
343 } else if (map->frLblTlvExists && flag & LDP_ATTR_LABEL) {
344 memcpy(&attr->frLblTlv, &map->frLblTlv, sizeof(mplsLdpFrLblTlv_t));
345 attr->frLblTlvExists = 1;
347 if (map->hopCountTlvExists && flag & LDP_ATTR_HOPCOUNT) {
348 memcpy(&attr->hopCountTlv, &map->hopCountTlv, sizeof(mplsLdpHopTlv_t));
349 attr->hopCountTlvExists = 1;
351 if (map->pathVecTlvExists && flag & LDP_ATTR_PATH) {
352 memcpy(&attr->pathVecTlv, &map->pathVecTlv, sizeof(mplsLdpPathTlv_t));
353 attr->pathVecTlvExists = 1;
355 if (map->lblMsgIdTlvExists && flag & LDP_ATTR_MSGID) {
356 memcpy(&attr->lblMsgIdTlv, &map->lblMsgIdTlv, sizeof(mplsLdpLblMsgIdTlv_t));
357 attr->lblMsgIdTlvExists = 1;
359 if (map->lspidTlvExists && flag & LDP_ATTR_LSPID) {
360 memcpy(&attr->lspidTlv, &map->lspidTlv, sizeof(mplsLdpLspIdTlv_t));
361 attr->lspidTlvExists = 1;
363 if (map->trafficTlvExists && flag & LDP_ATTR_TRAFFIC) {
364 memcpy(&attr->trafficTlv, &map->trafficTlv, sizeof(mplsLdpTrafficTlv_t));
365 attr->trafficTlvExists = 1;
369 void attr2map(ldp_attr * attr, mplsLdpLblMapMsg_t * map)
371 if (attr->fecTlvExists) {
372 memcpy(&map->fecTlv, &attr->fecTlv, sizeof(mplsLdpFecTlv_t));
373 map->fecTlvExists = 1;
375 if (attr->genLblTlvExists) {
376 memcpy(&map->genLblTlv, &attr->genLblTlv, sizeof(mplsLdpGenLblTlv_t));
377 map->genLblTlvExists = 1;
379 if (attr->atmLblTlvExists) {
380 memcpy(&map->atmLblTlv, &attr->atmLblTlv, sizeof(mplsLdpAtmLblTlv_t));
381 map->atmLblTlvExists = 1;
383 if (attr->frLblTlvExists) {
384 memcpy(&map->frLblTlv, &attr->frLblTlv, sizeof(mplsLdpFrLblTlv_t));
385 map->frLblTlvExists = 1;
387 if (attr->hopCountTlvExists) {
388 memcpy(&map->hopCountTlv, &attr->hopCountTlv, sizeof(mplsLdpHopTlv_t));
389 map->hopCountTlvExists = 1;
391 if (attr->pathVecTlvExists) {
392 memcpy(&map->pathVecTlv, &attr->pathVecTlv, sizeof(mplsLdpPathTlv_t));
393 map->pathVecTlvExists = 1;
395 if (attr->lblMsgIdTlvExists) {
396 memcpy(&map->lblMsgIdTlv, &attr->lblMsgIdTlv, sizeof(mplsLdpLblMsgIdTlv_t));
397 map->lblMsgIdTlvExists = 1;
399 if (attr->lspidTlvExists) {
400 memcpy(&map->lspidTlv, &attr->lspidTlv, sizeof(mplsLdpLspIdTlv_t));
401 map->lspidTlvExists = 1;
403 if (attr->trafficTlvExists) {
404 memcpy(&map->trafficTlv, &attr->trafficTlv, sizeof(mplsLdpTrafficTlv_t));
405 map->trafficTlvExists = 1;
409 void ldp_label_mapping_initial_callback(mpls_timer_handle timer, void *extra,
410 mpls_cfg_handle handle)
412 ldp_session *s = (ldp_session *) extra;
413 ldp_global *g = (ldp_global*)handle;
414 ldp_attr *ds_attr = NULL;
415 ldp_attr *us_attr = NULL;
416 ldp_session *nh_session = NULL;
417 mpls_bool done = MPLS_BOOL_FALSE;
418 ldp_fec *f;
420 LDP_ENTER(g->user_data, "ldp_label_mapping_initial_callback");
422 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_TIMER,
423 "Initial Label Mapping fired: session(%d)\n", s->index);
425 mpls_lock_get(g->global_lock);
427 mpls_timer_stop(g->timer_handle, timer);
429 if ((f = MPLS_LIST_HEAD(&g->fec))) {
430 do {
431 switch (f->info.type) {
432 case MPLS_FEC_PREFIX:
433 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
434 LDP_TRACE_FLAG_ROUTE, "Processing prefix FEC: %08x/%d ",
435 f->info.u.prefix.network.u.ipv4, f->info.u.prefix.length);
436 break;
437 case MPLS_FEC_HOST:
438 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
439 LDP_TRACE_FLAG_ROUTE, "Processing host FEC: %08x ",
440 f->info.u.host.u.ipv4);
441 break;
442 case MPLS_FEC_L2CC:
443 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
444 LDP_TRACE_FLAG_ROUTE, "Processingu L2CC FEC: %d %d %d ",
445 f->info.u.l2cc.connection_id, f->info.u.l2cc.group_id,
446 f->info.u.l2cc.type);
447 break;
448 default:
449 MPLS_ASSERT(0);
452 if (f->nh.type & MPLS_NH_IP) {
453 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
454 LDP_TRACE_FLAG_ROUTE, "via %08x\n", f->nh.addr->address.u.ipv4);
456 if (f->nh.type & MPLS_NH_IF) {
457 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
458 LDP_TRACE_FLAG_ROUTE, "via %s\n", f->nh.iff->name);
461 /* are we allowed to export this route from the rib */
462 if (mpls_policy_export_check(g->user_data, &f->info, &f->info.nh) ==
463 MPLS_BOOL_FALSE) {
464 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_POLICY,
465 "Rejected by export policy\n");
466 continue;
469 /* have we already sent a mapping for this fec to the new session? */
470 if ((us_attr = ldp_attr_find_upstream_state2(g, s, f,
471 LDP_LSP_STATE_MAP_SENT))) {
472 /* no need to sent another mapping */
473 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_ROUTE,
474 "Already sent this FEC to session %d\n", s->index);
475 continue;
478 if (!(nh_session = ldp_get_next_hop_session_for_fec2(f))) {
479 ds_attr = NULL;
480 } else {
481 if (nh_session->index == s->index) {
482 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
483 LDP_TRACE_FLAG_ROUTE, "Nexthop session(%d) == session(%d)\n",
484 nh_session->index, s->index);
485 continue;
487 ds_attr = ldp_attr_find_downstream_state2(g, nh_session, f,
488 LDP_LSP_STATE_MAP_RECV);
491 if ((g->label_merge != MPLS_BOOL_TRUE) && ldp_attr_num_us2ds(ds_attr)) {
492 /* we have a ds label, but can't use it */
493 ds_attr = NULL;
496 us_attr = NULL;
497 if (ds_attr) {
498 /* we can use it, merge on baby */
499 ldp_label_mapping_with_xc(g, s, f, &us_attr, ds_attr);
500 } else {
501 /* we don't have a ds label */
503 /* we will be egress? */
504 if (g->lsp_control_mode == LDP_CONTROL_ORDERED) {
505 if (mpls_policy_egress_check(g->user_data, &f->info, &f->info.nh) ==
506 MPLS_BOOL_TRUE) {
507 ldp_label_mapping_with_xc(g, s, f, &us_attr, NULL);
509 } else {
510 ldp_label_mapping_with_xc(g, s, f, &us_attr, NULL);
513 #if 0
514 /* why the hell are we requesting labels? this callback is only
515 * used for DU
517 if (nh_session && nh_session->oper_distribution_mode ==
518 LDP_DISTRIBUTION_ONDEMAND) {
519 ldp_label_request_for_xc(g, nh_session, &f->info, us_attr, &ds_attr);
521 #endif
523 } while ((f = MPLS_LIST_NEXT(&g->fec, f, _global)));
524 done = MPLS_BOOL_TRUE;
527 done = MPLS_BOOL_TRUE;
529 if (done == MPLS_BOOL_TRUE) {
530 mpls_timer_delete(g->timer_handle, timer);
531 MPLS_REFCNT_RELEASE(s, ldp_session_delete);
532 s->initial_distribution_timer = (mpls_timer_handle) 0;
533 } else {
534 mpls_timer_start(g->timer_handle, timer, MPLS_TIMER_ONESHOT);
535 /* need to mark the session with where it left off */
538 mpls_lock_release(g->global_lock);
540 LDP_EXIT(g->user_data, "ldp_label_mapping_initial_callback");
543 mpls_return_enum ldp_label_mapping_send(ldp_global * g, ldp_session * s,
544 ldp_attr * us_attr, ldp_attr * ds_attr)
546 ldp_inlabel *in = NULL;
547 ldp_attr *us_temp;
549 LDP_ENTER(g->user_data, "ldp_label_mapping_send");
550 MPLS_ASSERT(us_attr);
552 if ((in = ldp_inlabel_create_complete(g, s, us_attr)) == NULL) { /* SL.1-3 */
553 goto Send_Label_9;
556 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_BINDING,
557 "In Label Added\n");
559 us_attr->state = LDP_LSP_STATE_MAP_SENT;
561 us_attr->msg_id = g->message_identifier;
562 ldp_label_mapping_prepare_msg(s->tx_message, g->message_identifier++,
563 us_attr);
565 if (ldp_mesg_send_tcp(g, s, s->tx_message) != MPLS_SUCCESS) { /* SL.4 */
566 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_SEND, LDP_TRACE_FLAG_ERROR,
567 "Failed sending Label Mapping to %s\n",
568 s->session_name);
569 goto ldp_label_mapping_send_error;
572 ldp_attr_add_us2ds(us_attr, ds_attr);
574 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_SEND, LDP_TRACE_FLAG_LABEL,
575 "Label Mapping Sent to %s for %08x/%d\n",
576 s->session_name,
577 us_attr->fecTlv.fecElArray[0].addressEl.address,
578 us_attr->fecTlv.fecElArray[0].addressEl.preLen);
580 us_attr->state = LDP_LSP_STATE_MAP_SENT; /* SL.6,7 */
582 LDP_EXIT(g->user_data, "ldp_label_mapping_send");
583 return MPLS_SUCCESS; /* SL.8 */
585 Send_Label_9:
586 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_STATE,
587 "No Label Resources\n");
589 while ((us_temp = ldp_attr_find_upstream_state2(g, s, us_attr->fec,
590 LDP_LSP_STATE_REQ_RECV)) != NULL) { /* SL.9 */
591 ldp_notif_send(g, s, us_temp, LDP_NOTIF_NO_LABEL_RESOURCES_AVAILABLE);
592 /* SL.10 */
593 s->no_label_resource_sent = MPLS_BOOL_TRUE; /* SL.12 */
594 us_temp->state = LDP_LSP_STATE_NO_LABEL_RESOURCE_SENT; /* SL.13 */
597 LDP_EXIT(g->user_data, "ldp_label_mapping_send");
599 return MPLS_SUCCESS;
601 ldp_label_mapping_send_error:
603 LDP_EXIT(g->user_data, "ldp_label_mapping_send-error");
604 return MPLS_FAILURE;
607 void ldp_label_mapping_prepare_msg(ldp_mesg * msg, uint32_t msgid,
608 ldp_attr * s_attr)
610 mplsLdpLblMapMsg_t *map = NULL;
611 int i;
613 MPLS_ASSERT(msg);
615 ldp_mesg_prepare(msg, MPLS_LBLMAP_MSGTYPE, msgid);
616 map = &msg->u.map;
618 if (s_attr->fecTlvExists) {
619 /* JLEU: only 1 FEC is allowed!! */
620 map->fecTlvExists = 1;
621 map->baseMsg.msgLength += setupFecTlv(&map->fecTlv);
622 map->baseMsg.msgLength += addFecElem2FecTlv(&map->fecTlv,
623 &s_attr->fecTlv.fecElArray[0]);
625 if (s_attr->genLblTlvExists) {
626 map->genLblTlvExists = 1;
627 map->baseMsg.msgLength += setupGenLblTlv(&map->genLblTlv,
628 s_attr->genLblTlv.label);
630 if (s_attr->atmLblTlvExists) {
631 map->atmLblTlvExists = 1;
632 map->baseMsg.msgLength += setupAtmLblTlv(&map->atmLblTlv, 0, 0,
633 s_attr->atmLblTlv.flags.flags.vpi, s_attr->atmLblTlv.vci);
635 if (s_attr->frLblTlvExists) {
636 map->frLblTlvExists = 1;
637 map->baseMsg.msgLength += setupFrLblTlv(&map->frLblTlv, 0,
638 s_attr->frLblTlv.flags.flags.len, s_attr->frLblTlv.flags.flags.dlci);
640 if (s_attr->hopCountTlvExists) {
641 map->hopCountTlvExists = 1;
642 map->baseMsg.msgLength += setupHopCountTlv(&map->hopCountTlv,
643 s_attr->hopCountTlv.hcValue);
645 if (s_attr->pathVecTlvExists) {
646 map->pathVecTlvExists = 1;
647 map->baseMsg.msgLength += setupPathTlv(&map->pathVecTlv);
648 for (i = 0; i < MPLS_MAXHOPSNUMBER; i++) {
649 if (s_attr->pathVecTlv.lsrId[i]) {
650 map->baseMsg.msgLength += addLsrId2PathTlv(&map->pathVecTlv,
651 s_attr->pathVecTlv.lsrId[i]);
655 #if 0
656 if (s_attr->lblMsgIdTlvExists) {
658 if (s_attr->lspidTlvExists) {
660 if (s_attr->trafficTlvExists) {
662 #endif
665 mpls_return_enum ldp_label_mapping_process(ldp_global * g, ldp_session * s,
666 ldp_adj * a, ldp_entity * e, ldp_attr * r_attr, ldp_fec * f)
668 mpls_return_enum retval = MPLS_SUCCESS;
669 ldp_session *nh_session = NULL;
670 ldp_session *peer = NULL;
671 ldp_attr_list *us_list = NULL;
672 ldp_attr_list *ds_list = NULL;
673 ldp_attr *ds_attr = NULL;
674 ldp_attr *ds_temp = NULL;
675 ldp_attr *us_attr = NULL;
676 ldp_attr *us_temp = NULL;
677 ldp_attr dumb_attr;
679 ldp_outlabel *out = NULL;
680 mpls_bool requested = MPLS_BOOL_FALSE;
681 ldp_attr *update = NULL;
682 mpls_bool need_request = MPLS_BOOL_FALSE;
684 LDP_ENTER(g->user_data, "ldp_label_mapping_process");
686 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV, LDP_TRACE_FLAG_LABEL,
687 "Label Mapping Recv from %s for %08x/%d\n",
688 s->session_name,
689 r_attr->fecTlv.fecElArray[0].addressEl.address,
690 r_attr->fecTlv.fecElArray[0].addressEl.preLen);
692 if ((ds_attr = ldp_attr_find_downstream_state2(g, s, f,
693 LDP_LSP_STATE_REQ_SENT)) != NULL) { /* LMp.1 */
694 /* just remove the req from the tree, we will use the r_attr sent to us */
695 ldp_attr_delete_downstream(g, s, ds_attr);
696 requested = MPLS_BOOL_TRUE;
697 } else {
698 requested = MPLS_BOOL_FALSE;
701 ds_attr = r_attr;
702 ds_attr->state = LDP_LSP_STATE_MAP_RECV; /* LMp.2 */
705 * ds_attr is the mapping we will keep and is NOT in the tree, unless
706 * it is an update mapping ...
708 if (Check_Received_Attributes(g, s, ds_attr, MPLS_LBLMAP_MSGTYPE) ==
709 MPLS_SUCCESS) { /* LMp.3 */
710 goto LMp_9;
714 * A loop was detected
716 if ((ds_list = ldp_attr_find_downstream_all2(g, s, f))) {
717 ds_temp = MPLS_LIST_HEAD(ds_list);
719 * check all the labels this session has received from "s" for "fec"
720 * do we have a duplicat?
722 while (ds_temp) {
723 if ((ds_temp->state == LDP_LSP_STATE_MAP_RECV) && /* LMp.4 */
724 ldp_attr_is_equal(ds_temp, ds_attr, LDP_ATTR_LABEL) == /* LMp.5 */
725 MPLS_BOOL_TRUE) {
726 /* remove record of the label and remove it switching */
727 ldp_attr_remove_complete(g, ds_temp, MPLS_BOOL_TRUE); /* LMp.6,7 */
729 * I think this is supposed to be 32 NOT 33, we need to release
730 * it don't we?
732 goto LMp_33;
734 ds_temp = MPLS_LIST_NEXT(ds_list, ds_temp, _fs);
738 LDP_PRINT(g->user_data, "Receive_Label_Map_8: send release");
739 if (ldp_label_release_send(g, s, ds_attr, LDP_NOTIF_LOOP_DETECTED) !=
740 MPLS_SUCCESS) { /* LMp.8 */
741 retval = MPLS_FAILURE;
743 goto LMp_33;
745 LMp_9:
747 * No Loop Detected
749 ds_temp = ldp_attr_find_downstream_state2(g, s, f, LDP_LSP_STATE_MAP_RECV);
750 if (requested == MPLS_BOOL_TRUE ||
751 g->label_merge == MPLS_BOOL_FALSE || !ds_temp) {
752 /* !merging then this is always a new LSP
753 * merging w/o a recv'd mapping is a new LSP
754 * this check comes from Note 6
756 goto LMp_11;
759 /* searching all recv'd attrs for matched mappings,
760 * stop after finding 1st match
762 if ((ds_list = ldp_attr_find_downstream_all2(g, s, f))) {
763 ds_temp = MPLS_LIST_HEAD(ds_list);
764 while (ds_temp) {
765 if (ds_temp->state == LDP_LSP_STATE_MAP_RECV) { /* LMp.9 */
766 if (ldp_attr_is_equal(ds_attr, ds_temp, LDP_ATTR_LABEL) ==
767 MPLS_BOOL_TRUE) { /* LMp.10 */
769 * this mapping matches an existing mapping, but it
770 * could contain updated attributes
772 update = ds_temp;
773 break;
774 } else {
776 * we have been given another label for the same FEC and we
777 * didn't request it, release it
779 LDP_PRINT(g->user_data, "LMp.10 dup without req\n");
780 goto LMp_32;
783 ds_temp = MPLS_LIST_NEXT(ds_list, ds_temp, _fs);
787 LMp_11:
789 * update ONLY has a value for updated label mapping
791 /* LMp.11 */
792 nh_session = ldp_get_next_hop_session_for_fec2(f);
795 * the following departs from the procedure, it allows for filtering
796 * of label mappings
798 * Are we configured to accept and INSTALL this mapping?
800 if (mpls_policy_import_check(g->user_data, &f->info, &f->info.nh) ==
801 MPLS_BOOL_FALSE) {
803 * policy has rejected it, store it away
805 if (update) {
806 ldp_attr2ldp_attr(ds_attr, update, LDP_ATTR_HOPCOUNT | LDP_ATTR_PATH |
807 LDP_ATTR_MSGID | LDP_ATTR_LSPID | LDP_ATTR_TRAFFIC);
808 /* JLEU free ds_attr? */
809 update->filtered = MPLS_BOOL_TRUE;
810 if (update->outlabel && update->outlabel->switching == MPLS_BOOL_TRUE) {
811 /* the mapping has been filtered, but the original wasn't? */
812 MPLS_ASSERT(0);
814 } else {
815 ds_attr->filtered = MPLS_BOOL_TRUE;
816 if (ldp_attr_insert_downstream(g, s, ds_attr) != MPLS_SUCCESS) {
817 retval = MPLS_FAILURE;
820 goto LMp_33;
823 /* LMp.12 */
824 if ((!f) || (!nh_session) || (nh_session->index != s->index)) {
826 * if we don't know about the route, or we don't have a next hop session,
827 * or the next hop session isn't the one who sent us the mapping ....
829 if (g->label_retention_mode == LDP_RETENTION_CONSERVATIVE) { /* LMp.13C */
830 LDP_PRINT(g->user_data, "LMp.13C conservative\n");
831 goto LMp_32;
835 * store it away
837 LDP_PRINT(g->user_data, "index: %3d %08x/%d %d\n", ds_attr->index,
838 ds_attr->fecTlv.fecElArray[0].addressEl.address,
839 ds_attr->fecTlv.fecElArray[0].addressEl.preLen, ds_attr->state);
841 if (update) {
842 ldp_attr2ldp_attr(ds_attr, update, LDP_ATTR_HOPCOUNT | LDP_ATTR_PATH |
843 LDP_ATTR_MSGID | LDP_ATTR_LSPID | LDP_ATTR_TRAFFIC);
844 /* JLEU free ds_attr? */
845 } else {
846 /* LMp.13L */
847 if (ldp_attr_insert_downstream(g, s, ds_attr) != MPLS_SUCCESS) {
848 retval = MPLS_FAILURE;
851 goto LMp_33;
855 * this is slightly different form the procedure, we can still be
856 * transit for a FEC we are not configured to be ingress for.
857 * Either way we only need to do the "install for fwd/switching"
858 * only once. We could arrive here multiple times due to updates,
859 * only install it the first time
861 if ((!update) || (!update->outlabel)) {
863 * we haven't installed it yet.
864 * Either new (!update), or a result of a "Detect FEC Nexthop Change"
865 * and we had this mapping in our database (!update->outlabel))
868 if (!(out = ldp_outlabel_create_complete(g, s, ds_attr))) {
869 LDP_PRINT(g->user_data, "LMp.15 failure creating outlabel\n");
870 goto LMp_32;
873 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_BINDING,
874 "Out Label Added\n");
878 * are we configured to act as ingress for this FEC?
880 if (mpls_policy_ingress_check(g->user_data, &f->info, &f->info.nh) ==
881 MPLS_BOOL_TRUE) { /* LMp.14 */
883 * yep, bind the label to the FEC
885 if (ds_attr->ingress != MPLS_BOOL_TRUE) {
886 #if MPLS_USE_LSR
887 lsr_ftn ftn;
888 ftn.outsegment_index = ds_attr->outlabel->info.handle;
889 memcpy(&ftn.fec, &f->info, sizeof(mpls_fec));
890 lsr_cfg_ftn_set2(g->lsr_handle, &ftn, LSR_CFG_ADD|LSR_FTN_CFG_FEC|
891 LSR_FTN_CFG_OUTSEGMENT);
892 #else
893 mpls_mpls_fec2out_add(g->mpls_handle, &f->info, &ds_attr->outlabel->info);
894 #endif
895 ds_attr->ingress = MPLS_BOOL_TRUE;
896 ds_attr->outlabel->merge_count++;
897 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_BINDING,
898 "FEC Binding Added\n");
902 /* create a set of attrs that we will fill and compare against
903 * if this mapping were to be propogate these are the attrs it would have
904 * by comparing what we did sent in the past to these, we con figure out
905 * if we need to send an updated mapping
907 memset(&dumb_attr, 0, sizeof(ldp_attr));
908 mpls_fec2fec_tlv(&f->info, &dumb_attr.fecTlv, 0);
909 dumb_attr.fecTlvExists = 1;
910 dumb_attr.fecTlv.numberFecElements = 1;
913 * by definition (we received a label mapping that will be used) this
914 * LSR is _not_ the egress, so calculate a hop and path based on the
915 * mapping we received. We will compare this with mapping that have
916 * already been sent. If they differ, we will send an updated mapping
918 Prepare_Label_Mapping_Attributes(g, s, &f->info, ds_attr, &dumb_attr,
919 MPLS_BOOL_TRUE, MPLS_BOOL_TRUE, MPLS_BOOL_FALSE);
921 if (!update) {
923 * this is the first time we've seen this mapping, add it to the database.
924 * all future updates will modify this entry in place
926 /* LMp.16 */
927 if (ldp_attr_insert_downstream(g, s, ds_attr) != MPLS_SUCCESS) {
928 retval = MPLS_FAILURE;
929 goto LMp_33;
933 #if 0
934 if (update) {
936 * this is an update, propogate update to all member of this LSP
938 us_temp = MPLS_LIST_HEAD(&ds_attr->us_attr_root);
939 while (us_temp) {
940 us_temp = MPLS_LIST_NEXT(&ds_attr->us_attr_root, us_temp, _ds_attr);
943 #endif
945 peer = MPLS_LIST_HEAD(&g->session);
946 while (peer) { /* LMp.17 */
948 if (peer->state != LDP_STATE_OPERATIONAL ||
949 peer->index == s->index) {
950 /* peer equals msg source */
951 goto next_peer;
954 /* check to see if a upstream mapping has been xc'd to this
955 * downstream mapping for this session. If so we need to propogate
956 * the attr changes (if any)
958 us_temp = MPLS_LIST_HEAD(&ds_attr->us_attr_root);
959 while (us_temp) {
960 if (us_temp->session->index == peer->index) {
961 break;
963 us_temp = MPLS_LIST_NEXT(&ds_attr->us_attr_root, us_temp, _ds_attr);
966 if (us_temp) { /* LMp.18 */
967 /* LMp.22 - 27 */
968 if ((us_list = ldp_attr_find_upstream_all2(g, peer, f))) {
969 us_temp = MPLS_LIST_HEAD(us_list);
970 while (us_temp) {
971 if (us_temp->state == LDP_LSP_STATE_MAP_SENT) {
972 /* LMp.23 */
973 if (ldp_attr_is_equal(us_temp, &dumb_attr,
974 LDP_ATTR_HOPCOUNT | LDP_ATTR_PATH) != MPLS_BOOL_TRUE) {
975 if (ldp_label_mapping_with_xc(g, us_temp->session, f, &us_temp,
976 ds_attr) != MPLS_SUCCESS) { /* LMp.24-26 */
977 retval = MPLS_FAILURE;
978 goto LMp_33;
982 us_temp = MPLS_LIST_NEXT(us_list, us_temp, _fs);
987 if ((peer->oper_distribution_mode == LDP_DISTRIBUTION_UNSOLICITED) &&
988 (g->lsp_control_mode == LDP_CONTROL_ORDERED)) { /* LMp.19 */
991 * if we're not merging and we have multiple ORDERED DU sessions,
992 * we will to start requesting labels after we propogate the mapping to
993 * the first peer
995 if (need_request == MPLS_BOOL_TRUE) {
996 if (ldp_attr_find_downstream_state2(g, peer, f,
997 LDP_LSP_STATE_REQ_SENT) == NULL) {
999 * we don't have a request for FEC to peer outstanding, make one
1001 ds_temp = NULL;
1002 if (ldp_label_request_for_xc(g, peer, &f->info, NULL, &ds_temp) !=
1003 MPLS_SUCCESS) {
1004 retval = MPLS_FAILURE;
1005 goto LMp_33;
1008 } else {
1010 * We're in DU more, either we're merging, or we're not merging and
1011 * this is the first peer we're propogating this mapping to
1013 /* LMp.20-21,30 */
1014 us_attr = NULL;
1015 if (ldp_label_mapping_with_xc(g, peer, f, &us_attr, ds_attr) !=
1016 MPLS_SUCCESS) {
1017 retval = MPLS_FAILURE;
1018 goto LMp_33;
1021 * if we're not merging, we will need to request a label for
1022 * the next DU peer
1024 if (g->label_merge == MPLS_BOOL_FALSE) {
1025 need_request = MPLS_BOOL_TRUE;
1030 /* LMp.28 */
1031 while ((us_temp = ldp_attr_find_upstream_state2(g, peer, f,
1032 LDP_LSP_STATE_REQ_RECV))) {
1034 if (peer->oper_distribution_mode == LDP_DISTRIBUTION_UNSOLICITED) {
1035 if (need_request == MPLS_BOOL_TRUE) {
1036 if (ldp_attr_find_downstream_state2(g, peer, f,
1037 LDP_LSP_STATE_REQ_SENT) == NULL) {
1039 * we don't have a request for FEC to peer outstanding
1041 ds_temp = NULL;
1042 if (ldp_label_request_for_xc(g, peer, &f->info, us_temp,
1043 &ds_temp) != MPLS_SUCCESS) {
1044 retval = MPLS_FAILURE;
1045 goto LMp_33;
1048 } else {
1049 if (ldp_label_mapping_with_xc(g, peer, f, &us_temp,
1050 ds_attr) != MPLS_SUCCESS) {
1051 retval = MPLS_FAILURE;
1052 goto LMp_33;
1055 } else {
1056 if ((us_list = ldp_attr_find_upstream_all2(g, peer, f))) {
1057 us_temp = MPLS_LIST_HEAD(ds_list);
1058 while (us_temp) {
1059 if (us_temp->state == LDP_LSP_STATE_REQ_RECV) {
1060 if (need_request == MPLS_BOOL_TRUE) {
1061 if (ldp_attr_find_downstream_state2(g, peer, f,
1062 LDP_LSP_STATE_REQ_SENT) == NULL) {
1064 * we don't have a request for FEC to peer outstanding
1066 ds_temp = NULL;
1067 if (ldp_label_request_for_xc(g, peer, &f->info, us_temp,
1068 &ds_temp) != MPLS_SUCCESS) {
1069 retval = MPLS_FAILURE;
1070 goto LMp_33;
1073 } else {
1074 if (ldp_label_mapping_with_xc(g, peer, f, &us_temp,
1075 ds_attr) != MPLS_SUCCESS) {
1076 retval = MPLS_FAILURE;
1077 goto LMp_33;
1080 * if we're not merging, we will need to request a label for
1081 * the next DU peer
1083 if (g->label_merge == MPLS_BOOL_FALSE) {
1084 need_request = MPLS_BOOL_TRUE;
1088 us_temp = MPLS_LIST_NEXT(us_list, us_temp, _fs);
1094 next_peer:
1095 peer = MPLS_LIST_NEXT(&g->session, peer, _global);
1098 LMp_33:
1099 LDP_EXIT(g->user_data, "ldp_label_mapping_process");
1100 return retval;
1102 LMp_32:
1103 LDP_PRINT(g->user_data, "Receive_Label_Map_32: send release");
1104 if (ldp_label_release_send(g, s, ds_attr, LDP_NOTIF_NONE) != MPLS_SUCCESS) {
1105 retval = MPLS_FAILURE;
1107 LDP_EXIT(g->user_data, "ldp_label_mapping_process");
1108 return retval;