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