Re: using connected UDP socket to contact to portmapper?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 06.06.2012 08:12, Ian Kent wrote:
> On Tue, 2012-06-05 at 10:26 +0400, Michael Tokarev wrote:
[]
>> In order to eliminate this timeout, the socket used to contact
>> the remote portmapper needs to be connected - this way, the
>> OS will report ECONNREFUSED error instantly and the mount
>> operation will proceed without delays even if the remote
>> portmapper is not available.
> 
> Right, but the recent changes have changed the order to TCP then UDP so
> I'm not sure this is still accurate now, although I may not have changed
> them all, I need to check that.
> 
> But I thought ECONNREFUSED meant just that, in which case UDP should be
> tried following that, in case only the TCP port is blocked.

I tried exactly with the very recent changes.  My test version
is 09d4edb2469f9415f6ca33760d83b3c85b517de7, "autofs-5.0.6 -
fix libtirpc name clash".

Here's the debug output (with a few fprintf's I added):

Starting automounter version 5.0.6, master map /etc/auto.master
using kernel protocol version 5.02
lookup_nss_read_master: reading master file /etc/auto.master
parse_init: parse(sun): init gathered global options: (null)
spawn_mount: mtab link detected, passing -n to mount
spawn_umount: mtab link detected, passing -n to mount
lookup_read_master: lookup(file): read entry /misc
lookup_read_master: lookup(file): read entry +dir:/etc/auto.master.d
lookup_nss_read_master: reading master dir /etc/auto.master.d
lookup(dir): dir map /etc/auto.master.d missing or not readable
lookup(file): failed to read included master map dir:/etc/auto.master.d
master_do_mount: mounting /misc
automount_path_to_fifo: fifo name /run/autofs.fifo-misc
lookup_nss_read_map: reading map file /etc/auto.misc
parse_init: parse(sun): init gathered global options: (null)
spawn_mount: mtab link detected, passing -n to mount
spawn_umount: mtab link detected, passing -n to mount
mounted indirect on /misc with timeout 300, freq 75 seconds
st_ready: st_ready(): state = 0 path /misc
handle_packet: type = 3
handle_packet_missing_indirect: token 101, name test, request pid 14024
attempting to mount entry /misc/test
lookup_mount: lookup(file): looking up test
lookup_mount: lookup(file): test -> -vers=4 gnome:/data
parse_mount: parse(sun): expanded entry: -vers=4 gnome:/data
parse_mount: parse(sun): gathered options: vers=4
parse_mount: parse(sun): dequote("gnome:/data") -> gnome:/data
parse_mount: parse(sun): core of entry: options=vers=4, loc=gnome:/data
sun_mount: parse(sun): mounting root /misc, mountpoint test, what gnome:/data, fstype nfs, options vers=4
mount_mount: mount(nfs): root=/misc name=test what=gnome:/data, fstype=nfs, options=vers=4
mount_mount: mount(nfs): nfs options="vers=4", nobind=0, nosymlink=0, ro=0
get_nfs_info: called with host gnome(192.168.88.4) proto tcp version 0x70
get_nfs_info: nfs v4 rpc ping time: 0.004577
get_nfs_info.portmap_getclient begin
rpc_portmap_getclient.create_client begin
rpc_portmap_getclient.create_client end
get_nfs_info.portmap_getclient end
get_nfs_info: host gnome cost 4576 weight 0
get_nfs_info: done
get_nfs_info: called with host gnome(192.168.88.4) proto udp version 0x70
get_nfs_info: nfs v4 rpc ping time: 0.000387
get_nfs_info.portmap_getclient begin
rpc_portmap_getclient.create_client begin
rpc_portmap_getclient.create_client end
get_nfs_info.portmap_getclient end
get_nfs_info.portmap_getport begin
rpc_portmap_getport.clnt_call begin
   [several seconds pause here]
rpc_portmap_getport.clnt_call end
get_nfs_info.portmap_getport end
get_nfs_info: host gnome cost 386 weight 0
get_nfs_info: done
prune_host_list: selected subset of hosts that support NFS4 over TCP
mount_mount: mount(nfs): calling mkdir_path /misc/test
mount_mount: mount(nfs): calling mount -t nfs -s -o vers=4 gnome:/data /misc/test
spawn_mount: mtab link detected, passing -n to mount
mount_mount: mount(nfs): mounted gnome:/data on /misc/test
dev_ioctl_send_ready: token = 101
mounted /misc/test

It is doing first clnt_call() in rpc_portmap_getport(),
which is PMAPPROC_NULL, over UDP which times out.  After
that it just mounts things.

>> This is rpc_portmap_getport() function.
>>
>> I tried to follow the code, but the logic there is so twisted
>> I've lost track of things quite quickly.
> 
> Yes, it is a bit convoluted.
> 
> This code was originally written for two reasons.
> First to take control over the timeouts to avoid lengthy waits and
> second to reduce socket usage by allowing callers to reuse socket file
> descriptors.

Is that okay to made these sockets connected?  I mean, is the
same socket can be reused to connect to different destination
(host or port)?

>> The question is: is it possible to use connected UDP sockets
>> there in all cases, or is conn_info->client reused for
>> something else?  If it is, I guess we may just get rid of
>> cached (UDP) client and create new client for each call.
> 
> Don't think so.

>> Or is this completely backwards?  I mean, UDP is really
>> unreliable protocol, for it to actually work the app
>> should retry sending packet in case of timeout, and the
>> protocol is easy to spoof too...
> 
> Backward in the sense that we probably should (and should already) be
> using TCP first.

If you mean TCP for the portmapper access, well, maybe it
actually does, but obviously the portmapper does not respond
there if it isn't even running on the remote host.

Even with TCP, in case the portmapper port is firewalled,
we may get timeout.  But this should be easy to work around
in the configuration -- when port is specified explicltly,
portmapper isn't consulted at all.

> Another thing is that, since the change to mount.nfs(8), we now also
> need to change to probing on simple automounts (as well as multi-mounts)
> in order to maintain a reasonable interactive response.

I need to write another lengthly email about this.  I think
the whole approach to checking for /sbin/modprobe and /proc
(neither of which is actually used in the code), /sbin/mount.nfs,
fsck.ext* at configure time is wrong: instead, you should
assume nothing at compile time and call these programs when
needed at runtime using either fixed - standard paths or
searching in $PATH, probing their existance if necessary.

It turned out that Debian autofs package has never used
the "new" nfs mount code at all, because during compile
time mount.nfs has never been available (the compile is
done in a chroot), so the code never checked the "symbolic"
mount.nfs argument and always used the fallback.

But that's for another email.  For now I just want to
understand what to do with this UDP portmap probing,
the trivial fix for the problem at hand (assuming the
portmap port isn't firewalled) is to make UDP socket
connected, so ECONNREFUSED for UDP will be noticed
immediately without resorting to timeout.

This will keep the general potential problem of using
UDP in the first place, and this might want a separate
solution (maybe eliminating UDP altogether), but I'm
not sure I want to change that much in one go :)

>> Alternatively, we may try to contact 2049 port first,
>> and if that one does not respond, try to contact the
>> portmapper.  But I'm not sure if this is right thing
>> to do to start with.
> 
> Don't know that yet either.

Currently it doesn't work with at all /net map.  I asked
several times on IRC about this very case, -- whenever it
is ever possible to enumerate (nfsv4) exports without
portmapper, but no one replied :(  Note: I know right to
nothing about this RPC internals.

Thanks,

/mjt
--
To unsubscribe from this list: send the line "unsubscribe autofs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Filesystem Development]     [Linux Ext4]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux