Below is a write-up of some issues that I found with the sequence number arithmetic. This is mainly for the record. The most important thing is that there are currently two problems: 1) before48(a, b) can not decide if the difference between a and b is 2^47 2) unsigned sequence number arithmetic causes problems/headaches/curses. For instance, there are tests such as if( delta_seqno(a, b) > NUM_DUPACKS) in the code. What happens if a and b are reordered (e.g. (5, 3) instead of (3, 5))? When using unsigned difference, we get the two's complement and that is a large number. With signed arithmetic, the former case gives a negative result and we can then decide whether we want to be bothered with the reordering or not. Again, the text below is for the record - I hope to be back with a patch to implement this before the end of the week. Gerrit --- Modulo-2^48 Sequence Number Operations in DCCP ---------------------------------------------- This text is a write-up of issues regarding sequence number comparisons and operations when 48 bits are wanted, but 64 are given. A good illustration is given in section 24.7 of Stevens, vol 2. In particular, this text defines * ordering (the `before' relation which implies the `after' relation) * signed difference/delta of sequence numbers * derived relations Ordering n-bit numbers in modulo 2^n arithmetic ----------------------------------------------- The n-bits sequence numbers start at 0 and wrap around from 2^n-1 back to 0. For two n-bit sequence numbers, a and b, we want to determine whether a is `before' b. This is a strict ordering, i.e. for all a != b exactly one of a `before' b or b `before' must hold. When this condition is fulfilled, we obtain an implied relation: a `before' b <=> b `after' a (a) Assume first that a == 0 Then a `before' b for 1 <= b <= 2^n-1 But, since sequence numbers wrap, we also have that 2^(n-1)+1 ... 2^n-1 are `before' a = 0 To disambiguate, we define * 0 is `before' 1 ... 2^(n-1)-1 * 2^(n-1) ... 2^n-1 are `before' 0 (b) The general case: if a > 0 then the above just cycles around. The following table shows this. a | a `before' b | b `before' a ---+--------------------------+-------------------------------------------- 0 | 1 ... (2^(n-1) - 1) | 2^(n-1) ... (2^n - 1) 1 | 2 ... 2^(n-1) | (2^(n-1) + 1) ... (2^n - 1) ... 0 2 | 3 ... (2^(n-1) + 1) | (2^(n-1) + 2) ... (2^n - 1) ... 0 ... 1 ... ... ..... ... ... ... k | k+1 ... (2^(n-1) -1 + k) | (2^(n-1) + k) ... (2^n - 1 + k) ---+--------------------------+-------------------------------------------- (0 < k <= 2^n-1, all additions and subtractions are modulo-2^n) (c) Using the difference instead With differences we are independent of the value of k: * a is `before' a number b = a+1 ... (2^(n-1) - 1 + a) whenever (b - a) = 1 ... (2^(n-1) - 1) * this implies that the test "c `before' a" fails for all numbers c which are such that 2^(n-1) + a <= c <= 2^n - 1 + a * using two's complement, we get another, equivalent condition: a `before' b <=> 1 <= b-a <= 2^(n-1) - 1 <=> -2^(n-1) + 1 <= a-b <= -1 This is a necessary condition, and it also shows that testing whether "a-b < 0" is not sufficient for "a `before' b" since -2^(n-1) is also < 0 Modulo-2^48 arithmetic on 64 bit -------------------------------- With the above, we can instantiate a relation `before48' as follows: a `before48' b <=> 2^47 <= a-b <= 2^48-1 In [RFC 4340, sec. 3.1] it is suggested that "It may make sense to store DCCP sequence numbers in the most significant 48 bits of 64-bit integers and set the least significant 16 bits to zero, since this supports a common technique that implements circular comparison A < B by testing whether (A - B) < 0 using conventional two's-complement arithmetic." Unfortunately this does not work. Signed 64-bit numbers represent the range -2^63 ... 0 ... 2^63-1. When the difference between two left-shifted 48-bit numbers a and b is 2^63, we can not tell whether a is `before' b or b is `before' a - the difference will always be negative due to the constraints of the data type. This case occurs for all 48-bit numbers whose difference amounts to 2^47. Since there are 2^47 such numbers, the test based on the above test fails to produce correct results in 2^47 = 140.7375e12 cases. The suggestion from RFC 4340 can thus not be used is misleading. We therefore develop a definition of `sequence number delta', inspired by dccp_delta_seqno(). Computing sequence number delta ------------------------------- The aim is to develop a function delta_seqno(u64 a, u64 b) which essentially performs subtraction modulo-48 of signed numbers, i.e. it shall satisfy (a + delta_seqno(a, b)) % 2^48 = b Hence delta_seqno(a, b) reduces to the subtraction b-a modulo-48, i.e. delta_seqno(a, b) = (b + 2^48 - a) % 2^48 The main difference is that we want the return result to be a _signed_ 48-bit number, i.e. the range 2^47 ... 2^48-1 is to be mapped into the range -2^47 ... -1 (two's complement in 48 bit). The following table illustrates some cases; a, b are unsigned 48-bit numbers. +--------+---------+----------+---------+----------------+ | | | b + 2^48 - a | | | a | b | unsigned | signed | a `before' b | +--------+---------+----------+---------+----------------+ | 0 | 1 | 1 | 1 | X | | 0 | 2^47-1 | 2^47-1 | 2^47-1 | X | | 0 | 2^47 | 2^47 | -2^47 | | | 0 | 2^47+1 | 2^47+1 | -2^47-1 | | | 0 | 2^48-1 | 2^48-1 | -1 | | | 2^48-1 | 0 | 1 | 1 | X | | 2^47+1 | 0 | 2^47-1 | 2^47-1 | X | | 2^47 | 0 | 2^47 | -2^47 | | | 2^48-3 | 5 | 8 | 8 | X | | 2^47 | 1 | 2^47+1 | -2^47-1 | | | 2^47+1 | 1 | 2^47 | -2^47 | | | 5 | 2^48-3 | 2^48 - 8 | -8 | | +--------+---------+----------+---------+----------------+ The following is now the definition of the function delta_seqno: #define COMPLEMENT48(x) (2^48 - x) #define TO_SIGNED48(x) ((x < 2^47)? : -COMPLEMENT48(x)) /* returns: > 0 if a `before' b = 0 if a == b < 0 which indicates that b `before' a */ s64 delta_seqno(u64 a, u64 b) { s64 delta = (b + COMPLEMENT48(x)) % 2^48; return TO_SIGNED48(x); } Derived comparisons for n=48 bit -------------------------------- The dccp_delta_seqno function saves a lot of work: (i) `before' a `before' b <=> 1 <= b-a <= 2^(n-1)-1 <=> delta_seqno(a, b) > 0 (ii) `after' a `after' b <=> b `before' a <=> delta_seqno(b, a) > 0 (iii) `the same as' a `the same as' b <=> (a-b) == 0 <=> delta_seqno(b, a) == 0 (iv) `follows' (b is the immediate successor of a) b `follows' a <=> delta_seqno(b, a) == 1 (v) `precedes' (b is the immediate predecessor of a) b `precedes' a <=> delta_seqno(b, a) == -1 - To unsubscribe from this list: send the line "unsubscribe dccp" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html