OSPF sequence numbers – why 80 million is smaller than 70 million

So a bit of a specific topic today. Going through Doyle’s Routing TCP/IP Volume 1, I felt my brain melt as he went through explaining sequence numbers in link-state advertisements (in a general sense, not specific to just OSPF). He describes two types of number “spaces” – the range of possible values – to describe how protocols sequence their LSA’s.

Ignoring the historic bits, such as Radia Perlman’s “lollipop space”, which is essentially a combination of cycling numbers with a fixed initialization value (this was part of the first version of OSPF drafts – not relevant for OSPFv2 or anything else), numbering spaces either follow linearly or circular.

In linear spaces, numbers start at x and end at y. The issue with linear space is that you could potentially “run out” of number space. This could cause a link-state protocol to be unable to distinguish between LSA’s that are the most recent from the originating router or just LSA’s being flooded from one router to the next. Link-state protocols, when receiving an LSA with the highest possible sequence number, shut down and age out it’s link-state database (LSDB) to flush all the older LSA’s out. To mitigate this, the designers had to make sure the field for a sequence number was large enough so as to never reasonably hit that highest possible value (y). Both OSPFv2 and IS-IS uses this number space scheme.

Circular number spaces never end – once a maximum value number is reached, it “resets” back to the lower boundary of the space. Since IS-IS and OSPFv2 use linear spaces, this is included for completeness. Perlman’s lollipop scheme used both linear and circular as a combination but these are not included in modern link state protocols.

IS-IS uses a rather simple scheme for it’s number space. A router will originate it’s own directly-connected link states with a sequence number of one (0x00000001), with a maximum sequence number of 4.2 billion (0xFFFFFFFF). This is because the IS-IS field for sequence numbers in its LSP’s (link state packet) uses unsigned 32-bit integers. These values range from 1 – 4294967295 in decimal.

OSPF, on the other hand, uses signed 32-bit integers. While it uses the same scheme for number spaces as IS-IS (linear), the way the values are represented (especially on a router’s database outputs) is…different.

Observe:

Net Link States (Area 1)

Link ID         ADV Router      Age         Seq#       Checksum
192.168.1.112   10.0.0.112      1862        0x80000237 0x00D860
192.168.7.113   10.0.0.113      12          0x80000001 0x00E8F5

So…it starts are 80 000 000?

Obviously, the seq. number is represented in hexadecimal format…but why 0x80000001? Doesn’t that translate to 2 billion decimal? The detail to note is the fact that this field is a signed integer. That means the integers actually range from – 2147483648 to + 2147483648. When processing this field in binary, the CPU needs a way of comparing sequence numbers to determine which one is “higher” – in this case, closer to positive +2147483648.

Programming languages such as C/C++ must pay particular attention to integers declared as signed vs unsigned. Some google- and wiki-fu later, the reason we see sequence numbers starting at 0x80000001 (0x80000000 is reserved via the RFC standard) is because the left-most/most significant bit determines whether a number is represented as a positive value or a negative value. When the MSB is set, the integer is a negative value. When the MSB is not set, it is a positive integer.

 

So…
0x80000001 is 1000 0000 …. 0000 0001 in binary
Since the MSB is set, this is the “first” integer value in a 32-bit signed integer range. It doesn’t make sense to think of these values in decimal values, since this does indeed translate “directly” to 2 billion. These sequence numbers will increment 0x80000002….all the way to 0xFFFFFFFF (-1 in decimal). Incrementing one more time would start the sequence at decimal 0. This is because the MSB must become “unset” for it to represent positive values. The range then continues from 0x00000001 until 0x7FFFFFFE. Again, from the RFC, 0x7FFFFFFF is reserved (actually, an LSA received with this maximum possible sequence number triggers OSPF to flush its LSDB…more nuts and bolts to be expanded on later).

 

