]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Fixes a bug in LSA update of large LSAs.
authorOndrej Zajicek <santiago@crfreenet.org>
Thu, 4 Nov 2010 16:22:43 +0000 (17:22 +0100)
committerOndrej Zajicek <santiago@crfreenet.org>
Thu, 4 Nov 2010 16:22:43 +0000 (17:22 +0100)
lib/lists.h
proto/ospf/hello.c
proto/ospf/lsupd.c
proto/ospf/ospf.h
proto/ospf/packet.c
proto/ospf/packet.h

index 342dfd62b4f1f86cbd28cd114e945ff3de91e84f..6fab12c440082efef46ed0c1b9bdd1455f46fb35 100644 (file)
@@ -33,10 +33,10 @@ typedef struct list {                       /* In fact two overlayed nodes */
 #define NODE (node *)
 #define HEAD(list) ((void *)((list).head))
 #define TAIL(list) ((void *)((list).tail))
-#define WALK_LIST(n,list) for(n=HEAD(list);(NODE (n))->next; \
-                               n=(void *)((NODE (n))->next))
+#define NODE_NEXT(n) ((void *)((NODE (n))->next))
+#define WALK_LIST(n,list) for(n=HEAD(list);(NODE (n))->next; n=NODE_NEXT(n))
 #define WALK_LIST_DELSAFE(n,nxt,list) \
-     for(n=HEAD(list); nxt=(void *)((NODE (n))->next); n=(void *) nxt)
+     for(n=HEAD(list); nxt=NODE_NEXT(n); n=(void *) nxt)
 /* WALK_LIST_FIRST supposes that called code removes each processed node */
 #define WALK_LIST_FIRST(n,list) \
      while(n=HEAD(list), (NODE (n))->next)
