3 * Copyright (C) James R. Leu 2000
6 * This software is covered under the LGPL, for more
7 * info check out http://www.gnu.org/copyleft/lgpl.html
10 #include "ldp_struct.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"
31 #include "mpls_mpls_impl.h"
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
)
45 key
= fec
->u
.prefix
.network
.u
.ipv4
;
46 len
= fec
->u
.prefix
.length
;
49 key
= fec
->u
.host
.u
.ipv4
;
52 if (ldp_global_find_fec(g
, fec
, &f
) == MPLS_SUCCESS
) {
60 if (mpls_tree_get(g
->fec_tree
, key
, len
, (void **)&f
) != MPLS_SUCCESS
) {
66 mpls_return_enum
ldp_fec_insert2(ldp_global
*g
, ldp_fec
* fec
)
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
) {
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
;
116 key
= fec
->info
.u
.host
.u
.ipv4
;
119 /* they had better insert it into the global tree */
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
;
137 ldp_fec_insert2_error
:
141 ldp_fec
*ldp_fec_insert(ldp_global
*g
, mpls_fec
* fec
)
145 if ((f
= ldp_fec_create()) == NULL
) {
146 LDP_PRINT(g
->user_data
, "ldp_fec_insert: error creating address\n");
150 mpls_fec2ldp_fec(fec
,f
);
154 if (ldp_fec_insert2(g
,f
) != MPLS_SUCCESS
) {
155 MPLS_REFCNT_RELEASE(f
, ldp_fec_delete
);
161 void ldp_fec_remove(ldp_global
*g
, mpls_fec
*fec
)
168 case MPLS_FEC_PREFIX
:
169 key
= fec
->u
.prefix
.network
.u
.ipv4
;
170 len
= fec
->u
.prefix
.length
;
173 key
= fec
->u
.host
.u
.ipv4
;
176 /* they had better remove it from the global tree */
182 mpls_tree_remove(g
->fec_tree
, key
, len
, (void **)&f
);
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
)
213 f
->nh
.type
|= MPLS_NH_IF
;
216 void ldp_fec_del_if(ldp_fec
* f
)
219 MPLS_REFCNT_RELEASE(f
->nh
.iff
, ldp_if_delete
);
221 f
->nh
.type
&= ~MPLS_NH_IF
;
224 void ldp_fec_add_addr(ldp_fec
* f
, ldp_addr
* a
)
229 f
->nh
.type
|= MPLS_NH_IP
;
232 void ldp_fec_del_addr(ldp_fec
* f
)
235 MPLS_REFCNT_RELEASE(f
->nh
.addr
, ldp_addr_delete
);
237 f
->nh
.type
&= ~MPLS_NH_IP
;
240 void ldp_fec_add_outlabel(ldp_fec
* f
, ldp_outlabel
* o
)
245 f
->nh
.type
|= MPLS_NH_OUTSEGMENT
;
248 void ldp_fec_del_outlabel(ldp_fec
* f
)
251 MPLS_REFCNT_RELEASE(f
->nh
.outlabel
, ldp_outlabel_delete
);
252 f
->nh
.outlabel
= NULL
;
253 f
->nh
.type
&= ~MPLS_NH_OUTSEGMENT
;
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
);
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
)
289 if (f
->nh
.type
& MPLS_NH_IP
) {
290 MPLS_REFCNT_RELEASE(f
->nh
.addr
, ldp_addr_delete
);
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
);
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
;
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
;
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
);
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
);
331 ds_attr
->outlabel
= out
;
336 * for every peer except the nh hop peer, check to see if we need to
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
)) {
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 */
350 if (ldp_inlabel_add_outlabel(g
, us_attr
->inlabel
,
351 ds_attr
->outlabel
) != MPLS_SUCCESS
) {
358 if (peer
->oper_distribution_mode
== LDP_DISTRIBUTION_UNSOLICITED
) {
359 if (g
->lsp_control_mode
== LDP_CONTROL_INDEPENDENT
) {
361 ldp_attr_find_upstream_state2(g
, peer
, f
, LDP_LSP_STATE_REQ_RECV
);
364 if (ldp_label_mapping_with_xc(g
, peer
, f
, &us_attr
, ds_attr
) !=
366 if (!us_attr
->in_tree
) {
367 ldp_attr_remove_complete(g
, us_attr
, MPLS_BOOL_FALSE
);
376 if (ds_attr
|| egress
== MPLS_BOOL_TRUE
) { /* FEC.1.DUO2 */
377 if (!(us_attr
= ldp_attr_create(&f
->info
))) {
381 if ((egress
== MPLS_BOOL_TRUE
) && (mpls_policy_egress_check(
382 g
->user_data
, &f
->info
, &f
->info
.nh
) == MPLS_BOOL_TRUE
)) {
386 if (ldp_label_mapping_with_xc(g
, peer
, f
, &us_attr
, ds_attr
) !=
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 */
406 * LDP_DISTRIBUTION_ONDEMAND
410 nh_session
->oper_distribution_mode
== LDP_DISTRIBUTION_ONDEMAND
) {
411 /* assume we're always "request when needed" */
413 if (ldp_label_request_for_xc(g
, nh_session
, &f
->info
, NULL
, &ds_attr
) ==
414 MPLS_FAILURE
) { /* FEC.4 */
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
) {
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
);
450 mpls_mpls_fec2out_del(g
->mpls_handle
, &f
->info
, &ds_attr
->outlabel
->info
);
452 ds_attr
->ingress
= MPLS_BOOL_FALSE
;
453 ds_attr
->outlabel
->merge_count
--;
456 if (g
->label_retention_mode
== LDP_RETENTION_LIBERAL
) { /* NH.3 */
458 us_attr
= MPLS_LIST_HEAD(&ds_attr
->us_attr_root
);
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
);
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 */
486 if (ldp_label_abort_send(g
, nh_session_old
, ds_attr
) != MPLS_SUCCESS
) {
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 */
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
) {
519 if (ldp_label_request_for_xc(g
, nh_session_new
, &f
->info
, NULL
, &ds_attr
) !=
524 goto Detect_Change_Fec_Next_Hop_20
;
526 Detect_Change_Fec_Next_Hop_16
:
528 peer
= MPLS_LIST_HEAD(&g
->session
);
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
);
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");
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
;
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
)) {
569 if ((fec
= ldp_fec_insert(g
,f
)) == NULL
) {
572 _ldp_global_add_fec(g
, fec
);
574 LDP_PRINT(g
->user_data
, "Recognize_New_Fec: attempt at ECMP\n");
579 * find the info about the next hop for this FEC
581 switch (ldp_get_next_hop_session_for_fec(g
, f
, &nh_session
)) {
586 * we found the route, but no next hop
588 egress
= MPLS_BOOL_TRUE
;
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
);
604 ds_attr
->outlabel
= out
;
609 * for every peer except the nh hop peer, check to see if we need to
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
)) {
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 */
623 if (ldp_inlabel_add_outlabel(g
, us_attr
->inlabel
,
624 ds_attr
->outlabel
) != MPLS_SUCCESS
) {
631 if (peer
->oper_distribution_mode
== LDP_DISTRIBUTION_UNSOLICITED
) {
632 if (g
->lsp_control_mode
== LDP_CONTROL_INDEPENDENT
) {
634 ldp_attr_find_upstream_state(g
, peer
, f
, LDP_LSP_STATE_REQ_RECV
);
637 if (ldp_label_mapping_with_xc(g
, peer
, f
, &us_attr
, ds_attr
) !=
639 if (!us_attr
->in_tree
) {
640 ldp_attr_remove_complete(g
, us_attr
, MPLS_BOOL_FALSE
);
649 if (ds_attr
|| egress
== MPLS_BOOL_TRUE
) { /* FEC.1.DUO2 */
650 if (!(us_attr
= ldp_attr_create(f
))) {
654 if ((egress
== MPLS_BOOL_TRUE
) && (mpls_policy_egress_check(
655 g
->user_data
, f
, &f
->nh
) == MPLS_BOOL_TRUE
)) {
659 if (ldp_label_mapping_with_xc(g
, peer
, f
, &us_attr
, ds_attr
) !=
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 */
679 * LDP_DISTRIBUTION_ONDEMAND
683 nh_session
->oper_distribution_mode
== LDP_DISTRIBUTION_ONDEMAND
) {
684 /* assume we're always "request when needed" */
686 if (ldp_label_request_for_xc(g
, nh_session
, f
, NULL
, &ds_attr
) ==
687 MPLS_FAILURE
) { /* FEC.4 */
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
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
) {
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
);
727 mpls_mpls_fec2out_del(g
->mpls_handle
, f
, &ds_attr
->outlabel
->info
);
729 ds_attr
->ingress
= MPLS_BOOL_FALSE
;
730 ds_attr
->outlabel
->merge_count
--;
733 if (g
->label_retention_mode
== LDP_RETENTION_LIBERAL
) { /* NH.3 */
735 us_attr
= MPLS_LIST_HEAD(&ds_attr
->us_attr_root
);
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
);
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
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 */
763 if (ldp_label_abort_send(g
, nh_old
, ds_attr
) != MPLS_SUCCESS
) {
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
;
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 */
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
) {
796 if (ldp_label_request_for_xc(g
, nh_session_new
, f
, NULL
, &ds_attr
) !=
801 goto Detect_Change_Fec_Next_Hop_20
;
803 Detect_Change_Fec_Next_Hop_16
:
805 peer
= MPLS_LIST_HEAD(&g
->session
);
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
);
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");
829 ldp_fec
*ldp_fec_create()
831 ldp_fec
*fec
= (ldp_fec
*) mpls_malloc(sizeof(ldp_fec
));
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
);
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();
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();
862 fec
->info
.type
= MPLS_FEC_HOST
;
863 memcpy(&fec
->info
.u
.host
, host
, sizeof(mpls_inet_addr
));
868 ldp_fec
*ldp_fec_create_prefix(mpls_inet_addr
* prefix
, int prefix_len
)
870 ldp_fec
*fec
= ldp_fec_create();
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
;
880 void ldp_fec_delete(ldp_fec
* fec
)
885 void mpls_fec2fec_tlv(mpls_fec
* lf
, mplsLdpFecTlv_t
* tlv
, int i
)
887 tlv
->fecElArray
[i
].addressEl
.addressFam
= 1;
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
;
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
;
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
;
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
;
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;