Convert to a generic FEC handling architecture. Part of this change
[mpls-ldp-portable.git] / ldp / ldp_fec.c
blobc9aff15b26346a57c82e6756d06664ee0a4e2fba
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_fec.h"
12 #include "ldp_if.h"
13 #include "ldp_attr.h"
14 #include "ldp_addr.h"
15 #include "ldp_session.h"
16 #include "ldp_inlabel.h"
17 #include "ldp_outlabel.h"
18 #include "ldp_global.h"
19 #include "ldp_label_mapping.h"
20 #include "ldp_label_request.h"
21 #include "ldp_label_abort.h"
22 #include "ldp_label_rel_with.h"
23 #include "mpls_mm_impl.h"
24 #include "mpls_tree_impl.h"
25 #include "mpls_policy_impl.h"
26 #include "mpls_trace_impl.h"
28 #if MPLS_USE_LSR
29 #include "lsr_cfg.h"
30 #else
31 #include "mpls_mpls_impl.h"
32 #endif
34 static uint32_t _ldp_fec_next_index = 1;
35 static uint32_t _ldp_fec_get_next_index();
37 ldp_fec *ldp_fec_find(ldp_global *g, mpls_fec *fec)
39 ldp_fec *f = NULL;
40 uint32_t key;
41 uint8_t len;
43 switch(fec->type) {
44 case MPLS_FEC_PREFIX:
45 key = fec->u.prefix.network.u.ipv4;
46 len = fec->u.prefix.length;
47 break;
48 case MPLS_FEC_HOST:
49 key = fec->u.host.u.ipv4;
50 len = 32;
51 case MPLS_FEC_L2CC:
52 if (ldp_global_find_fec(g, fec, &f) == MPLS_SUCCESS) {
53 return f;
55 return NULL;
56 default:
57 MPLS_ASSERT(0);
60 if (mpls_tree_get(g->fec_tree, key, len, (void **)&f) != MPLS_SUCCESS) {
61 return NULL;
63 return f;
66 mpls_return_enum ldp_fec_insert2(ldp_global *g, ldp_fec * fec)
68 uint32_t key;
69 uint8_t len;
71 /* if this fec has a IP nexthop link it to the corresponding addr node */
72 if (fec->info.nh.type & MPLS_NH_IP) {
73 ldp_addr *addr = NULL;
74 if (!(addr = ldp_addr_find(g, &fec->info.nh.ip))) {
75 /* one does not exit, create it */
76 if (!(addr = ldp_addr_insert(g, &fec->info.nh.ip))) {
77 /* couldn't create, clean up */
78 goto ldp_fec_insert2_error;
82 /* we have a fec and a addr, bind them */
83 ldp_addr_add_fec(addr, fec);
87 if (fec->info.nh.type & MPLS_NH_IF) {
88 ldp_if *iff = NULL;
89 if (!(iff = ldp_global_find_if_handle(g, fec->info.nh.if_handle))) {
90 /* one does not exit create a place holder */
91 if (!(iff = ldp_if_insert(g, fec->info.nh.if_handle))) {
92 /* couldn't create, clean up */
93 goto ldp_fec_insert2_error;
97 /* we have a interface and a fec, bind them */
98 ldp_if_add_fec(iff, fec);
101 if (fec->info.nh.type & MPLS_NH_OUTSEGMENT) {
102 ldp_outlabel *out = NULL;
103 MPLS_ASSERT((out = ldp_global_find_outlabel_handle(g,
104 fec->info.nh.outsegment_handle)));
106 /* we have an outlabel and a fec, bind them */
107 ldp_outlabel_add_fec(out, fec);
110 switch(fec->info.type) {
111 case MPLS_FEC_PREFIX:
112 key = fec->info.u.prefix.network.u.ipv4;
113 len = fec->info.u.prefix.length;
114 break;
115 case MPLS_FEC_HOST:
116 key = fec->info.u.host.u.ipv4;
117 len = 32;
118 case MPLS_FEC_L2CC:
119 /* they had better insert it into the global tree */
120 return MPLS_SUCCESS;
121 default:
122 MPLS_ASSERT(0);
125 /* hold it since it is going in the tree */
126 MPLS_REFCNT_HOLD(fec);
128 if (mpls_tree_insert(g->fec_tree, key, len, (void *)fec) != MPLS_SUCCESS) {
129 LDP_PRINT(g->user_data, "ldp_fec_insert: error adding addr\n");
131 /* delete the refcnt we just took */
132 MPLS_REFCNT_RELEASE(fec, ldp_fec_delete);
133 goto ldp_fec_insert2_error;
135 return MPLS_SUCCESS;
137 ldp_fec_insert2_error:
138 return MPLS_FATAL;
141 ldp_fec *ldp_fec_insert(ldp_global *g, mpls_fec * fec)
143 ldp_fec *f = NULL;
145 if ((f = ldp_fec_create()) == NULL) {
146 LDP_PRINT(g->user_data, "ldp_fec_insert: error creating address\n");
147 return NULL;
150 mpls_fec2ldp_fec(fec,f);
152 MPLS_REFCNT_HOLD(f);
154 if (ldp_fec_insert2(g,f) != MPLS_SUCCESS) {
155 MPLS_REFCNT_RELEASE(f, ldp_fec_delete);
156 return NULL;
158 return f;
161 void ldp_fec_remove(ldp_global *g, mpls_fec *fec)
163 ldp_fec *f = NULL;
164 uint32_t key;
165 uint8_t len;
167 switch(fec->type) {
168 case MPLS_FEC_PREFIX:
169 key = fec->u.prefix.network.u.ipv4;
170 len = fec->u.prefix.length;
171 break;
172 case MPLS_FEC_HOST:
173 key = fec->u.host.u.ipv4;
174 len = 32;
175 case MPLS_FEC_L2CC:
176 /* they had better remove it from the global tree */
177 return;
178 default:
179 MPLS_ASSERT(0);
182 mpls_tree_remove(g->fec_tree, key, len, (void **)&f);
183 if (!f) {
184 return;
186 MPLS_REFCNT_RELEASE(f, ldp_fec_delete);
188 /* if this fec has a IP nexthop unlink it from the corresponding addr node */
189 if (f->info.nh.type & MPLS_NH_IP) {
190 ldp_addr_del_fec(f->addr, f);
192 if (f->info.nh.type & MPLS_NH_IF) {
193 ldp_if_del_fec(f->iff, f);
195 if (f->info.nh.type & MPLS_NH_OUTSEGMENT) {
199 mpls_bool ldp_fec_empty(ldp_fec *fec)
201 if (MPLS_LIST_EMPTY(&fec->fs_root_us) &&
202 MPLS_LIST_EMPTY(&fec->fs_root_ds)) {
203 return MPLS_BOOL_TRUE;
205 return MPLS_BOOL_FALSE;
208 void ldp_fec_add_if(ldp_fec * f, ldp_if * i)
210 MPLS_ASSERT(f && i);
211 MPLS_REFCNT_HOLD(i);
212 f->nh.iff = i;
213 f->nh.type |= MPLS_NH_IF;
216 void ldp_fec_del_if(ldp_fec * f)
218 MPLS_ASSERT(f);
219 MPLS_REFCNT_RELEASE(f->nh.iff, ldp_if_delete);
220 f->nh.iff = NULL;
221 f->nh.type &= ~MPLS_NH_IF;
224 void ldp_fec_add_addr(ldp_fec * f, ldp_addr * a)
226 MPLS_ASSERT(f && a);
227 MPLS_REFCNT_HOLD(a);
228 f->nh.addr = a;
229 f->nh.type |= MPLS_NH_IP;
232 void ldp_fec_del_addr(ldp_fec * f)
234 MPLS_ASSERT(f);
235 MPLS_REFCNT_RELEASE(f->nh.addr, ldp_addr_delete);
236 f->nh.addr = NULL;
237 f->nh.type &= ~MPLS_NH_IP;
240 void ldp_fec_add_outlabel(ldp_fec * f, ldp_outlabel * o)
242 MPLS_ASSERT(f && o);
243 MPLS_REFCNT_HOLD(o);
244 f->nh.outlabel = o;
245 f->nh.type |= MPLS_NH_OUTSEGMENT;
248 void ldp_fec_del_outlabel(ldp_fec * f)
250 MPLS_ASSERT(f);
251 MPLS_REFCNT_RELEASE(f->nh.outlabel, ldp_outlabel_delete);
252 f->nh.outlabel = NULL;
253 f->nh.type &= ~MPLS_NH_OUTSEGMENT;
256 #if 0
257 void ldp_fec_add_nexthop(ldp_fec * f, ldp_nexthop * nh)
259 MPLS_ASSERT(f && nh);
261 if (nh->type & MPLS_NH_IP) {
262 MPLS_REFCNT_HOLD(nh->addr);
263 f->nh.addr = nh->addr;
264 f->nh.type |= MPLS_NH_IP;
265 memcpy(&f->info.nexthop.ip, &nh->addr->address, sizeof(mpls_inet_addr));
266 f->info.nexthop.type |= MPLS_NH_IP;
268 if (nh->type & MPLS_NH_IF) {
269 MPLS_REFCNT_HOLD(nh->iff);
270 f->nh.iff = nh->iff;
271 f->nh.type |= MPLS_NH_IF;
272 memcpy(&f->info.nexthop.if_handle, &nh->iff->handle,
273 sizeof(mpls_if_handle));
274 f->info.nexthop.type |= MPLS_NH_IF;
276 if (nh->type & MPLS_NH_OUTSEGMENT) {
277 MPLS_REFCNT_HOLD(nh->outlabel);
278 f->nh.outlabel = nh->outlabel;
279 f->nh.type |= MPLS_NH_OUTSEGMENT;
280 memcpy(&f->info.nexthop.outsegment_handle, &nh->outlabel->info.handle,
281 sizeof(mpls_outsegment_handle));
282 f->info.nexthop.type |= MPLS_NH_OUTSEGMENT;
286 void ldp_fec_del_nexthop(ldp_fec * f)
288 MPLS_ASSERT(f);
289 if (f->nh.type & MPLS_NH_IP) {
290 MPLS_REFCNT_RELEASE(f->nh.addr, ldp_addr_delete);
291 f->nh.addr = NULL;
292 f->nh.type &= ~MPLS_NH_IP;
294 if (f->nh.type & MPLS_NH_IF) {
295 MPLS_REFCNT_RELEASE(f->nh.iff, ldp_if_delete);
296 f->nh.iff = NULL;
297 f->nh.type &= ~MPLS_NH_IF;
299 if (o->nh.type & MPLS_NH_OUTSEGMENT) {
300 MPLS_REFCNT_RELEASE(f->nh.outlabel, ldp_outlabel_delete);
301 f->nh.outlabel = NULL;
302 f->nh.type &= ~MPLS_NH_OUTSEGMENT;
305 #endif
307 mpls_return_enum ldp_fec_process_add(ldp_global * g, ldp_fec * f)
309 ldp_session *nh_session = NULL;
310 ldp_session *peer = NULL;
311 ldp_attr *ds_attr = NULL;
312 ldp_attr *us_attr = NULL;
313 mpls_bool egress = MPLS_BOOL_FALSE;
314 ldp_outlabel *out;
316 LDP_ENTER(g->user_data, "ldp_fec_process_add");
319 * find the info about the next hop for this FEC
321 nh_session = ldp_get_next_hop_session_for_fec2(f);
323 if (nh_session) {
324 ds_attr = ldp_attr_find_downstream_state2(g, nh_session, f,
325 LDP_LSP_STATE_MAP_RECV);
326 if (ds_attr && !ds_attr->outlabel) {
327 out = ldp_outlabel_create_complete(g, nh_session, ds_attr);
328 if (!out) {
329 return MPLS_FAILURE;
331 ds_attr->outlabel = out;
336 * for every peer except the nh hop peer, check to see if we need to
337 * send a mapping
339 peer = MPLS_LIST_HEAD(&g->session);
340 while (peer != NULL) { /* FEC.1 */
341 if ((peer->state != LDP_STATE_OPERATIONAL) ||
342 (nh_session && peer->index == nh_session->index)) {
343 goto next_peer;
345 /* have I already sent a mapping for FEC to peer */
346 if ((us_attr = ldp_attr_find_upstream_state2(g, peer, f,
347 LDP_LSP_STATE_MAP_SENT))) {
348 /* yep, don't send another */
349 if (ds_attr) {
350 if (ldp_inlabel_add_outlabel(g, us_attr->inlabel,
351 ds_attr->outlabel) != MPLS_SUCCESS) {
352 return MPLS_FAILURE;
355 goto next_peer;
358 if (peer->oper_distribution_mode == LDP_DISTRIBUTION_UNSOLICITED) {
359 if (g->lsp_control_mode == LDP_CONTROL_INDEPENDENT) {
360 us_attr =
361 ldp_attr_find_upstream_state2(g, peer, f, LDP_LSP_STATE_REQ_RECV);
363 /* FEC.1.DUI3,4 */
364 if (ldp_label_mapping_with_xc(g, peer, f, &us_attr, ds_attr) !=
365 MPLS_SUCCESS) {
366 if (!us_attr->in_tree) {
367 ldp_attr_remove_complete(g, us_attr, MPLS_BOOL_FALSE);
369 goto next_peer;
371 } else {
373 *LDP_CONTROL_ORDERED
376 if (ds_attr || egress == MPLS_BOOL_TRUE) { /* FEC.1.DUO2 */
377 if (!(us_attr = ldp_attr_create(&f->info))) {
378 return MPLS_FAILURE;
380 /* FEC.1.DUO3-4 */
381 if ((egress == MPLS_BOOL_TRUE) && (mpls_policy_egress_check(
382 g->user_data, &f->info, &f->info.nh) == MPLS_BOOL_TRUE)) {
383 goto next_peer;
386 if (ldp_label_mapping_with_xc(g, peer, f, &us_attr, ds_attr) !=
387 MPLS_SUCCESS) {
388 return MPLS_FAILURE;
393 next_peer:
394 peer = MPLS_LIST_NEXT(&g->session, peer, _global);
397 if (ds_attr) { /* FEC.2 */
398 if (ldp_label_mapping_process(g, nh_session, NULL, NULL, ds_attr, f) ==
399 MPLS_FAILURE) { /* FEC.5 */
400 return MPLS_FAILURE;
402 return MPLS_SUCCESS;
406 * LDP_DISTRIBUTION_ONDEMAND
408 /* FEC.3 */
409 if (nh_session &&
410 nh_session->oper_distribution_mode == LDP_DISTRIBUTION_ONDEMAND) {
411 /* assume we're always "request when needed" */
412 ds_attr = NULL;
413 if (ldp_label_request_for_xc(g, nh_session, &f->info, NULL, &ds_attr) ==
414 MPLS_FAILURE) { /* FEC.4 */
415 return MPLS_FAILURE;
419 LDP_EXIT(g->user_data, "ldp_fec_process_add");
421 return MPLS_SUCCESS; /* FEC.6 */
424 mpls_return_enum ldp_fec_process_change(ldp_global * g, ldp_fec * f,
425 ldp_session *nh_session_old) {
426 ldp_session *peer = NULL;
427 ldp_attr *us_attr = NULL;
428 ldp_attr *ds_attr = NULL;
429 ldp_session *nh_session_new = NULL;
431 LDP_ENTER(g->user_data, "ldp_fec_process_change");
434 * NH 1-5 decide if we need to release an existing mapping
436 ds_attr = ldp_attr_find_downstream_state2(g, nh_session_old, f,
437 LDP_LSP_STATE_MAP_RECV);
438 if (!ds_attr) { /* NH.1 */
439 goto Detect_Change_Fec_Next_Hop_6;
442 if (ds_attr->ingress == MPLS_BOOL_TRUE) {
444 #if MPLS_USE_LSR
445 lsr_ftn ftn;
446 ftn.outsegment_index = ds_attr->outlabel->info.handle;
447 memcpy(&ftn.fec, &f->info, sizeof(mpls_fec));
448 lsr_cfg_ftn_set2(g->lsr_handle, &ftn, LSR_CFG_DEL);
449 #else
450 mpls_mpls_fec2out_del(g->mpls_handle, &f->info, &ds_attr->outlabel->info);
451 #endif
452 ds_attr->ingress = MPLS_BOOL_FALSE;
453 ds_attr->outlabel->merge_count--;
456 if (g->label_retention_mode == LDP_RETENTION_LIBERAL) { /* NH.3 */
457 ldp_attr *us_temp;
458 us_attr = MPLS_LIST_HEAD(&ds_attr->us_attr_root);
459 while (us_attr) {
460 /* need to walk the list in such a way as not to
461 * "pull the rug out from under me self"
463 us_temp = MPLS_LIST_NEXT(&ds_attr->us_attr_root, us_attr, _ds_attr);
464 if (us_attr->state == LDP_LSP_STATE_MAP_SENT) {
465 ldp_inlabel_del_outlabel(g, us_attr->inlabel); /* NH.2 */
466 ldp_attr_del_us2ds(us_attr, ds_attr);
468 us_attr = us_temp;
470 goto Detect_Change_Fec_Next_Hop_6;
473 ldp_label_release_send(g, nh_session_old, ds_attr, LDP_NOTIF_NONE); /* NH.4 */
474 ldp_attr_remove_complete(g, ds_attr, MPLS_BOOL_FALSE); /* NH.2,5 */
476 Detect_Change_Fec_Next_Hop_6:
479 * NH 6-9 decides is we need to send a label request abort
481 ds_attr = ldp_attr_find_downstream_state2(g, nh_session_old, f,
482 LDP_LSP_STATE_REQ_SENT);
483 if (ds_attr) { /* NH.6 */
484 if (g->label_retention_mode != LDP_RETENTION_CONSERVATIVE) { /* NH.7 */
485 /* NH.8,9 */
486 if (ldp_label_abort_send(g, nh_session_old, ds_attr) != MPLS_SUCCESS) {
487 return MPLS_FAILURE;
493 * NH 10-12 decides if we can use a mapping from our database
495 if (!(nh_session_new = ldp_get_next_hop_session_for_fec2(f))) {
496 goto Detect_Change_Fec_Next_Hop_16;
499 ds_attr = ldp_attr_find_downstream_state2(g, nh_session_new, f,
500 LDP_LSP_STATE_MAP_RECV);
501 if (!ds_attr) { /* NH.11 */
502 goto Detect_Change_Fec_Next_Hop_13;
505 if (ldp_label_mapping_process(g, nh_session_new, NULL, NULL, ds_attr, f) !=
506 MPLS_SUCCESS) { /* NH.12 */
507 return MPLS_FAILURE;
509 goto Detect_Change_Fec_Next_Hop_20;
511 Detect_Change_Fec_Next_Hop_13:
514 * NH 13-15 decides if we need to make a label request
516 if (nh_session_new->oper_distribution_mode == LDP_DISTRIBUTION_ONDEMAND &&
517 g->label_retention_mode == LDP_RETENTION_CONSERVATIVE) {
518 /* NH.14-15 */
519 if (ldp_label_request_for_xc(g, nh_session_new, &f->info, NULL, &ds_attr) !=
520 MPLS_SUCCESS) {
521 return MPLS_FAILURE;
524 goto Detect_Change_Fec_Next_Hop_20;
526 Detect_Change_Fec_Next_Hop_16:
528 peer = MPLS_LIST_HEAD(&g->session);
529 while (peer) {
530 if (peer->state == LDP_STATE_OPERATIONAL) {
531 us_attr = ldp_attr_find_upstream_state2(g, peer, f,
532 LDP_LSP_STATE_MAP_SENT);
533 if (us_attr) { /* NH.17 */
534 if (ldp_label_withdraw_send(g, peer, us_attr, LDP_NOTIF_NONE) !=
535 MPLS_SUCCESS) { /* NH.18 */
536 ldp_attr_remove_complete(g, us_attr, MPLS_BOOL_FALSE);
537 return MPLS_FAILURE;
541 peer = MPLS_LIST_NEXT(&g->session, peer, _global);
544 Detect_Change_Fec_Next_Hop_20:
546 LDP_EXIT(g->user_data, "ldp_fec_process_change");
548 return MPLS_SUCCESS;
551 #if 0
552 mpls_return_enum Recognize_New_Fec(ldp_global * g, mpls_fec * f)
554 ldp_session *peer = NULL;
555 ldp_session *nh_session = NULL;
556 ldp_attr *ds_attr = NULL;
557 ldp_attr *us_attr = NULL;
558 mpls_bool egress = MPLS_BOOL_FALSE;
559 ldp_outlabel *out;
561 LDP_ENTER(g->user_data, "Recognize_New_Fec");
564 * try to add the fec and the associated next hop to the tree
565 * if this fails we have no hope of sending a label or a request
567 if (!ldp_fec_find(g, f)) {
568 ldp_fec *fec = NULL;
569 if ((fec = ldp_fec_insert(g,f)) == NULL) {
570 return MPLS_FATAL;
572 _ldp_global_add_fec(g, fec);
573 } else {
574 LDP_PRINT(g->user_data, "Recognize_New_Fec: attempt at ECMP\n");
575 MPLS_ASSERT(0);
579 * find the info about the next hop for this FEC
581 switch (ldp_get_next_hop_session_for_fec(g, f, &nh_session)) {
582 case MPLS_SUCCESS:
583 break;
584 case MPLS_FAILURE:
586 * we found the route, but no next hop
588 egress = MPLS_BOOL_TRUE;
589 break;
590 case MPLS_NO_ROUTE:
591 return MPLS_FAILURE;
592 default:
593 MPLS_ASSERT(0);
596 if (nh_session) {
597 ds_attr = ldp_attr_find_downstream_state(g, nh_session, f,
598 LDP_LSP_STATE_MAP_RECV);
599 if (ds_attr && !ds_attr->outlabel) {
600 out = ldp_outlabel_create_complete(g, nh_session, ds_attr);
601 if (!out) {
602 return MPLS_FAILURE;
604 ds_attr->outlabel = out;
609 * for every peer except the nh hop peer, check to see if we need to
610 * send a mapping
612 peer = MPLS_LIST_HEAD(&g->session);
613 while (peer != NULL) { /* FEC.1 */
614 if ((peer->state != LDP_STATE_OPERATIONAL) ||
615 (nh_session && peer->index == nh_session->index)) {
616 goto next_peer;
618 /* have I already sent a mapping for FEC to peer */
619 if ((us_attr = ldp_attr_find_upstream_state(g, peer, f,
620 LDP_LSP_STATE_MAP_SENT))) {
621 /* yep, don't send another */
622 if (ds_attr) {
623 if (ldp_inlabel_add_outlabel(g, us_attr->inlabel,
624 ds_attr->outlabel) != MPLS_SUCCESS) {
625 return MPLS_FAILURE;
628 goto next_peer;
631 if (peer->oper_distribution_mode == LDP_DISTRIBUTION_UNSOLICITED) {
632 if (g->lsp_control_mode == LDP_CONTROL_INDEPENDENT) {
633 us_attr =
634 ldp_attr_find_upstream_state(g, peer, f, LDP_LSP_STATE_REQ_RECV);
636 /* FEC.1.DUI3,4 */
637 if (ldp_label_mapping_with_xc(g, peer, f, &us_attr, ds_attr) !=
638 MPLS_SUCCESS) {
639 if (!us_attr->in_tree) {
640 ldp_attr_remove_complete(g, us_attr, MPLS_BOOL_FALSE);
642 goto next_peer;
644 } else {
646 *LDP_CONTROL_ORDERED
649 if (ds_attr || egress == MPLS_BOOL_TRUE) { /* FEC.1.DUO2 */
650 if (!(us_attr = ldp_attr_create(f))) {
651 return MPLS_FAILURE;
653 /* FEC.1.DUO3-4 */
654 if ((egress == MPLS_BOOL_TRUE) && (mpls_policy_egress_check(
655 g->user_data, f, &f->nh) == MPLS_BOOL_TRUE)) {
656 goto next_peer;
659 if (ldp_label_mapping_with_xc(g, peer, f, &us_attr, ds_attr) !=
660 MPLS_SUCCESS) {
661 return MPLS_FAILURE;
666 next_peer:
667 peer = MPLS_LIST_NEXT(&g->session, peer, _global);
670 if (ds_attr) { /* FEC.2 */
671 if (ldp_label_mapping_process(g, nh_session, NULL, NULL, ds_attr, f) ==
672 MPLS_FAILURE) { /* FEC.5 */
673 return MPLS_FAILURE;
675 return MPLS_SUCCESS;
679 * LDP_DISTRIBUTION_ONDEMAND
681 /* FEC.3 */
682 if (nh_session &&
683 nh_session->oper_distribution_mode == LDP_DISTRIBUTION_ONDEMAND) {
684 /* assume we're always "request when needed" */
685 ds_attr = NULL;
686 if (ldp_label_request_for_xc(g, nh_session, f, NULL, &ds_attr) ==
687 MPLS_FAILURE) { /* FEC.4 */
688 return MPLS_FAILURE;
692 LDP_EXIT(g->user_data, "Recognize_New_Fec");
694 return MPLS_SUCCESS; /* FEC.6 */
697 mpls_return_enum Detect_Change_Fec_Next_Hop(ldp_global * g, mpls_fec * f,
698 ldp_session * nh_old)
700 ldp_session *peer = NULL;
701 ldp_attr *us_attr = NULL;
702 ldp_attr *ds_attr = NULL;
703 ldp_session *nh_session_new = NULL;
704 mpls_return_enum result;
706 LDP_ENTER(g->user_data, "Detect_Change_Fec_Next_Hop");
708 result = ldp_get_next_hop_session_for_fec(g, f, &nh_session_new);
711 * NH 1-5 decide if we need to release an existing mapping
713 ds_attr =
714 ldp_attr_find_downstream_state(g, nh_old, f, LDP_LSP_STATE_MAP_RECV);
715 if (!ds_attr) { /* NH.1 */
716 goto Detect_Change_Fec_Next_Hop_6;
719 if (ds_attr->ingress == MPLS_BOOL_TRUE) {
721 #if MPLS_USE_LSR
722 lsr_ftn ftn;
723 ftn.outsegment_index = ds_attr->outlabel->info.handle;
724 memcpy(&ftn.fec, f, sizeof(mpls_fec));
725 lsr_cfg_ftn_set2(g->lsr_handle, &ftn, LSR_CFG_DEL);
726 #else
727 mpls_mpls_fec2out_del(g->mpls_handle, f, &ds_attr->outlabel->info);
728 #endif
729 ds_attr->ingress = MPLS_BOOL_FALSE;
730 ds_attr->outlabel->merge_count--;
733 if (g->label_retention_mode == LDP_RETENTION_LIBERAL) { /* NH.3 */
734 ldp_attr *us_temp;
735 us_attr = MPLS_LIST_HEAD(&ds_attr->us_attr_root);
736 while (us_attr) {
737 /* need to walk the list in such a way as not to
738 * "pull the rug out from under me self"
740 us_temp = MPLS_LIST_NEXT(&ds_attr->us_attr_root, us_attr, _ds_attr);
741 if (us_attr->state == LDP_LSP_STATE_MAP_SENT) {
742 ldp_inlabel_del_outlabel(g, us_attr->inlabel); /* NH.2 */
743 ldp_attr_del_us2ds(us_attr, ds_attr);
745 us_attr = us_temp;
747 goto Detect_Change_Fec_Next_Hop_6;
750 ldp_label_release_send(g, nh_old, ds_attr, LDP_NOTIF_NONE); /* NH.4 */
751 ldp_attr_remove_complete(g, ds_attr, MPLS_BOOL_FALSE); /* NH.2,5 */
753 Detect_Change_Fec_Next_Hop_6:
756 * NH 6-9 decides is we need to send a label request abort
758 ds_attr =
759 ldp_attr_find_downstream_state(g, nh_old, f, LDP_LSP_STATE_REQ_SENT);
760 if (ds_attr) { /* NH.6 */
761 if (g->label_retention_mode != LDP_RETENTION_CONSERVATIVE) { /* NH.7 */
762 /* NH.8,9 */
763 if (ldp_label_abort_send(g, nh_old, ds_attr) != MPLS_SUCCESS) {
764 return MPLS_FAILURE;
770 * NH 10-12 decides if we can use a mapping from our database
772 if (result != MPLS_SUCCESS) {
773 goto Detect_Change_Fec_Next_Hop_16;
776 ds_attr =
777 ldp_attr_find_downstream_state(g, nh_session_new, f, LDP_LSP_STATE_MAP_RECV);
778 if (!ds_attr) { /* NH.11 */
779 goto Detect_Change_Fec_Next_Hop_13;
782 if (ldp_label_mapping_process(g, nh_session_new, NULL, NULL, ds_attr, f) !=
783 MPLS_SUCCESS) { /* NH.12 */
784 return MPLS_FAILURE;
786 goto Detect_Change_Fec_Next_Hop_20;
788 Detect_Change_Fec_Next_Hop_13:
791 * NH 13-15 decides if we need to make a label request
793 if (nh_session_new->oper_distribution_mode == LDP_DISTRIBUTION_ONDEMAND &&
794 g->label_retention_mode == LDP_RETENTION_CONSERVATIVE) {
795 /* NH.14-15 */
796 if (ldp_label_request_for_xc(g, nh_session_new, f, NULL, &ds_attr) !=
797 MPLS_SUCCESS) {
798 return MPLS_FAILURE;
801 goto Detect_Change_Fec_Next_Hop_20;
803 Detect_Change_Fec_Next_Hop_16:
805 peer = MPLS_LIST_HEAD(&g->session);
806 while (peer) {
807 if (peer->state == LDP_STATE_OPERATIONAL) {
808 us_attr = ldp_attr_find_upstream_state(g, peer, f,
809 LDP_LSP_STATE_MAP_SENT);
810 if (us_attr) { /* NH.17 */
811 if (ldp_label_withdraw_send(g, peer, us_attr, LDP_NOTIF_NONE) !=
812 MPLS_SUCCESS) { /* NH.18 */
813 ldp_attr_remove_complete(g, us_attr, MPLS_BOOL_FALSE);
814 return MPLS_FAILURE;
818 peer = MPLS_LIST_NEXT(&g->session, peer, _global);
821 Detect_Change_Fec_Next_Hop_20:
823 LDP_EXIT(g->user_data, "Detect_Change_Fec_Next_Hop");
825 return MPLS_SUCCESS;
827 #endif
829 ldp_fec *ldp_fec_create()
831 ldp_fec *fec = (ldp_fec *) mpls_malloc(sizeof(ldp_fec));
833 if (fec != NULL) {
834 memset(fec, 0, sizeof(ldp_fec));
835 MPLS_REFCNT_INIT(fec, 0);
836 MPLS_LIST_ELEM_INIT(fec, _global);
837 MPLS_LIST_ELEM_INIT(fec, _inlabel);
838 MPLS_LIST_ELEM_INIT(fec, _outlabel);
839 MPLS_LIST_ELEM_INIT(fec, _fec);
840 fec->iff = NULL;
841 fec->addr = NULL;
842 MPLS_LIST_INIT(&fec->fs_root_us, ldp_fs);
843 MPLS_LIST_INIT(&fec->fs_root_ds, ldp_fs);
844 fec->info.type = MPLS_FEC_NONE;
845 fec->info.nh.type = MPLS_NH_NONE;
846 fec->info.nh.attached = MPLS_BOOL_FALSE;
847 fec->index = _ldp_fec_get_next_index();
849 return fec;
852 void mpls_fec2ldp_fec(mpls_fec * a, ldp_fec * b)
854 memcpy(&b->info, a, sizeof(mpls_fec));
857 ldp_fec *ldp_fec_create_host(mpls_inet_addr * host)
859 ldp_fec *fec = ldp_fec_create();
861 if (fec != NULL) {
862 fec->info.type = MPLS_FEC_HOST;
863 memcpy(&fec->info.u.host, host, sizeof(mpls_inet_addr));
865 return fec;
868 ldp_fec *ldp_fec_create_prefix(mpls_inet_addr * prefix, int prefix_len)
870 ldp_fec *fec = ldp_fec_create();
872 if (fec != NULL) {
873 fec->info.type = MPLS_FEC_PREFIX;
874 memcpy(&fec->info.u.prefix.network, prefix, sizeof(mpls_inet_addr));
875 fec->info.u.prefix.length = prefix_len;
877 return fec;
880 void ldp_fec_delete(ldp_fec * fec)
882 mpls_free(fec);
885 void mpls_fec2fec_tlv(mpls_fec * lf, mplsLdpFecTlv_t * tlv, int i)
887 tlv->fecElArray[i].addressEl.addressFam = 1;
889 switch (lf->type) {
890 case MPLS_FEC_PREFIX:
891 tlv->fecElArray[i].addressEl.type = MPLS_PREFIX_FEC;
892 tlv->fecElArray[i].addressEl.preLen = lf->u.prefix.length;
893 tlv->fecElArray[i].addressEl.address = lf->u.prefix.network.u.ipv4;
894 tlv->fecElemTypes[i] = MPLS_PREFIX_FEC;
895 break;
896 case MPLS_FEC_HOST:
897 tlv->fecElArray[i].addressEl.type = MPLS_HOSTADR_FEC;
898 tlv->fecElArray[i].addressEl.preLen = MPLS_IPv4LEN;
899 tlv->fecElArray[i].addressEl.address = lf->u.host.u.ipv4;
900 tlv->fecElemTypes[i] = MPLS_HOSTADR_FEC;
901 break;
902 default:
903 MPLS_ASSERT(0);
907 void fec_tlv2mpls_fec(mplsLdpFecTlv_t * tlv, int i, mpls_fec * lf) {
908 switch (tlv->fecElemTypes[i]) {
909 case MPLS_PREFIX_FEC:
910 lf->type = MPLS_FEC_PREFIX;
911 lf->u.prefix.length = tlv->fecElArray[i].addressEl.preLen;
912 lf->u.prefix.network.u.ipv4 = tlv->fecElArray[i].addressEl.address;
913 lf->u.prefix.network.type = MPLS_FAMILY_IPV4;
914 break;
915 case MPLS_HOSTADR_FEC:
916 lf->type = MPLS_FEC_HOST;
917 lf->u.host.u.ipv4 = tlv->fecElArray[i].addressEl.address;
918 lf->u.host.type = MPLS_FAMILY_IPV4;
919 break;
920 default:
921 MPLS_ASSERT(0);
925 static uint32_t _ldp_fec_get_next_index()
927 uint32_t retval = _ldp_fec_next_index;
929 _ldp_fec_next_index++;
930 if (retval > _ldp_fec_next_index) {
931 _ldp_fec_next_index = 1;
933 return retval;