index 70fb6548ee57063bcf365c4cca4c228c4c85e420..3d7d8de3677ed81340e5b59202bf3f70890082c0 100644 (file)
@@ -297,7 +297,7 @@ ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn)
   pp = (u32 *) (((u8 *) pkt) + sizeof(struct ospf_hello_packet));
   WALK_LIST(neigh, ifa->neigh_list)
   {
-    if ((i+1) * sizeof(u32) + sizeof(struct ospf_hello_packet) > ospf_pkt_maxsize(ifa))
+    if ((i+1) * sizeof(u32) + sizeof(struct ospf_hello_packet) > ospf_pkt_bufsize(ifa))
     {
       OSPF_TRACE(D_PACKETS, "Too many neighbors on the interface!");
       break;
index 62e7eac1cdea41c4cda883338a53c670c97bba3b..fb757d0865d587efc7f241aa7ff83f89dc3da639 100644 (file)
@@ -330,67 +330,74 @@ ospf_lsupd_flood(struct proto_ospf *po,
 void                           /* I send all I received in LSREQ */
 ospf_lsupd_send_list(struct ospf_neighbor *n, list * l)
 {
-  struct l_lsr_head *llsh;
-  u16 len;
-  u32 lsano;
-  struct top_hash_entry *en;
-  struct ospf_lsupd_packet *pk;
-  struct ospf_packet *op;
   struct ospf_area *oa = n->ifa->oa;
-  struct proto_ospf *po = oa->po;
-  struct proto *p = &po->proto;
-  void *pktpos;
-
-  if (EMPTY_LIST(*l))
-    return;
-
-  DBG("LSupd: 1st packet\n");
-
-  pk= ospf_tx_buffer(n->ifa);
-  op = &pk->ospf_packet;
+  struct proto *p = &oa->po->proto;
+  struct l_lsr_head *lsr;
+  struct top_hash_entry *en;
+  struct ospf_lsupd_packet *pkt;
+  u32 len, len2, lsano;
+  char *buf;
 
-  ospf_pkt_fill_hdr(n->ifa, pk, LSUPD_P);
-  len = sizeof(struct ospf_lsupd_packet);
-  lsano = 0;
-  pktpos = (pk + 1);
+  pkt = ospf_tx_buffer(n->ifa);
+  buf = (void *) pkt;
 
-  WALK_LIST(llsh, *l)
+  lsr = HEAD(*l);
+  while(NODE_NEXT(lsr))
   {
-    u32 domain = ospf_lsa_domain(llsh->lsh.type, n->ifa);
-    if ((en = ospf_hash_find(po->gr, domain, llsh->lsh.id,
-                              llsh->lsh.rt, llsh->lsh.type)) == NULL)
-      continue;                        /* Probably flushed LSA */
-    /* FIXME This is a bug! I cannot flush LSA that is in lsrt */
-
-    DBG("Sending LSA: Type=%u, ID=%R, RT=%R, SN: 0x%x, Age: %u\n",
-       llsh->lsh.type, llsh->lsh.id, llsh->lsh.rt, en->lsa.sn, en->lsa.age);
-    if (((u32) (len + en->lsa.length)) > ospf_pkt_maxsize(n->ifa))
+    /* Prepare the packet */
+    ospf_pkt_fill_hdr(n->ifa, pkt, LSUPD_P);
+    len = sizeof(struct ospf_lsupd_packet);
+    lsano = 0;
+
+    /* Fill the packet with LSAs */
+    while(NODE_NEXT(lsr))
     {
-      pk->lsano = htonl(lsano);
-      op->length = htons(len);
+      u32 domain = ospf_lsa_domain(lsr->lsh.type, n->ifa);
+      en = ospf_hash_find(oa->po->gr, domain, lsr->lsh.id, lsr->lsh.rt, lsr->lsh.type);
+      if (en == NULL)
+      {
+       /* Probably flushed LSA, this should not happen */
+       log(L_WARN "OSPF: LSA disappeared (Type: %04x, Id: %R, Rt: %R)", 
+           lsr->lsh.type, lsr->lsh.id, lsr->lsh.rt);
+       lsr = NODE_NEXT(lsr);
+       continue;                       
+      }
 
-      OSPF_PACKET(ospf_dump_lsupd, pk, "LSUPD packet sent to %I via %s", n->ip, n->ifa->iface->name);
-      ospf_send_to(n->ifa, n->ip);
+      len2 = len + en->lsa.length;
+      if (len2 > ospf_pkt_maxsize(n->ifa))
+      {
+       /* The packet if full, stop adding LSAs and sent it */
+       if (lsano > 0)
+         break;
+
+       /* LSA is larger than MTU, check buffer size */
+       if (len2 > ospf_pkt_bufsize(n->ifa))
+       {
+         /* Cannot fit in a tx buffer, skip that */
+         log(L_WARN "OSPF: LSA too large to send (Type: %04x, Id: %R, Rt: %R)", 
+             lsr->lsh.type, lsr->lsh.id, lsr->lsh.rt);
+         lsr = NODE_NEXT(lsr);
+         continue;
+       }
+      }
 
-      DBG("LSupd: next packet\n");
-      ospf_pkt_fill_hdr(n->ifa, pk, LSUPD_P);
-      len = sizeof(struct ospf_lsupd_packet);
-      lsano = 0;
-      pktpos = (pk + 1);
+      /* Copy the LSA to the packet */
+      htonlsah(&(en->lsa), (struct ospf_lsa_header *) (buf + len));
+      htonlsab(en->lsa_body, buf + len + sizeof(struct ospf_lsa_header),
+              en->lsa.length - sizeof(struct ospf_lsa_header));
+      len = len2;
+      lsano++;
+      lsr = NODE_NEXT(lsr);
     }
-    htonlsah(&(en->lsa), pktpos);
-    pktpos = pktpos + sizeof(struct ospf_lsa_header);
-    htonlsab(en->lsa_body, pktpos, en->lsa.length - sizeof(struct ospf_lsa_header));
-    pktpos = pktpos + en->lsa.length - sizeof(struct ospf_lsa_header);
-    len += en->lsa.length;
-    lsano++;
-  }
-  if (lsano > 0)
-  {
-    pk->lsano = htonl(lsano);
-    op->length = htons(len);
 
-    OSPF_PACKET(ospf_dump_lsupd, pk, "LSUPD packet sent to %I via %s", n->ip, n->ifa->iface->name);
+    if (lsano == 0)
+      break;
+
+    /* Send the packet */
+    pkt->lsano = htonl(lsano);
+    pkt->ospf_packet.length = htons(len);
+    OSPF_PACKET(ospf_dump_lsupd, pkt, "LSUPD packet sent to %I via %s",
+               n->ip, n->ifa->iface->name);
     ospf_send_to(n->ifa, n->ip);
   }
 }
index 103ca550b8e8fe7a6c4e15d54f564547c7178f52..1ae83c1c8d67ae1a12dc1fc449a68b77c70a0c46 100644 (file)
@@ -10,7 +10,6 @@
 #define _BIRD_OSPF_H_
 
 #define MAXNETS 10
-#define OSPF_VLINK_MTU 576     /* RFC2328 - A.1 */
 #define OSPF_MAX_PKT_SIZE 65536
                        /*
                          * RFC 2328 says, maximum packet size is 65535
@@ -53,11 +52,13 @@ do { if ((p->debug & D_PACKETS) || OSPF_FORCE_DEBUG) \
 #ifndef IPV6
 #define OSPFv2 1
 #define OSPF_VERSION 2
+#define OSPF_VLINK_MTU 576                     /* RFC 2328 A.1 */
 #define AllSPFRouters ipa_from_u32(0xe0000005) /* 224.0.0.5 */
 #define AllDRouters ipa_from_u32(0xe0000006)   /* 224.0.0.6 */
 #else
 #define OSPFv3 1
 #define OSPF_VERSION 3
+#define OSPF_VLINK_MTU 1280                    /* RFC 5340 A.1 */
 #define AllSPFRouters _MI(0xFF020000, 0, 0, 5) /* FF02::5 */
 #define AllDRouters   _MI(0xFF020000, 0, 0, 6) /* FF02::6 */
 #endif
index 6ae29a88d2b9c199456a9222661f7b1dcea43394..bfc17d767b7ae2922281de2327001a867c8000d7 100644 (file)
@@ -39,19 +39,17 @@ ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type)
 unsigned
 ospf_pkt_maxsize(struct ospf_iface *ifa)
 {
-  /* For virtual links use mtu=576, can be mtu < 576? */
   unsigned mtu = (ifa->type == OSPF_IT_VLINK) ? OSPF_VLINK_MTU : ifa->iface->mtu;
-  unsigned add = 0;
+  unsigned headers = SIZE_OF_IP_HEADER;
 
 #ifdef OSPFv2
-  add = ((ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0);
+  if (ifa->autype == OSPF_AUTH_CRYPT)
+    headers += OSPF_AUTH_CRYPT_SIZE;
 #endif
 
-  return ((mtu <=  ifa->iface->mtu) ? mtu : ifa->iface->mtu) -
-  SIZE_OF_IP_HEADER - add;
+  return mtu - headers;
 }
 
-
 #ifdef OSPFv2
 
 static void
index 1c74a7035a56dd348a9d88612f6ec6a9bbd2e72c..c0185b9c3d296bc969091048501f1daa3845a797 100644 (file)
@@ -21,4 +21,17 @@ void ospf_send_to(struct ospf_iface *ifa, ip_addr ip);
 
 static inline void * ospf_tx_buffer(struct ospf_iface *ifa) { return ifa->sk->tbuf; }
 
+static inline unsigned
+ospf_pkt_bufsize(struct ospf_iface *ifa)
+{
+#ifdef OSPFv2
+  unsigned headers = (ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0;
+#else
+  unsigned headers = 0;
+#endif
+
+  return ifa->sk->tbsize - headers;
+}
+
+
 #endif /* _BIRD_OSPF_PACKET_H_ */