]> git.puffer.fish Git - mirror/frr.git/commitdiff
Bug #362 is fixed now.
authorDenis Ovsienko <linux@pilot.org.ua>
Tue, 21 Aug 2007 16:32:56 +0000 (16:32 +0000)
committerDenis Ovsienko <linux@pilot.org.ua>
Tue, 21 Aug 2007 16:32:56 +0000 (16:32 +0000)
lib/ChangeLog
lib/sockopt.c
lib/sockopt.h
ospfd/ChangeLog
ospfd/ospf_interface.c
ospfd/ospf_network.c
ospfd/ospf_network.h
ospfd/ospf_packet.c
ospfd/ospfd.c
ospfd/ospfd.h

index 55ddfff8b172902166e0426c941c23ed8a9c77ac..26a251713ee274d795e579838e950d3190b6635f 100644 (file)
@@ -1,3 +1,8 @@
+2007-08-21 Denis Ovsienko
+
+       * sockopt.[ch]: (setsockopt_so_sendbuf, getsockopt_so_sendbuf):
+         new functions to adjust ospfd working socket.
+
 2007-08-13 Denis Ovsienko
 
        * zebra.h: introduce ZEBRA_ERR_KERNEL and ZEBRA_ERR_NOERROR
index f5f1a7edd8d182cf334fd5993f0c32b5af3c6b58..f8fa946ef4df77508fa752a1eb2d34be7f179840 100644 (file)
@@ -36,6 +36,35 @@ setsockopt_so_recvbuf (int sock, int size)
   return ret;
 }
 
+int
+setsockopt_so_sendbuf (const int sock, int size)
+{
+  int ret = setsockopt (sock, SOL_SOCKET, SO_SNDBUF,
+    (char *)&size, sizeof (int));
+  
+  if (ret < 0)
+    zlog_err ("fd %d: can't setsockopt SO_SNDBUF to %d: %s",
+      sock, size, safe_strerror (errno));
+
+  return ret;
+}
+
+int
+getsockopt_so_sendbuf (const int sock)
+{
+  u_int32_t optval;
+  socklen_t optlen = sizeof (optval);
+  int ret = getsockopt (sock, SOL_SOCKET, SO_SNDBUF,
+    (char *)&optval, &optlen);
+  if (ret < 0)
+  {
+    zlog_err ("fd %d: can't getsockopt SO_SNDBUF: %d (%s)",
+      sock, errno, safe_strerror (errno));
+    return ret;
+  }
+  return optval;
+}
+
 static void *
 getsockopt_cmsg_data (struct msghdr *msgh, int level, int type)
 {
index 65ba34f1bafad9674b47126fa672b2da2225dad8..ebb71430e97c4e3257f02b8225015573c8b1db38 100644 (file)
@@ -23,6 +23,8 @@
 #define _ZEBRA_SOCKOPT_H
 
 extern int setsockopt_so_recvbuf (int sock, int size);
+extern int setsockopt_so_sendbuf (const int sock, int size);
+extern int getsockopt_so_sendbuf (const int sock);
 
 #ifdef HAVE_IPV6
 extern int setsockopt_ipv6_pktinfo (int, int);
index af5ace4847c8e2d75ddb0f87e696847fc2e84c97..feba89a3f29ac52f907cfd1f70d7d8a89b639383 100644 (file)
@@ -1,3 +1,16 @@
+2007-08-21 Denis Ovsienko
+
+       * ospfd.h: Extend struct ospf with maxsndbuflen field and
+         define its default value.
+       * ospfd.c: (ospf_new) init maxsndbuflen
+       * ospf_interface.c: (ospf_if_up) Call ospf_adjust_sndbuflen()
+         for each regular interface being brought up.
+       * ospf_network.[ch]: (ospf_adjust_sndbuflen) New function
+         makes sure ospf socket sending buffer is large enough
+         to cover the biggest interface MTU we have seen ever.
+       * ospf_packet.c: (ospf_write) Use maxsndbuflen to decide on
+         the biggest amount of data we are going to send at once.
+
 2007-08-07 Paul Jakma <paul.jakma@sun.com>
 
        * ospf_spf.c: (ospf_spf_next) Finish off the explanatory
index bf53668b95ed4ddc952a91214e448039cb844799..862735be79e5e81f8dc54e0b4846c6692ab1516f 100644 (file)
@@ -781,6 +781,11 @@ ospf_if_up (struct ospf_interface *oi)
     OSPF_ISM_EVENT_SCHEDULE (oi, ISM_LoopInd);
   else
     {
+      struct ospf *ospf = ospf_lookup ();
+      if (ospf != NULL)
+        ospf_adjust_sndbuflen (ospf, oi->ifp->mtu);
+      else
+        zlog_warn ("%s: ospf_lookup() returned NULL");
       ospf_if_stream_set (oi);
       OSPF_ISM_EVENT_SCHEDULE (oi, ISM_InterfaceUp);
     }
index e8c983712953d8077cd7db387787b9aa4248e7a3..11155dbcb1923ec3314ee05ef6564835eb943a7d 100644 (file)
@@ -41,6 +41,7 @@ extern struct zebra_privs_t ospfd_privs;
 #include "ospfd/ospf_lsdb.h"
 #include "ospfd/ospf_neighbor.h"
 #include "ospfd/ospf_packet.h"
+#include "ospfd/ospf_dump.h"
 
 
 
@@ -233,3 +234,37 @@ ospf_sock_init (void)
  
   return ospf_sock;
 }
