/* * 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_prefix.h" #include "ldp_fec.h" #include "ldp_if.h" #include "ldp_attr.h" #include "ldp_session.h" #include "ldp_inlabel.h" #include "ldp_outlabel.h" #include "ldp_global.h" #include "ldp_label_mapping.h" #include "ldp_label_request.h" #include "ldp_label_abort.h" #include "ldp_label_rel_with.h" #include "ldp_mpls_impl.h" #include "ldp_mm_impl.h" #include ldp_return_enum Recognize_New_Fec(ldp_global* g,ldp_fec* f) { ldp_session* peer = NULL; ldp_session* nh_session = NULL; ldp_attr* ds_attr = NULL; ldp_attr* s_attr = NULL; ldp_bool propogating = LDP_FALSE; ldp_bool egress = LDP_FALSE; /* * find the info about the next hop for this FEC */ switch(ldp_get_next_hop_session_for_fec(g,f,NULL,&nh_session)) { case LDP_SUCCESS: break; case LDP_FAILURE: /* * we found the route, but no next hop */ egress = LDP_TRUE; break; case LDP_NO_ROUTE: return LDP_FAILURE; default: LDP_ASSERT(0); } ds_attr = ldp_attr_find_downstream_state(g,nh_session,f, LDP_LSP_STATE_MAP_RECV); /* * if we have an received a mapping then any mapping we sent will be * a "propogated" mapping */ if(ds_attr != NULL) { /* FEC.1.DUI2 */ propogating = LDP_TRUE; } else { propogating = LDP_FALSE; } /* * for every peer except the nh hop peer, check to see if we need to * send a mapping */ peer = LDP_LIST_HEAD(&g->session); while(peer != NULL) { /* FEC.1 */ if(nh_session && peer->index == nh_session->index) { goto next_peer; } if(peer->oper_distribution_mode == LDP_DISTRIBUTION_UNSOLICITED) { if(g->lsp_control_mode == LDP_CONTROL_INDEPENDENT) { s_attr = ldp_attr_create(f); if(s_attr == NULL) { goto next_peer; } Prepare_Label_Mapping_Attributes(g,peer,f,ds_attr,s_attr,propogating, LDP_TRUE); /* FEC.1.DUI3 */ s_attr->state = LDP_LSP_STATE_MAP_SENT; if(ldp_label_mapping_send(g,peer,s_attr) == LDP_FAILURE) { /* FEC.1.DUI4 */ ldp_attr_delete(s_attr); goto next_peer; } } else { /* *LDP_CONTROL_ORDERED */ if(ds_attr != NULL || egress == LDP_TRUE) { /* FEC.1.DUO2 */ s_attr = ldp_attr_create(f); if(s_attr == NULL) { goto next_peer; } Prepare_Label_Mapping_Attributes(g,peer,f,ds_attr,s_attr,propogating, LDP_TRUE); /* FEC.1.DUO3 */ s_attr->state = LDP_LSP_STATE_MAP_SENT; if(ldp_label_mapping_send(g,peer,s_attr) == LDP_FAILURE) { /* FEC.1.DUO4 */ ldp_attr_delete(s_attr); goto next_peer; } } } } next_peer: peer = LDP_LIST_NEXT(&g->session,peer,_global); } if(ds_attr != NULL) { /* FEC.2 */ if(ldp_label_mapping_process(g,nh_session,NULL,NULL,ds_attr,f) == LDP_FAILURE) { /* FEC.5 */ return LDP_FAILURE; } return LDP_SUCCESS; } /* * LDP_DISTRIBUTION_ONDEMAND */ if(nh_session != NULL) { /* FEC.3 */ if(ldp_label_request_for_xc(g,nh_session,f,NULL) == LDP_FAILURE) { /* FEC.4 */ return LDP_FAILURE; } } return LDP_SUCCESS; /* FEC.6 */ } ldp_return_enum Detect_Change_Fec_Next_Hop(ldp_global* g,ldp_fec* f, ldp_session* nh_old) { ldp_session* peer = NULL; ldp_attr_list* us_list = NULL; ldp_attr* s_attr = NULL; ldp_attr* us_attr = NULL; ldp_attr* ds_attr = NULL; ldp_session* nh_new = NULL; ldp_return_enum result; result = ldp_get_next_hop_session_for_fec(g,f,NULL,&nh_new); /* * NH 1-5 decide if we need to release an existing mapping */ ds_attr = ldp_attr_find_downstream_state(g,nh_old,f,LDP_LSP_STATE_MAP_RECV); if(ds_attr == NULL) { /* NH.1 */ goto Detect_Change_Fec_Next_Hop_6; } if(g->label_retention_mode == LDP_RETENTION_LIBERAL) { /* NH.3 */ goto Detect_Change_Fec_Next_Hop_6; } ldp_label_release_send(g,nh_old,ds_attr,LDP_NOTIF_NONE); /* NH.4 */ ldp_attr_remove_complete(g,ds_attr); /* 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_state(g,nh_old,f,LDP_LSP_STATE_REQ_SENT); if(ds_attr == NULL) { /* NH.6 */ goto Detect_Change_Fec_Next_Hop_10; } if(g->label_retention_mode != LDP_RETENTION_CONSERVATIVE) { /* NH.7 */ goto Detect_Change_Fec_Next_Hop_10; } ldp_label_abort_send(g,nh_old,ds_attr); /* NH.8 */ ds_attr->state = LDP_LSP_STATE_ABORT_SENT; /* NH.9 */ Detect_Change_Fec_Next_Hop_10: /* * NH 10-12 decides if we can use a mapping from our database */ if(nh_new == NULL) { goto Detect_Change_Fec_Next_Hop_16; } ds_attr = ldp_attr_find_downstream_state(g,nh_new,f,LDP_LSP_STATE_REQ_SENT); if(ds_attr == NULL) { /* NH.13 */ goto Detect_Change_Fec_Next_Hop_13; } ldp_label_mapping_process(g,nh_new,NULL,NULL,ds_attr,f); /* NH.12 */ 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_new->oper_distribution_mode != LDP_DISTRIBUTION_ONDEMAND && g->label_retention_mode != LDP_RETENTION_CONSERVATIVE) { goto Detect_Change_Fec_Next_Hop_20; } s_attr = ldp_attr_create(f); if(s_attr == NULL) { return LDP_FAILURE; } s_attr->state = LDP_LSP_STATE_REQ_SENT; Prepare_Label_Request_Attributes(g,nh_new,f,NULL,s_attr); /* NH.14 */ /* JLEU XXX * send a label request message, do not call * ldp_label_request_send() */ /* NH.15 */ ldp_attr_insert_downstream(g,nh_new,s_attr); goto Detect_Change_Fec_Next_Hop_20; Detect_Change_Fec_Next_Hop_16: /* * NH 16-19 we don't a outgoing label, withdraw all of the labels I * advertised for this FEC (this is a global repair!) */ peer = LDP_LIST_HEAD(&g->session); while(peer != NULL) { /* NH.16 */ us_attr = NULL; if((us_list = ldp_attr_find_upstream_all(g,peer,f)) != NULL) { us_attr = LDP_LIST_HEAD(us_list); while(us_attr != NULL) { if(us_attr->state == LDP_LSP_STATE_MAP_SENT) { /* NH.17 */ ldp_label_withdraw_send(g,peer,us_attr,LDP_NOTIF_NONE);/*NH.18 */ } us_attr = LDP_LIST_NEXT(us_list,us_attr,_fs); } } peer = LDP_LIST_NEXT(&g->session,peer,_global); } /* NH.19 */ Detect_Change_Fec_Next_Hop_20: return LDP_SUCCESS; } ldp_return_enum ldp_prefix_empty(ldp_prefix* p) { LDP_ASSERT(p != NULL); p->out_if_handle = (ldp_if_handle)0; memset(&p->network,0,sizeof(ldp_inet_addr)); memset(&p->next_hop,0,sizeof(ldp_inet_addr)); p->prefix_len = 0; return LDP_SUCCESS; } ldp_return_enum ldp_prefix_fill(ldp_prefix* p,ldp_inet_addr* prefix, int prefix_len,ldp_inet_addr* next_hop,ldp_if* out_if) { LDP_ASSERT(p != NULL); if(out_if != NULL) { p->out_if_handle = out_if->handle; } if(prefix != NULL) memcpy(&p->network,prefix,sizeof(ldp_inet_addr)); if(next_hop != NULL) memcpy(&p->next_hop,next_hop,sizeof(ldp_inet_addr)); p->prefix_len = prefix_len; return LDP_SUCCESS; } ldp_fec* ldp_fec_create() { ldp_fec* fec = (ldp_fec*)ldp_malloc(sizeof(ldp_fec)); if(fec != NULL) { memset(fec,0,sizeof(ldp_fec)); LDP_REFCNT_INIT(fec,0); LDP_LIST_ELEM_INIT(fec,_global); LDP_LIST_ELEM_INIT(fec,_inlabel); LDP_LIST_ELEM_INIT(fec,_outlabel); LDP_LIST_ELEM_INIT(fec,_fec); LDP_LIST_ELEM_INIT(fec,_nh); LDP_LIST_INIT(&fec->fs_root_us,ldp_fs); LDP_LIST_INIT(&fec->fs_root_ds,ldp_fs); fec->type = LDP_FEC_PREFIX; } return fec; } void ldp_fec2ldp_fec(ldp_fec* a,ldp_fec* b) { b->type = a->type; memcpy(&b->prefix,&a->prefix,sizeof(ldp_inet_addr)); b->prefix_len = a->prefix_len; } ldp_fec* ldp_fec_create_host(ldp_inet_addr* host) { ldp_fec* fec = ldp_fec_create(); if(fec != NULL) { fec->type = LDP_FEC_HOST; memcpy(&fec->prefix,host,sizeof(ldp_inet_addr)); fec->prefix_len = 32; } return fec; } ldp_fec* ldp_fec_create_prefix(ldp_inet_addr* prefix,int prefix_len) { ldp_fec* fec = ldp_fec_create(); if(fec != NULL) { fec->type = LDP_FEC_PREFIX; memcpy(&fec->prefix,prefix,sizeof(ldp_inet_addr)); fec->prefix_len = prefix_len; } return fec; } void ldp_fec_delete(ldp_fec* fec) { ldp_free(fec); } void ldp_fec2fec_tlv(ldp_fec* lf,mplsLdpFecTlv_t* tlv,int i) { tlv->fecElArray[i].addressEl.addressFam = 1; switch(lf->type) { case LDP_FEC_PREFIX: tlv->fecElArray[i].addressEl.type = MPLS_PREFIX_FEC; tlv->fecElArray[i].addressEl.preLen = lf->prefix_len; tlv->fecElArray[i].addressEl.address = lf->prefix.u.ipv4; tlv->fecElemTypes[i] = MPLS_PREFIX_FEC; break; case LDP_FEC_HOST: tlv->fecElArray[i].addressEl.type = MPLS_HOSTADR_FEC; tlv->fecElArray[i].addressEl.preLen = MPLS_IPv4LEN; tlv->fecElArray[i].addressEl.address = lf->prefix.u.ipv4; tlv->fecElemTypes[i] = MPLS_HOSTADR_FEC; break; default: LDP_ASSERT(0); } } void fec_tlv2ldp_fec(mplsLdpFecTlv_t* tlv,int i,ldp_fec* lf) { switch(tlv->fecElemTypes[i]) { case MPLS_PREFIX_FEC: lf->type = LDP_FEC_PREFIX; lf->prefix_len = tlv->fecElArray[i].addressEl.preLen; lf->prefix.u.ipv4 = tlv->fecElArray[i].addressEl.address; lf->prefix.protocol = AF_INET; break; case MPLS_HOSTADR_FEC: lf->type = LDP_FEC_HOST; lf->prefix_len = 32; lf->prefix.u.ipv4 = tlv->fecElArray[i].addressEl.address; lf->prefix.protocol = AF_INET; break; default: LDP_ASSERT(0); } }