]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Merge commit 'c404f4b968b69a2c5c1975d04abf7474891d5656' into integrated
authorOndrej Zajicek <santiago@crfreenet.org>
Tue, 29 Apr 2014 11:11:02 +0000 (13:11 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Tue, 29 Apr 2014 11:11:02 +0000 (13:11 +0200)
1  2 
proto/ospf/lsupd.c

index d76bb388c60954ca54c97d4f6d4b2b96eb646396,b19f2619f340649d8ef51329981eedb7fa08f75c..a2d04fb4f468f4110825935d6abb62b5a3d3ab68
@@@ -406,244 -735,16 +406,244 @@@ ospf_lsupd_receive(struct ospf_packet *
    }
  }
  
-           if (EMPTY_SLIST(n->lsrql))
 +
 +/**
 + * 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, unsigned lsa_count)
 +{
 +  struct ospf_packet *pkt;
 +  unsigned 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];
 +    unsigned 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 ((pos + len) > ospf_pkt_bufsize(ifa))
 +      {
 +      /* Cannot fit in a tx buffer, skip that */
 +      log(L_WARN "OSPF: LSA too large to send (Type: %04x, Id: %R, Rt: %R)", 
 +          en->lsa_type, en->lsa.id, en->lsa.rt);
 +      XXXX();
 +      continue;
 +      }
 +    }
 +
 +    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->iface->name);
 +
 +  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, unsigned lsa_count)
 +{
 +  struct ospf_iface *ifa = n->ifa;
 +  struct proto_ospf *po = ifa->oa->po;
 +  unsigned 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->iface->name);
 +
 +    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 unsigned max = 128;
 +  struct top_hash_entry *entries[max];
 +  struct top_hash_entry *ret, *en;
 +  unsigned 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);
 +
 +      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);
  }