/* * 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_session.h" #include "ldp_attr.h" #include "ldp_fec.h" #include "ldp_msg.h" #include "ldp_notif.h" #include "ldp_entity.h" #include "ldp_inlabel.h" #include "ldp_outlabel.h" #include "ldp_global.h" #include "ldp_pdu_setup.h" #include "ldp_label_rel_with.h" #include "ldp_label_mapping.h" #include "ldp_label_request.h" #include #include "ldp_timer_impl.h" #include "ldp_fib_impl.h" #include "ldp_lock_impl.h" #include "ldp_tree_impl.h" #include "ldp_trace_impl.h" #include "ldp_mpls_impl.h" #include "ldp_mm_impl.h" #include "ldp_policy_impl.h" ldp_return_enum ldp_label_mapping_with_xc(ldp_global* g,ldp_session* s, ldp_fec* f,ldp_attr* r_attr) { ldp_attr* s_attr = ldp_attr_create(f); ldp_bool propogating = LDP_TRUE; if(s_attr == NULL) { return LDP_FAILURE; } if(r_attr == NULL) { propogating = LDP_FALSE; } Prepare_Label_Mapping_Attributes(g,s,f,r_attr,s_attr,propogating,LDP_TRUE); /* ldp_label_mapping_send will remove the attr for the REQ */ s_attr->state = LDP_LSP_STATE_MAP_SENT; if(ldp_label_mapping_send(g,s,s_attr) == LDP_FAILURE) { ldp_attr_delete(s_attr); return LDP_FAILURE; } if(r_attr != NULL) { LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_ALL, LDP_TRACE_FLAG_BINDING,"Cross Connect Added\n"); if(ldp_mpls_in2out_add(g->mpls_handle,s_attr->inlabel,r_attr->outlabel) == LDP_FAILURE) { ldp_label_withdraw_send(g,s,s_attr,LDP_NOTIF_NONE); ldp_attr_remove_complete(g,s_attr); return LDP_FAILURE; } ldp_inlabel_add_outlabel(s_attr->inlabel,r_attr->outlabel); } return LDP_SUCCESS; } ldp_return_enum ldp_label_request_for_xc(ldp_global* g,ldp_session* s,ldp_fec* fec,ldp_attr* r_attr) { ldp_attr* s_attr = ldp_attr_create(fec); if(s_attr == NULL) { return LDP_FAILURE; } Prepare_Label_Request_Attributes(g,s,fec,r_attr,s_attr); s_attr->state = LDP_LSP_STATE_REQ_SENT; if(ldp_label_request_send(g,s,s_attr) == LDP_FAILURE) { ldp_attr_delete(s_attr); return LDP_FAILURE; } return LDP_SUCCESS; } ldp_session* ldp_get_session_by_next_hop(ldp_global* g,ldp_inet_addr* a, ldp_addr** next_hop) { ldp_addr* addr = NULL; LDP_ASSERT(a->protocol == AF_INET); if(ldp_tree_get(g->addr_tree,a->u.ipv4,32,(void**)&addr) == LDP_SUCCESS) { ldp_session_elem* e = NULL; e = LDP_LIST_HEAD(&addr->session_root); /* JLEU if there is more then one session that has given this address then were in trouble, just choose the first for now */ if(e != NULL) { if(next_hop) { *next_hop = addr; } return e->session; } } return NULL; } ldp_return_enum ldp_get_next_hop_session_for_fec(ldp_global* g,ldp_fec* fec, ldp_addr** next_hop,ldp_session** next_hop_session) { ldp_addr* addr = NULL; ldp_session* session = NULL; ldp_prefix dest; ldp_prefix route; if(next_hop_session) { *next_hop_session = NULL; } if(next_hop) { *next_hop = NULL; } switch(fec->type) { case LDP_FEC_PREFIX: dest.network.protocol = AF_INET; dest.network.u.ipv4 = fec->prefix.u.ipv4; dest.prefix_len = fec->prefix_len; break; case LDP_FEC_HOST: dest.network.protocol = AF_INET; dest.network.u.ipv4 = fec->prefix.u.ipv4; dest.prefix_len = 32; break; default: LDP_ASSERT(0); } if(ldp_fib_get_route(g->fib_handle,1,&dest,&route) != 1) { /* JLEU: how to handle the multipath case */ LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_ALL,LDP_TRACE_FLAG_NORMAL, "No route to FEC (%08x/%d)\n",route.network.u.ipv4,route.prefix_len); return LDP_NO_ROUTE; } if(route.next_hop.protocol != 0) { session = ldp_get_session_by_next_hop(g,&route.next_hop,&addr); if(next_hop_session) { *next_hop_session = session; } if(next_hop) { *next_hop = addr; } return LDP_SUCCESS; } return LDP_FAILURE; } ldp_return_enum Check_Received_Attributes(ldp_global* g,ldp_session* s, ldp_attr* r_attr,uint16_t type) { int count = 0; int i; if(!r_attr->hopCountTlvExists) { /* CRa.1 */ goto Check_Received_Attributes_5; } if(r_attr->hopCountTlv.hcValue >= s->entity->hop_count_limit) {/* CRa.2 */ LDP_PRINT(g->user_data,"CRa.2\n"); goto Check_Received_Attributes_6; } if(!r_attr->pathVecTlvExists) { /* CRa.3 */ goto Check_Received_Attributes_5; } for(i = 0;i < MPLS_MAXHOPSNUMBER;i++) { /* CRa.4 */ if(r_attr->pathVecTlv.lsrId[i]) { count++; if(r_attr->pathVecTlv.lsrId[i] == g->lsr_identifier.u.ipv4) { goto Check_Received_Attributes_6; LDP_PRINT(g->user_data,"CRa.4a\n"); } if(count > s->entity->path_vector_limit) { goto Check_Received_Attributes_6; LDP_PRINT(g->user_data,"CRa.4b\n"); } } } Check_Received_Attributes_5: return LDP_SUCCESS; Check_Received_Attributes_6: if(type != MPLS_LBLMAP_MSGTYPE) { ldp_notif_send(g,s,LDP_NOTIF_LOOP_DETECTED); /* CRa.7 */ } return LDP_FAILURE; /* CRa.8 */ } void Prepare_Label_Mapping_Attributes(ldp_global* g,ldp_session* s, ldp_fec* fec,ldp_attr* r_attr,ldp_attr* s_attr,ldp_bool propogating, ldp_bool already) { ldp_attr dummy; int i; /* NOTE: PMpA.21 is the end of the procedure (ie return) */ /* this function uses goto quite extensivly for a REASON!! */ /* Check Appedix A of the LDP draft */ LDP_ENTER(g->user_data,"Prepare_Label_Mapping_Attributes"); if(r_attr == NULL) { memset(&dummy,0,sizeof(ldp_attr)); ldp_fec2fec_tlv(fec,&dummy.fecTlv,0); dummy.fecTlvExists = 1; dummy.fecTlv.numberFecElements = 1; r_attr = &dummy; } if(!(s->entity->require_hop_count == LDP_TRUE || r_attr->hopCountTlvExists || s->oper_loop_detection != LDP_LOOP_NONE)) { /* PMpA.1 */ return; } switch(ldp_get_next_hop_session_for_fec(g,fec,NULL,NULL)) {/* PMpA.2 */ case LDP_SUCCESS: break; case LDP_FAILURE: /* I'm egress (for now) */ s_attr->hopCountTlvExists = 1; s_attr->hopCountTlv.hcValue = 1; /* PMpA.3 */ return; case LDP_NO_ROUTE: default: break; } if(!(r_attr->hopCountTlvExists)) { /* PMpA.4 */ goto Prepare_Label_Mapping_Attributes_8; } if(!(g->ttl_less_domain == LDP_TRUE && s->entity->remote_in_ttl_less_domain == LDP_TRUE)) {/* PMpA.5 */ goto Prepare_Label_Mapping_Attributes_7; } s_attr->hopCountTlvExists = 1; s_attr->hopCountTlv.hcValue = 1; /* PMpA.6 */ goto Prepare_Label_Mapping_Attributes_9; Prepare_Label_Mapping_Attributes_7: s_attr->hopCountTlvExists = 1; s_attr->hopCountTlv.hcValue = (r_attr->hopCountTlv.hcValue)? (r_attr->hopCountTlv.hcValue + 1):0; goto Prepare_Label_Mapping_Attributes_9; Prepare_Label_Mapping_Attributes_8: s_attr->hopCountTlvExists = 1; s_attr->hopCountTlv.hcValue = 0; Prepare_Label_Mapping_Attributes_9: if(s->oper_loop_detection == LDP_LOOP_NONE) { return; } if(r_attr->pathVecTlvExists) { /* PMpA.10 */ goto Prepare_Label_Mapping_Attributes_19; } if(propogating == LDP_FALSE) { /* PMpA.11 */ goto Prepare_Label_Mapping_Attributes_20; } if(g->label_merge != LDP_TRUE) { /* PMpA.12 */ goto Prepare_Label_Mapping_Attributes_14; } if(already == LDP_FALSE) { /* PMpA.13 */ goto Prepare_Label_Mapping_Attributes_20; } Prepare_Label_Mapping_Attributes_14: if(!r_attr->hopCountTlvExists) { return; } if(r_attr->hopCountTlv.hcValue == 0) { /* PMpA.15 */ goto Prepare_Label_Mapping_Attributes_20; } if(already == LDP_FALSE) { /* PMpA.16 */ return; } /* r_attr contain PrevHopCount _IF_ we had one */ return; /* PMpA.17 */ if(r_attr->hopCountTlv.hcValue != 0) { /* PMpA.18 */ return; } Prepare_Label_Mapping_Attributes_19: 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]; } } LDP_EXIT(g->user_data,"Prepare_Label_Mapping_Attributes"); return; Prepare_Label_Mapping_Attributes_20: s_attr->pathVecTlvExists = 1; s_attr->pathVecTlv.lsrId[0] = g->lsr_identifier.u.ipv4; LDP_EXIT(g->user_data,"Prepare_Label_Mapping_Attributes"); return; } void map2attr(mplsLdpLblMapMsg_t* map,ldp_attr* attr,uint32_t flag) { attr->msg_id = map->baseMsg.msgId; if(map->fecTlvExists && flag & LDP_ATTR_FEC) { memcpy(&attr->fecTlv,&map->fecTlv,sizeof(mplsLdpFecTlv_t)); attr->fecTlvExists = 1; } if(map->genLblTlvExists && flag & LDP_ATTR_LABEL) { memcpy(&attr->genLblTlv,&map->genLblTlv,sizeof(mplsLdpGenLblTlv_t)); attr->genLblTlvExists = 1; } else if(map->atmLblTlvExists && flag & LDP_ATTR_LABEL) { memcpy(&attr->atmLblTlv,&map->atmLblTlv,sizeof(mplsLdpAtmLblTlv_t)); attr->atmLblTlvExists = 1; } else if(map->frLblTlvExists && flag & LDP_ATTR_LABEL) { memcpy(&attr->frLblTlv,&map->frLblTlv,sizeof(mplsLdpFrLblTlv_t)); attr->frLblTlvExists = 1; } if(map->hopCountTlvExists && flag & LDP_ATTR_HOPCOUNT) { memcpy(&attr->hopCountTlv,&map->hopCountTlv,sizeof(mplsLdpHopTlv_t)); attr->hopCountTlvExists = 1; } if(map->pathVecTlvExists && flag & LDP_ATTR_PATH) { memcpy(&attr->pathVecTlv,&map->pathVecTlv,sizeof(mplsLdpPathTlv_t)); attr->pathVecTlvExists = 1; } if(map->lblMsgIdTlvExists && flag & LDP_ATTR_MSGID) { memcpy(&attr->lblMsgIdTlv,&map->lblMsgIdTlv,sizeof(mplsLdpLblMsgIdTlv_t)); attr->lblMsgIdTlvExists = 1; } if(map->lspidTlvExists && flag & LDP_ATTR_LSPID) { memcpy(&attr->lspidTlv,&map->lspidTlv,sizeof(mplsLdpLspIdTlv_t)); attr->lspidTlvExists = 1; } if(map->trafficTlvExists && flag & LDP_ATTR_TRAFFIC) { memcpy(&attr->trafficTlv,&map->trafficTlv,sizeof(mplsLdpTrafficTlv_t)); attr->trafficTlvExists = 1; } } void attr2map(ldp_attr* attr,mplsLdpLblMapMsg_t* map) { if(attr->fecTlvExists) { memcpy(&map->fecTlv,&attr->fecTlv,sizeof(mplsLdpFecTlv_t)); map->fecTlvExists = 1; } if(attr->genLblTlvExists) { memcpy(&map->genLblTlv,&attr->genLblTlv,sizeof(mplsLdpGenLblTlv_t)); map->genLblTlvExists = 1; } if(attr->atmLblTlvExists) { memcpy(&map->atmLblTlv,&attr->atmLblTlv,sizeof(mplsLdpAtmLblTlv_t)); map->atmLblTlvExists = 1; } if(attr->frLblTlvExists) { memcpy(&map->frLblTlv,&attr->frLblTlv,sizeof(mplsLdpFrLblTlv_t)); map->frLblTlvExists = 1; } if(attr->hopCountTlvExists) { memcpy(&map->hopCountTlv,&attr->hopCountTlv,sizeof(mplsLdpHopTlv_t)); map->hopCountTlvExists = 1; } if(attr->pathVecTlvExists) { memcpy(&map->pathVecTlv,&attr->pathVecTlv,sizeof(mplsLdpPathTlv_t)); map->pathVecTlvExists = 1; } if(attr->lblMsgIdTlvExists) { memcpy(&map->lblMsgIdTlv,&attr->lblMsgIdTlv,sizeof(mplsLdpLblMsgIdTlv_t)); map->lblMsgIdTlvExists = 1; } if(attr->lspidTlvExists) { memcpy(&map->lspidTlv,&attr->lspidTlv,sizeof(mplsLdpLspIdTlv_t)); map->lspidTlvExists = 1; } if(attr->trafficTlvExists) { memcpy(&map->trafficTlv,&attr->trafficTlv,sizeof(mplsLdpTrafficTlv_t)); map->trafficTlvExists = 1; } } void ldp_label_mapping_initial_callback(ldp_timer_handle timer,void* extra, ldp_cfg_handle g) { ldp_session* s = (ldp_session*)extra; ldp_bool done = LDP_FALSE; ldp_fec* fec = NULL; ldp_attr* ds_attr = NULL; ldp_attr* us_attr = NULL; ldp_outlabel* out = NULL; ldp_bool already = LDP_TRUE; ldp_bool propogating = LDP_TRUE; LDP_ENTER(g->user_data,"ldp_label_mapping_initial_callback"); LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_ALL,LDP_TRACE_FLAG_TIMER, "Initial Label Mapping fired: session(%d)\n",s->index); ldp_lock_get(g->global_lock); ldp_timer_stop(g->timer_handle,timer); if(g->send_lsrid_mapping == LDP_TRUE) { fec = ldp_fec_create_prefix(&g->lsr_identifier,32); us_attr = ldp_attr_find_upstream(g,s,fec); if(us_attr == NULL) { already = LDP_FALSE; us_attr = ldp_attr_create(fec); } ds_attr = ldp_attr_find_downstream(g,NULL,fec); Prepare_Label_Mapping_Attributes(g,s,fec,ds_attr,us_attr,propogating, already); if(ldp_label_mapping_send(g,s,us_attr) == LDP_FAILURE) { /* JLEU: send a notification? */ ldp_session_shutdown(g,s,1); } done = LDP_TRUE; } out = LDP_LIST_HEAD(&g->outlabel); while(out != NULL) { if(out->session->index != s->index) { fec_tlv2ldp_fec(&out->attr->fecTlv,0,fec); if(ldp_attr_find_upstream_state(g,s,fec,LDP_LSP_STATE_MAP_SENT) == NULL) { #ifdef JLEU_FUNCTIONALITY /* * we haven't sent a mapping yet. if merge count is 0, * and we don't merge sent a label request to the next hop * else send a mapping */ if(out->merge_count > 0 && g->label_merge == LDP_FALSE) { if(ldp_label_request_for_xc(g,out->session,fec,out->attr) == LDP_FAILURE) { goto ldp_label_mapping_initial_end; } } else { #endif if(ldp_label_mapping_with_xc(g,s,fec,out->attr) == LDP_FAILURE) { goto ldp_label_mapping_initial_end; } #ifdef JLEU_FUNCTIONALITY } #endif } } out = LDP_LIST_NEXT(&g->outlabel,out,_global); } // fib get/getnext loop if(done == LDP_TRUE) { ldp_timer_delete(g->timer_handle,timer); LDP_REFCNT_RELEASE(s,ldp_session_delete); s->initial_distribution_timer = (ldp_timer_handle)0; } else { ldp_timer_start(g->timer_handle,timer,LDP_ONESHOT); } ldp_label_mapping_initial_end: if(fec != NULL) ldp_free(fec); ldp_lock_release(g->global_lock); LDP_EXIT(g->user_data,"ldp_label_mapping_initial_callback"); } ldp_return_enum ldp_label_mapping_send(ldp_global* g, ldp_session* s, ldp_attr* s_attr) { ldp_msg* msg = NULL; ldp_inlabel* in = NULL; ldp_fec fec; ldp_attr* us_attr = NULL; LDP_ENTER(g->user_data,"ldp_label_mapping_send"); fec_tlv2ldp_fec(&s_attr->fecTlv,0,&fec); if((in = ldp_inlabel_create_complete(g,s,s_attr)) == NULL) { /* SL.1-3 */ goto Send_Label_9; } LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_ALL,LDP_TRACE_FLAG_BINDING, "In Label Added\n"); s_attr->installed = LDP_TRUE; s_attr->state = LDP_LSP_STATE_MAP_SENT; if((msg = ldp_label_mapping_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 mapping message\n"); goto ldp_label_mapping_send_error; } if(ldp_attr_insert_upstream(g,s,s_attr) == LDP_FAILURE) {/* SL.5 */ 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_mapping_send_error; } if(ldp_msg_send_tcp(g,s,msg) == LDP_FAILURE) { /* SL.4 */ LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_SEND,LDP_TRACE_FLAG_ERROR, "Failed sending Label Mapping to %08x:%d\n", s->adj->remote_lsr_address.u.ipv4,s->adj->remote_label_space); goto ldp_label_mapping_send_error; } LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_SEND,LDP_TRACE_FLAG_LABEL, "Label Mapping Sent to %08x:%d for %08x/%d\n", s->adj->remote_lsr_address.u.ipv4,s->adj->remote_label_space, s_attr->fecTlv.fecElArray[0].addressEl.address, s_attr->fecTlv.fecElArray[0].addressEl.preLen); if((us_attr = ldp_attr_find_upstream_state(g,s,&fec, LDP_LSP_STATE_REQ_RECV)) != NULL) { /* SL.6 */ ldp_attr_remove_complete(g,us_attr); /* SL.7 */ } LDP_EXIT(g->user_data,"ldp_label_mapping_send"); ldp_msg_delete(msg); return LDP_SUCCESS; /* SL.8 */ Send_Label_9: LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_ALL,LDP_TRACE_FLAG_STATE, "No Label Resources\n"); while((us_attr = ldp_attr_find_upstream_state(g,s,&fec, LDP_LSP_STATE_REQ_RECV)) != NULL) { /* SL.9 */ ldp_notif_send(g,s,LDP_NOTIF_NO_LABEL_RESOURCES_AVAILABLE); /* SL.10 */ s->no_label_resource_sent = LDP_TRUE; /* SL.12 */ us_attr->state = LDP_LSP_STATE_NO_LABEL_RESOURCE_SENT; /* SL.13 */ } LDP_EXIT(g->user_data,"ldp_label_mapping_send"); return LDP_SUCCESS; ldp_label_mapping_send_error: ldp_attr_remove_complete(g,s_attr); if(msg != NULL) { ldp_msg_delete(msg); } LDP_EXIT(g->user_data,"ldp_label_mapping_send-error"); return LDP_FAILURE; } ldp_msg* ldp_label_mapping_create_msg(uint32_t msgid,ldp_attr* s_attr) { mplsLdpLblMapMsg_t* map = NULL; ldp_msg* msg = NULL; int i; msg = ldp_msg_create(MPLS_LBLMAP_MSGTYPE,msgid); if(msg == NULL) { return NULL; } map = (mplsLdpLblMapMsg_t*)msg->body; if(s_attr->fecTlvExists) { /* JLEU: only 1 FEC is allowed!! */ map->fecTlvExists = 1; map->baseMsg.msgLength += setupFecTlv(&map->fecTlv); map->baseMsg.msgLength += addFecElem2FecTlv(&map->fecTlv, &s_attr->fecTlv.fecElArray[0]); } if(s_attr->genLblTlvExists) { map->genLblTlvExists = 1; map->baseMsg.msgLength += setupGenLblTlv(&map->genLblTlv, s_attr->genLblTlv.label); } if(s_attr->atmLblTlvExists) { map->atmLblTlvExists = 1; map->baseMsg.msgLength += setupAtmLblTlv(&map->atmLblTlv,0,0, s_attr->atmLblTlv.flags.flags.vpi,s_attr->atmLblTlv.vci); } if(s_attr->frLblTlvExists) { map->frLblTlvExists = 1; map->baseMsg.msgLength += setupFrLblTlv(&map->frLblTlv,0, s_attr->frLblTlv.flags.flags.len,s_attr->frLblTlv.flags.flags.dlci); } if(s_attr->hopCountTlvExists) { map->hopCountTlvExists = 1; map->baseMsg.msgLength += setupHopCountTlv(&map->hopCountTlv, s_attr->hopCountTlv.hcValue); } if(s_attr->pathVecTlvExists) { map->pathVecTlvExists = 1; map->baseMsg.msgLength += setupPathTlv(&map->pathVecTlv); for(i = 0;i < MPLS_MAXHOPSNUMBER;i++) { if(s_attr->pathVecTlv.lsrId[i]) { map->baseMsg.msgLength += addLsrId2PathTlv(&map->pathVecTlv, s_attr->pathVecTlv.lsrId[i]); } } } #if 0 if(s_attr->lblMsgIdTlvExists) { } if(s_attr->lspidTlvExists) { } if(s_attr->trafficTlvExists) { } #endif return msg; } ldp_return_enum ldp_label_mapping_process(ldp_global *g,ldp_session *s, ldp_adj *a,ldp_entity *e,ldp_attr* r_attr,ldp_fec* fec) { ldp_session* nh_session = NULL; ldp_session* peer = NULL; ldp_attr_list* us_list = NULL; ldp_attr_list* ds_list = NULL; ldp_attr* ds_attr = NULL; ldp_attr* us_attr = NULL; ldp_attr* temp_attr = NULL; ldp_attr dumb_attr; ldp_outlabel* out = NULL; ldp_addr* next_hop = NULL; ldp_bool dup = LDP_FALSE; ldp_bool requested = LDP_FALSE; ldp_bool update = LDP_FALSE; ldp_bool installed = LDP_FALSE; #ifdef JLEU_FUNCTIONALITY ldp_bool need_request = LDP_FALSE; #endif ldp_return_enum result; LDP_ENTER(g->user_data,"ldp_label_mapping_process"); LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_RECV,LDP_TRACE_FLAG_LABEL, "Label Mapping Recv from %08x:%d for %08x/%d\n", s->adj->remote_lsr_address.u.ipv4,s->adj->remote_label_space, r_attr->fecTlv.fecElArray[0].addressEl.address, r_attr->fecTlv.fecElArray[0].addressEl.preLen); r_attr->state = LDP_LSP_STATE_MAP_RECV; if((ds_attr = ldp_attr_find_downstream_state(g,s,fec, LDP_LSP_STATE_REQ_SENT)) != NULL) { /* LMp.1 */ /* get rid of our outstanding request */ ldp_attr_remove_complete(g,ds_attr); /* LMp.2 */ requested = LDP_TRUE; } if(Check_Received_Attributes(g,s,r_attr,MPLS_LBLMAP_MSGTYPE) == LDP_SUCCESS) { /* LMp.3 */ goto Receive_Label_Map_9; } /* * A loop was detected */ ds_attr = NULL; if((ds_list = ldp_attr_find_downstream_all(g,s,fec)) != NULL) { ds_attr = LDP_LIST_HEAD(ds_list); /* * check all the labels this session has received from "s" for "fec" * do we have any duplicats? */ while(ds_attr != NULL) { if((ds_attr->state == LDP_LSP_STATE_MAP_RECV) && /* LMp.4 */ ldp_attr_is_equal(ds_attr,r_attr,LDP_ATTR_LABEL) == LDP_TRUE) { /* LMp.5 */ temp_attr = ds_attr; LDP_REFCNT_HOLD(temp_attr); dup = LDP_TRUE; /* remove record of the label and remove it switching */ ldp_attr_remove_complete(g,ds_attr); /* LMp.6,7 */ } else { temp_attr = NULL; } ds_attr = LDP_LIST_NEXT(ds_list,ds_attr,_fs); if(temp_attr) LDP_REFCNT_RELEASE(temp_attr,ldp_attr_delete); } if(dup == LDP_TRUE) { /* we found a dup in LMp.4 */ goto Receive_Label_Map_33; /* LMp.7 */ } } LDP_PRINT(g->user_data,"Receive_Label_Map_8: send release"); if(ldp_label_release_send(g,s,r_attr,LDP_NOTIF_LOOP_DETECTED) == LDP_FAILURE) { /* LMp.8 */ goto ldp_label_mapping_process_failure; } goto Receive_Label_Map_33; Receive_Label_Map_9: /* * No Loop Detected */ if(requested == LDP_TRUE) { /* this check comes from Note 6 */ goto Receive_Label_Map_11; } dup = LDP_FALSE; ds_attr = NULL; 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) { /* LMp.9 */ dup = LDP_TRUE; if(ldp_attr_is_equal(ds_attr,r_attr,LDP_ATTR_LABEL) == LDP_TRUE) { /* LMp.10 */ /* * this mapping matches an existing mapping, but it * contains updated attributes */ update = LDP_TRUE; installed = ds_attr->installed; ldp_attr2ldp_attr(r_attr,ds_attr,LDP_ATTR_HOPCOUNT|LDP_ATTR_PATH| LDP_ATTR_MSGID|LDP_ATTR_LSPID|LDP_ATTR_TRAFFIC); break; } } ds_attr = LDP_LIST_NEXT(ds_list,ds_attr,_fs); } } if(dup == LDP_TRUE && ds_attr == NULL) { /* * if we get here, then we recieved an unsolicted mapping for an FEC * that we already have a label for, if we want mulitple labels per * FEC we will request it, thus it won't be unsolicited * * label values are not the same, if they were ds_attr would not be NULL */ LDP_PRINT(g->user_data,"LMp.10 dup without req\n"); goto Receive_Label_Map_32; } Receive_Label_Map_11: result = ldp_get_next_hop_session_for_fec(g,fec,&next_hop, &nh_session); /* LMp.11 */ /* * are we configured to accept and INSTALL this mapping? */ if(ldp_policy_import_check(g->user_data,fec,next_hop,s) == LDP_FALSE) { /* * policy has rejected it, store it away */ r_attr->filtered = LDP_TRUE; ldp_attr_insert_downstream(g,s,r_attr); goto Receive_Label_Map_33; } if(result != LDP_SUCCESS || nh_session->index != s->index) { /* LMp.12 */ /* * the active next hop of the FEC isn't doesn't match this * mapping */ if(g->label_retention_mode == LDP_RETENTION_CONSERVATIVE) { /* LMp.13C */ LDP_PRINT(g->user_data,"LMp.13C conservative\n"); goto Receive_Label_Map_32; } /* * store it away */ fprintf(stderr,"index: %3d %08x/%d %d\n",r_attr->index, r_attr->fecTlv.fecElArray[0].addressEl.address, r_attr->fecTlv.fecElArray[0].addressEl.preLen,r_attr->state); ldp_attr_insert_downstream(g,s,r_attr); /* LMp.13L */ goto Receive_Label_Map_33; } if(installed == LDP_FALSE) { /* * we haven't installed it yet (either new, or a result of a FEC change * and we had this mapping in our database) */ if((out = ldp_outlabel_create_complete(g,s,next_hop,r_attr)) == NULL) { LDP_PRINT(g->user_data,"LMp.13L failure creating outlabel\n"); goto Receive_Label_Map_32; } LDP_TRACE_LOG(g->user_data,LDP_TRACE_STATE_ALL,LDP_TRACE_FLAG_BINDING, "Out Label Added\n"); if(ldp_mpls_outlabel_add(g->mpls_handle,out) == LDP_FAILURE) {/* LMp.15 */ ldp_outlabel_delete_complete(g,out); LDP_PRINT(g->user_data,"LMp.15 failure installing label\n"); goto Receive_Label_Map_32; } /* * are we configured to act as ingress for this FEC? */ if(ldp_policy_ingress_check(g->user_data,fec,next_hop,nh_session) == LDP_TRUE) { /* LMp.14 */ /* * yep, bind the label to the FEC */ ldp_mpls_fec2out_add(g->mpls_handle,fec,out); out->merge_count++; } /* * the first time we see this mapping we need to add it to the database * all future updats will modify this entry in place */ r_attr->installed = LDP_TRUE; if(r_attr->in_tree == LDP_FALSE) { ldp_attr_insert_downstream(g,s,r_attr); /* LMp.16 */ } } /* create a set of attrs that we would sent out, if we do sent out */ memset(&dumb_attr,0,sizeof(ldp_attr)); ldp_fec2fec_tlv(fec,&dumb_attr.fecTlv,0); dumb_attr.fecTlvExists = 1; dumb_attr.fecTlv.numberFecElements = 1; peer = LDP_LIST_HEAD(&g->session); while(peer != NULL) { /* LMp.17 */ if(peer->index == s->index) { goto next_peer; } if((us_attr = ldp_attr_find_upstream_state(g,peer,fec, LDP_LSP_STATE_MAP_SENT)) != NULL) { /* LMp.18 */ goto Receive_Label_Map_22; } if(peer->oper_distribution_mode == LDP_DISTRIBUTION_UNSOLICITED && g->lsp_control_mode == LDP_CONTROL_ORDERED) { /* LMp.19 */ #ifdef JLEU_FUNCIONALITY /* * if we're not merging and we have multiple DU sessions, we will * to start requesting labels after we propogate the mapping to * the first peer */ if(need_request == LDP_TRUE) { if(ldp_attr_find_downstream_state(g,peer,fec, LDP_LSP_STATE_REQ_SENT) == NULL) { /* * we don't have a request for FEC to peer outstanding, make one */ if(ldp_label_request_for_xc(g,peer,fec,r_attr) == LDP_FAILURE) { goto ldp_label_mapping_process_failure; } } } else { #endif /* * either we're merging and in DU mode, or we're not merging and * int DU mode AND this is the first peer we're propogating this * mapping to */ if(ldp_label_mapping_with_xc(g,peer,fec,r_attr) == LDP_FAILURE) { /* LMp.20-21,30 */ goto ldp_label_mapping_process_failure; } #ifdef JLEU_FUNCIONALITY if(g->label_merge == LDP_FALSE) { need_request = LDP_TRUE; } } #endif } goto Receive_Label_Map_28; Receive_Label_Map_22: /* * processing here only occurs if we have already * sent atleast one label map for this FEC to "s" */ /* * this next loop is for updating our peers of changed attributes */ Prepare_Label_Mapping_Attributes(g,peer,fec,r_attr,&dumb_attr, LDP_TRUE,LDP_TRUE); if((us_list = ldp_attr_find_upstream_all(g,peer,fec)) != NULL) { us_attr = LDP_LIST_HEAD(us_list); while(us_attr != NULL) { if(us_attr->state == LDP_LSP_STATE_MAP_SENT && (ldp_attr_is_equal( us_attr,&dumb_attr,LDP_ATTR_HOPCOUNT|LDP_ATTR_PATH) != LDP_TRUE)) { /* LMp.23 */ Prepare_Label_Mapping_Attributes(g,peer,fec,r_attr,us_attr, LDP_TRUE,LDP_TRUE); /* LMp.24,26 */ if(ldp_label_mapping_send(g,peer,us_attr) == LDP_FAILURE) { /* LMp.25 */ goto next_peer; } } us_attr = LDP_LIST_NEXT(us_list,us_attr,_fs); } /* LMp.27 */ } Receive_Label_Map_28: if((us_attr = ldp_attr_find_upstream_state(g,peer,fec, LDP_LSP_STATE_REQ_RECV)) == NULL) { /* * this deviates from the LMp procudure because I do the * cross connect where ever I send a new label mapping */ goto next_peer; } /* * processing here is to handle the case where * this mapping is in reponsed to a label request */ if(peer->oper_distribution_mode == LDP_DISTRIBUTION_UNSOLICITED) { /* * if there are outstanding requests when in DU mode, then we aren't * merging, therefore we can only services one request with this * mapping */ if(ldp_label_mapping_with_xc(g,peer,fec,r_attr) == LDP_FAILURE) { /* LMp.29.DU,30 */ goto ldp_label_mapping_process_failure; } if(g->label_merge == LDP_FALSE) { goto Receive_Label_Map_33; } goto next_peer; } /* * this peer is in DoD and has atleast one outstanding * requests for this FEC */ if((us_list = ldp_attr_find_upstream_all(g,peer,fec)) == NULL) { goto next_peer; } us_attr = LDP_LIST_HEAD(us_list); while(us_attr != NULL) { if(us_attr->state == LDP_LSP_STATE_REQ_RECV) { /* LMp.29.D1 */ if(ldp_label_mapping_with_xc(g,peer,fec,r_attr) == LDP_FAILURE) { /* LMp.29.DoD,30 */ goto ldp_label_mapping_process_failure; } if(g->label_merge == LDP_FALSE) { goto Receive_Label_Map_33; } } us_attr = LDP_LIST_NEXT(us_list,us_attr,_fs); } next_peer: peer = LDP_LIST_NEXT(&g->session,peer,_global); } /* LMp.31 */ goto Receive_Label_Map_33; Receive_Label_Map_32: LDP_PRINT(g->user_data,"Receive_Label_Map_32: send release"); if(ldp_label_release_send(g,s,r_attr,LDP_NOTIF_NONE) == LDP_FAILURE) { /* LMp.32 */ goto ldp_label_mapping_process_failure; } return LDP_SUCCESS; Receive_Label_Map_33: LDP_EXIT(g->user_data,"ldp_label_mapping_process"); return LDP_SUCCESS; ldp_label_mapping_process_failure: LDP_EXIT(g->user_data,"ldp_label_mapping_process-failure"); return LDP_FAILURE; }