--- lib/sockopt.c.orig 2007-07-09 16:36:45.000000000 +0400 +++ lib/sockopt.c 2007-08-02 17:38:50.000000000 +0400 @@ -29,20 +29,49 @@ int ret; if ( (ret = setsockopt (sock, SOL_SOCKET, SO_RCVBUF, (char *) &size, sizeof (int))) < 0) zlog_err ("fd %d: can't setsockopt SO_RCVBUF to %d: %s", sock,size,safe_strerror(errno)); 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) { struct cmsghdr *cmsg; void *ptr = NULL; for (cmsg = ZCMSG_FIRSTHDR(msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(msgh, cmsg)) if (cmsg->cmsg_level == level && cmsg->cmsg_type) --- lib/sockopt.h.orig 2007-07-09 16:36:45.000000000 +0400 +++ lib/sockopt.h 2007-08-01 17:37:33.000000000 +0400 @@ -16,20 +16,22 @@ * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _ZEBRA_SOCKOPT_H #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); extern int setsockopt_ipv6_checksum (int, int); extern int setsockopt_ipv6_multicast_hops (int, int); extern int setsockopt_ipv6_unicast_hops (int, int); extern int setsockopt_ipv6_hoplimit (int, int); extern int setsockopt_ipv6_multicast_loop (int, int); #endif /* HAVE_IPV6 */ --- ospfd/ospfd.c.orig 2007-05-01 03:42:20.000000000 +0400 +++ ospfd/ospfd.c 2007-08-01 19:07:46.000000000 +0400 @@ -205,20 +205,22 @@ new->t_lsa_refresher = thread_add_timer (master, ospf_lsa_refresh_walker, new, new->lsa_refresh_interval); new->lsa_refresher_started = quagga_time (NULL); if ((new->fd = ospf_sock_init()) < 0) { zlog_err("ospf_new: fatal error: ospf_sock_init was unable to open " "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", OSPF_MAX_PACKET_SIZE+1); exit(1); } new->t_read = thread_add_read (master, ospf_read, new, new->fd); new->oi_write_q = list_new (); return new; --- ospfd/ospfd.h.orig 2006-10-18 00:45:04.000000000 +0400 +++ ospfd/ospfd.h 2007-08-01 17:10:36.000000000 +0400 @@ -122,20 +122,23 @@ /* OSPF Database Description flags. */ #define OSPF_DD_FLAG_MS 0x01 #define OSPF_DD_FLAG_M 0x02 #define OSPF_DD_FLAG_I 0x04 #define OSPF_DD_FLAG_ALL 0x07 #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 { /* OSPF instance. */ struct list *ospf; /* OSPF thread master. */ struct thread_master *master; /* Zebra interface list. */ @@ -259,20 +262,21 @@ #ifdef HAVE_OPAQUE_LSA struct thread *t_opaque_lsa_self; /* Type-11 Opaque-LSAs origin event. */ #endif /* HAVE_OPAQUE_LSA */ struct thread *t_maxage; /* MaxAge LSA remover timer. */ struct thread *t_maxage_walker; /* MaxAge LSA checking timer. */ struct thread *t_deferred_shutdown; /* deferred/stub-router shutdown timer*/ struct thread *t_write; struct thread *t_read; int fd; + int maxsndbuflen; struct stream *ibuf; struct list *oi_write_q; /* Distribute lists out of other route sources. */ struct { char *name; struct access_list *list; } dlist[ZEBRA_ROUTE_MAX]; #define DISTRIBUTE_NAME(O,T) (O)->dlist[T].name --- ospfd/ospf_interface.c.orig 2007-04-22 17:26:38.000000000 +0400 +++ ospfd/ospf_interface.c 2007-08-02 18:31:53.000000000 +0400 @@ -774,20 +774,25 @@ int ospf_if_up (struct ospf_interface *oi) { if (oi == NULL) return 0; if (oi->type == OSPF_IFTYPE_LOOPBACK) 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); } return 1; } int ospf_if_down (struct ospf_interface *oi) { --- ospfd/ospf_network.c.orig 2005-05-09 22:37:56.000000000 +0400 +++ ospfd/ospf_network.c 2007-08-01 20:03:26.000000000 +0400 @@ -34,20 +34,21 @@ extern struct zebra_privs_t ospfd_privs; #include "ospfd/ospfd.h" #include "ospfd/ospf_network.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_lsdb.h" #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_packet.h" +#include "ospfd/ospf_dump.h" /* Join to the OSPF ALL SPF ROUTERS multicast group. */ int ospf_if_add_allspfrouters (struct ospf *top, struct prefix *p, unsigned int ifindex) { int ret; @@ -226,10 +227,44 @@ zlog_warn ("Can't set pktinfo option for fd %d", ospf_sock); if (ospfd_privs.change (ZPRIVS_LOWER)) { zlog_err ("ospf_sock_init: could not lower privs, %s", safe_strerror (errno) ); } 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)); +} --- ospfd/ospf_network.h.orig 2005-05-06 21:26:18.000000000 +0400 +++ ospfd/ospf_network.h 2007-08-01 19:17:11.000000000 +0400 @@ -27,12 +27,13 @@ extern int ospf_if_add_allspfrouters (struct ospf *, struct prefix *, unsigned int); extern int ospf_if_drop_allspfrouters (struct ospf *, struct prefix *, unsigned int); extern int ospf_if_add_alldrouters (struct ospf *, struct prefix *, unsigned int); 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 */ --- ospfd/ospf_packet.c.orig 2007-05-10 00:59:34.000000000 +0400 +++ ospfd/ospf_packet.c 2007-08-01 18:32:36.000000000 +0400 @@ -595,22 +595,26 @@ assert (node); oi = listgetdata (node); assert (oi); #ifdef WANT_OSPF_WRITE_FRAGMENT /* seed ipid static with low order bits of time */ if (ipid == 0) 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); assert (op); assert (op->length >= OSPF_HEADER_SIZE); if (op->dst.s_addr == htonl (OSPF_ALLSPFROUTERS) || op->dst.s_addr == htonl (OSPF_ALLDROUTERS)) ospf_if_ipmulticast (ospf, oi->address, oi->ifp->ifindex);