The choice of using signed vs unsigned gets kind of blurred between hardware and software. The use of signed integers simplifies ALU designs for CPUs and most (if not all) programming languages implement signedness in their integer data types…Why the IETF chose to use signed integers as part of the OSPFv2 spec? Who knows…

 

Anyways, this really bothered me for a couple days. I feel better now that it’s on paper. Any gross errors or omissions, leave it in the comments!

 

PS: More math-savvy folks will scream at this in regards to two’s complement role here with signed integer binary representation…I just wanted to know and jot down why IOS shows the starting sequence numbers in show ip ospf database as 0x80000001. So there you have it. Further reading for the curious

Cosmetic Bug: IS-IS Network Entity Title

cosmetic bug:

a software error condition that does not impact a system in any functional way; types of errors can include spelling mistakes, transient error messages, etc.

I thought I’d start a series of blog posts dedicated to what I call “cosmetic bugs” in terms of networking technology. What I mean by that is, things that we learn, see and do in networking without any reason as to the why, because it doesn’t impact a router, switch or protocol in anyway…Just that the why’s have somehow been lost in translation of the years.

One such case is related to the lovely link-state protocol IS-IS. IS-IS stands for “Intermediate System to Intermediate System” and was originally developed to facilitate routing between “intermediate systems” – synonymous with an IP router – over the OSI Connectionless Network Service (CLNS) protocol stack. It was later extended in RFC 1195 to support both OSI and TCP/IP networks (renamed to Integrated IS-IS or Dual IS-IS). Since the OSI protocol stack has been obsoleted by TCP/IP, IS-IS is typically used in service provider core networks due to its scalability and link-state properties.

Having taken CCNP BSCI in college and gone through ROUTE in my current profession, I’ve always been intrigued by the mystical awe that is the IS-IS protocol. Being a link-state routing protocol, IS-IS is similar to OSPF in that networks are learned through flooding of link-state information throughout a domain. However, since IS-IS originated from the ISO to work in tandem with the OSI protocol stack, certain “legacy” properties remain. As indicated in the title of this blog post, I just wanted to spend some time as to the “why” behind the Network Entity Title; also known as the IS-IS NET.

The NET is a configured identifier on IS-IS routers that defines a topology. It is a hexadecimal value and indicates both an area ID and a System ID.

An IS-IS NET is made up of Area ID and a System ID. The Area ID performs the same functions as it does with OSPF (with some key differences that I won’t go into in this blog post) and is topology-driven. The System ID performs the same functions as the Router ID does in OSPF. Unlike in OSPF, it does not have to be derived from an IP address nor requires an IP address to be configured on any interface to function. Also, unlike OSPF which sits at Layer 3 (ie. has an IP header below the OSPF header), IS-IS exists directly at Layer 2 (ie. IS-IS PDU header directly after Layer 2 header). To further compare the two, IS-IS NETs must be defined within a certain structure, whereas OSPF uses arbitary values for Area ID’s and Router ID’s. Some of the details I won’t go into just because it simply has nothing to do with the TCP/IP stack. If, like me, you’ve ever wondered why Cisco uses the same configuration example in all IS-IS documentation, hopefully I can shed some light on that. Let’s look at the structure of a NET to give us some more detail:

As indicated in the diagram above, the following rules must be followed when defining the NET:

  • AFI must be 1 byte
  • Area ID can be 0 to 12 bytes long
  • System ID must be 6 bytes long
  • SEL must be 1 byte

The reason for these “rules” is that a NET is a special version of an ISO network service access point (NSAP) address, familiar to anyone who has worked with ISO protocols.

The AFI, or the Authority & Format Identifier, holds no real value in a IP-only environment. In relation to ISO protocols, the AFI was used similarly to an OUI (Organizationally Unique Identifier) in a MAC address, which would have identified the assigning authority of the address. However, in an IP-only environment, this number has no meaning separate from the Area ID itself. Most vendors and operators tend to stay compliant with the defunct protocols by specifying an AFI of “49”. This is synonymous with RFC 1918 IP addresses – it is privately administered and not assigned to another one specific organization. While best practice, the AFI byte can be combined to format a single Area ID value and is left to the discretion of the network admin.

