Hi,
I noticed udp buffers overflowing when submitting large amounts of traps at
the snmptrapd (1000 traps would make you see the problem). This was a
critical issue ... (yes I know one can never guarantee a trap will arrive,
but if someone can easily reproduce the problem without a workaround to
improve the behaviour then some people will even call it a "bug" rather than
a "limitation").
Anyway, I noticed it was related to udp buffers overflowing and there was no
way to tune these buffers, because the snmpUDPDomain was using a fixed
buffer of 131k. Therefore I wrote the patch below.
I also thought that people might want to tune their "server" applications
(eg. snmptrapd) differently than their client applications (eg.
snmpbulkget), and their receive buffers differently than their send buffers.
Therefore I added 4 directives to the snmp.conf
udpServerRecvBuf integer
udpServerRecvBuf is used to specify the UDP receive buffer size (in
bytes)
for the initialization of server sockets (eg. snmptrapd).
If the OS hard limit is smaller than udpServerRecvBuf the resulting
buffer
will be lowered so it is close to the hard limit.
Some platforms may decide to increment the actual buffersize
themselves
for internal housekeeping.
This directive will be ignored on platforms that don't support
setsockopt()
udpServerSendBuf integer
Similar to udpServerRecvBuf, but this directive applies to the send
buffer of server sockets.
udpClientRecvBuf integer
Similar to udpServerRecvBuf, but this directive applies to the
receive
buffer of client sockets (eg. snmpget).
udpClientSendBuf integer
Similar to udpServerRecvBuf, but this directive applies to the send
buffer of client sockets.
The codechange is pretty straightforward (with comments and 'extensive'
logging).
The patch below also contains the changes to the man pages.
The IPv6/UDP patch can be done by applying the snmpUDPDomain.c patch to
snmpUDPIPv6Domain.c
Comments appreciated.
Thanks,
-- Geert
Index: include/net-snmp/library/default_store.h
===================================================================
RCS file:
/cvsroot/net-snmp/net-snmp/include/net-snmp/library/default_store.h,v
retrieving revision 5.19
diff -u -r5.19 default_store.h
--- include/net-snmp/library/default_store.h 17 Aug 2004 09:08:53 -0000
5.19
+++ include/net-snmp/library/default_store.h 5 Sep 2004 21:55:54 -0000
@@ -88,6 +88,10 @@
#define NETSNMP_DS_LIB_PRINT_SUFFIX_ONLY NETSNMP_DS_LIB_OID_OUTPUT_FORMAT
#define NETSNMP_DS_LIB_STRING_OUTPUT_FORMAT 5
#define NETSNMP_DS_LIB_HEX_OUTPUT_LENGTH 6
+#define NETSNMP_DS_LIB_UDP_SERVERSENDBUF 7 /* send buffer for
UDP server connections */
+#define NETSNMP_DS_LIB_UDP_SERVERRECVBUF 8 /* receive buffer
for UDP server connections */
+#define NETSNMP_DS_LIB_UDP_CLIENTSENDBUF 9 /* send buffer for
UDP client connections */
+#define NETSNMP_DS_LIB_UDP_CLIENTRECVBUF 10 /* receive buffer
for UDP client connections */
/*
* special meanings for the default SNMP version slot
(NETSNMP_DS_LIB_SNMPVERSION)
Index: man/snmp.conf.5.def
===================================================================
RCS file: /cvsroot/net-snmp/net-snmp/man/snmp.conf.5.def,v
retrieving revision 5.9
diff -u -r5.9 snmp.conf.5.def
--- man/snmp.conf.5.def 14 Apr 2004 19:27:31 -0000 5.9
+++ man/snmp.conf.5.def 5 Sep 2004 21:55:55 -0000
@@ -159,6 +159,26 @@
The debugging tokens that should be printed. See the
.I snmpcmd(1)
manual page for debugging usage details.
+.IP "udpServerRecvBuf integer"
+.B udpServerRecvBuf
+is used to specify the UDP receive buffer size (in bytes)
+for the initialization of server sockets (eg. snmptrapd).
+If the OS hard limit is smaller than
+.B udpServerRecvBuf
+the resulting buffer will be lowered so it is close to the hard limit.
+Some platforms may decide to increment the actual buffersize themselves
+for internal housekeeping.
+This directive will be ignored on platforms that don't support
+..I setsockopt()
+.IP "udpServerSendBuf integer"
+Similar to udpServerRecvBuf, but this directive applies to the send
+buffer of server sockets.
+.IP "udpClientRecvBuf integer"
+Similar to udpServerRecvBuf, but this directive applies to the receive
+buffer of client sockets (eg. snmpget).
+.IP "udpClientSendBuf integer"
+Similar to udpServerRecvBuf, but this directive applies to the send
+buffer of client sockets.
.SH "SEE ALSO"
snmp_config(5), read_config(3), snmpcmd(1).
.\" Local Variables:
Index: snmplib/snmpUDPDomain.c
===================================================================
RCS file: /cvsroot/net-snmp/net-snmp/snmplib/snmpUDPDomain.c,v
retrieving revision 5.22
diff -u -r5.22 snmpUDPDomain.c
--- snmplib/snmpUDPDomain.c 2 Sep 2004 02:32:27 -0000 5.22
+++ snmplib/snmpUDPDomain.c 5 Sep 2004 21:55:55 -0000
@@ -193,6 +193,115 @@
}
+/* Change the udp buffer
+ * IN: s : socket
+ * optname: SO_SNDBUF or SO_RCVBUF
+ * local: server=1 or client=0
+ */
+static void
+netsnmp_set_udp_buffer(int s, int optname, int local)
+{
+ int reqbuf = 0;
+ int oldbuf = 0, oldbuflen = sizeof(int);
+ int newbuf = 0, newbuflen = sizeof(int);
+ const char *buftype;
+
+ /* What is the requested buffer
+ * if not specified, we will use the default buffer
+ */
+ if (optname == SO_SNDBUF) {
+ if (local) {
+ buftype = "server send buffer";
+ reqbuf = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
+ NETSNMP_DS_LIB_UDP_SERVERSENDBUF);
+ } else {
+ buftype = "client send buffer";
+ reqbuf = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
+ NETSNMP_DS_LIB_UDP_CLIENTSENDBUF);
+ }
+ } else {
+ if (local) {
+ buftype = "server receive buffer";
+ reqbuf = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
+ NETSNMP_DS_LIB_UDP_SERVERRECVBUF);
+ } else {
+ buftype = "client receive buffer";
+ reqbuf = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
+ NETSNMP_DS_LIB_UDP_CLIENTRECVBUF);
+ }
+ }
+
+ /* If this variable was not specified, just use a hardcoded
+ * default
+ */
+ if (!reqbuf)
+ reqbuf = 1<<17;
+
+ DEBUGMSGTL(("netsnmp_udp",
+ "requested %s is %d\n", buftype, reqbuf));
+
+ /* Get the current send buffer */
+ if ((getsockopt(s,SOL_SOCKET, optname, (void *) &oldbuf,
+ &oldbuflen) == 0)
+ && (oldbuflen == sizeof(int))) {
+ DEBUGMSGTL(("netsnmp_udp", "Old %s is %d\n", buftype, oldbuf));
+ } else {
+ DEBUGMSGTL(("netsnmp_udp", "Get %s failed (1)\n", buftype));
+ }
+
+ /* Try to set the requested send buffer */
+ if (setsockopt
+ (s, SOL_SOCKET, optname, (void *) &reqbuf, sizeof(int)) == 0) {
+ DEBUGMSGTL(("netsnmp_udp", "Changed the %s to %d\n", buftype,
reqbuf));
+ } else {
+ DEBUGMSGTL(("netsnmp_udp", "couldn't set %s to %d: %s\n",
+ buftype, reqbuf, strerror(errno)));
+ }
+
+ /* Verify that it worked
+ * Some OS's will silently fail the setsockopt() -- Solaris for example
+ * Other OS's will gladly allocate more than requested -- Linux for
example
+ */
+ if ((getsockopt(s,SOL_SOCKET,optname, (void *) &newbuf,
+ &newbuflen) == 0)
+ && (newbuflen == sizeof(int))) {
+
+ DEBUGMSGTL(("netsnmp_udp", "New %s: %d\n", buftype, newbuf));
+
+ /* If the new buffer is smaller than the size we requested, we will
+ * try to increment the new buffer with 1k increments
+ * (this will sometime allow us to reach a more optimal buffer.)
+ * For example : On Solaris, if the max OS buffer is 100k and you
+ * request 110k, you end up with the default 8k :-(
+ * So we walk up from 8k with 1k increments until it fails.
Rather
+ * bruteforce, but simple
+ */
+ if (newbuf < reqbuf)
+ {
+ DEBUGMSGTL(("netsnmp_udp", "Optimizing buffer\n"));
+
+ while (newbuf < reqbuf) {
+ /* Add 1k to the buffer that worked */
+ newbuf += 1<<9;
+ if (!setsockopt(s, SOL_SOCKET, optname, (void *) &newbuf,
+ sizeof(int)) == 0) {
+ break;
+ }
+ }
+
+ /* Now print if this optimization helped or not */
+ if (getsockopt(s,SOL_SOCKET, optname, (void *) &newbuf,
+ &newbuflen) == 0) {
+ DEBUGMSGTL(("netsnmp_udp",
+ "Optimized %s: %d\n",buftype, newbuf));
+ } else {
+ DEBUGMSGTL(("netsnmp_udp", "Get %s failed (2)\n",
buftype));
+ }
+ }
+ } else {
+ DEBUGMSGTL(("netsnmp_udp", "Get %s failed (3)\n", buftype));
+ }
+}
/*
* Open a UDP-based transport for SNMP. Local is TRUE if addr is the local
@@ -204,7 +313,7 @@
netsnmp_udp_transport(struct sockaddr_in *addr, int local)
{
netsnmp_transport *t = NULL;
- int rc = 0, udpbuf = (1 << 17);
+ int rc = 0;
char *string = NULL;
char *client_socket = NULL;
@@ -272,21 +381,17 @@
*/
#ifdef SO_SNDBUF
- if (setsockopt
- (t->sock, SOL_SOCKET, SO_SNDBUF, (void *) &udpbuf,
- sizeof(int)) != 0) {
- DEBUGMSGTL(("netsnmp_udp", "couldn't set SO_SNDBUF to %d bytes:
%s\n",
- udpbuf, strerror(errno)));
- }
+ /* Set the send buffer */
+ netsnmp_set_udp_buffer(t->sock, SO_SNDBUF, local);
+#else
+ DEBUGMSGTL(("netsnmp_udp", "Changing UDP send buffers is not
supported\n"));
#endif /*SO_SNDBUF */
#ifdef SO_RCVBUF
- if (setsockopt
- (t->sock, SOL_SOCKET, SO_RCVBUF, (void *) &udpbuf,
- sizeof(int)) != 0) {
- DEBUGMSGTL(("netsnmp_udp", "couldn't set SO_RCVBUF to %d bytes:
%s\n",
- udpbuf, strerror(errno)));
- }
+ /* Set the receive buffer */
+ netsnmp_set_udp_buffer(t->sock, SO_RCVBUF, local);
+#else
+ DEBUGMSGTL(("netsnmp_udp", "Changing UDP receive buffers is not
supported\n"));
#endif /*SO_RCVBUF */
if (local) {
Index: snmplib/snmp_api.c
===================================================================
RCS file: /cvsroot/net-snmp/net-snmp/snmplib/snmp_api.c,v
retrieving revision 5.63
diff -u -r5.63 snmp_api.c
--- snmplib/snmp_api.c 8 Jul 2004 15:36:01 -0000 5.63
+++ snmplib/snmp_api.c 5 Sep 2004 21:56:00 -0000
@@ -726,6 +726,14 @@
NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS);
netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "clientaddr",
NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CLIENT_ADDR);
+ netsnmp_ds_register_config(ASN_INTEGER, "snmp", "udpServerSendBuf",
+ NETSNMP_DS_LIBRARY_ID,
NETSNMP_DS_LIB_UDP_SERVERSENDBUF);
+ netsnmp_ds_register_config(ASN_INTEGER, "snmp", "udpServerRecvBuf",
+ NETSNMP_DS_LIBRARY_ID,
NETSNMP_DS_LIB_UDP_SERVERRECVBUF);
+ netsnmp_ds_register_config(ASN_INTEGER, "snmp", "udpClientSendBuf",
+ NETSNMP_DS_LIBRARY_ID,
NETSNMP_DS_LIB_UDP_CLIENTSENDBUF);
+ netsnmp_ds_register_config(ASN_INTEGER, "snmp", "udpClientRecvBuf",
+ NETSNMP_DS_LIBRARY_ID,
NETSNMP_DS_LIB_UDP_CLIENTRECVBUF);
}
void
-------------------------------------------------------
This SF.Net email is sponsored by BEA Weblogic Workshop
FREE Java Enterprise J2EE developer tools!
Get your free copy of BEA WebLogic Workshop 8.1 today.
http://ads.osdn.com/?ad_idP47&alloc_id808&op=click
_______________________________________________
Net-snmp-coders mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/net-snmp-coders