+
+void
+ospf_adjust_sndbuflen (struct ospf * ospf, int buflen)
+{
+  int ret, newbuflen;
+  /* Check if any work has to be done at all. */
+  if (ospf->maxsndbuflen >= buflen)
+    return;
+  if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
+    zlog_debug ("%s: adjusting OSPF send buffer size to %d",
+      __func__, buflen);
+  if (ospfd_privs.change (ZPRIVS_RAISE))
+    zlog_err ("%s: could not raise privs, %s", __func__,
+      safe_strerror (errno));
+  /* Now we try to set SO_SNDBUF to what our caller has requested
+   * (OSPF_SNDBUFLEN_DEFAULT initially, which seems to be a sane
+   * default; or the MTU of a newly added interface). However,
+   * if the OS has truncated the actual buffer size to somewhat
+   * less or bigger size, try to detect it and update our records
+   * appropriately.
+   */
+  ret = setsockopt_so_sendbuf (ospf->fd, buflen);
+  newbuflen = getsockopt_so_sendbuf (ospf->fd);
+  if (ret < 0 || newbuflen != buflen)
+    zlog_warn ("%s: tried to set SO_SNDBUF to %d, but got %d",
+      __func__, buflen, newbuflen);
+  if (newbuflen >= 0)
+    ospf->maxsndbuflen = newbuflen;
+  else
+    zlog_warn ("%s: failed to get SO_SNDBUF", __func__);
+  if (ospfd_privs.change (ZPRIVS_LOWER))
+    zlog_err ("%s: could not lower privs, %s", __func__,
+      safe_strerror (errno));
+}
index 1b43df1c7b1f5bb06962246740e751859b5f74eb..f69099127c1f6fbf3b88a6b2b7749ed1c0786aac 100644 (file)
@@ -34,5 +34,6 @@ extern int ospf_if_drop_alldrouters (struct ospf *, struct prefix *,
                                     unsigned int);
 extern int ospf_if_ipmulticast (struct ospf *, struct prefix *, unsigned int);
 extern int ospf_sock_init (void);
+extern void ospf_adjust_sndbuflen (struct ospf *, int);
 
 #endif /* _ZEBRA_OSPF_NETWORK_H */
index 4735f99ba126f6fa124567ec7e4fbb260ec88165..a778a50b5e58113d263f0e242004b80b0ca81ba6 100644 (file)
@@ -602,8 +602,12 @@ ospf_write (struct thread *thread)
     ipid = (time(NULL) & 0xffff);
 #endif /* WANT_OSPF_WRITE_FRAGMENT */
 
-  /* convenience - max OSPF data per packet */
-  maxdatasize = oi->ifp->mtu - sizeof (struct ip);
+  /* convenience - max OSPF data per packet,
+   * and reliability - not more data, than our
+   * socket can accept
+   */
+  maxdatasize = MIN (oi->ifp->mtu, ospf->maxsndbuflen) -
+    sizeof (struct ip);
   
   /* Get one packet from queue. */
   op = ospf_fifo_head (oi->obuf);
index 80b97fab9005acbe785e6d7a179b7c59ea999941..8133050d7b501646eaed543500407d9297a0054c 100644 (file)
@@ -212,6 +212,8 @@ ospf_new (void)
               "a socket");
       exit(1);
     }
+  new->maxsndbuflen = 0;
+  ospf_adjust_sndbuflen (new, OSPF_SNDBUFLEN_DEFAULT);
   if ((new->ibuf = stream_new(OSPF_MAX_PACKET_SIZE+1)) == NULL)
     {
       zlog_err("ospf_new: fatal error: stream_new(%u) failed allocating ibuf",
index ec9d9d6b2ed467d0fa0870ade74f4ac738b9712c..b0a14ce29e9b13594ec602351ef6fb8841454f92 100644 (file)
 #define OSPF_LS_REFRESH_SHIFT       (60 * 15)
 #define OSPF_LS_REFRESH_JITTER      60
 
+/* Initial send buffer size for ospfd raw sending socket. */
+#define OSPF_SNDBUFLEN_DEFAULT           1024
+
 /* OSPF master for system wide configuration and variables. */
 struct ospf_master
 {
@@ -266,6 +269,7 @@ struct ospf
   struct thread *t_write;
   struct thread *t_read;
   int fd;
+  int maxsndbuflen;
   struct stream *ibuf;
   struct list *oi_write_q;