Area ID’s function just as they do in OSPF and are decimal-notated only.

System ID can be anything chosen by the administrator, similarly to an OSPF Router ID. However, best practice with NETs is to keep the configuration as simple as humanly possible. The System ID is typically derived from either the 48-bit MAC address of an interface (“0cad.83b4.03e9”) or an IP address such as configured on a loopback interface. When defining a System ID as derived from an IP address, you can use a few conversion methods since it must be 6 bytes in length and an IPv4 address is only 4 bytes long. One is to simply add enough zeros to fulfill the 6 byte requirement, which is the simplest. You can also convert an IP address to decimal or hexadecimal formats.

Loopback IP address of 10.255.255.200
NET System ID = 1025.5255.2000

The System ID is solely up to the administrator to choose and requires to be unique within a routing domain. MAC addresses are the easiest choice since MAC addresses are globally unique burned-in addresses and *should not* under normal circumstances be the same between different devices.

The final piece in a NET is the SEL byte, or the NSAP Selector byte. In ISO, this value is used to indicate an upper-layer function. Think of this as being similar to a TCP or UDP port number. In an IP-only network, where no upper-layer ISO protocols exist, an IP router will expect a SEL value of 0x00. This value should always be set to 0x00, which indicates the router itself is the “upper layer” protocol. The take away here is that the SEL is not relevant in an IP network and should be set to 00 to keep NET assignment simple.

*note: As pointed out by Marko Milivojevic on Twitter, a non-0 SEL value indicates a pseudonode. IS-IS on multiaccess networks elect a Designated Intermediate System (DIS). Think DR in OSPF. I’m leaving a lot of details out but just keep in mind that configuring a non-zero value for the SEL will throw you a syslog message since IOS will expect this to be configured as a 0. Non-zeros indicate pseudonodes, such as a DIS, which are “virtual nodes”. More on this later.

Below I’ll list some examples of NETs based on the above rules.

For NSAP format compliant NET, AFI of 49, Area ID of 0001, System ID of 0cad.83b4.03e9 (example MAC address) and a SEL of 00:


Router(config)#router isis
Router(config-router)#net 49.0001.0cad.83b4.03e9.00

Routers in different areas can simply use a different Area ID, no different than in OSPF. You just need to be sure the System ID is still unique, as shown below:


Router(config-router)#net 49.0002.0cad.83b4.03f0.00

For smaller networks with fewer areas, you can also define NETs according to this format:

this time using a loopback IP address of 172.31.255.254:
Router(config)#router isis
Router(config-router)#net 01.1723.1255.2540.00

An important note about NETs is that a router can only be part of ONE area. This is different than OSPF, which ABR’s will typically have at least one interface in area 0 and another interface in a standard or stub area. There are slight topology differences that account for this, which will be the topic of a future post.

The biggest thing to note when it comes to IS-IS NETs is to Keep-It-Simple-Stupid! Personally, I got hung up on the why a NET is always shown with an AFI value of 49. Details like this are just “cosmetic” – your IS-IS network will function just fine if you don’t follow ISO standards, since they’re really not relevant in an IP-only world. However, as you can see on Cisco’s website, best practices and simplicity are what determines what we’re told when learning the protocols. The “why” may not be important, but it’s still worth knowing a thing or two about it, even just to quell your own curiosity.

More on IS-IS in future post(s) – it’s worth knowing, being another tool in the Network Wizard’s tool belt.

EDIT: Thanks to Marko for his corrections and clarifications on some of the key terms and concepts. More posts in the future will be needed to explain IS-IS in more depth…stay tuned 😉

OSPF Area ID’s – Dotted or Decimal?

I had a thought the other day while at work regarding OSPF area numbers in Cisco IOS.

