/* * Copyright (C) James R. Leu 2000 * jleu@mindspring.com * * This software is covered under the LGPL, for more * info check out http://www.gnu.org/copyleft/lgpl.html */ #include "ldp_struct.h" #include "ldp_attr.h" #include "ldp_session.h" #include "ldp_global.h" #include "ldp_inlabel.h" #include "ldp_outlabel.h" #include "ldp_label_rel_with.h" #include "ldp_label_mapping.h" #include "ldp_mpls_impl.h" #include "ldp_fec.h" #include "ldp_msg.h" #include "ldp_pdu_setup.h" #include "ldp_trace_impl.h" ldp_bool rel_with2attr(mplsLdpLbl_W_R_Msg_t* rw,ldp_attr* attr) { ldp_bool retval = LDP_FALSE; if(rw->fecTlvExists) { memcpy(&attr->fecTlv,&rw->fecTlv,sizeof(mplsLdpFecTlv_t)); attr->fecTlvExists = 1; } if(rw->genLblTlvExists) { retval = LDP_TRUE; memcpy(&attr->genLblTlv,&rw->genLblTlv,sizeof(mplsLdpGenLblTlv_t)); attr->genLblTlvExists = 1; } else if(rw->atmLblTlvExists) { retval = LDP_TRUE; memcpy(&attr->atmLblTlv,&rw->atmLblTlv,sizeof(mplsLdpAtmLblTlv_t)); attr->atmLblTlvExists = 1; } else if(rw->frLblTlvExists) { retval = LDP_TRUE; memcpy(&attr->frLblTlv,&rw->frLblTlv,sizeof(mplsLdpFrLblTlv_t)); attr->frLblTlvExists = 1; } return retval; } ldp_msg* ldp_label_rel_with_create_msg(uint32_t msgid,ldp_attr* a, ldp_notif_status status,uint16_t type) { mplsLdpLbl_W_R_Msg_t* rw = NULL; ldp_msg* msg = NULL; msg = ldp_msg_create(type,msgid); if(msg == NULL) { return NULL; } rw = (mplsLdpLbl_W_R_Msg_t*)msg->body; if(a->fecTlvExists) { rw->fecTlvExists = 1; rw->baseMsg.msgLength += setupFecTlv(&rw->fecTlv); rw->baseMsg.msgLength += addFecElem2FecTlv(&rw->fecTlv, &a->fecTlv.fecElArray[0]); } if(a->genLblTlvExists) { rw->genLblTlvExists = 1; rw->baseMsg.msgLength += setupGenLblTlv(&rw->genLblTlv, a->genLblTlv.label); } if(a->atmLblTlvExists) { rw->atmLblTlvExists = 1; rw->baseMsg.msgLength += setupAtmLblTlv(&rw->atmLblTlv,0,0, a->atmLblTlv.flags.flags.vpi,a->atmLblTlv.vci); } if(a->frLblTlvExists) { rw->frLblTlvExists = 1; rw->baseMsg.msgLength += setupFrLblTlv(&rw->frLblTlv,0, a->frLblTlv.flags.flags.len,a->frLblTlv.flags.flags.dlci); } if(a->lspidTlvExists) { rw->lspidTlvExists = 1; rw->baseMsg.msgLength += setupLspidTlv(&rw->lspidTlv,0, a->lspidTlv.localCrlspId,a->lspidTlv.routerId); } return msg; } ldp_return_enum ldp_label_rel_with_send(ldp_global* g,ldp_session* s, ldp_attr* a,ldp_notif_status status,uint16_t type) { ldp_msg* msg = NULL; LDP_ENTER(g->user_data,"ldp_label_rel_with_send"); msg = ldp_label_rel_with_create_msg(g->message_identifier++,a,status,type); if(msg == NULL) { return LDP_FAILURE; } ldp_msg_send_tcp(g,s,msg); ldp_msg_delete(msg); LDP_EXIT(g->user_data,"ldp_label_rel_with_send"); return LDP_SUCCESS; } ldp_return_enum ldp_label_release_send(ldp_global* g,ldp_session* s, ldp_attr* a,ldp_notif_status status) { LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_SEND,LDP_TRACE_FLAG_LABEL, "Release Sent: session(%d)\n",s->index); return ldp_label_rel_with_send(g,s,a,status,MPLS_LBLREL_MSGTYPE); } ldp_return_enum ldp_label_withdraw_send(ldp_global* g,ldp_session* s, ldp_attr* a,ldp_notif_status status) { ldp_attr* new_attr = ldp_attr_create(NULL); ldp_fec fec; if(new_attr == NULL) { return LDP_FAILURE; } new_attr->state = LDP_LSP_STATE_WITH_SENT; ldp_attr2ldp_attr(a,new_attr,LDP_ATTR_ALL); if(ldp_label_rel_with_send(g,s,a,status,MPLS_LBLWITH_MSGTYPE) == LDP_FAILURE) { ldp_attr_delete(new_attr); return LDP_FAILURE; } LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_SEND,LDP_TRACE_FLAG_LABEL, "Withdraw Sent: session(%d)\n",s->index); fec_tlv2ldp_fec(&new_attr->fecTlv,0,&fec); ldp_attr_insert_upstream(g,s,new_attr); return LDP_SUCCESS; } ldp_return_enum ldp_label_release_process(ldp_global* g,ldp_session* s, ldp_adj *a,ldp_entity *e,ldp_attr* r_attr,ldp_fec* fec) { ldp_bool label_exists = LDP_FALSE; ldp_session* next_hop = NULL; ldp_outlabel* out = NULL; ldp_attr* attr = NULL; ldp_attr* ds_attr = NULL; ldp_attr* us_attr = NULL; LDP_ENTER(g->user_data,"ldp_label_release_process"); LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_RECV,LDP_TRACE_FLAG_LABEL, "Release Recv: session(%d)\n",s->index); if(r_attr->genLblTlvExists||r_attr->atmLblTlvExists||r_attr->frLblTlvExists) { label_exists = LDP_TRUE; } if(fec) { attr = ldp_attr_find_upstream_state(g,s,fec,LDP_LSP_STATE_MAP_SENT); if(attr == NULL) { return LDP_SUCCESS; } us_attr = ldp_attr_find_upstream_state(g,s,fec,LDP_LSP_STATE_WITH_SENT); if(us_attr != NULL) { /* LRl.2 */ ldp_attr_remove_complete(g,us_attr); /* LRl.3 */ } out = attr->inlabel->outlabel; if(out != NULL) { ds_attr = out->attr; } else { ds_attr = NULL; } if(out == NULL || out->merge_count <= 1) { /* LR1.4 */ goto LRl_6; } if(attr->inlabel->reuse_count > 1) { /* LR1.5 */ goto LRl_10; } LRl_6: switch(ldp_get_next_hop_session_for_fec(g,fec,NULL,&next_hop)) { case LDP_SUCCESS: case LDP_NO_ROUTE: break; case LDP_FAILURE: /* egress */ goto LRl_10; default: LDP_ASSERT(0); } if(!(next_hop != NULL && ds_attr != NULL)) { /* LRl.7 */ goto LRl_10; } if(g->propagate_release == LDP_FALSE) { /* LRl.8 */ goto LRl_10; } ldp_label_release_send(g,next_hop,ds_attr,LDP_NOTIF_NONE); /* LRl.9 */ ldp_attr_remove_complete(g,ds_attr); LRl_10: ldp_attr_remove_complete(g,attr); /* LRl.10,11 */ } else { LDP_PRINT(g->user_data,"No FEC in release, need to implement\n"); LDP_ASSERT(0); } LDP_EXIT(g->user_data,"ldp_label_release_process"); return LDP_SUCCESS; } ldp_return_enum ldp_label_withdraw_process(ldp_global* g,ldp_session* s, ldp_adj *a, ldp_entity *e,ldp_attr *r_attr,ldp_fec* fec) { ldp_bool label_exists = LDP_FALSE; ldp_attr_list* ds_list = NULL; ldp_attr* ds_attr = NULL; ldp_attr* ds_temp = NULL; ldp_outlabel* out = NULL; ldp_inlabel* in = NULL; LDP_ENTER(g->user_data,"ldp_label_withdraw_process"); LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_RECV,LDP_TRACE_FLAG_LABEL, "Withdraw Recv: session(%d)\n",s->index); if(r_attr->genLblTlvExists||r_attr->atmLblTlvExists||r_attr->frLblTlvExists) { label_exists = LDP_TRUE; } else { LDP_ASSERT(0); } if(fec) { if((ds_list = ldp_attr_find_downstream_all(g,s,fec)) != NULL) { ds_attr = LDP_LIST_HEAD(ds_list); while(ds_attr != NULL) { if(ds_attr->state == LDP_LSP_STATE_MAP_RECV) { if(ldp_attr_is_equal(r_attr,ds_attr,LDP_ATTR_LABEL)) { ds_temp = ds_attr; LDP_REFCNT_HOLD(ds_temp); out = ds_attr->outlabel; LDP_REFCNT_HOLD(out); ldp_label_release_send(g,s,ds_attr,LDP_NOTIF_NONE); /* LWd.2 */ ldp_attr_remove_complete(g,ds_attr); /* LWd.4 */ in = LDP_LIST_HEAD(&out->inlabel_root); while(in != NULL) { /* LWd.8 */ if(g->lsp_control_mode == LDP_CONTROL_ORDERED) { /* LWd.5 */ ldp_attr_elem* ae = LDP_LIST_HEAD(&in->attr_root); while(ae != NULL) { ldp_label_withdraw_send(g,ae->attr->session, ae->attr,LDP_NOTIF_NONE); /* LWd.11 */ ae = LDP_LIST_NEXT(&in->attr_root,ae,_elem); } } else { if(s->oper_distribution_mode == LDP_DISTRIBUTION_ONDEMAND) { /* LWd.6 */ Detect_Change_Fec_Next_Hop(g,fec,s); /* LWd.7*/ } } in = LDP_LIST_NEXT(&out->inlabel_root,in,_outlabel); } LDP_REFCNT_RELEASE(out,ldp_outlabel_delete); } else { ds_temp = NULL; } } ds_attr = LDP_LIST_NEXT(ds_list,ds_attr,_fs); if(ds_temp) LDP_REFCNT_RELEASE(ds_temp,ldp_attr_delete); } } } else { /* JLEU: process wildcard FEC stuff here */ LDP_ASSERT(0); } LDP_EXIT(g->user_data,"ldp_label_withdraw_process"); return LDP_SUCCESS; }