On Wed, 26 Apr 2006, Jeffrey Hutzelman wrote:
>
>
> On Wednesday, April 26, 2006 05:15:22 PM +0200 Tommie Gannert
> <[EMAIL PROTECTED]> wrote:
>
> > Hi!
> >
> > I've been trying to make my behind-NAT AFS-server do backups to
> > a butc-server behind another NAT.
> >
> > That didn't work because the vlserver keeps sending the file servers'
> > first address instead of the one matching the client address. vlnat
> > is a patch against 1.4.0 which
> >
> > 1) Makes vlserver choose the best fs-address based on the number of
> > common address-bits of the RX-client.
>
> Huh? The modern vlserver interfaces return _all_ the addresses of a
> server, not just one. The decision of which address to use should be up to
> the client, which is in a better position to make a decision. It's
> possible that the backup system is still using ancient interfaces that
> refer to fileservers by a single address instead of by UUID; if so, the
> right long-term fix is to make it use the modern interfaces.
First, I'm using 1.4.0 so far. Migrating to 1.4.1 shortly.
Ok, does this have to do with the three variants of
vlentry_to_{,u,n}vldbentry()
in vlprocs.c? But how do i get 'vos listvldb' to list more than one
address, for instance?
If I remember correctly, buserver sends an address. One address. It
seems like a small performance gain, though. butc could be doing the
VLDB lookups in all passes.
I'm not sure if the clients are better off making the decision,
though. If they are behind NAT with the same subnet as the server,
things will get messy. The idea of using common address bits means
it will resort to global address space pretty easily. However, it's
a hack, yes.
Anyway, I don't like butc at all, so maybe I'll just make a new
generation...
> Yup, that's a bug. You should send it to openafs-bugs. Including a patch
> wouldn't hurt, but also shouldn't strictly be necessary in this case, since
> the fix is so obvious.
>
Yeah, and if I had remembered to include the patches... ;)
They'll go to openafs-bugs.
> > (Isn't anyone else using "-syslog"?)
>
> Yes; we've been using -syslog in production for quite a long time. I bet
> not too many people use -rxmaxmtu, though, and this bug should be very
> unlikely to affect people who don't.
>
Actually it affects any command line parameter which is strcmp-parsed
after '-rxmaxmtu' (which was placed in the middle of the list). It
says
if (!strcmp(argv[i], "-rxmaxmtu")) ...
Regards,
Tommie Gannert--- openafs-1.4.0/src/vlserver/vlprocs.c 2005-06-21 22:19:29.000000000
+0200
+++ openafs-1.4.0-vlnat/src/vlserver/vlprocs.c 2006-04-03 22:32:58.000000000
+0200
@@ -429,11 +429,11 @@
}
/* Convert from the internal to external form */
if (new == 1)
- vlentry_to_nvldbentry(&tentry, (struct nvldbentry *)aentry);
+ vlentry_to_nvldbentry(&tentry, (struct nvldbentry *)aentry,
rxcall->conn->peer->host);
else if (new == 2)
- vlentry_to_uvldbentry(&tentry, (struct uvldbentry *)aentry);
+ vlentry_to_uvldbentry(&tentry, (struct uvldbentry *)aentry,
rxcall->conn->peer->host);
else
- vlentry_to_vldbentry(&tentry, (struct vldbentry *)aentry);
+ vlentry_to_vldbentry(&tentry, (struct vldbentry *)aentry,
rxcall->conn->peer->host);
return (ubik_EndTrans(trans));
}
@@ -2887,11 +2887,107 @@
}
+/* Count the number of common bits in A and B. They are assumed to be IP
addresses in network byte order. */
+static int
+CountCommonAddressBits(A, B)
+ afs_uint32 A;
+ afs_uint32 B;
+{
+ int i;
+
+ for (i = 0; i < sizeof(A) * 8; ++i) {
+ if ((A & 1) != (B & 1))
+ break;
+
+ A >>= 1;
+ B >>= 1;
+ }
+
+ return i;
+}
+
+
+/*
+ * Return an integer describing the IP class. 0 is the public address space.
+ */
+static int
+GetAddressClass(Addr)
+ afs_uint32 Addr;
+{
+ if ((Addr & 0x00000080) == 0x00000000) return 1;
+ if ((Addr & 0x000000C0) == 0x00000080) return 2;
+ if ((Addr & 0x000000E0) == 0x000000C0) return 3;
+ if ((Addr & 0x000000F0) == 0x000000E0) return 4;
+
+ return 0;
+}
+
+
+/* Return >0 if Addr is a "better" match to Mask than is Best.
+ * This is pretty hard coded. Two major classes of addresses exist:
+ * Private IP-class A-D
+ * Public anything else
+ *
+ * The logic should be according to this table, where A, M, B are the
+ * function parameters. a, b, are distinct private classes, and p is the
+ * public class.
+ *
+ * A M B Result Condition
+ * CC(A, M) > CC(B, M) A == B
+ * p p p
+ * p a p
+ * a p a **
+ * a b a **
+ * a a a
+ *
+ * true A == M (&& B != M) || B != M && B == p
+ * p p a
+ * a a p
+ * a a b
+ * a b p
+ *
+ * false B == M (&& A != M) || A != M && A == p
+ * p a a
+ * a p p
+ * a b b
+ * p a b
+ * a p b **
+ *
+ * ** don't care (equally bad decision)
+ * The don't cares have been incorporated into the other categories to
+ * save some code, generalizing the expressions somewhat.
+ *
+ * According to my calculations a full table of three ABP should contain
+ * 3^3 = 27 entries. Since A, and B are just distinct placeholders, they
+ * could be swapped. This eliminates half of the table (except the P P P case
+ * is separate). This leaves (3^3 - 1) / 2 + 1 = 14 entries.
+ */
+static int
+AddressIsTighterMatch(Addr, Mask, Best)
+ afs_uint32 Addr;
+ afs_uint32 Mask;
+ afs_uint32 Best;
+{
+ int addrClass = GetAddressClass(Addr);
+ int maskClass = GetAddressClass(Mask);
+ int bestClass = GetAddressClass(Best);
+
+ if (addrClass == bestClass)
+ return CountCommonAddressBits(Addr, Mask) >
CountCommonAddressBits(Best, Mask);
+
+ if (addrClass == maskClass || bestClass != maskClass && bestClass == 0)
+ return 1;
+
+ return 0;
+}
+
+
/* Convert from the internal (compacted) vldb entry to the external
representation used by the interface. */
static
-vlentry_to_vldbentry(VlEntry, VldbEntry)
+vlentry_to_vldbentry(VlEntry, VldbEntry, host)
struct nvlentry *VlEntry;
struct vldbentry *VldbEntry;
+ afs_uint32 host;
{
int i, j;
@@ -2903,18 +2999,20 @@
if ((HostAddress[j = VlEntry->serverNumber[i]] & 0xff000000) ==
0xff000000) {
struct extentaddr *exp;
- int base, index;
+ int base, index, best = -1;
base = (HostAddress[j] >> 16) & 0xff;
index = HostAddress[j] & 0x0000ffff;
exp = &ex_addr[base][index];
- /* For now return the first ip address back */
for (j = 0; j < VL_MAXIPADDRS_PERMH; j++) {
if (exp->ex_addrs[j]) {
- VldbEntry->serverNumber[i] = ntohl(exp->ex_addrs[j]);
- break;
+ if (best < 0 || AddressIsTighterMatch(exp->ex_addrs[j],
host, exp->ex_addrs[best]))
+ best = j;
}
}
+
+ if (best >= 0)
+ VldbEntry->serverNumber[i] = ntohl(exp->ex_addrs[best]);
} else
VldbEntry->serverNumber[i] =
HostAddress[VlEntry->serverNumber[i]];
@@ -2931,9 +3029,10 @@
/* Convert from the internal (compacted) vldb entry to the external
representation used by the interface. */
static
-vlentry_to_nvldbentry(VlEntry, VldbEntry)
+vlentry_to_nvldbentry(VlEntry, VldbEntry, host)
struct nvlentry *VlEntry;
struct nvldbentry *VldbEntry;
+ afs_uint32 host;
{
int i, j;
@@ -2945,18 +3044,20 @@
if ((HostAddress[j = VlEntry->serverNumber[i]] & 0xff000000) ==
0xff000000) {
struct extentaddr *exp;
- int base, index;
+ int base, index, best = -1;
base = (HostAddress[j] >> 16) & 0xff;
index = HostAddress[j] & 0x0000ffff;
exp = &ex_addr[base][index];
- /* For now return the first ip address back */
for (j = 0; j < VL_MAXIPADDRS_PERMH; j++) {
if (exp->ex_addrs[j]) {
- VldbEntry->serverNumber[i] = ntohl(exp->ex_addrs[j]);
- break;
+ if (best < 0 || AddressIsTighterMatch(exp->ex_addrs[j],
host, exp->ex_addrs[best]))
+ best = j;
}
}
+
+ if (best >= 0)
+ VldbEntry->serverNumber[i] = ntohl(exp->ex_addrs[best]);
} else
VldbEntry->serverNumber[i] =
HostAddress[VlEntry->serverNumber[i]];
@@ -2971,9 +3072,10 @@
}
static
-vlentry_to_uvldbentry(VlEntry, VldbEntry)
+vlentry_to_uvldbentry(VlEntry, VldbEntry, host)
struct nvlentry *VlEntry;
struct uvldbentry *VldbEntry;
+ afs_uint32 host;
{
int i, j;
--- openafs-1.4.0/src/butc/dump.c 2005-04-03 20:15:45.000000000 +0200
+++ openafs-1.4.0-vlnat/src/butc/dump.c 2006-04-04 10:43:55.000000000 +0200
@@ -869,9 +869,9 @@
/* Determine location of the volume.
* In case the volume moved has moved.
*/
- if (passNumber > 1) { /*pass */
+ if (passNumber > 0) { /*pass */
tcode =
- bc_GetEntryByID(cstruct, curDump->vid, curDump->vtype,
+ ubik_Call(VL_GetEntryByID, cstruct, 0, curDump->vid,
curDump->vtype,
&vldbEntry);
if (tcode) {
ErrorLog(0, taskId, tcode, 0,