If and when I implement RSVP-TE I need the naming scheme to make
[mpls-ldp-portable.git] / ldp / ldp_label_mapping.c
blob5ccefac55e07998837916b3fc507810647b848a4
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 mpls_fec * fec, ldp_attr ** us_attr, ldp_attr * ds_attr)
42 mpls_return_enum result;
43 mpls_bool propogating = MPLS_BOOL_TRUE;
46 MPLS_ASSERT(us_attr);
48 if (!(*us_attr)) {
49 if (!((*us_attr) = ldp_attr_create(fec))) {
50 return MPLS_FAILURE;
53 if (!ds_attr) {
54 propogating = MPLS_BOOL_FALSE;
57 Prepare_Label_Mapping_Attributes(g, s, fec, ds_attr, (*us_attr), propogating,
58 MPLS_BOOL_TRUE);
59 if (ldp_label_mapping_send(g, s, (*us_attr), ds_attr) != MPLS_SUCCESS) {
60 if ((*us_attr)->in_tree != MPLS_BOOL_TRUE) {
61 ldp_attr_delete(*us_attr);
63 return MPLS_FAILURE;
66 if (ds_attr && ds_attr->outlabel) {
68 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
69 LDP_TRACE_FLAG_BINDING, "Cross Connect Added\n");
71 result = ldp_inlabel_add_outlabel(g,(*us_attr)->inlabel,ds_attr->outlabel);
72 if (result != MPLS_SUCCESS) {
73 ldp_label_withdraw_send(g, s, (*us_attr), LDP_NOTIF_NONE);
74 return MPLS_FAILURE;
77 return MPLS_SUCCESS;
80 ldp_session *ldp_get_session_by_next_hop(ldp_global * g, mpls_nexthop * a,
81 ldp_addr ** next_hop)
83 ldp_addr *addr = NULL;
84 uint32_t key = 0;
86 if (a->type & MPLS_NH_IP) {
87 key = a->ip.u.ipv4;
88 } else if (a->type & MPLS_NH_IF) {
89 ldp_if *iff = ldp_global_find_if_handle(g, a->if_handle);
90 ldp_adj *a;
92 if (iff) {
93 /* JLEU if there is more then one session on this interface
94 then we're in trouble, just choose the first for now */
95 if (next_hop) {
96 *next_hop = NULL;
98 a = MPLS_LIST_HEAD(&iff->entity->adj_root);
99 return a->session;
101 } else {
102 MPLS_ASSERT(0);
105 if (mpls_tree_get(g->addr_tree, key, 32, (void **)&addr) == MPLS_SUCCESS) {
106 ldp_session *ses = NULL;
108 /* JLEU if there is more then one session that has given this address
109 then we're in trouble, just choose the first for now */
110 if ((ses = (ldp_session*)mpls_link_list_head_data(&addr->session_root))) {
111 if (next_hop) {
112 *next_hop = addr;
114 return ses;
117 return NULL;
120 mpls_return_enum ldp_get_next_hop_session_for_fec(ldp_global * g,
121 mpls_fec * fec, ldp_addr ** next_hop, ldp_session ** next_hop_session)
123 ldp_session *session = NULL;
124 ldp_addr *addr = NULL;
125 mpls_fec route;
127 if (next_hop_session) {
128 *next_hop_session = NULL;
130 if (next_hop) {
131 *next_hop = NULL;
134 if (mpls_fib_get_route(g->fib_handle, 1, fec, &route) != 1) {
135 /* JLEU: how to handle the multipath case */
136 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_NORMAL,
137 "No route to FEC (%08x/%d)\n", fec->u.prefix.network.u.ipv4,
138 fec->u.prefix.length);
139 return MPLS_NO_ROUTE;
142 if (route.nh.attached == MPLS_BOOL_TRUE) {
143 return MPLS_SUCCESS;
146 if (!(session = ldp_get_session_by_next_hop(g, &route.nh, &addr))) {
147 return MPLS_SUCCESS;
150 if (next_hop_session) {
151 *next_hop_session = session;
153 if (next_hop) {
154 *next_hop = addr;
156 return MPLS_SUCCESS;
159 mpls_return_enum Check_Received_Attributes(ldp_global * g, ldp_session * s,
160 ldp_attr * r_attr, uint16_t type)
162 int count = 0;
163 int i;
165 if (!r_attr->hopCountTlvExists) { /* CRa.1 */
166 goto Check_Received_Attributes_5;
169 if (r_attr->hopCountTlv.hcValue >= s->cfg_hop_count_limit) { /* CRa.2 */
170 LDP_PRINT(g->user_data, "CRa.2\n");
171 goto Check_Received_Attributes_6;
174 if (!r_attr->pathVecTlvExists) { /* CRa.3 */
175 goto Check_Received_Attributes_5;
178 for (i = 0; i < MPLS_MAXHOPSNUMBER; i++) { /* CRa.4 */
179 if (r_attr->pathVecTlv.lsrId[i]) {
180 count++;
181 if (r_attr->pathVecTlv.lsrId[i] == g->lsr_identifier.u.ipv4) {
182 goto Check_Received_Attributes_6;
183 LDP_PRINT(g->user_data, "CRa.4a\n");
185 if (count > s->oper_path_vector_limit) {
186 goto Check_Received_Attributes_6;
187 LDP_PRINT(g->user_data, "CRa.4b\n");
192 Check_Received_Attributes_5:
193 return MPLS_SUCCESS;
195 Check_Received_Attributes_6:
196 if (type != MPLS_LBLMAP_MSGTYPE) {
197 ldp_notif_send(g, s, r_attr, LDP_NOTIF_LOOP_DETECTED); /* CRa.7 */
199 return MPLS_FAILURE; /* CRa.8 */
202 void Prepare_Label_Mapping_Attributes(ldp_global * g, ldp_session * s,
203 mpls_fec * fec, ldp_attr * r_attr, ldp_attr * s_attr, mpls_bool propogating,
204 mpls_bool already)
206 ldp_attr dummy;
207 int i;
209 /* NOTE: PMpA.21 is the end of the procedure (ie return) */
210 /* this function uses goto quite extensivly for a REASON!! */
211 /* Check Appedix A of the LDP draft */
213 LDP_ENTER(g->user_data, "Prepare_Label_Mapping_Attributes");
215 if (r_attr == NULL) {
216 memset(&dummy, 0, sizeof(ldp_attr));
217 mpls_fec2fec_tlv(fec, &dummy.fecTlv, 0);
218 dummy.fecTlvExists = 1;
219 dummy.fecTlv.numberFecElements = 1;
220 r_attr = &dummy;
223 if (!(s->oper_loop_detection == LDP_LOOP_HOPCOUNT ||
224 s->oper_loop_detection == LDP_LOOP_HOPCOUNT_PATHVECTOR ||
225 r_attr->hopCountTlvExists)) { /* PMpA.1 */
226 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
227 return;
230 switch (ldp_get_next_hop_session_for_fec(g, fec, NULL, NULL)) { /* PMpA.2 */
231 case MPLS_SUCCESS:
233 break;
235 case MPLS_FAILURE:
237 /* I'm egress (for now) */
238 s_attr->hopCountTlvExists = 1;
239 s_attr->hopCountTlv.hcValue = 1; /* PMpA.3 */
240 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
241 return;
243 case MPLS_NO_ROUTE:
244 default:
246 break;
250 if (!(r_attr->hopCountTlvExists)) { /* PMpA.4 */
251 goto Prepare_Label_Mapping_Attributes_8;
254 if (!(g->ttl_less_domain == MPLS_BOOL_TRUE &&
255 s->cfg_remote_in_ttl_less_domain == MPLS_BOOL_TRUE)) { /* PMpA.5 */
256 goto Prepare_Label_Mapping_Attributes_7;
259 s_attr->hopCountTlvExists = 1;
260 s_attr->hopCountTlv.hcValue = 1; /* PMpA.6 */
261 goto Prepare_Label_Mapping_Attributes_9;
263 Prepare_Label_Mapping_Attributes_7:
264 s_attr->hopCountTlvExists = 1;
265 s_attr->hopCountTlv.hcValue = (r_attr->hopCountTlv.hcValue) ?
266 (r_attr->hopCountTlv.hcValue + 1) : 0;
267 goto Prepare_Label_Mapping_Attributes_9;
269 Prepare_Label_Mapping_Attributes_8:
270 s_attr->hopCountTlvExists = 1;
271 s_attr->hopCountTlv.hcValue = 0;
273 Prepare_Label_Mapping_Attributes_9:
274 if (s->oper_loop_detection == LDP_LOOP_NONE) {
275 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
276 return;
279 if (r_attr->pathVecTlvExists) { /* PMpA.10 */
280 goto Prepare_Label_Mapping_Attributes_19;
283 if (propogating == MPLS_BOOL_FALSE) { /* PMpA.11 */
284 goto Prepare_Label_Mapping_Attributes_20;
287 if (g->label_merge != MPLS_BOOL_TRUE) { /* PMpA.12 */
288 goto Prepare_Label_Mapping_Attributes_14;
291 if (already == MPLS_BOOL_FALSE) { /* PMpA.13 */
292 goto Prepare_Label_Mapping_Attributes_20;
295 Prepare_Label_Mapping_Attributes_14:
296 if (!r_attr->hopCountTlvExists) {
297 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
298 return;
301 if (r_attr->hopCountTlv.hcValue == 0) { /* PMpA.15 */
302 goto Prepare_Label_Mapping_Attributes_20;
305 if (already == MPLS_BOOL_FALSE) { /* PMpA.16 */
306 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
307 return;
310 /* r_attr contain PrevHopCount _IF_ we had one */
311 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
312 return; /* PMpA.17 */
314 if (r_attr->hopCountTlv.hcValue != 0) { /* PMpA.18 */
315 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
316 return;
319 Prepare_Label_Mapping_Attributes_19:
320 s_attr->pathVecTlvExists = 1;
321 s_attr->pathVecTlv.lsrId[0] = g->lsr_identifier.u.ipv4;
322 for (i = 1; i < (MPLS_MAXHOPSNUMBER - 1); i++) {
323 if (r_attr->pathVecTlv.lsrId[i - 1]) {
324 s_attr->pathVecTlv.lsrId[0] = r_attr->pathVecTlv.lsrId[i - 1];
328 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
329 return;
331 Prepare_Label_Mapping_Attributes_20:
332 s_attr->pathVecTlvExists = 1;
333 s_attr->pathVecTlv.lsrId[0] = g->lsr_identifier.u.ipv4;
335 LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes");
336 return;
339 void map2attr(mplsLdpLblMapMsg_t * map, ldp_attr * attr, uint32_t flag)
341 attr->msg_id = map->baseMsg.msgId;
343 if (map->fecTlvExists && flag & LDP_ATTR_FEC) {
344 memcpy(&attr->fecTlv, &map->fecTlv, sizeof(mplsLdpFecTlv_t));
345 attr->fecTlvExists = 1;
347 if (map->genLblTlvExists && flag & LDP_ATTR_LABEL) {
348 memcpy(&attr->genLblTlv, &map->genLblTlv, sizeof(mplsLdpGenLblTlv_t));
349 attr->genLblTlvExists = 1;
350 } else if (map->atmLblTlvExists && flag & LDP_ATTR_LABEL) {
351 memcpy(&attr->atmLblTlv, &map->atmLblTlv, sizeof(mplsLdpAtmLblTlv_t));
352 attr->atmLblTlvExists = 1;
353 } else if (map->frLblTlvExists && flag & LDP_ATTR_LABEL) {
354 memcpy(&attr->frLblTlv, &map->frLblTlv, sizeof(mplsLdpFrLblTlv_t));
355 attr->frLblTlvExists = 1;
357 if (map->hopCountTlvExists && flag & LDP_ATTR_HOPCOUNT) {
358 memcpy(&attr->hopCountTlv, &map->hopCountTlv, sizeof(mplsLdpHopTlv_t));
359 attr->hopCountTlvExists = 1;
361 if (map->pathVecTlvExists && flag & LDP_ATTR_PATH) {
362 memcpy(&attr->pathVecTlv, &map->pathVecTlv, sizeof(mplsLdpPathTlv_t));
363 attr->pathVecTlvExists = 1;
365 if (map->lblMsgIdTlvExists && flag & LDP_ATTR_MSGID) {
366 memcpy(&attr->lblMsgIdTlv, &map->lblMsgIdTlv, sizeof(mplsLdpLblMsgIdTlv_t));
367 attr->lblMsgIdTlvExists = 1;
369 if (map->lspidTlvExists && flag & LDP_ATTR_LSPID) {
370 memcpy(&attr->lspidTlv, &map->lspidTlv, sizeof(mplsLdpLspIdTlv_t));
371 attr->lspidTlvExists = 1;
373 if (map->trafficTlvExists && flag & LDP_ATTR_TRAFFIC) {
374 memcpy(&attr->trafficTlv, &map->trafficTlv, sizeof(mplsLdpTrafficTlv_t));
375 attr->trafficTlvExists = 1;
379 void attr2map(ldp_attr * attr, mplsLdpLblMapMsg_t * map)
381 if (attr->fecTlvExists) {
382 memcpy(&map->fecTlv, &attr->fecTlv, sizeof(mplsLdpFecTlv_t));
383 map->fecTlvExists = 1;
385 if (attr->genLblTlvExists) {
386 memcpy(&map->genLblTlv, &attr->genLblTlv, sizeof(mplsLdpGenLblTlv_t));
387 map->genLblTlvExists = 1;
389 if (attr->atmLblTlvExists) {
390 memcpy(&map->atmLblTlv, &attr->atmLblTlv, sizeof(mplsLdpAtmLblTlv_t));
391 map->atmLblTlvExists = 1;
393 if (attr->frLblTlvExists) {
394 memcpy(&map->frLblTlv, &attr->frLblTlv, sizeof(mplsLdpFrLblTlv_t));
395 map->frLblTlvExists = 1;
397 if (attr->hopCountTlvExists) {
398 memcpy(&map->hopCountTlv, &attr->hopCountTlv, sizeof(mplsLdpHopTlv_t));
399 map->hopCountTlvExists = 1;
401 if (attr->pathVecTlvExists) {
402 memcpy(&map->pathVecTlv, &attr->pathVecTlv, sizeof(mplsLdpPathTlv_t));
403 map->pathVecTlvExists = 1;
405 if (attr->lblMsgIdTlvExists) {
406 memcpy(&map->lblMsgIdTlv, &attr->lblMsgIdTlv, sizeof(mplsLdpLblMsgIdTlv_t));
407 map->lblMsgIdTlvExists = 1;
409 if (attr->lspidTlvExists) {
410 memcpy(&map->lspidTlv, &attr->lspidTlv, sizeof(mplsLdpLspIdTlv_t));
411 map->lspidTlvExists = 1;
413 if (attr->trafficTlvExists) {
414 memcpy(&map->trafficTlv, &attr->trafficTlv, sizeof(mplsLdpTrafficTlv_t));
415 map->trafficTlvExists = 1;
419 void ldp_label_mapping_initial_callback(mpls_timer_handle timer, void *extra,
420 mpls_cfg_handle handle)
422 ldp_session *s = (ldp_session *) extra;
423 ldp_global *g = (ldp_global*)handle;
424 ldp_attr *ds_attr = NULL;
425 ldp_attr *us_attr = NULL;
426 ldp_addr *nh_addr = NULL;
427 ldp_session *nh_session = NULL;
428 mpls_bool done = MPLS_BOOL_FALSE;
429 mpls_fec dest;
430 mpls_return_enum result;
432 LDP_ENTER(g->user_data, "ldp_label_mapping_initial_callback");
434 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_TIMER,
435 "Initial Label Mapping fired: session(%d)\n", s->index);
437 mpls_lock_get(g->global_lock);
439 mpls_timer_stop(g->timer_handle, timer);
441 if (mpls_fib_getfirst_route(g->fib_handle, &dest) == MPLS_SUCCESS) {
442 do {
444 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_ROUTE,
445 "Processing: %08x/%d ", dest.u.prefix.network.u.ipv4,
446 dest.u.prefix.length);
448 if (dest.nh.type & MPLS_NH_IP) {
449 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
450 LDP_TRACE_FLAG_ROUTE, "via %08x\n", dest.nh.ip.u.ipv4);
451 } else if (dest.nh.type & MPLS_NH_IF) {
452 struct ldp_if *iff = ldp_global_find_if_handle(g,dest.nh.if_handle);
453 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL,
454 LDP_TRACE_FLAG_ROUTE, "via %s\n",
455 iff ? iff->name : "(not an LDP interface)\n");
456 } else {
457 MPLS_ASSERT(0);
460 /* are we allowed to export this route from the rib */
461 if (mpls_policy_export_check(g->user_data, &dest, &dest.nh) ==
462 MPLS_BOOL_FALSE) {
463 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_POLICY,
464 "Rejected by export policy\n");
465 continue;
468 /* have we already sent a mapping for this fec to the new session? */
469 if ((us_attr = ldp_attr_find_upstream_state(g, s, &dest,
470 LDP_LSP_STATE_MAP_SENT))) {
471 /* no need to sent another mapping */
472 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_ROUTE,
473 "Already sent this FEC to session %d\n", s->index);
474 continue;
477 result = ldp_get_next_hop_session_for_fec(g,&dest,&nh_addr,&nh_session);
478 if (result != MPLS_SUCCESS || !nh_session) {
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_state(g, nh_session, &dest,
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, &dest, &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, &dest, &dest.nh) ==
506 MPLS_BOOL_TRUE) {
507 ldp_label_mapping_with_xc(g, s, &dest, &us_attr, NULL);
509 } else {
510 ldp_label_mapping_with_xc(g, s, &dest, &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, &dest, us_attr, &ds_attr);
521 #endif
523 } while (mpls_fib_getnext_route(g->fib_handle, &dest) == MPLS_SUCCESS);
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;
548 mpls_fec fec;
550 LDP_ENTER(g->user_data, "ldp_label_mapping_send");
551 MPLS_ASSERT(us_attr);
553 fec_tlv2mpls_fec(&us_attr->fecTlv, 0, &fec);
555 if ((in = ldp_inlabel_create_complete(g, s, us_attr)) == NULL) { /* SL.1-3 */
556 goto Send_Label_9;
559 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_BINDING,
560 "In Label Added\n");
562 us_attr->state = LDP_LSP_STATE_MAP_SENT;
564 us_attr->msg_id = g->message_identifier;
565 ldp_label_mapping_prepare_msg(s->tx_message, g->message_identifier++,
566 us_attr);
568 if (us_attr->in_tree == MPLS_BOOL_FALSE &&
569 ldp_attr_insert_upstream(g, s, us_attr) != MPLS_SUCCESS) { /* SL.5 */
570 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_SEND, LDP_TRACE_FLAG_ERROR,
571 "Couldn't insert sent attributes in tree\n");
572 goto ldp_label_mapping_send_error;
575 if (ldp_mesg_send_tcp(g, s, s->tx_message) != MPLS_SUCCESS) { /* SL.4 */
576 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_SEND, LDP_TRACE_FLAG_ERROR,
577 "Failed sending Label Mapping to %s\n",
578 s->session_name);
579 goto ldp_label_mapping_send_error;
582 ldp_attr_add_us2ds(us_attr, ds_attr);
584 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_SEND, LDP_TRACE_FLAG_LABEL,
585 "Label Mapping Sent to %s for %08x/%d\n",
586 s->session_name,
587 us_attr->fecTlv.fecElArray[0].addressEl.address,
588 us_attr->fecTlv.fecElArray[0].addressEl.preLen);
590 us_attr->state = LDP_LSP_STATE_MAP_SENT; /* SL.6,7 */
592 LDP_EXIT(g->user_data, "ldp_label_mapping_send");
593 return MPLS_SUCCESS; /* SL.8 */
595 Send_Label_9:
596 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_STATE,
597 "No Label Resources\n");
599 while ((us_temp = ldp_attr_find_upstream_state(g, s, &fec,
600 LDP_LSP_STATE_REQ_RECV)) != NULL) { /* SL.9 */
601 ldp_notif_send(g, s, us_temp, LDP_NOTIF_NO_LABEL_RESOURCES_AVAILABLE);
602 /* SL.10 */
603 s->no_label_resource_sent = MPLS_BOOL_TRUE; /* SL.12 */
604 us_temp->state = LDP_LSP_STATE_NO_LABEL_RESOURCE_SENT; /* SL.13 */
607 LDP_EXIT(g->user_data, "ldp_label_mapping_send");
609 return MPLS_SUCCESS;
611 ldp_label_mapping_send_error:
613 LDP_EXIT(g->user_data, "ldp_label_mapping_send-error");
614 return MPLS_FAILURE;
617 void ldp_label_mapping_prepare_msg(ldp_mesg * msg, uint32_t msgid,
618 ldp_attr * s_attr)
620 mplsLdpLblMapMsg_t *map = NULL;
621 int i;
623 MPLS_ASSERT(msg);
625 ldp_mesg_prepare(msg, MPLS_LBLMAP_MSGTYPE, msgid);
626 map = &msg->u.map;
628 if (s_attr->fecTlvExists) {
629 /* JLEU: only 1 FEC is allowed!! */
630 map->fecTlvExists = 1;
631 map->baseMsg.msgLength += setupFecTlv(&map->fecTlv);
632 map->baseMsg.msgLength += addFecElem2FecTlv(&map->fecTlv,
633 &s_attr->fecTlv.fecElArray[0]);
635 if (s_attr->genLblTlvExists) {
636 map->genLblTlvExists = 1;
637 map->baseMsg.msgLength += setupGenLblTlv(&map->genLblTlv,
638 s_attr->genLblTlv.label);
640 if (s_attr->atmLblTlvExists) {
641 map->atmLblTlvExists = 1;
642 map->baseMsg.msgLength += setupAtmLblTlv(&map->atmLblTlv, 0, 0,
643 s_attr->atmLblTlv.flags.flags.vpi, s_attr->atmLblTlv.vci);
645 if (s_attr->frLblTlvExists) {
646 map->frLblTlvExists = 1;
647 map->baseMsg.msgLength += setupFrLblTlv(&map->frLblTlv, 0,
648 s_attr->frLblTlv.flags.flags.len, s_attr->frLblTlv.flags.flags.dlci);
650 if (s_attr->hopCountTlvExists) {
651 map->hopCountTlvExists = 1;
652 map->baseMsg.msgLength += setupHopCountTlv(&map->hopCountTlv,
653 s_attr->hopCountTlv.hcValue);
655 if (s_attr->pathVecTlvExists) {
656 map->pathVecTlvExists = 1;
657 map->baseMsg.msgLength += setupPathTlv(&map->pathVecTlv);
658 for (i = 0; i < MPLS_MAXHOPSNUMBER; i++) {
659 if (s_attr->pathVecTlv.lsrId[i]) {
660 map->baseMsg.msgLength += addLsrId2PathTlv(&map->pathVecTlv,
661 s_attr->pathVecTlv.lsrId[i]);
665 #if 0
666 if (s_attr->lblMsgIdTlvExists) {
668 if (s_attr->lspidTlvExists) {
670 if (s_attr->trafficTlvExists) {
672 #endif
675 mpls_return_enum ldp_label_mapping_process(ldp_global * g, ldp_session * s,
676 ldp_adj * a, ldp_entity * e, ldp_attr * r_attr, mpls_fec * fec)
678 mpls_return_enum retval = MPLS_SUCCESS;
679 ldp_session *nh_session = NULL;
680 ldp_session *peer = NULL;
681 ldp_attr_list *us_list = NULL;
682 ldp_attr_list *ds_list = NULL;
683 ldp_attr *ds_attr = NULL;
684 ldp_attr *ds_temp = NULL;
685 ldp_attr *us_attr = NULL;
686 ldp_attr *us_temp = NULL;
687 ldp_attr dumb_attr;
689 ldp_outlabel *out = NULL;
690 ldp_addr *nh_addr = NULL;
691 mpls_bool requested = MPLS_BOOL_FALSE;
692 ldp_attr *update = NULL;
693 mpls_bool need_request = MPLS_BOOL_FALSE;
694 mpls_return_enum result;
696 LDP_ENTER(g->user_data, "ldp_label_mapping_process");
698 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV, LDP_TRACE_FLAG_LABEL,
699 "Label Mapping Recv from %s for %08x/%d\n",
700 s->session_name,
701 r_attr->fecTlv.fecElArray[0].addressEl.address,
702 r_attr->fecTlv.fecElArray[0].addressEl.preLen);
704 if ((ds_attr = ldp_attr_find_downstream_state(g, s, fec,
705 LDP_LSP_STATE_REQ_SENT)) != NULL) { /* LMp.1 */
706 /* just remove the req from the tree, we will use the r_attr sent to us */
707 ldp_attr_delete_downstream(g, s, ds_attr);
708 requested = MPLS_BOOL_TRUE;
709 } else {
710 requested = MPLS_BOOL_FALSE;
713 ds_attr = r_attr;
714 ds_attr->state = LDP_LSP_STATE_MAP_RECV; /* LMp.2 */
717 * ds_attr is the mapping we will keep and is NOT in the tree, unless
718 * it is an update mapping ...
720 if (Check_Received_Attributes(g, s, ds_attr, MPLS_LBLMAP_MSGTYPE) ==
721 MPLS_SUCCESS) { /* LMp.3 */
722 goto LMp_9;
726 * A loop was detected
728 if ((ds_list = ldp_attr_find_downstream_all(g, s, fec))) {
729 ds_temp = MPLS_LIST_HEAD(ds_list);
731 * check all the labels this session has received from "s" for "fec"
732 * do we have a duplicat?
734 while (ds_temp) {
735 if ((ds_temp->state == LDP_LSP_STATE_MAP_RECV) && /* LMp.4 */
736 ldp_attr_is_equal(ds_temp, ds_attr, LDP_ATTR_LABEL) == /* LMp.5 */
737 MPLS_BOOL_TRUE) {
738 /* remove record of the label and remove it switching */
739 ldp_attr_remove_complete(g, ds_temp, MPLS_BOOL_TRUE); /* LMp.6,7 */
741 * I think this is supposed to be 32 NOT 33, we need to release
742 * it don't we?
744 goto LMp_33;
746 ds_temp = MPLS_LIST_NEXT(ds_list, ds_temp, _fs);
750 LDP_PRINT(g->user_data, "Receive_Label_Map_8: send release");
751 if (ldp_label_release_send(g, s, ds_attr, LDP_NOTIF_LOOP_DETECTED) !=
752 MPLS_SUCCESS) { /* LMp.8 */
753 retval = MPLS_FAILURE;
755 goto LMp_33;
757 LMp_9:
759 * No Loop Detected
761 ds_temp = ldp_attr_find_downstream_state(g, s, fec, LDP_LSP_STATE_MAP_RECV);
762 if (requested == MPLS_BOOL_TRUE ||
763 g->label_merge == MPLS_BOOL_FALSE || !ds_temp) {
764 /* !merging then this is always a new LSP
765 * merging w/o a recv'd mapping is a new LSP
766 * this check comes from Note 6
768 goto LMp_11;
771 /* searching all recv'd attrs for matched mappings,
772 * stop after finding 1st match
774 if ((ds_list = ldp_attr_find_downstream_all(g, s, fec))) {
775 ds_temp = MPLS_LIST_HEAD(ds_list);
776 while (ds_temp) {
777 if (ds_temp->state == LDP_LSP_STATE_MAP_RECV) { /* LMp.9 */
778 if (ldp_attr_is_equal(ds_attr, ds_temp, LDP_ATTR_LABEL) ==
779 MPLS_BOOL_TRUE) { /* LMp.10 */
781 * this mapping matches an existing mapping, but it
782 * could contain updated attributes
784 update = ds_temp;
785 break;
786 } else {
788 * we have been given another label for the same FEC and we
789 * didn't request it, release it
791 LDP_PRINT(g->user_data, "LMp.10 dup without req\n");
792 goto LMp_32;
795 ds_temp = MPLS_LIST_NEXT(ds_list, ds_temp, _fs);
799 LMp_11:
801 * update ONLY has a value for updated label mapping
803 /* LMp.11 */
804 result = ldp_get_next_hop_session_for_fec(g, fec, &nh_addr, &nh_session);
807 * the following departs from the procedure, it allows for filtering
808 * of label mappings
810 * Are we configured to accept and INSTALL this mapping?
812 if (mpls_policy_import_check(g->user_data, fec, &fec->nh) ==
813 MPLS_BOOL_FALSE) {
815 * policy has rejected it, store it away
817 if (update) {
818 ldp_attr2ldp_attr(ds_attr, update, LDP_ATTR_HOPCOUNT | LDP_ATTR_PATH |
819 LDP_ATTR_MSGID | LDP_ATTR_LSPID | LDP_ATTR_TRAFFIC);
820 /* JLEU free ds_attr? */
821 update->filtered = MPLS_BOOL_TRUE;
822 if (update->outlabel && update->outlabel->switching == MPLS_BOOL_TRUE) {
823 /* the mapping has been filtered, but the original wasn't? */
824 MPLS_ASSERT(0);
826 } else {
827 ds_attr->filtered = MPLS_BOOL_TRUE;
828 if (ldp_attr_insert_downstream(g, s, ds_attr) != MPLS_SUCCESS) {
829 retval = MPLS_FAILURE;
832 goto LMp_33;
835 /* LMp.12 */
836 if (result != MPLS_SUCCESS || !nh_session || nh_session->index != s->index) {
838 * if we don't know about the route, or the next hop isn't a peer,
839 * or if the next hop isn't the one who sent us the mapping ....
841 if (g->label_retention_mode == LDP_RETENTION_CONSERVATIVE) { /* LMp.13C */
842 LDP_PRINT(g->user_data, "LMp.13C conservative\n");
843 goto LMp_32;
847 * store it away
849 LDP_PRINT(g->user_data, "index: %3d %08x/%d %d\n", ds_attr->index,
850 ds_attr->fecTlv.fecElArray[0].addressEl.address,
851 ds_attr->fecTlv.fecElArray[0].addressEl.preLen, ds_attr->state);
853 if (update) {
854 ldp_attr2ldp_attr(ds_attr, update, LDP_ATTR_HOPCOUNT | LDP_ATTR_PATH |
855 LDP_ATTR_MSGID | LDP_ATTR_LSPID | LDP_ATTR_TRAFFIC);
856 /* JLEU free ds_attr? */
857 } else {
858 /* LMp.13L */
859 if (ldp_attr_insert_downstream(g, s, ds_attr) != MPLS_SUCCESS) {
860 retval = MPLS_FAILURE;
863 goto LMp_33;
867 * this is slightly different form the procedure, we can still be
868 * transit for a FEC we are not configured to be ingress for.
869 * Either way we only need to do the "install for fwd/switching"
870 * only once. We could arrive here multiple times due to updates,
871 * only install it the first time
873 if ((!update) || (!update->outlabel)) {
875 * we haven't installed it yet.
876 * Either new (!update), or a result of a "Detect FEC Nexthop Change"
877 * and we had this mapping in our database (!update->outlabel))
880 if (!(out = ldp_outlabel_create_complete(g, s, nh_addr, ds_attr))) {
881 LDP_PRINT(g->user_data, "LMp.15 failure creating outlabel\n");
882 goto LMp_32;
885 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_BINDING,
886 "Out Label Added\n");
890 * are we configured to act as ingress for this FEC?
892 if (mpls_policy_ingress_check(g->user_data, fec, &fec->nh) ==
893 MPLS_BOOL_TRUE) { /* LMp.14 */
895 * yep, bind the label to the FEC
897 if (ds_attr->ingress != MPLS_BOOL_TRUE) {
898 #if MPLS_USE_LSR
899 lsr_ftn ftn;
900 ftn.outsegment_index = ds_attr->outlabel->info.handle;
901 memcpy(&ftn.fec, fec, sizeof(mpls_fec));
902 lsr_cfg_ftn_set2(g->lsr_handle, &ftn, LSR_CFG_ADD|LSR_FTN_CFG_FEC|
903 LSR_FTN_CFG_OUTSEGMENT);
904 #else
905 mpls_mpls_fec2out_add(g->mpls_handle, fec, &ds_attr->outlabel->info);
906 #endif
907 ds_attr->ingress = MPLS_BOOL_TRUE;
908 ds_attr->outlabel->merge_count++;
909 LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_BINDING,
910 "FEC Binding Added\n");
914 /* create a set of attrs that we will fill and compare against
915 * if this mapping were to be propogate these are the attrs it would have
916 * by comparing what we did sent in the past to these, we con figure out
917 * if we need to send an updated mapping
919 memset(&dumb_attr, 0, sizeof(ldp_attr));
920 mpls_fec2fec_tlv(fec, &dumb_attr.fecTlv, 0);
921 dumb_attr.fecTlvExists = 1;
922 dumb_attr.fecTlv.numberFecElements = 1;
924 Prepare_Label_Mapping_Attributes(g, s, fec, ds_attr, &dumb_attr,
925 MPLS_BOOL_TRUE, MPLS_BOOL_TRUE);
927 if (!update) {
929 * this is the first time we've seen this mapping, add it to the database.
930 * all future updates will modify this entry in place
932 /* LMp.16 */
933 if (ldp_attr_insert_downstream(g, s, ds_attr) != MPLS_SUCCESS) {
934 retval = MPLS_FAILURE;
935 goto LMp_33;
939 #if 0
940 if (update) {
942 * this is an update, propogate update to all member of this LSP
944 us_temp = MPLS_LIST_HEAD(&ds_attr->us_attr_root);
945 while (us_temp) {
946 us_temp = MPLS_LIST_NEXT(&ds_attr->us_attr_root, us_temp, _ds_attr);
949 #endif
951 peer = MPLS_LIST_HEAD(&g->session);
952 while (peer) { /* LMp.17 */
954 if (peer->state != LDP_STATE_OPERATIONAL ||
955 peer->index == s->index) {
956 /* peer equals msg source */
957 goto next_peer;
960 /* check to see if a upstream mapping has been xc'd to this
961 * downstream mapping for this session. If so we need to propogate
962 * the attr changes (if any)
964 us_temp = MPLS_LIST_HEAD(&ds_attr->us_attr_root);
965 while (us_temp) {
966 if (us_temp->session->index == peer->index) {
967 break;
969 us_temp = MPLS_LIST_NEXT(&ds_attr->us_attr_root, us_temp, _ds_attr);
972 if (us_temp) { /* LMp.18 */
973 /* LMp.22 - 27 */
974 if ((us_list = ldp_attr_find_upstream_all(g, peer, fec))) {
975 us_temp = MPLS_LIST_HEAD(us_list);
976 while (us_temp) {
977 if (us_temp->state == LDP_LSP_STATE_MAP_SENT) {
978 /* LMp.23 */
979 if (ldp_attr_is_equal(us_temp, &dumb_attr,
980 LDP_ATTR_HOPCOUNT | LDP_ATTR_PATH) != MPLS_BOOL_TRUE) {
981 if (ldp_label_mapping_with_xc(g, us_temp->session, fec, &us_temp,
982 ds_attr) != MPLS_SUCCESS) { /* LMp.24-26 */
983 retval = MPLS_FAILURE;
984 goto LMp_33;
988 us_temp = MPLS_LIST_NEXT(us_list, us_temp, _fs);
993 if ((peer->oper_distribution_mode == LDP_DISTRIBUTION_UNSOLICITED) &&
994 (g->lsp_control_mode == LDP_CONTROL_ORDERED)) { /* LMp.19 */
997 * if we're not merging and we have multiple ORDERED DU sessions,
998 * we will to start requesting labels after we propogate the mapping to
999 * the first peer
1001 if (need_request == MPLS_BOOL_TRUE) {
1002 if (ldp_attr_find_downstream_state(g, peer, fec,
1003 LDP_LSP_STATE_REQ_SENT) == NULL) {
1005 * we don't have a request for FEC to peer outstanding, make one
1007 ds_temp = NULL;
1008 if (ldp_label_request_for_xc(g, peer, fec, NULL, &ds_temp) !=
1009 MPLS_SUCCESS) {
1010 retval = MPLS_FAILURE;
1011 goto LMp_33;
1014 } else {
1016 * We're in DU more, either we're merging, or we're not merging and
1017 * this is the first peer we're propogating this mapping to
1019 /* LMp.20-21,30 */
1020 us_attr = NULL;
1021 if (ldp_label_mapping_with_xc(g, peer, fec, &us_attr, ds_attr) !=
1022 MPLS_SUCCESS) {
1023 retval = MPLS_FAILURE;
1024 goto LMp_33;
1027 * if we're not merging, we will need to request a label for
1028 * the next DU peer
1030 if (g->label_merge == MPLS_BOOL_FALSE) {
1031 need_request = MPLS_BOOL_TRUE;
1036 /* LMp.28 */
1037 while ((us_temp = ldp_attr_find_upstream_state(g, peer, fec,
1038 LDP_LSP_STATE_REQ_RECV))) {
1040 if (peer->oper_distribution_mode == LDP_DISTRIBUTION_UNSOLICITED) {
1041 if (need_request == MPLS_BOOL_TRUE) {
1042 if (ldp_attr_find_downstream_state(g, peer, fec,
1043 LDP_LSP_STATE_REQ_SENT) == NULL) {
1045 * we don't have a request for FEC to peer outstanding
1047 ds_temp = NULL;
1048 if (ldp_label_request_for_xc(g, peer, fec, us_temp,
1049 &ds_temp) != MPLS_SUCCESS) {
1050 retval = MPLS_FAILURE;
1051 goto LMp_33;
1054 } else {
1055 if (ldp_label_mapping_with_xc(g, peer, fec, &us_temp,
1056 ds_attr) != MPLS_SUCCESS) {
1057 retval = MPLS_FAILURE;
1058 goto LMp_33;
1061 } else {
1062 if ((us_list = ldp_attr_find_upstream_all(g, peer, fec))) {
1063 us_temp = MPLS_LIST_HEAD(ds_list);
1064 while (us_temp) {
1065 if (us_temp->state == LDP_LSP_STATE_REQ_RECV) {
1066 if (need_request == MPLS_BOOL_TRUE) {
1067 if (ldp_attr_find_downstream_state(g, peer, fec,
1068 LDP_LSP_STATE_REQ_SENT) == NULL) {
1070 * we don't have a request for FEC to peer outstanding
1072 ds_temp = NULL;
1073 if (ldp_label_request_for_xc(g, peer, fec, us_temp,
1074 &ds_temp) != MPLS_SUCCESS) {
1075 retval = MPLS_FAILURE;
1076 goto LMp_33;
1079 } else {
1080 if (ldp_label_mapping_with_xc(g, peer, fec, &us_temp,
1081 ds_attr) != MPLS_SUCCESS) {
1082 retval = MPLS_FAILURE;
1083 goto LMp_33;
1086 * if we're not merging, we will need to request a label for
1087 * the next DU peer
1089 if (g->label_merge == MPLS_BOOL_FALSE) {
1090 need_request = MPLS_BOOL_TRUE;
1094 us_temp = MPLS_LIST_NEXT(us_list, us_temp, _fs);
1100 next_peer:
1101 peer = MPLS_LIST_NEXT(&g->session, peer, _global);
1104 LMp_33:
1105 LDP_EXIT(g->user_data, "ldp_label_mapping_process");
1106 return retval;
1108 LMp_32:
1109 LDP_PRINT(g->user_data, "Receive_Label_Map_32: send release");
1110 if (ldp_label_release_send(g, s, ds_attr, LDP_NOTIF_NONE) != MPLS_SUCCESS) {
1111 retval = MPLS_FAILURE;
1113 LDP_EXIT(g->user_data, "ldp_label_mapping_process");
1114 return retval;