Ejemplo n.º 1
0
/* RFC2740 3.8.1.  Calculating the shortest path tree for an area */
void ospf6_spf_calculation(u_int32_t router_id,
                           struct ospf6_route_table * result_table,
                           struct ospf6_area * oa, unsigned int hostnum)
{
  struct pqueue * candidate_list;
  struct ospf6_vertex * root, * v, * w;
  int i;
  int size;
  caddr_t lsdesc;
  struct ospf6_lsa * lsa;

  if(IS_OSPF6_SIBLING_DEBUG_SPF)
  {
    zlog_debug("Starting spf calculation...");
  }

  /* initialize */
  candidate_list = pqueue_create();
  candidate_list->cmp = ospf6_vertex_cmp;

  ospf6_spf_table_finish (result_table);

  /* Install the calculating router itself as the root of the SPF tree */
  /* construct root vertex */
  lsa = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_ROUTER), htonl (0),
                                   router_id, oa->lsdb);
  if (lsa == NULL)
  {
    if(IS_OSPF6_SIBLING_DEBUG_SPF)
    {
      zlog_debug("Looking for type %d from lsdb %p with router id %d", htons(OSPF6_LSTYPE_ROUTER), oa->lsdb, router_id);
      zlog_debug("No router LSAs present, quiting spf calculation");
    }
    return;
  }

  root = ospf6_vertex_create (lsa);
  root->area = oa;
  root->cost = 0;
  root->hops = 0;
  root->nexthop[0].ifindex = 0; /* loopbak I/F is better ... */
  inet_pton (AF_INET6, "::1", &root->nexthop[0].address);

  /* Actually insert root to the candidate-list as the only candidate */
  pqueue_enqueue (root, candidate_list);

  /* Iterate until candidate-list becomes empty */
  while (candidate_list->size)
  {
    /* get closest candidate from priority queue */
    v = pqueue_dequeue (candidate_list);

    /* installing may result in merging or rejecting of the vertex */
    if (ospf6_spf_install (v, result_table, hostnum) < 0)
      continue;

    /* For each LS description in the just-added vertex V's LSA */
    size = (VERTEX_IS_TYPE (ROUTER, v) ?
            sizeof (struct ospf6_router_lsdesc) :
            sizeof (struct ospf6_network_lsdesc));
    for (lsdesc = OSPF6_LSA_HEADER_END (v->lsa->header) + 4;
         lsdesc + size <= OSPF6_LSA_END (v->lsa->header); lsdesc += size)
    {
      lsa = ospf6_lsdesc_lsa (lsdesc, v);
      if (lsa == NULL)
        continue;

      if (! ospf6_lsdesc_backlink (lsa, lsdesc, v))
        continue;

      w = ospf6_vertex_create (lsa);
      w->area = oa;
      w->parent = v;
      if (VERTEX_IS_TYPE (ROUTER, v))
      {
        w->cost = v->cost + ROUTER_LSDESC_GET_METRIC (lsdesc);
        w->hops = v->hops + (VERTEX_IS_TYPE (NETWORK, w) ? 0 : 1);
      }
      else /* NETWORK */
      {
        w->cost = v->cost;
        w->hops = v->hops + 1;
      }
      /* nexthop calculation */
      if (w->hops == 0)
        w->nexthop[0].ifindex = ROUTER_LSDESC_GET_IFID (lsdesc);
      else if (w->hops == 1 && v->hops == 0)
        ospf6_nexthop_calc (w, v, lsdesc);
      else
      {
        for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
             i < OSPF6_MULTI_PATH_LIMIT; i++)
          ospf6_nexthop_copy (&w->nexthop[i], &v->nexthop[i]);
      }

      /* add new candidate to the candidate_list */
      if (IS_OSPF6_SIBLING_DEBUG_SPF)
        zlog_debug ("  New candidate: %s hops %d cost %d",
                    w->name, w->hops, w->cost);
        pqueue_enqueue (w, candidate_list);
    }
  }

  pqueue_delete (candidate_list);
}
Ejemplo n.º 2
0
void
ospf6_asbr_lsa_add (struct ospf6_lsa *lsa)
{
  struct ospf6_as_external_lsa *external;
  struct prefix asbr_id;
  struct ospf6_route *asbr_entry, *route;
  char buf[64];
  int i;

  external = (struct ospf6_as_external_lsa *)
    OSPF6_LSA_HEADER_END (lsa->header);

  if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL))
    zlog_debug ("Calculate AS-External route for %s", lsa->name);

  if (lsa->header->adv_router == ospf6->router_id)
    {
      /*if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL))
        zlog_debug ("Ignore self-originated AS-External-LSA");*/
      return;
    }

  if (OSPF6_ASBR_METRIC (external) == LS_INFINITY)
    {
      if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL))
        zlog_debug ("Ignore LSA with LSInfinity Metric");
      return;
    }

  ospf6_linkstate_prefix (lsa->header->adv_router, htonl (0), &asbr_id);
  asbr_entry = ospf6_route_lookup (&asbr_id, ospf6->brouter_table);
  if (asbr_entry == NULL ||
      ! CHECK_FLAG (asbr_entry->path.router_bits, OSPF6_ROUTER_BIT_E))
    {
      if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL))
        {
          prefix2str (&asbr_id, buf, sizeof (buf));
          zlog_debug ("ASBR entry not found: %s", buf);
        }
      return;
    }

  route = ospf6_route_create ();
  route->type = OSPF6_DEST_TYPE_NETWORK;
  route->prefix.family = AF_INET6;
  route->prefix.prefixlen = external->prefix.prefix_length;
  ospf6_prefix_in6_addr (&route->prefix.u.prefix6, &external->prefix);

  route->path.area_id = asbr_entry->path.area_id;
  route->path.origin.type = lsa->header->type;
  route->path.origin.id = lsa->header->id;
  route->path.origin.adv_router = lsa->header->adv_router;

  route->path.prefix_options = external->prefix.prefix_options;
  if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E))
    {
      route->path.type = OSPF6_PATH_TYPE_EXTERNAL2;
      route->path.metric_type = 2;
      route->path.cost = asbr_entry->path.cost;
      route->path.cost_e2 = OSPF6_ASBR_METRIC (external);
    }
  else
    {
      route->path.type = OSPF6_PATH_TYPE_EXTERNAL1;
      route->path.metric_type = 1;
      route->path.cost = asbr_entry->path.cost + OSPF6_ASBR_METRIC (external);
      route->path.cost_e2 = 0;
    }

  for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++)
    ospf6_nexthop_copy (&route->nexthop[i], &asbr_entry->nexthop[i]);

  if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL))
    {
      prefix2str (&route->prefix, buf, sizeof (buf));
      zlog_debug ("AS-External route add: %s", buf);
    }

  ospf6_route_add (route, ospf6->route_table);
}
Ejemplo n.º 3
0
static int
ospf6_spf_install (struct ospf6_vertex *v,
                       struct ospf6_route_table *result_table, 
                       unsigned int hostnum)
{
  struct ospf6_route *route;
  int i, j;
  struct ospf6_vertex *prev, *w;
  struct listnode *node, *nnode;

  if(IS_OSPF6_SIBLING_DEBUG_SPF)
    zlog_debug ("SPF install %s hops %d cost %d",
                v->name, v->hops, v->cost);

  route = ospf6_route_lookup (&v->vertex_id, result_table);
  if (route && route->path.cost < v->cost)
  {
    if (IS_OSPF6_SIBLING_DEBUG_SPF)
      zlog_debug ("  already installed with lower cost (%d), ignore",
                  route->path.cost);
    ospf6_vertex_delete (v);
    return -1;
  }
  else if (route && route->path.cost == v->cost)
  {
    if (IS_OSPF6_SIBLING_DEBUG_SPF)
      zlog_debug ("  another path found, merge");

    for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
         i < OSPF6_MULTI_PATH_LIMIT; i++)
    {
      for (j = 0; j < OSPF6_MULTI_PATH_LIMIT; j++)
      {
        if (ospf6_nexthop_is_set (&route->nexthop[j]))
        {
          if (ospf6_nexthop_is_same (&route->nexthop[j],
                                     &v->nexthop[i]))
            break;
          else
            continue;
        }
        ospf6_nexthop_copy (&route->nexthop[j], &v->nexthop[i]);
        break;
      }
    }

    prev = (struct ospf6_vertex *) route->route_option;
    assert (prev->hops <= v->hops);
    ospf6_vertex_delete (v);

    return -1;
  }

  /* There should be no case where candidate being installed (variable
     "v") is closer than the one in the SPF tree (variable "route").
     In the case something has gone wrong with the behavior of
     Priority-Queue. */

  /* the case where the route exists already is handled and returned
     up to here. */
  assert (route == NULL);

  route = ospf6_route_create ();
  memcpy (&route->prefix, &v->vertex_id, sizeof (struct prefix));
  route->type = OSPF6_DEST_TYPE_LINKSTATE;
  route->path.type = OSPF6_PATH_TYPE_INTRA;
  route->path.origin.type = v->lsa->header->type;
  route->path.origin.id = v->lsa->header->id;
  route->path.origin.adv_router = v->lsa->header->adv_router;
  route->path.metric_type = 1;
  route->path.cost = v->cost;
  route->path.cost_e2 = v->hops;
  route->path.router_bits = v->capability;
  route->path.options[0] = v->options[0];
  route->path.options[1] = v->options[1];
  route->path.options[2] = v->options[2];
  route->hostnum = hostnum; // number corresponding to host, 0 if hostnum is unknown

  for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
       i < OSPF6_MULTI_PATH_LIMIT; i++)
       ospf6_nexthop_copy (&route->nexthop[i], &v->nexthop[i]);

  if (v->parent)
    alt_listnode_add_sort (v->parent->child_list, v);
  route->route_option = v;

  ospf6_route_add (route, result_table);
  return 0;
}