mpls_return_enum ldp_fec_process_change(ldp_global * g, ldp_fec * f, ldp_nexthop *nh, ldp_nexthop *nh_old, ldp_session *nh_session_old) { ldp_session *peer = NULL; ldp_attr *us_attr = NULL; ldp_attr *ds_attr = NULL; ldp_session *nh_session = NULL; LDP_ENTER(g->user_data, "ldp_fec_process_change"); if (!nh_session_old) { nh_session_old = ldp_session_for_nexthop(nh_old); } /* * NH 1-5 decide if we need to release an existing mapping */ ds_attr = ldp_attr_find_downstream_state2(g, nh_session_old, f, LDP_LSP_STATE_MAP_RECV); if (!ds_attr) { /* NH.1 */ goto Detect_Change_Fec_Next_Hop_6; } if (ds_attr->ingress == MPLS_BOOL_TRUE) { #if MPLS_USE_LSR lsr_ftn ftn; ftn.outsegment_index = ds_attr->outlabel->info.handle; memcpy(&ftn.fec, &f->info, sizeof(mpls_fec)); lsr_cfg_ftn_set2(g->lsr_handle, &ftn, LSR_CFG_DEL); #else mpls_mpls_fec2out_del(g->mpls_handle, &f->info, &ds_attr->outlabel->info); #endif ds_attr->ingress = MPLS_BOOL_FALSE; ds_attr->outlabel->merge_count--; } if (g->label_retention_mode == LDP_RETENTION_LIBERAL) { /* NH.3 */ ldp_attr *us_temp; us_attr = MPLS_LIST_HEAD(&ds_attr->us_attr_root); while (us_attr) { /* need to walk the list in such a way as not to * "pull the rug out from under me self" */ us_temp = MPLS_LIST_NEXT(&ds_attr->us_attr_root, us_attr, _ds_attr); if (us_attr->state == LDP_LSP_STATE_MAP_SENT) { ldp_inlabel_del_outlabel(g, us_attr->inlabel); /* NH.2 */ ldp_attr_del_us2ds(us_attr, ds_attr); } us_attr = us_temp; } goto Detect_Change_Fec_Next_Hop_6; } ldp_label_release_send(g, nh_session_old, ds_attr, LDP_NOTIF_NONE); /* NH.4 */ ldp_attr_remove_complete(g, ds_attr, MPLS_BOOL_FALSE); /* NH.2,5 */ Detect_Change_Fec_Next_Hop_6: /* * NH 6-9 decides is we need to send a label request abort */ ds_attr = ldp_attr_find_downstream_state2(g, nh_session_old, f, LDP_LSP_STATE_REQ_SENT); if (ds_attr) { /* NH.6 */ if (g->label_retention_mode != LDP_RETENTION_CONSERVATIVE) { /* NH.7 */ /* NH.8,9 */ if (ldp_label_abort_send(g, nh_session_old, ds_attr) != MPLS_SUCCESS) { return MPLS_FAILURE; } } } /* * NH 10-12 decides if we can use a mapping from our database */ if (!(nh_session = ldp_get_next_hop_session_for_fec2(f,nh))){ goto Detect_Change_Fec_Next_Hop_16; } ds_attr = ldp_attr_find_downstream_state2(g, nh_session, f, LDP_LSP_STATE_MAP_RECV); if (!ds_attr) { /* NH.11 */ goto Detect_Change_Fec_Next_Hop_13; } if (ldp_label_mapping_process(g, nh_session, NULL, NULL, ds_attr, f) != MPLS_SUCCESS) { /* NH.12 */ return MPLS_FAILURE; } goto Detect_Change_Fec_Next_Hop_20; Detect_Change_Fec_Next_Hop_13: /* * NH 13-15 decides if we need to make a label request */ if (nh_session->oper_distribution_mode == LDP_DISTRIBUTION_ONDEMAND && g->label_retention_mode == LDP_RETENTION_CONSERVATIVE) { /* NH.14-15 */ if (ldp_label_request_for_xc(g, nh_session, &f->info, NULL, &ds_attr) != MPLS_SUCCESS) { return MPLS_FAILURE; } } goto Detect_Change_Fec_Next_Hop_20; Detect_Change_Fec_Next_Hop_16: peer = MPLS_LIST_HEAD(&g->session); while (peer) { if (peer->state == LDP_STATE_OPERATIONAL) { us_attr = ldp_attr_find_upstream_state2(g, peer, f, LDP_LSP_STATE_MAP_SENT); if (us_attr) { /* NH.17 */ if (ldp_label_withdraw_send(g, peer, us_attr, LDP_NOTIF_NONE) != MPLS_SUCCESS) { /* NH.18 */ ldp_attr_remove_complete(g, us_attr, MPLS_BOOL_FALSE); return MPLS_FAILURE; } } } peer = MPLS_LIST_NEXT(&g->session, peer, _global); } Detect_Change_Fec_Next_Hop_20: LDP_EXIT(g->user_data, "ldp_fec_process_change"); return MPLS_SUCCESS; }
mpls_return_enum ldp_label_withdraw_process(ldp_global * g, ldp_session * s, ldp_adj * a, ldp_entity * e, ldp_attr * r_attr, ldp_fec * f) { mpls_bool label_exists = MPLS_BOOL_FALSE; ldp_attr_list *ds_list = NULL; ldp_attr *ds_attr = NULL; ldp_attr *ds_temp = NULL; ldp_attr *us_temp = NULL; ldp_nexthop *nh = NULL; mpls_return_enum retval = MPLS_SUCCESS; LDP_ENTER(g->user_data, "ldp_label_withdraw_process"); LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV, LDP_TRACE_FLAG_LABEL, "Withdraw Recv for %s\n", s->session_name); if (r_attr->genLblTlvExists || r_attr->atmLblTlvExists || r_attr->frLblTlvExists) { label_exists = MPLS_BOOL_TRUE; } else { MPLS_ASSERT(0); } if (f) { if ((ds_list = ldp_attr_find_downstream_all2(g, s, f)) != NULL) { ds_temp = MPLS_LIST_HEAD(ds_list); while (ds_temp) { if (ds_temp->state == LDP_LSP_STATE_MAP_RECV) { /* LWd.3 */ if (ldp_attr_is_equal(r_attr, ds_temp, LDP_ATTR_LABEL)) { ds_attr = ds_temp; break; } } ds_temp = MPLS_LIST_NEXT(ds_list, ds_temp, _fs); } } if (!ds_attr) { retval = MPLS_FAILURE; LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV, LDP_TRACE_FLAG_LABEL, "Withdraw Recv for a non-existant mapping from %s\n",s->session_name); goto LWd_13; } /* * we want to remove it from the tree, but not delete it yet * so hold a refcnt, we will release that refcnt at the end, thus * deleting it if no one else it holding a refcnt */ MPLS_REFCNT_HOLD(ds_attr); ldp_attr_remove_complete(g, ds_attr, MPLS_BOOL_FALSE); /* LWd.4 */ /* LWd.2 */ if (ldp_label_release_send(g, s, ds_attr, LDP_NOTIF_NONE) != MPLS_SUCCESS) { retval = MPLS_FATAL; goto LWd_13; } if (g->lsp_control_mode == LDP_CONTROL_ORDERED) { /* LWd.5 */ goto LWd_8; } if (s->oper_distribution_mode != LDP_DISTRIBUTION_ONDEMAND) { /* LWd.6 */ goto LWd_13; } MPLS_ASSERT((nh = ldp_nexthop_for_fec_session(f, s))); retval = ldp_fec_process_add(g, f, nh, s); /* LWd.7 */ goto LWd_13; LWd_8: /* I can only propogate a label withdraw to the upstreams attached to the downstream found above */ us_temp = MPLS_LIST_HEAD(&ds_attr->us_attr_root); while (us_temp) { if (us_temp->state == LDP_LSP_STATE_MAP_SENT) { if (ldp_label_withdraw_send(g, us_temp->session, us_temp, LDP_NOTIF_NONE) != MPLS_SUCCESS) { /* LWd.11 */ retval = MPLS_FATAL; goto LWd_13; } } us_temp = MPLS_LIST_NEXT(&ds_attr->us_attr_root, us_temp, _ds_attr); } } else { /* JLEU: process wildcard FEC stuff here */ MPLS_ASSERT(0); } LWd_13: if (ds_attr) { MPLS_REFCNT_RELEASE2(g, ds_attr, ldp_attr_delete); } LDP_EXIT(g->user_data, "ldp_label_withdraw_process"); return retval; }