Currently ospfd has a problem when a single lsupdate is bigger then the
MTU. Normaly this is not a problem but Benjamin Papillon hit this limit on
a VPN hub.

This diff changes the way lsupdate.c handels buffers. The buffer is
changed from a MTU sized to a dynamic one that can grow up to 64k -
header. By default ospfd will try not to send out packets bigger then MTU
(e.g. not adding multiple updates into one message causing fragmentation)
but in case a single update is bigger then the MTU it will build a huge
packet with just that update in.

While there I also fixed a few other buffers (hello packet and the self
generated LSA) to have more correct upper bounds.

Last missing bit is now lsa_ack which is a separate diff.
Please test.
-- 
:wq Claudio

Index: hello.c
===================================================================
RCS file: /cvs/src/usr.sbin/ospfd/hello.c,v
retrieving revision 1.19
diff -u -p -r1.19 hello.c
--- hello.c     26 May 2010 13:56:08 -0000      1.19
+++ hello.c     17 Feb 2011 19:19:19 -0000
@@ -64,8 +64,8 @@ send_hello(struct iface *iface)
                fatalx("send_hello: unknown interface type");
        }
 
-       /* XXX IBUF_READ_SIZE */
-       if ((buf = ibuf_dynamic(PKG_DEF_SIZE, IBUF_READ_SIZE)) == NULL)
+       if ((buf = ibuf_dynamic(PKG_DEF_SIZE,
+           IP_MAXPACKET - sizeof(struct ip))) == NULL)
                fatal("send_hello");
 
        /* OSPF header */
Index: lsupdate.c
===================================================================
RCS file: /cvs/src/usr.sbin/ospfd/lsupdate.c,v
retrieving revision 1.39
diff -u -p -r1.39 lsupdate.c
--- lsupdate.c  26 May 2010 13:56:08 -0000      1.39
+++ lsupdate.c  17 Feb 2011 19:19:19 -0000
@@ -152,7 +152,8 @@ prepare_ls_update(struct iface *iface)
 {
        struct ibuf             *buf;
 
-       if ((buf = ibuf_open(iface->mtu - sizeof(struct ip))) == NULL)
+       if ((buf = ibuf_dynamic(iface->mtu - sizeof(struct ip),
+           IP_MAXPACKET - sizeof(struct ip))) == NULL)
                fatal("prepare_ls_update");
 
        /* OSPF header */
@@ -177,8 +178,13 @@ add_ls_update(struct ibuf *buf, struct i
        void            *lsage;
        u_int16_t        age;
 
-       if (ibuf_left(buf) < (size_t)len + MD5_DIGEST_LENGTH)
-               return (0);
+       if ((size_t)iface->mtu < sizeof(struct ip) + sizeof(struct ospf_hdr) +
+           sizeof(u_int32_t) + ibuf_size(buf) + len + MD5_DIGEST_LENGTH) {
+               /* start new packet unless this is the first LSA to pack */
+               if (ibuf_size(buf) > sizeof(struct ospf_hdr) +
+                   sizeof(u_int32_t))
+                       return (0);
+       }
 
        lsage = ibuf_reserve(buf, 0);
        if (ibuf_add(buf, data, len)) {
@@ -475,8 +481,19 @@ ls_retrans_timer(int fd, short event, vo
                        d = MAX_AGE;
 
                if (add_ls_update(buf, nbr->iface, le->le_ref->data,
-                   le->le_ref->len, d) == 0)
+                   le->le_ref->len, d) == 0) {
+                       if (nlsa == 0) {
+                               /* something bad happend retry later */
+                               log_warnx("ls_retrans_timer: sending LS update "
+                                   "to neighbor ID %s failed",
+                                   inet_ntoa(nbr->id));
+                               TAILQ_REMOVE(&nbr->ls_retrans_list, le, entry);
+                               nbr->ls_ret_cnt--;
+                               le->le_when = nbr->iface->rxmt_interval;
+                               ls_retrans_list_insert(nbr, le);
+                       }
                        break;
+               }
                nlsa++;
                if (le->le_oneshot)
                        ls_retrans_list_free(nbr, le);
@@ -487,7 +504,10 @@ ls_retrans_timer(int fd, short event, vo
                        ls_retrans_list_insert(nbr, le);
                }
        }
-       send_ls_update(buf, nbr->iface, addr, nlsa);
+       if (nlsa)
+               send_ls_update(buf, nbr->iface, addr, nlsa);
+       else
+               ibuf_free(buf);
 
 done:
        if ((le = TAILQ_FIRST(&nbr->ls_retrans_list)) != NULL) {
Index: ospfe.c
===================================================================
RCS file: /cvs/src/usr.sbin/ospfd/ospfe.c,v
retrieving revision 1.77
diff -u -p -r1.77 ospfe.c
--- ospfe.c     1 Oct 2010 13:29:25 -0000       1.77
+++ ospfe.c     17 Feb 2011 19:19:19 -0000
@@ -183,7 +183,7 @@ ospfe(struct ospfd_conf *xconf, int pipe
        TAILQ_INIT(&ctl_conns);
        control_listen();
 
-       if ((pkt_ptr = calloc(1, IBUF_READ_SIZE)) == NULL)
+       if ((pkt_ptr = calloc(1, READ_BUF_SIZE)) == NULL)
                fatal("ospfe");
 
        /* start interfaces */
@@ -756,8 +756,9 @@ orig_rtr_lsa(struct area *area)
 
        log_debug("orig_rtr_lsa: area %s", inet_ntoa(area->id));
 
-       /* XXX IBUF_READ_SIZE */
-       if ((buf = ibuf_dynamic(sizeof(lsa_hdr), READ_BUF_SIZE)) == NULL)
+       if ((buf = ibuf_dynamic(sizeof(lsa_hdr),
+           IP_MAXPACKET - sizeof(struct ip) - sizeof(struct ospf_hdr) -
+           sizeof(u_int32_t) - MD5_DIGEST_LENGTH)) == NULL)
                fatal("orig_rtr_lsa");
 
        /* reserve space for LSA header and LSA Router header */
@@ -1024,8 +1025,9 @@ orig_net_lsa(struct iface *iface)
        int                      num_rtr = 0;
        u_int16_t                chksum;
 
-       /* XXX IBUF_READ_SIZE */
-       if ((buf = ibuf_dynamic(sizeof(lsa_hdr), IBUF_READ_SIZE)) == NULL)
+       if ((buf = ibuf_dynamic(sizeof(lsa_hdr),
+           IP_MAXPACKET - sizeof(struct ip) - sizeof(struct ospf_hdr) -
+           sizeof(u_int32_t) - MD5_DIGEST_LENGTH)) == NULL)
                fatal("orig_net_lsa");
 
        /* reserve space for LSA header and LSA Router header */

Reply via email to