Beispiel #1
0
static int ldp_out_segment_read(int cmd, struct zclient *client,
    zebra_size_t size) {
    struct zapi_mpls_out_segment api;
    struct listnode *n;
    struct listnode *nn;
    mpls_outsegment *o;
    struct pending_ftn_data *fn;
    struct pending_xc_data *x;

    mpls_out_segment_stream_read(client->ibuf, &api);

    for (ALL_LIST_ELEMENTS(pending_out_segment, n, nn, o)) {
	if (api.req == o->handle) {
	    zlog_info("found pending NHLFE: %p", o);
	    o->handle = api.index;
	    list_delete_node(pending_out_segment,n);
	    goto ftn;
	}
    }
    zlog_info("requested out segment %d not in list", api.req);
    return 0;

ftn:
    /* if we've gotten this for then the o->handle is not the proper index */
    for (ALL_LIST_ELEMENTS(pending_ftn, n, nn, fn)) {
	if (api.index == fn->o->handle) {
	    mpls_mpls_fec2out_add(fn->h, fn->f, fn->o);
	    list_delete_node(pending_ftn,n);
	    break;
	}
    }
    for (ALL_LIST_ELEMENTS(pending_xc, n, nn, x)) {
	if (api.index == x->o->handle) {
	    mpls_mpls_xconnect_add(x->h, x->i, x->o);
	    list_delete_node(pending_xc,n);
	    break;
	}
    }
    return 0;
}
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;
}