/* * 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_fec.h" #include "ldp_msg.h" #include "ldp_pdu_setup.h" #include "ldp_timer_impl.h" #include "ldp_fib_impl.h" #include "ldp_lock_impl.h" #include "ldp_trace_impl.h" #include "ldp_notif.h" #include "ldp_session.h" #include "ldp_label_mapping.h" #include "ldp_mpls_impl.h" #include "ldp_label_request.h" ldp_msg* ldp_label_request_create_msg(uint32_t msgid,ldp_attr* s_attr) { mplsLdpLblReqMsg_t* req = NULL; ldp_msg* msg = NULL; int i; msg = ldp_msg_create(MPLS_LBLREQ_MSGTYPE,msgid); if(msg == NULL) { return NULL; } req = (mplsLdpLblReqMsg_t*)msg->body; if(s_attr->fecTlvExists) { req->fecTlvExists = 1; req->baseMsg.msgLength += setupFecTlv(&req->fecTlv); req->baseMsg.msgLength += addFecElem2FecTlv(&req->fecTlv, &s_attr->fecTlv.fecElArray[0]); } if(s_attr->hopCountTlvExists) { req->hopCountTlvExists = 1; req->baseMsg.msgLength += setupHopCountTlv(&req->hopCountTlv, s_attr->hopCountTlv.hcValue); } if(s_attr->pathVecTlvExists) { req->pathVecTlvExists = 1; req->baseMsg.msgLength += setupPathTlv(&req->pathVecTlv); for(i = 0;i < MPLS_MAXHOPSNUMBER;i++) { if(s_attr->pathVecTlv.lsrId[i]) { req->baseMsg.msgLength += addLsrId2PathTlv(&req->pathVecTlv, s_attr->pathVecTlv.lsrId[i]); } } } return msg; } ldp_return_enum ldp_label_request_send(ldp_global* g, ldp_session* s, ldp_attr* s_attr) { ldp_msg* msg = NULL; ldp_fec fec; ldp_attr* ds_attr = NULL; LDP_ENTER(g->user_data,"ldp_label_request_send"); fec_tlv2ldp_fec(&s_attr->fecTlv,0,&fec); if((ds_attr = ldp_attr_find_downstream_state(g,s,&fec, LDP_LSP_STATE_REQ_SENT)) != NULL) { /* SLRq.1 */ LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_SEND,LDP_TRACE_FLAG_LABEL, "Label Request Send: outstanding label request(%d)\n",ds_attr->index); return LDP_SUCCESS; } if(s->no_label_resource_recv == LDP_TRUE) { /* SLRq.2 */ goto ldp_label_request_send_error; } if((msg = ldp_label_request_create_msg(g->message_identifier++, s_attr)) == NULL) { LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_SEND,LDP_TRACE_FLAG_ERROR, "Couldn't create label request message\n"); goto ldp_label_request_send_error; } LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_SEND,LDP_TRACE_FLAG_LABEL, "Label Request Sent: session(%d)\n",s->index); if(ldp_msg_send_tcp(g,s,msg) == LDP_FAILURE) { /* SLRq.3 */ LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_SEND,LDP_TRACE_FLAG_ERROR, "Label Request send failed\n"); goto ldp_label_request_send_error; } s_attr->state = LDP_LSP_STATE_REQ_SENT; if(ldp_attr_insert_downstream(g,s,s_attr) == LDP_FAILURE) { /* SLRq.4 */ LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_SEND,LDP_TRACE_FLAG_ERROR, "Couldn't insert sent attributes in tree\n"); goto ldp_label_request_send_error; } ldp_msg_delete(msg); LDP_EXIT(g->user_data,"ldp_label_request_send"); return LDP_SUCCESS; /* SLRq.5 */ ldp_label_request_send_error: LDP_PRINT(g->user_data,"SLRq.6\n"); s_attr->state = LDP_LSP_STATE_NO_LABEL_RESOURCE_SENT; ldp_attr_insert_downstream(g,s,s_attr); /* SLRq.6 */ if(msg != NULL) { ldp_msg_delete(msg); } LDP_EXIT(g->user_data,"ldp_label_request_send-error"); return LDP_FAILURE; /* SLRq.7 */ } void req2attr(mplsLdpLblReqMsg_t* req,ldp_attr* attr,uint32_t flag) { attr->msg_id = req->baseMsg.msgId; if(req->fecTlvExists && flag & LDP_ATTR_FEC) { memcpy(&attr->fecTlv,&req->fecTlv,sizeof(mplsLdpFecTlv_t)); attr->fecTlvExists = 1; } if(req->hopCountTlvExists && flag & LDP_ATTR_HOPCOUNT) { memcpy(&attr->hopCountTlv,&req->hopCountTlv,sizeof(mplsLdpHopTlv_t)); attr->hopCountTlvExists = 1; } if(req->pathVecTlvExists && flag & LDP_ATTR_PATH) { memcpy(&attr->pathVecTlv,&req->pathVecTlv,sizeof(mplsLdpPathTlv_t)); attr->pathVecTlvExists = 1; } if(req->lblMsgIdTlvExists && flag & LDP_ATTR_MSGID) { memcpy(&attr->lblMsgIdTlv,&req->lblMsgIdTlv,sizeof(mplsLdpLblMsgIdTlv_t)); attr->lblMsgIdTlvExists = 1; } if(req->lspidTlvExists && flag & LDP_ATTR_LSPID) { memcpy(&attr->lspidTlv,&req->lspidTlv,sizeof(mplsLdpLspIdTlv_t)); attr->lspidTlvExists = 1; } if(req->trafficTlvExists && flag & LDP_ATTR_TRAFFIC) { memcpy(&attr->trafficTlv,&req->trafficTlv,sizeof(mplsLdpTrafficTlv_t)); attr->trafficTlvExists = 1; } } void ldp_label_request_initial_callback(ldp_timer_handle timer,void* extra, ldp_cfg_handle g) { ldp_session* s = (ldp_session*)extra; LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_ALL,LDP_TRACE_FLAG_TIMER, "Initial Label Request fired: session(%d)\n",s->index); ldp_lock_get(g->global_lock); ldp_timer_stop(g->timer_handle,timer); ldp_timer_delete(g->timer_handle,timer); LDP_REFCNT_RELEASE(s,ldp_session_delete); s->initial_distribution_timer = (ldp_timer_handle)0; ldp_lock_release(g->global_lock); } void Prepare_Label_Request_Attributes(ldp_global* g,ldp_session* s, ldp_fec* fec,ldp_attr* r_attr,ldp_attr* s_attr) { int i; if(!(s->entity->require_hop_count == LDP_TRUE || r_attr->hopCountTlvExists || s->oper_loop_detection != LDP_LOOP_NONE)) { /* PRqA.1 */ return; } /* is this LSR allowed to be an LER for FEC? */ /* PRqA.2 */ /* some policy gunk needs to be checked here */ /* if not goto PRqA.6 */ s_attr->hopCountTlvExists = 1; /* PRqA.3 */ s_attr->hopCountTlv.hcValue = 1; if(s->oper_loop_detection == LDP_LOOP_NONE) { /* PRqA.4 */ return; } if(g->label_merge == LDP_TRUE) { /* PRqA.5 */ return; } goto Prepare_Label_Request_Attributes_13; if(r_attr->hopCountTlvExists) { /* PRqA.6 */ s_attr->hopCountTlvExists = 1; /* PRqA.7 */ s_attr->hopCountTlv.hcValue = (r_attr->hopCountTlv.hcValue)? (r_attr->hopCountTlv.hcValue + 1):0; } else { s_attr->hopCountTlvExists = 1; /* PRqA.8 */ s_attr->hopCountTlv.hcValue = 0; } if(s->oper_loop_detection == LDP_LOOP_NONE) { /* PRqA.9 */ return; } if(r_attr->pathVecTlvExists) { /* PRqA.10 */ goto Prepare_Label_Request_Attributes_12; } if(g->label_merge == LDP_TRUE) { /* PRqA.11 */ return; } goto Prepare_Label_Request_Attributes_13; Prepare_Label_Request_Attributes_12: s_attr->pathVecTlvExists = 1; s_attr->pathVecTlv.lsrId[0] = g->lsr_identifier.u.ipv4; for(i=1;i<(MPLS_MAXHOPSNUMBER - 1);i++) { if(r_attr->pathVecTlv.lsrId[i-1]) { s_attr->pathVecTlv.lsrId[0] = r_attr->pathVecTlv.lsrId[i-1]; } } Prepare_Label_Request_Attributes_13: s_attr->pathVecTlvExists = 1; s_attr->pathVecTlv.lsrId[0] = g->lsr_identifier.u.ipv4; } ldp_return_enum ldp_label_request_process(ldp_global *g,ldp_session *s, ldp_adj *a,ldp_entity *e,ldp_attr* r_attr,ldp_fec* fec) { ldp_session* next_hop = NULL; ldp_addr* nh_addr = NULL; ldp_attr_list* us_list = NULL; ldp_attr* us_attr = NULL; ldp_attr* ds_attr = NULL; ldp_attr* s_attr = NULL; ldp_bool egress = LDP_FALSE; ldp_bool propogating = LDP_FALSE; r_attr->state = LDP_LSP_STATE_REQ_RECV; if(Check_Received_Attributes(g,s,r_attr,MPLS_LBLREQ_MSGTYPE) == LDP_FAILURE) { /* LRp.1 */ goto Receive_Label_Request_13; } switch(ldp_get_next_hop_session_for_fec(g,fec,&nh_addr,&next_hop)) { case LDP_SUCCESS: /* LRq.2 */ if(nh_addr == NULL) { egress = LDP_TRUE; } if(next_hop != NULL && s->index == next_hop->index) { /* LRq.3 */ ldp_notif_send(g,s,LDP_NOTIF_LOOP_DETECTED); /* LRq.4 */ goto Receive_Label_Request_13; } break; case LDP_FAILURE: egress = LDP_TRUE; break; case LDP_NO_ROUTE: ldp_notif_send(g,s,LDP_NOTIF_NO_ROUTE); /* LRq.5 */ goto Receive_Label_Request_13; default: LDP_ASSERT(0); } us_attr = NULL; if((us_list = ldp_attr_find_upstream_all(g,s,fec)) != NULL) { us_attr = LDP_LIST_HEAD(us_list); while(us_attr != NULL) { if(us_attr->state == LDP_LSP_STATE_REQ_RECV && /* LRq.6 */ us_attr->msg_id == r_attr->msg_id) { /* LRq.7 */ goto Receive_Label_Request_13; } us_attr = LDP_LIST_NEXT(us_list,us_attr,_fs); } } r_attr->state = LDP_LSP_STATE_REQ_RECV; /* LRq.8 */ if(ldp_attr_insert_upstream(g,s,r_attr) == LDP_FAILURE) { LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_RECV,LDP_TRACE_FLAG_ERROR, "Couldn't insert recv attributes in tree\n"); goto ldp_label_request_process_error; } ds_attr = ldp_attr_find_downstream_state(g,next_hop,fec, LDP_LSP_STATE_MAP_RECV); if(g->lsp_control_mode == LDP_CONTROL_INDEPENDENT) { /* LRq.9 */ if(ds_attr != NULL) { propogating = LDP_TRUE; } else { propogating = LDP_FALSE; } s_attr = ldp_attr_create(fec); if(s_attr == NULL) { goto ldp_label_request_process_error; } Prepare_Label_Mapping_Attributes(g,s,fec,r_attr,s_attr,propogating, LDP_TRUE); if(ldp_label_mapping_send(g,s,s_attr) == LDP_FAILURE) { goto ldp_label_request_process_error; } if(egress == LDP_TRUE || ds_attr != NULL) { goto Receive_Label_Request_11; } } else { if(!(egress == LDP_TRUE || ds_attr != NULL)) { goto Receive_Label_Request_10; } s_attr = ldp_attr_create(fec); if(s_attr == NULL) { goto ldp_label_request_process_error; } Prepare_Label_Mapping_Attributes(g,s,fec,r_attr,s_attr,LDP_TRUE,LDP_TRUE); if(ldp_label_mapping_send(g,s,s_attr) == LDP_FAILURE) { goto ldp_label_request_process_error; } goto Receive_Label_Request_11; } Receive_Label_Request_10: s_attr = ldp_attr_create(fec); if(s_attr == NULL) { goto ldp_label_request_process_error; } Prepare_Label_Request_Attributes(g,next_hop,fec,r_attr,s_attr); if(ldp_label_request_send(g,next_hop,s_attr) == LDP_FAILURE) { goto ldp_label_request_process_error; } goto Receive_Label_Request_13; Receive_Label_Request_11: if((us_list = ldp_attr_find_upstream_all(g,s,fec)) != NULL) { us_attr = LDP_LIST_HEAD(us_list); while(us_attr != NULL) { if(us_attr->state == LDP_LSP_STATE_MAP_SENT && us_attr->session->index == s->index) { break; } us_attr = LDP_LIST_NEXT(us_list,us_attr,_fs); } } if(us_attr == NULL) { /* LRq.11 */ goto Receive_Label_Request_13; } if(egress != LDP_TRUE && ds_attr != NULL) { if(ldp_mpls_in2out_add(g->mpls_handle,us_attr->inlabel, /* LRq.12 */ ds_attr->outlabel) == LDP_FAILURE) { goto ldp_label_request_process_error; } } Receive_Label_Request_13: if(s_attr != NULL && s_attr->in_tree == LDP_FALSE) { ldp_attr_delete(s_attr); } return LDP_SUCCESS; ldp_label_request_process_error: return LDP_FAILURE; }