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 [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to