Commit Graph
12 Commits
Author SHA1 Message Date
David Fifield 1251acc351 Simplify DNSPacketConn.sendLoop a little. 2021-08-02 01:00:16 -06:00
David Fifield 27dbee1b66 Make pollChan buffered, and send on it only once.
Formerly we sent twice on pollChan, but because it was unbuffered, the
second send was almost always dropped. KCP's own ACK packets should also
serve as another source of what are effectively polling queries at a
rate proportional to the rate at which we are receiving.

I did some performance tests of downloading 10 MiB between two servers
with 100 ms RTT between them. Server:
	dnstt-server -udp :53 -privkey-file server.key t.example.com 127.0.0.1:9321
	ncat -l -k -v 9321 --send-only --sh-exec 'dd bs=1M count=10 if=/dev/urandom'
Client:
	dnstt-client -pubkey-file server.pub t.example.com 127.0.0.1:7000
	ncat --recv-only 127.0.0.1 7000 | pv -t -r -a -b -i 0.2 > /dev/null
I did the download under every treatment twice and recorded the download
rate in KiB/s.

First, the results for the commit before this one. I also hacked in
fewer sends on pollChan for each packet received. The result for 1 poll
are about the same as for 2 polls, which is expected, with the
observation that the unbuffered pollChan was usually dropping the second
send. 0 polls results in a very slow rate (possibly driven only by smux
keepalive packets). ("~" means I stopped waiting for the download after
about 2 minutes.)

resolver	method	pollChan cap	SetACKNoDelay	polls	KiB/s	KiB/s
--------	------	------------	-------------	-----	-----	-----
direct		udp	unbuffered	false		2	146	159	(status quo before this commit)
dns.google	udp	unbuffered	false		2	 58.3	 60.2	(status quo before this commit)
dns.google	doh	unbuffered	false		2	125	126	(status quo before this commit)
direct		udp	unbuffered	false		1	155	165
dns.google	udp	unbuffered	false		1	 57.5	 58.7
dns.google	doh	unbuffered	false		1	124	123
direct		udp	unbuffered	false		0	 ~7	~11
dns.google	udp	unbuffered	false		0	 ~6	 ~5
dns.google	doh	unbuffered	false		0	 ~6	 ~6

Now, the result after this commit. A buffered pollChan with 1 poll per
receive has almost identical performance to an unbuffered pollChan with
1 or 2 polls per receive, which is expected. Using 2 polls rather than 1
actually helps performance a fair bit in the direct/UDP and Google/UDP
treatments, but hurts performance in the Google/DoH treatment. 0 polls
still yields poor performance.

resolver	method	pollChan cap	SetACKNoDelay	polls	KiB/s	KiB/s
--------	------	------------	-------------	-----	-----	-----
direct		udp	16		false		2	174	175
dns.google	udp	16		false		2	 76.0	 75.3
dns.google	doh	16		false		2	 68.7	68.0
direct		udp	16		false		1	149	151	(this commit)
dns.google	udp	16		false		1	 60.2	 60.3	(this commit)
dns.google	doh	16		false		1	123	121	(this commit)
direct		udp	16		false		0	 ~7	 ~8
dns.google	udp	16		false		0	 ~5	 ~5
dns.google	doh	16		false		0	 ~6	 ~7

I tried the additional modification of calling conn.SetACKNoDelay(true).
My guess was that this would cause every received data packet to be
ACKed immediately, which should have the same function as a poll.
Unexpectedly for me, SetACKNoDelay(true) actually slows down the
direct/UDP and Google/DoH cases a lot. But strangely, Google/UDP becomes
faster (and 1 poll is even faster than 2 polls in that case). Strangest
of all, SetACKNoDelay(true) makes the 0-poll Google/UDP and Google/DoH
treatments run reasonably fast. My best guess as to why that is the case
is that routing through a Google resolver tends to disorder the packet
sequence, which maybe results in more ACKs, which effectively act as
polls.

resolver	method	pollChan cap	SetACKNoDelay	polls	KiB/s	KiB/s
--------	------	------------	-------------	-----	-----	-----
direct		udp	16		true		2	 87.7	 84.2
dns.google	udp	16		true		2	 82.7	 68.9
dns.google	doh	16		true		2	 59.8	 60.8
direct		udp	16		true		1	 54.1	 47.8
dns.google	udp	16		true		1	 97.5	100
dns.google	doh	16		true		1	 71.4	 70.9
direct		udp	16		true		0	 ~9	 ~8
dns.google	udp	16		true		0	 48.0	 48.6
dns.google	doh	16		true		0	 59.2	 59.2
2021-08-01 22:09:03 -06:00
David Fifield 58c01e740f requestor → requester
RFC 1035 uses "requester" and RFC 6891 uses "requestor". I think I
prefer "requester", and aspell agrees.
2020-08-30 19:50:23 -06:00
David Fifield 4663433c08 Do receive-triggered polls based packets received.
Not amount of raw payload. This allows for the case where the received
payload is only padding, for example. (That can't happen with the
current downstream encoding scheme, which doesn't allow for padding, so
I believe this change results in equivalent behavior.)
2020-04-29 09:45:29 -06:00
David Fifield d14deab12b Documentation and light refactoring. 2020-04-19 17:16:27 -06:00
David Fifield 813a8564e8 Move some helper functions into dns.go. 2020-04-19 11:29:50 -06:00
David Fifield e7098959e2 Move global base32Encoding into dns.go. 2020-04-18 23:39:35 -06:00
David Fifield b7c18be90f Lowercase base32-encoded data in DNS names. 2020-04-18 23:39:35 -06:00
David Fifield 7ed79218eb Insert more padding when polling. 2020-04-18 18:46:54 -06:00
David Fifield 973f6310c5 Don't expire ClientMap if timeout is zero. 2020-04-18 16:02:14 -06:00
David Fifield 7cbddf5fd9 Rework polling.
Give priority to data-carrying packets over polling packets.
Discard a polling packet whenever sending a data-carrying packet.
2020-04-18 16:02:14 -06:00
David Fifield be9c3f1ac7 Refactor PacketConn handling. 2020-04-18 14:34:10 -06:00