Having been brought up on Cisco Net Academy in college, Cisco always teaches the following command syntax:

R1(config-t)#router ospf 1
R1(config-router)#network 10.1.1.0 0.0.0.255 area 0

In fact, 90% of all Cisco documentation and command references will always express OSPF Area ID’s as decimal numbers.
One thing you probably want to keep in mind is what is actually transmitted on the wire.
As an experiment, I used area ID’s of 1000 and 2000 on two directly connected routers, and used both formats for configuring the areas.

On R1
router ospf 1
router-id 1.1.1.1
log-adjacency-changes
network 10.0.0.0 0.0.0.3 area 0

On R2
router ospf 1
router-id 2.2.2.2
log-adjacency-changes
network 10.0.0.0 0.0.0.3 area 0.0.0.0

As expected, the OSPF neighbors came up, since we know that when configuring area 0 as a decimal, it’s sent out irregardless as dotted decimal in OSPF packets.

R1#sh ip os int fa1/0
FastEthernet1/0 is up, line protocol is up
Internet Address 10.0.0.1/30, Area 0
Process ID 1, Router ID 1.1.1.1, Network Type BROADCAST, Cost: 1
Transmit Delay is 1 sec, State BDR, Priority 1
Designated Router (ID) 2.2.2.2, Interface address 10.0.0.2
Backup Designated router (ID) 1.1.1.1, Interface address 10.0.0.1
Timer intervals configured, Hello 10, Dead 40, Wait 40, Retransmit 5
truncated...

R2#sh ip osp int fa1/0
FastEthernet1/0 is up, line protocol is up
Internet Address 10.0.0.2/30, Area 0.0.0.0
Process ID 1, Router ID 2.2.2.2, Network Type BROADCAST, Cost: 1
Transmit Delay is 1 sec, State DR, Priority 1
Designated Router (ID) 2.2.2.2, Interface address 10.0.0.2
Backup Designated router (ID) 1.1.1.1, Interface address 10.0.0.1
Timer intervals configured, Hello 10, Dead 40, Wait 40, Retransmit 5
truncated...

Now that I have these routers talking to each other over the backbone area, let’s see how LSA’s for the loopback areas (1000 and 2000) look when configured with decimals under Cisco IOS:


R1(config-if)#do sh run int fa1/1
Building configuration...

Current configuration : 116 bytes
!
interface FastEthernet1/1
ip address 10.10.1.1 255.255.255.0
ip ospf 1 area 1000

R2(config-if)#do sh run int fa1/1
Building configuration...

Current configuration : 116 bytes
!
interface FastEthernet1/1
ip address 10.20.1.1 255.255.255.0
ip ospf 1 area 2000

And the captures:

R1 OSPF Hello on Area 1000
R2 OSPF Hello on Area 2000

As we can see, even though we use decimal notation, OSPF packets are always sent using dotted decimal.
It’s fairly simple why, being just a matter of binary conversation of decimal numbers to dotted decimal format.
For example, R1 was configured on Area ID 1000.

Decimal 1000 in binary is = 0011 1110 1000
Expanding that out to dotted decimal, we have the following in binary = 0000 0000.0000 0000.0000 0011.1110 1000

Converting it back to dotted decimal, we see in the hellos that OSPF Area ID 1000 = Area ID 0.0.3.232.

We can do the same for R2 on Area ID 2000.

Decimal 2000 = 0111 1101 0000 binary
32-bit binary 0000 0000.0000 00000.0000 0111.1101 0000 = 0.0.7.208

So regardless of which way you configure your area ID’s, OSPF will always transmit using dotted decimal format.
While it is easy to maintain and see decimal base-10 on small OSPF networks, an area ID greater than 255 will result in the next 8-bit octet incrementing as your area ID numbers increase (ie. Area ID 256 = 0.0.1.0 in dotted decimal). While 1000 and 2000 are nice numbers in a running config, it will always transmit in dotted decimal.