Amanda-Users

Re: BUG

2006-01-05 12:55:31
Subject: Re: BUG
From: Paul Bijnens <paul.bijnens AT xplanation DOT com>
To: John E Hein <jhein AT timing DOT com>
Date: Thu, 05 Jan 2006 18:44:46 +0100
John E Hein wrote:
I don't know if this is exactly the same as a problem I found and
patched, but it smells similar.

See the attached emails (from emails I sent to hackers last July).  I
patched my amanda (2.4.5) and have been using it without problems
since.  I don't know if this was ever checked in or put on the patches
page.


This patch was already merged in 2.4.5.

These patches actually introduce the problem that Michael encounters:
planner now splits the "REQ" type packets into max MAX_DGRAM/2 size,
but amandad.c is not patched to allow for such "REQ" packets to span
more than one UDP dgram.


===================================================================
RCS file: /cvsroot/amanda/amanda/common-src/dgram.h,v
retrieving revision 1.6.2.2
diff -u -r1.6.2.2 dgram.h
--- common-src/dgram.h  1999/09/01 17:58:39     1.6.2.2
+++ common-src/dgram.h  2001/06/29 17:52:34
@@ -34,7 +34,12 @@
#include "amanda.h" -#define MAX_DGRAM (64*1024)
+/*
+ * Maximum datagram (UDP packet) we can generate.  Size is limited by
+ * a 16 bit length field in an IPv4 header (65535), which must include
+ * the 24 byte IP header and the 8 byte UDP header.
+ */
+#define MAX_DGRAM      (((1<<16)-1)-24-8)

Better definition of the payload of a 64K packet indeed...

[...]
RCS file: /cvsroot/amanda/amanda/server-src/amcheck.c,v
retrieving revision 1.50.2.20
diff -u -r1.50.2.20 amcheck.c
[...]
+       if(req_len + l_len > MAX_DGRAM / 2) {        /* allow 2X for err 
response */

amcheck has the same code as planner when assembling the packet for the remote amandad client. Good!


[...]
===================================================================
RCS file: /cvsroot/amanda/amanda/server-src/planner.c,v
retrieving revision 1.76.2.20
diff -u -r1.76.2.20 planner.c
[...]
+       if(req_len + s_len > MAX_DGRAM / 2) {        /* allow 2X for err 
response */
+           amfree(s);
+           break;
+       }


This is where planner limits the size of the REQ packet to 32K.

[...]

But there is no patch for amandad.c to allow for more than one REQ packet.



FreeBSD has a max udp datagram size of 9216 ('sysctl -a | grep dgram'
or reading sys/netinet/udp_usrreq.c shows it).

So calling sendto(2) with a message larger than this causes EMSGSIZE.

Dumping a host that has 42 disklist entries causes that for us.  The
sendsize request message gets large.  There are requests for
information about multiple dump levels per disklist entry, and we are
seeing nominally 2-3 requests per DLE (42 * 2.5 * ~130 chars/line =
13650).

Below is a patch to use setsockopt to bump that up to MAX_DGRAM for
the amanda udp sockets.  This should last a lot longer until we hit
the ~64 KiB limit.

There's still a problem with jrj's dgram split fix from 2001 once you
hit that limit - specifically a truncation of the list rather than
sending multiple estimate request chunks.  So you get 'missing
results' for the DLEs that sendsize is never asked to reports
estimates.  I'll address that in a separate email if I get the time to
come up with a patch.

This patch compiles on FreeBSD, but should work on other OS's, too,
since SO_SNDBUF is a standard option.

In fact, this option is used in stream.c to set socket buffer sizes.
We could, in theory, use the same function (try_socksize) to set the
UDP socket buffer size.  It just uses a socket handle and doesn't care
if it's udp/tcp.  If someone wants to tweak the patch to share
try_socksize() for dgram.c as well, that should work also.

That would involve making try_socksize() non-static (possibly moving
it to a different .c file if desired) and putting the prototype in a
.h file that both dgram.c and stream.c could include.

Lots of chatter for a little patch...

--- common-src/dgram.c.orig     Tue Nov 12 12:19:03 2002
+++ common-src/dgram.c  Wed Jul 13 12:29:19 2005
@@ -53,6 +53,7 @@
     socklen_t len;
     struct sockaddr_in name;
     int save_errno;
+    int size = MAX_DGRAM;
if((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
        save_errno = errno;
@@ -70,6 +71,10 @@
        errno = EMFILE;                         /* out of range */
        return -1;
     }
+    if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (void *) &size,
+       sizeof(size)) < 0)
+       dbprintf(("%s: dgram_bind: could not set udp send buffer to %d\n",
+                 debug_prefix(NULL), size));
memset(&name, 0, sizeof(name));
     name.sin_family = AF_INET;

The above patch is not implemented.  But the installation notes for
FreeBSD do mention to increase the UDP dgram size using the sysctl
command or /etc/sysctl.conf file.


--
Paul Bijnens, Xplanation                            Tel  +32 16 397.511
Technologielaan 21 bus 2, B-3001 Leuven, BELGIUM    Fax  +32 16 397.512
http://www.xplanation.com/          email:  Paul.Bijnens AT xplanation DOT com
***********************************************************************
* I think I've got the hang of it now:  exit, ^D, ^C, ^\, ^Z, ^Q, ^^, *
* F6, quit, ZZ, :q, :q!, M-Z, ^X^C, logoff, logout, close, bye, /bye, *
* stop, end, F3, ~., ^]c, +++ ATH, disconnect, halt,  abort,  hangup, *
* PF4, F20, ^X^X, :D::D, KJOB, F14-f-e, F8-e,  kill -1 $$,  shutdown, *
* init 0, kill -9 1, Alt-F4, Ctrl-Alt-Del, AltGr-NumLock, Stop-A, ... *
* ...  "Are you sure?"  ...   YES   ...   Phew ...   I'm out          *
***********************************************************************