ldp_attr *ldp_attr_create(ldp_global *g, mpls_fec * fec) { ldp_attr *a = (ldp_attr *) mpls_malloc(sizeof(ldp_attr)); if (a != NULL) { memset(a, 0, sizeof(ldp_attr)); MPLS_LIST_ELEM_INIT(a, _session); MPLS_LIST_ELEM_INIT(a, _global); MPLS_LIST_ELEM_INIT(a, _fs); MPLS_LIST_INIT(&a->us_attr_root, ldp_attr); MPLS_REFCNT_INIT(a, 0); a->index = _ldp_attr_get_next_index(); a->in_tree = MPLS_BOOL_FALSE; a->ingress = MPLS_BOOL_FALSE; a->filtered = MPLS_BOOL_FALSE; if (fec != NULL) { mpls_fec2fec_tlv(fec, &a->fecTlv, 0); a->fecTlv.numberFecElements = 1; a->fecTlvExists = 1; } _ldp_global_add_attr(g, a); } return a; }
mpls_return_enum ldp_label_mapping_process(ldp_global * g, ldp_session * s, ldp_adj * a, ldp_entity * e, ldp_attr * r_attr, ldp_fec * f) { mpls_return_enum retval = MPLS_SUCCESS; ldp_session *peer = NULL; ldp_attr_list *us_list = NULL; ldp_attr_list *ds_list = NULL; ldp_attr *ds_attr = NULL; ldp_attr *ds_temp = NULL; ldp_attr *us_attr = NULL; ldp_attr *us_temp = NULL; ldp_attr dumb_attr; ldp_nexthop *nh = NULL; ldp_outlabel *out = NULL; mpls_bool requested = MPLS_BOOL_FALSE; ldp_attr *existing = NULL; mpls_bool need_request = MPLS_BOOL_FALSE; LDP_ENTER(g->user_data, "ldp_label_mapping_process"); LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV, LDP_TRACE_FLAG_LABEL, "Label Mapping Recv from %s for %08x/%d\n", s->session_name, r_attr->fecTlv.fecElArray[0].addressEl.address, r_attr->fecTlv.fecElArray[0].addressEl.preLen); if ((ds_attr = ldp_attr_find_downstream_state2(g, s, f, LDP_LSP_STATE_REQ_SENT)) != NULL) { /* LMp.1 */ /* just remove the req from the tree, we will use the r_attr sent to us */ ldp_attr_delete_downstream(g, s, ds_attr); requested = MPLS_BOOL_TRUE; } else { requested = MPLS_BOOL_FALSE; } ds_attr = r_attr; ds_attr->state = LDP_LSP_STATE_MAP_RECV; /* LMp.2 */ /* * ds_attr is the mapping we will keep and is NOT in the tree, unless * it is an update mapping ... */ if (Check_Received_Attributes(g, s, ds_attr, MPLS_LBLMAP_MSGTYPE) == MPLS_SUCCESS) { /* LMp.3 */ goto LMp_9; } /* * A loop was detected */ if ((ds_list = ldp_attr_find_downstream_all2(g, s, f))) { ds_temp = MPLS_LIST_HEAD(ds_list); /* * check all the labels this session has received from "s" for "fec" * do we have a duplicat? */ while (ds_temp) { if ((ds_temp->state == LDP_LSP_STATE_MAP_RECV) && /* LMp.4 */ ldp_attr_is_equal(ds_temp, ds_attr, LDP_ATTR_LABEL) == /* LMp.5 */ MPLS_BOOL_TRUE) { /* remove record of the label and remove it switching */ ldp_attr_remove_complete(g, ds_temp, MPLS_BOOL_TRUE); /* LMp.6,7 */ /* * I think this is supposed to be 32 NOT 33, we need to release * it don't we? */ goto LMp_33; } ds_temp = MPLS_LIST_NEXT(ds_list, ds_temp, _fs); } } LDP_PRINT(g->user_data, "Receive_Label_Map_8: send release"); if (ldp_label_release_send(g, s, ds_attr, LDP_NOTIF_LOOP_DETECTED) != MPLS_SUCCESS) { /* LMp.8 */ retval = MPLS_FAILURE; } goto LMp_33; LMp_9: /* * No Loop Detected */ ds_temp = ldp_attr_find_downstream_state2(g, s, f, LDP_LSP_STATE_MAP_RECV); if (requested == MPLS_BOOL_TRUE || g->label_merge == MPLS_BOOL_FALSE || !ds_temp) { /* !merging then this is always a new LSP * merging w/o a recv'd mapping is a new LSP * this check comes from Note 6 */ goto LMp_11; } /* searching all recv'd attrs for matched mappings, * stop after finding 1st match */ if ((ds_list = ldp_attr_find_downstream_all2(g, s, f))) { ds_temp = MPLS_LIST_HEAD(ds_list); while (ds_temp) { if (ds_temp->state == LDP_LSP_STATE_MAP_RECV) { /* LMp.9 */ if (ldp_attr_is_equal(ds_attr, ds_temp, LDP_ATTR_LABEL) == MPLS_BOOL_TRUE) { /* LMp.10 */ /* * this mapping matches an existing mapping, but it * could contain updated attributes */ existing = ds_temp; break; } else { /* * we have been given another label for the same FEC and we * didn't request it, release it */ LDP_PRINT(g->user_data, "LMp.10 dup without req\n"); goto LMp_32; } } ds_temp = MPLS_LIST_NEXT(ds_list, ds_temp, _fs); } } if (existing) { ldp_attr2ldp_attr(ds_attr, existing, LDP_ATTR_HOPCOUNT | LDP_ATTR_PATH | LDP_ATTR_MSGID | LDP_ATTR_LSPID | LDP_ATTR_TRAFFIC); ds_attr = existing; /* * no need to free ds_attr, since it was not added to the tree it * will be deleted when we exit ldp_label_mapping_process(), see * ldp_state_process(). */ } /* * from this point on.... if this is an updated mapping then ds_attr * is the existing mapping which has now been update, else ds_attr * is the new mapping */ LMp_11: /* * existing ONLY has a value for updated label mapping */ nh = ldp_nexthop_for_fec_session(f,s); /* LMp.11 */ /* * the following departs from the procedure, it allows for filtering * of label mappings * * Are we configured to accept and INSTALL this mapping? */ if (mpls_policy_import_check(g->user_data, &f->info, &nh->info) == MPLS_BOOL_FALSE) { /* * policy has rejected it, store it away */ LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV, LDP_TRACE_FLAG_LABEL, "Label Mapping for %08x/%d from %s filtered by import policy\n", r_attr->fecTlv.fecElArray[0].addressEl.address, r_attr->fecTlv.fecElArray[0].addressEl.preLen, s->session_name); if (existing) { ds_attr->filtered = MPLS_BOOL_TRUE; if (ds_attr->outlabel && ds_attr->outlabel->switching == MPLS_BOOL_TRUE) { /* the mapping has been filtered, but the original wasn't? */ MPLS_ASSERT(0); } } else { ds_attr->filtered = MPLS_BOOL_TRUE; if (ldp_attr_insert_downstream(g, s, ds_attr) != MPLS_SUCCESS) { retval = MPLS_FAILURE; } } goto LMp_33; } if (!nh) { /* LMp.12 */ /* * if we did not find a nh hop for this FEC that corresponded to the * MsgSource then the MsgSource is not a nexthop for the FEC */ if (g->label_retention_mode == LDP_RETENTION_CONSERVATIVE) { /* LMp.13C */ LDP_PRINT(g->user_data, "LMp.13C conservative\n"); goto LMp_32; } /* * store it away */ LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV, LDP_TRACE_FLAG_LABEL, "Session %s is not a valid nexthop for %08x/%d\n", s->session_name, r_attr->fecTlv.fecElArray[0].addressEl.address, r_attr->fecTlv.fecElArray[0].addressEl.preLen); if (!existing) { /* LMp.13L */ if (ldp_attr_insert_downstream(g, s, ds_attr) != MPLS_SUCCESS) { retval = MPLS_FAILURE; } } goto LMp_33; } /* * this is slightly different form the procedure, we can still be * transit for a FEC we are not configured to be ingress for. * Either way we only need to do the "install for fwd/switching" * only once. We could arrive here multiple times due to updates, * only install it the first time */ if ((!existing) || (!existing->outlabel)) { /* * we haven't installed it yet. * Either new (!existing), or a result of a "Detect FEC Nexthop Change" * and we had this mapping in our database (!existing->outlabel)) */ if (!(out = ldp_outlabel_create_complete(g, s, ds_attr, nh))) { LDP_PRINT(g->user_data, "LMp.15 failure creating outlabel\n"); goto LMp_32; } LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_ALL, LDP_TRACE_FLAG_BINDING, "Out Label Added\n"); } /* * are we configured to act as ingress for this FEC? */ if (mpls_policy_ingress_check(g->user_data, &f->info, &nh->info) == MPLS_BOOL_TRUE) { /* LMp.14 */ /* * yep, bind the label to the FEC */ 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_ADD|LSR_FTN_CFG_FEC| LSR_FTN_CFG_OUTSEGMENT); #else mpls_mpls_fec2out_add(g->mpls_handle, &f->info, &ds_attr->outlabel->info); #endif ds_attr->ingress = MPLS_BOOL_TRUE; ds_attr->outlabel->merge_count++; LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV, LDP_TRACE_FLAG_BINDING, "Acting as ingress for %08x/%d from %s\n", r_attr->fecTlv.fecElArray[0].addressEl.address, r_attr->fecTlv.fecElArray[0].addressEl.preLen, s->session_name); } } /* create a set of attrs that we will fill and compare against * if this mapping were to be propogate these are the attrs it would have * by comparing what we did sent in the past to these, we con figure out * if we need to send an updated mapping */ memset(&dumb_attr, 0, sizeof(ldp_attr)); mpls_fec2fec_tlv(&f->info, &dumb_attr.fecTlv, 0); dumb_attr.fecTlvExists = 1; dumb_attr.fecTlv.numberFecElements = 1; /* * by definition (we received a label mapping that will be used) this * LSR is _not_ the egress, so calculate a hop and path based on the * mapping we received. We will compare this with mapping that have * already been sent. If they differ, we will send an updated mapping */ Prepare_Label_Mapping_Attributes(g, s, &f->info, ds_attr, &dumb_attr, MPLS_BOOL_TRUE, MPLS_BOOL_TRUE, MPLS_BOOL_FALSE); if (!existing) { /* * this is the first time we've seen this mapping, add it to the database. * all future updates will modify this entry in place */ /* LMp.16 */ printf("!!!LMp16!!!\n"); if (ldp_attr_insert_downstream(g, s, ds_attr) != MPLS_SUCCESS) { retval = MPLS_FAILURE; goto LMp_33; } } peer = MPLS_LIST_HEAD(&g->session); while (peer) { /* LMp.17 */ if (peer->state != LDP_STATE_OPERATIONAL) { goto next_peer; } /* * it is just as easy to walk the list of all upstream attr for this * peer as it is to the individual check to see if we have sent a * label mapping for this FEC LSP */ // #error this whole section is f ed /* LMp.22 - 27 */ if ((us_list = ldp_attr_find_upstream_all2(g, peer, f))) { /* LMp.23 */ us_temp = MPLS_LIST_HEAD(us_list); while (us_temp) { /* * if we have sent a label mapping for the FEC and that label mapping * was an done in independent mode or it is part of an LSP created * due as part of an existing received label mapping */ /* LMp.18 */ if (us_temp->state == LDP_LSP_STATE_MAP_SENT) { LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV, LDP_TRACE_FLAG_BINDING, "Already sent mapping for %08x/%d to %s\n", r_attr->fecTlv.fecElArray[0].addressEl.address, r_attr->fecTlv.fecElArray[0].addressEl.preLen, peer->session_name); if ((!existing) || (existing->index == us_temp->ds_attr->index)) { LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV, LDP_TRACE_FLAG_BINDING, "Part of same LSP\n"); /* are the received attrs the same as the ones we've already sent */ if (ldp_attr_is_equal(us_temp, &dumb_attr, LDP_ATTR_HOPCOUNT | LDP_ATTR_PATH) != MPLS_BOOL_TRUE) { LDP_TRACE_LOG(g->user_data, MPLS_TRACE_STATE_RECV, LDP_TRACE_FLAG_BINDING, "Propogating updated attrs\n"); /* send an updated label mapping */ if (ldp_label_mapping_with_xc(g, us_temp->session, f, &us_temp, ds_attr) != MPLS_SUCCESS) { /* LMp.24-26 */ retval = MPLS_FAILURE; goto LMp_33; } } } } us_temp = MPLS_LIST_NEXT(us_list, us_temp, _fs); } } if ((peer->oper_distribution_mode == LDP_DISTRIBUTION_UNSOLICITED) && (g->lsp_control_mode == LDP_CONTROL_ORDERED)) { /* LMp.19 */ /* * if we're not merging and we have multiple ORDERED DU sessions, * we will to start requesting labels after we propogate the mapping to * the first peer */ if (need_request == MPLS_BOOL_TRUE) { if (ldp_attr_find_downstream_state2(g, peer, f, LDP_LSP_STATE_REQ_SENT) == NULL) { /* * we don't have a request for FEC to peer outstanding, make one */ ds_temp = NULL; if (ldp_label_request_for_xc(g, peer, &f->info, NULL, &ds_temp) != MPLS_SUCCESS) { retval = MPLS_FAILURE; goto LMp_33; } } } else { /* * We're in DU more, either we're merging, or we're not merging and * this is the first peer we're propogating this mapping to */ /* LMp.20-21,30 */ us_attr = NULL; if (ldp_label_mapping_with_xc(g, peer, f, &us_attr, ds_attr) != MPLS_SUCCESS) { retval = MPLS_FAILURE; goto LMp_33; } /* * if we're not merging, we will need to request a label for * the next DU peer */ if (g->label_merge == MPLS_BOOL_FALSE) { need_request = MPLS_BOOL_TRUE; } } } /* LMp.28 */ while ((us_temp = ldp_attr_find_upstream_state2(g, peer, f, LDP_LSP_STATE_REQ_RECV))) { if (peer->oper_distribution_mode == LDP_DISTRIBUTION_UNSOLICITED) { if (need_request == MPLS_BOOL_TRUE) { if (ldp_attr_find_downstream_state2(g, peer, f, LDP_LSP_STATE_REQ_SENT) == NULL) { /* * we don't have a request for FEC to peer outstanding */ ds_temp = NULL; if (ldp_label_request_for_xc(g, peer, &f->info, us_temp, &ds_temp) != MPLS_SUCCESS) { retval = MPLS_FAILURE; goto LMp_33; } } } else { if (ldp_label_mapping_with_xc(g, peer, f, &us_temp, ds_attr) != MPLS_SUCCESS) { retval = MPLS_FAILURE; goto LMp_33; } } } else { if ((us_list = ldp_attr_find_upstream_all2(g, peer, f))) { us_temp = MPLS_LIST_HEAD(ds_list); while (us_temp) { if (us_temp->state == LDP_LSP_STATE_REQ_RECV) { if (need_request == MPLS_BOOL_TRUE) { if (ldp_attr_find_downstream_state2(g, peer, f, LDP_LSP_STATE_REQ_SENT) == NULL) { /* * we don't have a request for FEC to peer outstanding */ ds_temp = NULL; if (ldp_label_request_for_xc(g, peer, &f->info, us_temp, &ds_temp) != MPLS_SUCCESS) { retval = MPLS_FAILURE; goto LMp_33; } } } else { if (ldp_label_mapping_with_xc(g, peer, f, &us_temp, ds_attr) != MPLS_SUCCESS) { retval = MPLS_FAILURE; goto LMp_33; } /* * if we're not merging, we will need to request a label for * the next DU peer */ if (g->label_merge == MPLS_BOOL_FALSE) { need_request = MPLS_BOOL_TRUE; } } } us_temp = MPLS_LIST_NEXT(us_list, us_temp, _fs); } } } } next_peer: peer = MPLS_LIST_NEXT(&g->session, peer, _global); } LMp_33: LDP_EXIT(g->user_data, "ldp_label_mapping_process"); return retval; LMp_32: LDP_PRINT(g->user_data, "Receive_Label_Map_32: send release"); if (ldp_label_release_send(g, s, ds_attr, LDP_NOTIF_NONE) != MPLS_SUCCESS) { retval = MPLS_FAILURE; } LDP_EXIT(g->user_data, "ldp_label_mapping_process"); return retval; }
void Prepare_Label_Mapping_Attributes(ldp_global * g, ldp_session * s, mpls_fec * fec, ldp_attr * r_attr, ldp_attr * s_attr, mpls_bool propogating, mpls_bool already, mpls_bool egress) { 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) { memset(&dummy, 0, sizeof(ldp_attr)); mpls_fec2fec_tlv(fec, &dummy.fecTlv, 0); dummy.fecTlvExists = 1; dummy.fecTlv.numberFecElements = 1; r_attr = &dummy; } if (!(s->oper_loop_detection == LDP_LOOP_HOPCOUNT || s->oper_loop_detection == LDP_LOOP_HOPCOUNT_PATHVECTOR || r_attr->hopCountTlvExists)) { /* PMpA.1 */ LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes"); return; } if (egress) {/* PMpA.2 */ /* I'm egress (for now) */ s_attr->hopCountTlvExists = 1; s_attr->hopCountTlv.hcValue = 1; /* PMpA.3 */ LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes"); return; } if (!(r_attr->hopCountTlvExists)) { /* PMpA.4 */ goto Prepare_Label_Mapping_Attributes_8; } if (!(g->ttl_less_domain == MPLS_BOOL_TRUE && s->cfg_remote_in_ttl_less_domain == MPLS_BOOL_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) { LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes"); return; } if (r_attr->pathVecTlvExists) { /* PMpA.10 */ goto Prepare_Label_Mapping_Attributes_19; } if (propogating == MPLS_BOOL_FALSE) { /* PMpA.11 */ goto Prepare_Label_Mapping_Attributes_20; } if (g->label_merge != MPLS_BOOL_TRUE) { /* PMpA.12 */ goto Prepare_Label_Mapping_Attributes_14; } if (already == MPLS_BOOL_FALSE) { /* PMpA.13 */ goto Prepare_Label_Mapping_Attributes_20; } Prepare_Label_Mapping_Attributes_14: if (!r_attr->hopCountTlvExists) { LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes"); return; } if (r_attr->hopCountTlv.hcValue == 0) { /* PMpA.15 */ goto Prepare_Label_Mapping_Attributes_20; } if (already == MPLS_BOOL_FALSE) { /* PMpA.16 */ LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes"); return; } /* r_attr contain PrevHopCount _IF_ we had one */ LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes"); return; /* PMpA.17 */ if (r_attr->hopCountTlv.hcValue != 0) { /* PMpA.18 */ LDP_EXIT(g->user_data, "Prepare_Label_Mapping_Attributes"); 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; }