IRCaBot 2.1.0
GPLv3 © acetone, 2021-2022
#ls2
/2022/03/31
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 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 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
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 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?
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 can I ask you about RI fragmentation?
zzz did you see what I posted above yesterday morning ^^^ ?