4-byte (32-bit) BGP Neighbor Information with AsDotNotation

A problem currently exists within Solarwinds where 4-byte (32-bit) ASNs overflow into a negative number when utilizing a portion of the private scoped ASN space specifically, the ranges 2,147,483,648 (32768.0) through 4,294,967,296 (65535.65535) overflow into -2,147,483,648 through -1 respectively.

To show the correct data, we created a custom table utilizing the following WSQL to generate the correct information. See past the snippet for an explanation as to how and why this works.

SELECT 
  NeighborIP, 
  ProtocolName, 
  ProtocolStatus,

  -- AutonomousSystem is stored in a signed 32 bit integer, and will therefore 
  -- overflow into a negative number when the number exceeds 2,147,483,648.
  -- High Bound of AS before this event is 32768.65535.
  --   NOTE: THIS FIELD IS FOR REFERENCE ONLY AND CAN BE DROPPED IN PRODUCTION.
  AutonomousSystem AS RawAS,

  -- AsPlainNotation represents the correct enumeration for 4-byte AS (as well 
  -- as 2-byte AS by adding the Autonomous system to 4,294,967,296)
  CASE
    WHEN AutonomousSystem < 0 THEN (
      -- NEGATIVE ASN INTEGER OVERFLOW ENCOUNTERED
      -- Add 64-bit CONST Integer representing positive offset to counteract 
      -- negative overflow... 
      4294967296 + AutonomousSystem
    )
    ELSE ( 
      -- ASN WITHIN NORMAL BOUNDS
      -- Return RAW ASN.
      AutonomousSystem 
    )
    END AS AsPlainNotation,

  -- AsDotNotation represents the X.Y Dot Notation specified in RFC4893 for
  -- the 4-byte (or 32-bit) BGP Peer's AS.
  CASE
    WHEN AutonomousSystem <      0 THEN (
      -- NEGATIVE ASN INTEGER OVERFLOW ENCOUNTERED
      -- Add 64-bit CONST Integer representing positive offset to counteract
      -- negative overflow... split components:
      --   +  To get most significant 16-bits divide by 2^16 (65536) and 
      --      truncate with FLOOR.
      --   +  To get least significant 16-bits perform 'most significant bit
      --      calculation' and Left shift 16-bits by multiplying by 2^16
      --      and subtracting from the full 32-bit value.
      TOSTRING(
           FLOOR( (4294967296 + AutonomousSystem) / 65536)
      )
      + '.' + 
      TOSTRING(
        (4294967296 + AutonomousSystem) -
          (FLOOR( (4294967296 + AutonomousSystem) / 65536) * 65536)
      )
    )
    WHEN AutonomousSystem <      0 THEN (
      -- POSITIVE 4-BYTE ASN ENCOUNTERED
      -- Split components:
      --   +  To get most significant 16-bits divide by 2^16 (65536) and 
      --      truncate with FLOOR.
      --   +  To get least significant 16-bits perform 'most significant bit
      --      calculation' and Left shift 16-bits by multiplying by 2^16
      --      and subtracting from the full 32-bit value.
    WHEN AutonomousSystem >  65535 THEN (
       TOSTRING(
            FLOOR( (AutonomousSystem) / 65536)
       )
       + '.' + 
       TOSTRING(
         (AutonomousSystem) -
           (FLOOR( (AutonomousSystem) / 65536) * 65536)
      )
    )
    ELSE (
      -- POSITIVE 2-BYTE ASN ENCOUNTERED
      -- Append 0. to the autonomous system.
      '0.' + 
      TOSTRING(AutonomousSystem)
    )
  END AS AsDotNotation
FROM Orion.Routing.Neighbors
WHERE NodeID = ${NodeID}

NOTE: RFC6996 defines private scoped ASNs as 4,200,000,000 (64806.0) through 4294967294 (65535.65535) inclusive.

Linear assignment of Binary Symbol to Decimal Number for a 32-bit Signed Integer:
10000000 00000000 00000000 00000000 = -2,147,483,648
10000000 00000000 00000000 00000001 = -2,147,483,647
10000000 00000000 00000000 00000010 = -2,147,483,646
10000000 00000000 00000000 00000011 = -2,147,483,645
... lines removed for brevity ...
11111111 11111111 11111111 11111100 = -4
11111111 11111111 11111111 11111101 = -3
11111111 11111111 11111111 11111110 = -2
11111111 11111111 11111111 11111111 = -1
00000000 00000000 00000000 00000000 =  0 
00000000 00000000 00000000 00000001 =  1
00000000 00000000 00000000 00000010 =  2
00000000 00000000 00000000 00000011 =  3
00000000 00000000 00000000 00000100 =  4
... lines removed for brevity ...
‭01111111 11111111 11111111 11111100‬ =  2,147,483,644
‭01111111 11111111 11111111 11111101‬ =  2,147,483,645
‭01111111 11111111 11111111 11111110‬ =  2,147,483,646
‭01111111 11111111 11111111 11111111‬ =  2,147,483,647
‭10000000 00000000 00000000 00000000 = -2,147,483,648 NEGATIVE OVERFLOW

Details

Storage of a 4-byte/32-bit ASN in 32-bit signed integer causes
        2,147,483,648 (32768.0) through 4,294,967,295 (65535.65535)
to be be interpreted as:
        -2,147,483,648 through -1
which do not represent legitimate ASNs.

We don’t care about negative numbers when dealing with ASNs, and so the better storage mechanism would be to keep these in Unsigned 32-bit Integers or 64-bit Signed integers. However, that is beyond the scope of this.. I only note this to point out, we can easily fix the output by summing this 32-bit signed (negative) integer with a 64-bit signed integer in the amount of the offset needed.

Lets imagine we are using the AS Number of 32768.4 (2,147,483,652)

So what happens when we store this number in a 32-bit Singed Integer, the accumulator (in theory) would get to:

    2,147,483,647 (32767.65535)

and increase the value by 1, which becomes into

   -2,147,483,648 (32768.0) ... which should be 2,147,483,648

then the accumulator continues increase the value by 1, 4 more times:

   -2,147,483,647 (32768.1) ... which should be 2,147,483,649
   -2,147,483,646 (32768.2) ... which should be 2,147,483,650
   -2,147,483,645 (32768.3) ... which should be 2,147,483,651
   -2,147,483,644 (32768.4) ... which should be 2,147,483,652

What you will notice is the result of -2,147,483,644 is always the total bit storage quantity offset from its intended value of 2,147,483,652.

This total bit storage quantity of a 32-bit word provides 4,294,967,296 total symbols. By making the 32-bit Integer Signed, the system is simply using half of those symbols for negative integers.

Advertisements