]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Merge commit 'cba9cbf1bdb253c7727da10ff4f835d7ffbadeed' into integrated
authorOndrej Zajicek <santiago@crfreenet.org>
Fri, 2 May 2014 15:15:25 +0000 (17:15 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Fri, 2 May 2014 15:15:25 +0000 (17:15 +0200)
1  2 
proto/ospf/lsupd.c

index e8069b793055bdb962a0e8fe5a3bcad0120e09c1,8f65c532217cbcc8ed0336a83d92f0474f8e9d74..bcbd226ff7d33effca50ec62d857630c55638543
@@@ -406,247 -748,16 +406,247 @@@ ospf_lsupd_receive(struct ospf_packet *
    }
  }
  
 +
 +/**
 + * ospf_lsupd_flood - send received or generated LSA to the neighbors
 + * @po: OSPF protocol
 + * @en: LSA entry
 + * @from: neighbor than sent this LSA (or NULL if LSA is local)
 + *
 + * return value - was the LSA flooded back?
 + */
 +
 +int
 +ospf_lsupd_flood(struct proto_ospf *po, struct top_hash_entry *en, struct ospf_neighbor *from)
 +{
 +  struct ospf_iface *ifa;
 +  struct ospf_neighbor *n;
 +
 +  int back = 0;
 +  WALK_LIST(ifa, po->iface_list)
 +  {
 +    if (ifa->stub)
 +      continue;
 +
 +    if (! lsa_flooding_allowed(en->lsa_type, en->domain, ifa))
 +      continue;
 +
 +    DBG("Wanted to flood LSA: Type: %u, ID: %R, RT: %R, SN: 0x%x, Age %u\n",
 +      hh->type, hh->id, hh->rt, hh->sn, hh->age);
 +
 +    int used = 0;
 +    WALK_LIST(n, ifa->neigh_list)
 +    {
 +      /* 13.3 (1a) */
 +      if (n->state < NEIGHBOR_EXCHANGE)
 +      continue;
 +
 +      /* 13.3 (1b) */
 +      if (n->state < NEIGHBOR_FULL)
 +      {
 +      struct top_hash_entry *req = ospf_hash_find_entry(n->lsrqh, en);
 +      if (req != NULL)
 +      {
 +        int cmp = lsa_comp(&en->lsa, &req->lsa);
 +
 +        /* If same or newer, remove LSA from the link state request list */
 +        if (cmp > CMP_OLDER)
 +        {
 +          s_rem_node(SNODE req);
 +          ospf_hash_delete(n->lsrqh, req);
 +          if ((EMPTY_SLIST(n->lsrql)) && (n->state == NEIGHBOR_LOADING))
 +            ospf_neigh_sm(n, INM_LOADDONE);
 +        }
 +
 +        /* If older or same, skip processing of this LSA */
 +        if (cmp < CMP_NEWER)
 +          continue;
 +      }
 +      }
 +
 +      /* 13.3 (1c) */
 +      if (n == from)
 +      continue;
 +
 +      /* In OSPFv3, there should be check whether receiving router understand
 +       that type of LSA (for LSA types with U-bit == 0). But as we do not support
 +       any optional LSA types, this is not needed yet */
 +
 +      /* 13.3 (1d) - add LSA to the link state retransmission list */
 +      ospf_lsa_lsrt_up(en, n);
 +
 +      used = 1;
 +    }
 +
 +    /* 13.3 (2) */
 +    if (!used)
 +      continue;
 +
 +    if (from && (from->ifa == ifa))
 +    {
 +      /* 13.3 (3) */
 +      if ((from->rid == ifa->drid) || from->rid == ifa->bdrid)
 +      continue;
 +
 +      /* 13.3 (4) */
 +      if (ifa->state == OSPF_IS_BACKUP)
 +      continue;
 +
 +      back = 1;
 +    }
 +
 +    /* 13.3 (5) - finally flood the packet */
 +    ospf_lsupd_flood_ifa(po, ifa, en);
 +  }
 +
 +  return back;
 +}
 +
 +static int
 +ospf_lsupd_prepare(struct proto_ospf *po, struct ospf_iface *ifa,
 +                 struct top_hash_entry **lsa_list, uint lsa_count)
 +{
 +  struct ospf_packet *pkt;
 +  uint hlen, pos, i, maxsize;
 +
 +  pkt = ospf_tx_buffer(ifa);
 +  hlen = ospf_lsupd_hdrlen(po);
 +  maxsize = ospf_pkt_maxsize(ifa);
 +
 +  ospf_pkt_fill_hdr(ifa, pkt, LSUPD_P);
 +  pos = hlen;
 +
 +  for (i = 0; i < lsa_count; i++)
 +  {
 +    struct top_hash_entry *en = lsa_list[i];
 +    uint len = en->lsa.length;
 +
 +    if ((pos + len) > maxsize)
 +    {
 +      /* The packet if full, stop adding LSAs and sent it */
 +      if (i > 0)
 +      break;
 +
 +      /* LSA is larger than MTU, check buffer size */
 +      if (ospf_iface_assure_bufsize(ifa, pos + len) < 0)
 +      {
 +      /* Cannot fit in a tx buffer, skip that */
 +      log(L_ERR "OSPF: LSA too large to send on %s (Type: %04x, Id: %R, Rt: %R)", 
 +          ifa->ifname, en->lsa_type, en->lsa.id, en->lsa.rt);
 +      XXXX(); /* XXXX: handle packets with no LSA */
 +      continue;
 +      }
 +
 +      /* TX buffer could be reallocated */
 +      pkt = ospf_tx_buffer(ifa);
 +    }
 +
 +    struct ospf_lsa_header *buf = ((void *) pkt) + pos;
 +    lsa_hton_hdr(&en->lsa, buf);
 +    lsa_hton_body(en->lsa_body, ((void *) buf) + sizeof(struct ospf_lsa_header),
 +                len - sizeof(struct ospf_lsa_header));
 +    buf->age = htons(MIN(en->lsa.age + ifa->inftransdelay, LSA_MAXAGE));
 +
 +    pos += len;
 +  }
 +   
 +  ospf_lsupd_set_lsa_count(pkt, hlen, i);
 +  pkt->length = htons(pos);
 +
 +  return i;
 +}
 +
 +
 +static void
 +ospf_lsupd_flood_ifa(struct proto_ospf *po, struct ospf_iface *ifa, struct top_hash_entry *en)
 +{
 +  ospf_lsupd_prepare(po, ifa, &en, 1);
 +
 +  OSPF_PACKET(ospf_lsupd_dump, ospf_tx_buffer(ifa),
 +            "LSUPD packet flooded via %s", ifa->ifname);
 +
 +  switch (ifa->type)
 +  {
 +  case OSPF_IT_BCAST:
 +    if ((ifa->state == OSPF_IS_BACKUP) || (ifa->state == OSPF_IS_DR))
 +      ospf_send_to_all(ifa);
 +    else
 +      ospf_send_to_des(ifa);
 +    break;
 +
 +  case OSPF_IT_NBMA:
 +    if ((ifa->state == OSPF_IS_BACKUP) || (ifa->state == OSPF_IS_DR))
 +      ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE);
 +    else
 +      ospf_send_to_bdr(ifa);
 +    break;
 +
 +  case OSPF_IT_PTP:
 +    ospf_send_to_all(ifa);
 +    break;
 +
 +  case OSPF_IT_PTMP:
 +    ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE);
 +    break;
 +
 +  case OSPF_IT_VLINK:
 +    ospf_send_to(ifa, ifa->vip);
 +    break;
 +
 +  default:
 +    bug("Bug in ospf_lsupd_flood()");
 +  }
 +}
 +
 +int
 +ospf_lsupd_send(struct ospf_neighbor *n, struct top_hash_entry **lsa_list, uint lsa_count)
 +{
 +  struct ospf_iface *ifa = n->ifa;
 +  struct proto_ospf *po = ifa->oa->po;
 +  uint i, c;
 +
 +  for (i = 0; i < lsa_count; i += c)
 +  {
 +    c = ospf_lsupd_prepare(po, ifa, lsa_list + i, lsa_count - i);
 +
 +    OSPF_PACKET(ospf_lsupd_dump, ospf_tx_buffer(ifa),
 +              "LSUPD packet sent to %I via %s", n->ip, ifa->ifname);
 +
 +    ospf_send_to(ifa, n->ip);
 +  }
 +
 +  return lsa_count;
 +}
 +
  void
 -ospf_lsupd_flush_nlsa(struct proto_ospf *po, struct top_hash_entry *en)
 +ospf_lsupd_rxmt(struct ospf_neighbor *n)
  {
 -  struct ospf_lsa_header *lsa = &en->lsa;
 -  struct proto *p = &po->proto;
 +  struct proto_ospf *po = n->ifa->oa->po;
 +
 +  const uint max = 128;
 +  struct top_hash_entry *entries[max];
 +  struct top_hash_entry *ret, *en;
 +  uint i = 0;
 +
 +  WALK_SLIST(ret, n->lsrtl)
 +  {
 +    en = ospf_hash_find_entry(po->gr, ret);
 +    if (!en)
 +    {
 +      /* Probably flushed LSA, this should not happen */
-       log(L_WARN "%s: LSA disappeared (Type: %04x, Id: %R, Rt: %R)",
-         po->proto.name, ret->lsa_type, ret->lsa.id, ret->lsa.rt);
++      // log(L_WARN "%s: LSA disappeared (Type: %04x, Id: %R, Rt: %R)",
++      //     po->proto.name, ret->lsa_type, ret->lsa.id, ret->lsa.rt);
 +
 +      XXXX(); /* remove entry */
 +      continue;
 +    }
 +
 +    entries[i] = en;
 +    i++;
 +
 +    if (i == max)
 +      break;
 +  }
  
 -  lsa->age = LSA_MAXAGE;
 -  lsa->sn = LSA_MAXSEQNO;
 -  lsasum_calculate(lsa, en->lsa_body);
 -  OSPF_TRACE(D_EVENTS, "Premature aging self originated lsa!");
 -  OSPF_TRACE(D_EVENTS, "Type: %04x, Id: %R, Rt: %R", lsa->type, lsa->id, lsa->rt);
 -  ospf_lsupd_flood(po, NULL, NULL, lsa, en->domain, 0);
 +  ospf_lsupd_send(n, entries, i);
  }