orignal
zzz, the irony is
orignal
that I'm a client of alfa-bank ))
orignal
they are my broken on russian stock market
orignal
zzz also I would like to discuss acks
orignal
I don't like a way how it's now and have some better proposal
orignal
basically
orignal
1. acktrough should have oacket number stating that all messages before acked
orignal
2. ranges after it: acks and nacks
orignal
acnt is not needed
orignal
it's basially last range with zero nacks
orignal
in this case we use direct rather than reverse iterators
orignal
if no gaps only acktrough is presented
zzz
re: alfa, good luck
zzz
re: acks, thanks for the comments, I expected you to have some
zzz
here's what I was thinking:
zzz
it's a simplified version of what is in QUIC
zzz
in the common case, there are no nacks
zzz
so 4 byte ack through and 1 byte acnt is a nice, small, 8 byte block. we want the ack block to be as small as possible
zzz
if we had a range instead of acnt, it would be 9 bytes
zzz
how would we do 'all messages before are acked' ?
zzz
back in 30 min
orignal
so ack through means "I ack all message before ack through and ack through"
orignal
<orignal> so ack through means "I ack all message before ack through and ack through"
orignal
basically acnt is not a problem
orignal
reverse order is
zzz
please explain
orignal
current logic
orignal
I have an ordered map of sent packets
orignal
and unconfirmed
orignal
I receive Axk block
orignal
I have to find first packet with packet num <= acktrough
zzz
ok I get it
orignal
then I have to interate in reverse order until I find packetnum < acktrough - acnt
zzz
here's how I think of it
orignal
then I have to do the same for all range
orignal
two issues
zzz
the ack block is just an encoding
orignal
1. reverse iterators is always less effecient
orignal
2. not every data structure support it (single-listed list for example)
orignal
go ahead
zzz
so, the ack block is an efficient way to encode a bitfield
zzz
starting at the highest number, then keep going for as much "room" as you have in the packet, or to some max number of ranges
zzz
so when I get an ack block, I "decode" it to a bitfield
orignal
what bitfield you are talking about?
zzz
and then process it bottom-up, in the "forward" order
orignal
don't we ack packets?
zzz
yes
zzz
what I'm calling a "bitfield" is just a concept, a collection of bits that are set
zzz
so I first convert the ack block to a bitfield, going top-down
zzz
but then I _process_ the bitfield bottom-up
orignal
so you store unacked packets and bitfields?
zzz
yes
orignal
ok. so you do two passes
zzz
yes, a quick pass top down, then the slower pass bottom up to look for unacked packets
orignal
that's waht I do now
orignal
my proposal however assumes one pass
zzz
the "bitfield" is implemented in the SSU2Bitfield code I linked you to on monday
orignal
I take acktrough
orignal
find first packetnum that hight then acktrough delete all packets before
zzz
isn't that what acnt does (if no ranges) ?
orignal
acnt goes in opposite direction
orignal
backward not forward
zzz
oh, you want a 'lowest acked' field instead of highest?
orignal
yes
orignal
that's my idea
orignal
so acktrough gurantees everything below is acked
orignal
and we can ack milliion packets using single acktrough
zzz
see the thing is, we can't do that
zzz
because we don't "remember" a million packets
zzz
the design is to remember only the last ~256
orignal
I mean in genaral
orignal
the whole idea is once I receive an ack block
orignal
I insttantly delete all remebered packet with packnum less then ack trough
orignal
regardless how many
orignal
using a single opration
zzz
but there's no guarantee of that
orignal
why?
orignal
when I set acktrough in Ack I say then everything below has been received by me
zzz
let me give an example:
zzz
say I want to ack packet 1000
zzz
but I'm missing packet 999
zzz
and I only have room in the data packet for 8 bytes: block header (3), ack through, and acnt
orignal
I send acktrough=998
orignal
and range 1 1
zzz
no room for ranges in this packet
zzz
only have 8 bytes
zzz
the most important thing in any ack protocol is to send the _highest_ ack
orignal
if so don't confirm 1000 until you get 999
zzz
no, because maybe 999 wasn't important, could have been an ack-only packet. Also, individual packet numbers aren't retransmitted
zzz
I may never get 999
orignal
then use acnt to show lowest packet
zzz
so it would be ack thru 1000, acnt 0
zzz
the important thing is you _dont_ assume anything below that is acked
zzz
anything below that is neither acked nor nacked. it's nothing. no information
zzz
the most important thing to ack is always the highest packet numbers. if there's more room then add ranges
orignal
as I said
orignal
ackrought - acnt as lowest number works for me
orignal
without ranges
orignal
if I have ranges it means I have to find lowest number first
orignal
and then go from that
orignal
meaning two passes
zzz
yes, in the usual case, without ranges, it's easy
zzz
but that's why it has to be encoded "backwards", because the highest numbers are most important, and we add ranges if there's room, for more history
zzz
and below the lowest number is simply "don't know"
zzz
not acked, not nacked
orignal
fine than
orignal
assume ranges is rare case
orignal
and we can do second pass
zzz
I usually don't see any ranges
zzz
often some nacks after about 100-200 packets
zzz
the way I do it is I have my bitfield. then I do 'construct an ack block with X ranges maximum' from that bitfield, based on how much room is left in the packet
zzz
my ack processing isn't very efficient right now either, but I have some ideas
zzz
save the last ack block received. If the next ack block is the same, ignore it
zzz
or compare the last ack block to the new one, and only process what's different
orignal
two passes is a good idea anyway
zzz
this is MUCH simpler than QUIC. If I proposed what QUIC does you'd be asking for my head
zzz
but yeah, think of ack block as "efficient encoding of most recent ACKs". There's lots of flexibility on how you "decode" and/or process it
zzz
yeah first pass is super simple. just add up ackthrough + (every byte after that). Now you know what the beginning is. Then proces it however you want
orignal
no problem
orignal
I know what to do now
orignal
but my question is
orignal
should we use ranges at all?
zzz
yes, from the example above, if I got 1000 and not 999, I can't ack 998 or below at all
zzz
see QUIC RFC 9000, section 13.2.3
orignal
can't you send two ack blocks?
orignal
one for 1000 and another for 998?
zzz
you could, but then the 998 one is missing the most important info, which is the highest number (1000)
zzz
it's also less efficient
orignal
fine than
orignal
let me implement ranges
zzz
just to explain a little further:
zzz
without ranges, we don't have NACKs at all
zzz
ack 1000 (only) doesn't say that 999 is missing
zzz
ack 998-900 doesn't say that 999 is missing
orignal
well I would keep resending 999
orignal
until I get ack
orignal
or number of attempts
zzz
yeah but you don't ever resend 999. you resend the _contents_ of 999, in packet 1001
zzz
so it's not like TCP. we need to send acks in a way that assumes there will be gaps, you don't ever go back and "fill in" the gaps or stop the congestion window
zzz
so if 999 is out-of-order, the gap will be "filled" when I get it
zzz
but if 999 is lost, that gap will always be there, until the bitfield "shifts up"
orignal
please explain
orignal
I thought I always resend 999 as is
orignal
just an encryoted packet
orignal
that's important
orignal
say I send 999 and store it
orignal
then I don't see ack and need to resend it
orignal
do I resend with current packet num or 999?
zzz
you resend with current packet number
zzz
the packet number is the nonce for chacha, never reused
zzz
so you don't store _packets_ for retransmission, you remember the _contents_ of the packet and retransmit the contents in a new packet with a new packet number
orignal
what's wrong to resend a packet as is?
zzz
the new packet will possibly have a different ack block
orignal
it will be considered as ordinary out of order UDP packet
zzz
it's also inefficient to store packets for retransmission
orignal
why?
zzz
just remember that packet 999 had fragment 1 of i2np message x
zzz
you don't want to store both the i2np message and the packet
zzz
this is also from QUIC
zzz
and SSU 1
orignal
I'm not going to store i2np message at all
orignal
just packets I have sent
zzz
but you store the fragments, don't you?
orignal
no
orignal
as I said I store packets
orignal
say fragment 2 is in packet 1000
orignal
you receive 1000 but not 999
orignal
you store this fragment 2 and wait a paekt with fragment 1
orignal
then you receive packet 999
orignal
you decrypt it and take fragment 1
orignal
what's wrong in this system?
zzz
sure, on the receiver side, that's right
orignal
on the sender I store packet 999
orignal
if I don't get ack for it I resend it again
zzz
but on the sender side, you store the fragments for retransmission, not the packets, same as in SSU 1, and same as in QUIC
zzz
that's the way the spec is written now
orignal
please tell me a reason why I should do it?
zzz
ok
orignal
my way breaks nothing
zzz
- retransmitted data looks different to an on-path observer, can't tell it's retransmitted
zzz
- retransmitted data gets an updated ack block sent with it, not the old ack block
zzz
- you only retransmit what's necessary. some fragments could have been already retransmitted once and been acked
zzz
- you can fit as much as you need into each retransmitted packet if more is pending
zzz
- much more flexible
zzz
eot
orignal
so basically DPI
orignal
then I should store payload without padding
zzz
DPI is the first one, yes. But the whole design is from QUIC, where packet numbers are not reused
orignal
fine. I will store payload only
zzz
yes, that's the design. Been a while since I read through this part of the QUIC spec
zzz
basically the same as SSU 1, except for "remembering" what was in what packet
orignal
I don't remeber what was there
orignal
anyway thank you for clarification
orignal
will fix it
zzz
:)
zzz
can I ask you about RI fragmentation?
zzz
did you see what I posted above yesterday morning ^^^ ?