Tag Archives: ospf

Demystifying the OSPFv3 database – Part 3

Previous posts in this series has been limited to a single area. Let’s now start adding new areas and see what LSAs are produced. I’m going to add R6 to area 6 as follows:
OSPFv3 4 Demystifying the OSPFv3 database – Part 3
Area 1 is a standard area. R6 is originating it’s loopback into OSPFv3. R1 is a regular ABR. In OSPFv2 I would expect R1 to originate Type3 LSAs for all the Type1 and Type2 LSAs in area 0. In OSPFv3 this is similar behaviour. The Type3 LSA is now labelled as the ‘Inter Area Prefix Link States’

R6#show ospfv3 database | begin Inter
		Inter Area Prefix Link States (Area 1)

ADV Router       Age         Seq#        Prefix
 1.1.1.1         783         0x80000001  2001:DB8::1:1:1:1/128
 1.1.1.1         783         0x80000001  2001:DB8:12::/64
 1.1.1.1         783         0x80000001  2001:DB8::2:2:2:2/128
 1.1.1.1         783         0x80000001  2001:DB8::3:3:3:3/128
 1.1.1.1         783         0x80000001  2001:DB8::7:7:7:7/128
 1.1.1.1         783         0x80000001  2001:DB8:13::/64

Note that there is a separate Type3 for each and every prefix. This is similar the Type3 in OSPFv2. If I add another loopback to R7, I would expect R7 to originate a new single Type9 in area 0 listing all it’s connected prefixes. I would also then expect R1 to originate an extra Type3 for that prefix in addition to the existing Type3s:

R7(config)#int lo0
R7(config-if)#ipv6 address 2001:db8::77:77:77:77/128
R1#show ospfv3 database prefix adv-router 7.7.7.7

          OSPFv3 1 address-family ipv6 (router-id 1.1.1.1)

		Intra Area Prefix Link States (Area 0)

  Routing Bit Set on this LSA
  LS age: 56
  LS Type: Intra-Area-Prefix-LSA
  Link State ID: 0
  Advertising Router: 7.7.7.7
  LS Seq Number: 80000002
  Checksum: 0xDB08
  Length: 72
  Referenced LSA Type: 2001
  Referenced Link State ID: 0
  Referenced Advertising Router: 7.7.7.7
  Number of Prefixes: 2
  Prefix Address: 2001:DB8::7:7:7:7
  Prefix Length: 128, Options: LA, Metric: 0
  Prefix Address: 2001:DB8::77:77:77:77
  Prefix Length: 128, Options: LA, Metric: 0
R6#show ospfv3 database | begin Inter
		Inter Area Prefix Link States (Area 1)

ADV Router       Age         Seq#        Prefix
 1.1.1.1         1464        0x80000001  2001:DB8::1:1:1:1/128
 1.1.1.1         1464        0x80000001  2001:DB8:12::/64
 1.1.1.1         1464        0x80000001  2001:DB8::2:2:2:2/128
 1.1.1.1         1464        0x80000001  2001:DB8::3:3:3:3/128
 1.1.1.1         1464        0x80000001  2001:DB8:13::/64
 1.1.1.1         82          0x80000001  2001:DB8::7:7:7:7/128
 1.1.1.1         82          0x80000001  2001:DB8::77:77:77:77/128

R1 being the ABR is also originating Type3′s into area 0:

R2#show ospfv3 database inter-area prefix

          OSPFv3 1 address-family ipv6 (router-id 2.2.2.2)

		Inter Area Prefix Link States (Area 0)

  Routing Bit Set on this LSA
  LS age: 560
  LS Type: Inter Area Prefix Links
  Link State ID: 0
  Advertising Router: 1.1.1.1
  LS Seq Number: 80000001
  Checksum: 0x6F46
  Length: 36
  Metric: 64
  Prefix Address: 2001:DB8:16::
  Prefix Length: 64, Options: None

  Routing Bit Set on this LSA
  LS age: 560
  LS Type: Inter Area Prefix Links
  Link State ID: 1
  Advertising Router: 1.1.1.1
  LS Seq Number: 80000001
  Checksum: 0xFF6A
  Length: 44
  Metric: 64
  Prefix Address: 2001:DB8::6:6:6:6
  Prefix Length: 128, Options: None

Area 1 will now be converted to a total stub.

R6(config)#router ospfv3 1
R6(config-router)#add ipv6 un
R6(config-router-af)#area 1 stub
R1(config)#router ospfv3 1
R1(config-router)#add ipv6 un
R1(config-router-af)#area 1 stub no-summary

R6 still has the area 1 Type1, Type8, and Type9s. There is now only a single Type3 advertising a default route:

R6#show ospfv3 database inter-area prefix

          OSPFv3 1 address-family ipv6 (router-id 6.6.6.6)

		Inter Area Prefix Link States (Area 1)

  Routing Bit Set on this LSA
  LS age: 243
  LS Type: Inter Area Prefix Links
  Link State ID: 7
  Advertising Router: 1.1.1.1
  LS Seq Number: 80000001
  Checksum: 0x49E9
  Length: 28
  Metric: 1
  Prefix Address: ::
  Prefix Length: 0, Options: None

This will create a standard inter-area route:

R6#sh ipv6 route ::/0
Routing entry for ::/0
  Known via "ospf 1", distance 110, metric 65, type inter area
  Route count is 1/1, share count 0
  Routing paths:
    FE80::C801:7BFF:FE9E:8, Serial1/0
      Last updated 00:05:54 ago

I’ll now originate an external LSA on R2:

R2(config)#router ospfv3 1
R2(config-router)#address-family ipv6 unicast
R2(config-router-af)#default-information originate always

This action will cause R2 to originate a Type5 LSA. This is pretty much identical to an OSPFv2 Type5:

R7#show ospfv3 database external

          OSPFv3 1 address-family ipv6 (router-id 7.7.7.7)

		Type-5 AS External Link States

  Routing Bit Set on this LSA
  LS age: 221
  LS Type: AS External Link
  Link State ID: 0
  Advertising Router: 2.2.2.2
  LS Seq Number: 80000001
  Checksum: 0x9871
  Length: 32
  Prefix Address: ::
  Prefix Length: 0, Options: None
  Metric Type: 2 (Larger than any link state path)
  Metric: 1
  External Route Tag: 1

I’m going to change area 1 back to a regular area. As there is an external LSA on area 0, that LSA should be flooded into area 1. Routers in area 1 also need to know how to get to the ASBR, R2 in this case. In OSPFv2 the ABR originated a Type4 LSA, the ASBR-Summary LSA. In OSPFv3 it’s also a Type4, but it’s now called the Inter-Area Router LSA. With this Type4 and Type5, R6 is able to work out a path for the external route:

R6#show ospfv3 database inter-area router

          OSPFv3 1 address-family ipv6 (router-id 6.6.6.6)

		Inter Area Router Link States (Area 1)

  Routing Bit Set on this LSA
  LS age: 150
  Options: (V6-Bit, E-Bit, R-bit, DC-Bit)
  LS Type: Inter Area Router Links
  Link State ID: 33686018
  Advertising Router: 1.1.1.1
  LS Seq Number: 80000001
  Checksum: 0xC829
  Length: 32
  Metric: 1
  Destination Router ID: 2.2.2.2

I’m now going to convert area 1 to an NSSA and originate an external route via R6:

R1(config)#router ospfv3 1
R1(config-router)#add ipv6 un
R1(config-router-af)#area 1 nssa no-sum
R6(config)#int lo1
R6(config-if)#ipv6 add 2001:db8::66:66:66:66/128

R6(config-if)#route-map LOOPBACK1
R6(config-route-map)#match interface lo1

R6(config-route-map)#router ospfv3 1
R6(config-router)#add ipv6 un
R6(config-router-af)#area 1 nssa
R6(config-router-af)#redistribute connected route-map LOOPBACK1

R1 should see this as a Type7 NSSA external. OSPFv2 and OSPFv3 are the same in this regard:

R1#sh ospfv3 database nssa-external

          OSPFv3 1 address-family ipv6 (router-id 1.1.1.1)

		Type-7 AS External Link States (Area 1)

  Routing Bit Set on this LSA
  LS age: 60
  LS Type: AS External Link
  Link State ID: 1
  Advertising Router: 6.6.6.6
  LS Seq Number: 80000001
  Checksum: 0x8857
  Length: 60
  Prefix Address: 2001:DB8::66:66:66:66
  Prefix Length: 128, Options: P
  Metric Type: 2 (Larger than any link state path)
  Metric: 20
  Forward Address: 2001:DB8::6:6:6:6

R1 being the ABR into area 0 should convert that Type7 into a Type5:

R1#show ospfv3 database external adv-router 1.1.1.1

          OSPFv3 1 address-family ipv6 (router-id 1.1.1.1)

		Type-5 AS External Link States

  LS age: 172
  LS Type: AS External Link
  Link State ID: 0
  Advertising Router: 1.1.1.1
  LS Seq Number: 80000001
  Checksum: 0x23BB
  Length: 60
  Prefix Address: 2001:DB8::66:66:66:66
  Prefix Length: 128, Options: None
  Metric Type: 2 (Larger than any link state path)
  Metric: 20
  Forward Address: 2001:DB8::6:6:6:6

As R1 is originating this LSA, routers in area 0 don’t need the Type4 for information on how to get to the ASBR R6.

In part 4 I’ll go over various other parts of OSPFv3, including using IPv4.

Demystifying the OSPFv3 database – Part 2

In yesterday’s post I forgot to mention a very interesting behaviour of the way router’s originate Type9 LSAs over a broadcast segment. Let’s remind ourselves of the topology we were up to:
OSPFv3 3 Demystifying the OSPFv3 database – Part 2
I’ve reset this topology and currently R3 is the DR. Let’s first check the non-broadcast link between R1 and R2. Each router oritiginates a Type9 with all their OSPFv3 enabled prefixes. This includes the link between them:

R2#show ospfv3 database prefix self-originate

          OSPFv3 1 address-family ipv6 (router-id 2.2.2.2)

		Intra Area Prefix Link States (Area 0)

  Routing Bit Set on this LSA
  LS age: 568
  LS Type: Intra-Area-Prefix-LSA
  Link State ID: 0
  Advertising Router: 2.2.2.2
  LS Seq Number: 80000003
  Checksum: 0xF340
  Length: 64
  Referenced LSA Type: 2001
  Referenced Link State ID: 0
  Referenced Advertising Router: 2.2.2.2
  Number of Prefixes: 2
  Prefix Address: 2001:DB8::2:2:2:2
  Prefix Length: 128, Options: LA, Metric: 0
  Prefix Address: 2001:DB8:12::
  Prefix Length: 64, Options: None, Metric: 1

Here R2 has two prefixes in the LSA. R1 is also originating 2001:DB8:12::/64 in it’s LSA. When connected to a broadcast segment, routers do NOT advertise the connected prefixes address. Take a look at R7′s Type9:

R7#show ospfv3 database prefix self-originate

          OSPFv3 1 address-family ipv6 (router-id 7.7.7.7)

		Intra Area Prefix Link States (Area 0)

  Routing Bit Set on this LSA
  LS age: 6
  LS Type: Intra-Area-Prefix-LSA
  Link State ID: 0
  Advertising Router: 7.7.7.7
  LS Seq Number: 80000003
  Checksum: 0x2E11
  Length: 52
  Referenced LSA Type: 2001
  Referenced Link State ID: 0
  Referenced Advertising Router: 7.7.7.7
  Number of Prefixes: 1
  Prefix Address: 2001:DB8::7:7:7:7
  Prefix Length: 128, Options: LA, Metric: 0

R7 is not showing it’s connected to the 2001:db8:13::/64 subnet.

Responsibility for advertising that Type9 lies with the DR. The interesting part is that the DR actually originates two separate Type9s:

R3#show ospfv3 database prefix self-originate

          OSPFv3 1 address-family ipv6 (router-id 3.3.3.3)

		Intra Area Prefix Link States (Area 0)

  Routing Bit Set on this LSA
  LS age: 876
  LS Type: Intra-Area-Prefix-LSA
  Link State ID: 0
  Advertising Router: 3.3.3.3
  LS Seq Number: 80000004
  Checksum: 0xE984
  Length: 52
  Referenced LSA Type: 2001
  Referenced Link State ID: 0
  Referenced Advertising Router: 3.3.3.3
  Number of Prefixes: 1
  Prefix Address: 2001:DB8::3:3:3:3
  Prefix Length: 128, Options: LA, Metric: 0

  Routing Bit Set on this LSA
  LS age: 1150
  LS Type: Intra-Area-Prefix-LSA
  Link State ID: 2048
  Advertising Router: 3.3.3.3
  LS Seq Number: 80000001
  Checksum: 0x1297
  Length: 44
  Referenced LSA Type: 2002
  Referenced Link State ID: 2
  Referenced Advertising Router: 3.3.3.3
  Number of Prefixes: 1
  Prefix Address: 2001:DB8:13::
  Prefix Length: 64, Options: None, Metric: 0

There is an important detail to note. The Type9 originated for the segment has a reference LSA Type value of 2002 while a regular Type9 has a value of 2001. The 2002 value tells you that the LSA was originated by the DR for the segment.

Ultimately this means that a DR will originate two separate LSAs for each broadcast segment. The second LSA being the link state Type2:

R3#show ospfv3 database network self-originate

          OSPFv3 1 address-family ipv6 (router-id 3.3.3.3)

		Net Link States (Area 0)

  LS age: 1524
  Options: (V6-Bit, E-Bit, R-bit, DC-Bit)
  LS Type: Network Links
  Link State ID: 2 (Interface ID of Designated Router)
  Advertising Router: 3.3.3.3
  LS Seq Number: 80000002
  Checksum: 0xF0D8
  Length: 36
	Attached Router: 3.3.3.3
	Attached Router: 1.1.1.1
	Attached Router: 7.7.7.7

In part 3 I’ll be going over inter-area LSAs

Demystifying the OSPFv3 database – Part 1

Two years ago I published a post demystifying the OSPF database. I thought I’d do the same with OSPFv3 and the LSA types are fundamentally different. OSPFv3 is not simply OSPF for IPV6. OSPFv3 can also be used for IPv4 and has the capability to be extended.

In order to go through the LSA types, I’m going to be building a network as we go along and viewing the database. One thing to note is that since OSPFv3 has been extended on IOS, you can either use ipv6 ospf or simply ospfv3 in your configuration and show commands. I’m going to be using the ospfv3 version.

LSA Types

Let’s start with the following basic topology:
OSPFv3 1 Demystifying the OSPFv3 database   Part 1

I’ll be running this ethernet link in point-to-point mode. I’ll also have an IPv6 adress on each loopback in OSPFv3.

R2(config)#interface Loopback0
R2(config-if)#ipv6 address 2001:DB8::2:2:2:2/128
R2(config-if)#ipv6 ospf 1 area 0
R2(config-if)#int fa0/0
R2(config-if)#ipv6 address 2001:DB8:12:0:10:1:2:2/64
R2(config-if)#ipv6 ospf 1 area 0
R2(config-if)#ipv6 ospf network point-to-point
*Jul 29 16:04:26.915: %OSPFv3-4-NORTRID: Process OSPFv3-1-IPv6 could not pick a router-id, please configure manually

OSPFv3 still needs a 32bit router-id. Usually IOS will take the highest IPv4 loopback address as the 32bit number. I have no IPv4 configured on this router and hence will need to hard-code this value. Remember this is a 32bit number in dotted decimal format. It is not an IPv4 address in itself.

First, let’s confirm our adjacency is up:

R2#show ospfv3 neighbor

          OSPFv3 1 address-family ipv6 (router-id 2.2.2.2)

Neighbor ID     Pri   State           Dead Time   Interface ID    Interface
1.1.1.1           0   FULL/  -        00:00:39    2               FastEthernet0/0

The neighbour ID is the 32bit router-id on the other side. OSPFv3 uses IPv6 link-local addresses to form the adjacency:

R2#show ospfv3 neighbor detail

          OSPFv3 1 address-family ipv6 (router-id 2.2.2.2)

 Neighbor 1.1.1.1
    In the area 0 via interface FastEthernet0/0
    Neighbor: interface-id 2, link-local address FE80::C800:6FFF:FE16:8
    Neighbor priority is 0, State is FULL, 6 state changes
    Options is 0x000013 in Hello (V6-Bit, E-Bit, R-bit)
    Options is 0x000013 in DBD (V6-Bit, E-Bit, R-bit)
    Dead timer due in 00:00:38
    Neighbor is up for 00:27:24
    Index 1/1/1, retransmission queue length 0, number of retransmission 0
    First 0x0(0)/0x0(0)/0x0(0) Next 0x0(0)/0x0(0)/0x0(0)
    Last retransmission scan length is 0, maximum is 0
    Last retransmission scan time is 0 msec, maximum is 0 msec

Let’s take a quick look at the database. In OSPFv2 I would expect to see 2 Type1 LSAs only. What does OSPFv3 give us?:

R1#show ospfv3 database

          OSPFv3 1 address-family ipv6 (router-id 1.1.1.1)

		Router Link States (Area 0)

ADV Router       Age         Seq#        Fragment ID  Link count  Bits
 1.1.1.1         12          0x80000007  0            1           None
 2.2.2.2         18          0x8000000B  0            1           None

		Link (Type-8) Link States (Area 0)

ADV Router       Age         Seq#        Link ID    Interface
 1.1.1.1         13          0x80000005  2          Fa0/0
 2.2.2.2         18          0x80000004  2          Fa0/0

		Intra Area Prefix Link States (Area 0)

ADV Router       Age         Seq#        Link ID    Ref-lstype  Ref-LSID
 1.1.1.1         12          0x8000000B  0          0x2001      0
 2.2.2.2         18          0x80000007  0          0x2001      0

A lot more than just two Type1s! There are still Type1 LSAs, but also Type8 and Type9s. In OSPFv2, the Type1 LSA would be originated by each router in the area and would contain it’s router-id, links, and IPs associated with those links. OSPFv3 removes the IP addressing from the Type1 as it’s now there to show the router-id and links it’s connected to:

R1#show ospfv3 database router adv-router 1.1.1.1

          OSPFv3 1 address-family ipv6 (router-id 1.1.1.1)

		Router Link States (Area 0)

  LS age: 87
  Options: (V6-Bit, E-Bit, R-bit, DC-Bit)
  LS Type: Router Links
  Link State ID: 0
  Advertising Router: 1.1.1.1
  LS Seq Number: 80000007
  Checksum: 0xDA0F
  Length: 40
  Number of Links: 1

    Link connected to: another Router (point-to-point)
      Link Metric: 1
      Local Interface ID: 2
      Neighbor Interface ID: 2
      Neighbor Router ID: 2.2.2.2

Remember 2.2.2.2 is simply the neighbours router-id. Note that this LSA does not contain the p2p IPv6 address, nor the loopback address. It’s simply a link topology LSA.
Type8 LSAs have link flooding scope, something you simply do not see in OSPFv2. I’ll get back to this one once we hadd another router into the area as it’ll make more sense then.

The IP addressing information in this topology is contained in the Type9 LSA. The intra-area prefix LSA:

R1#show ospfv3 database prefix adv-router 1.1.1.1

          OSPFv3 1 address-family ipv6 (router-id 1.1.1.1)

		Intra Area Prefix Link States (Area 0)

  Routing Bit Set on this LSA
  LS age: 454
  LS Type: Intra-Area-Prefix-LSA
  Link State ID: 0
  Advertising Router: 1.1.1.1
  LS Seq Number: 80000026
  Checksum: 0x1DFF
  Length: 64
  Referenced LSA Type: 2001
  Referenced Link State ID: 0
  Referenced Advertising Router: 1.1.1.1
  Number of Prefixes: 2
  Prefix Address: 2001:DB8::1:1:1:1
  Prefix Length: 128, Options: LA, Metric: 0
  Prefix Address: 2001:DB8:12::
  Prefix Length: 64, Options: None, Metric: 1

Here we see the two prefixes originated. Also notice the LSA can contain more than one prefix at a time. Much like a Type1 LSA.

I’ll now add a third router to the topology. This will also be in Area 0
OSPFv3 21 Demystifying the OSPFv3 database   Part 1

Let’s go back to the Type8 LSA we delayed earlier. In OSPFv2 all routers in an area need to have identical databases. In OSPFv3 this is not the case as each router will have different link LSAs. This LSA has link-only flooding scope and so is never flooded past the link in question. If we look at the Type8s from R3′s perspective:

R3#show ospfv3 database link

          OSPFv3 1 address-family ipv6 (router-id 3.3.3.3)

		Link (Type-8) Link States (Area 0)

  LS age: 847
  Options: (V6-Bit, E-Bit, R-bit, DC-Bit)
  LS Type: Link-LSA (Interface: FastEthernet0/0)
  Link State ID: 3 (Interface ID)
  Advertising Router: 1.1.1.1
  LS Seq Number: 80000002
  Checksum: 0x9063
  Length: 56
  Router Priority: 1
  Link Local Address: FE80::C800:6FFF:FE16:6
  Number of Prefixes: 1
  Prefix Address: 2001:DB8:13::
  Prefix Length: 64, Options: None

  LS age: 772
  Options: (V6-Bit, E-Bit, R-bit, DC-Bit)
  LS Type: Link-LSA (Interface: FastEthernet0/0)
  Link State ID: 2 (Interface ID)
  Advertising Router: 3.3.3.3
  LS Seq Number: 80000001
  Checksum: 0xAC3D
  Length: 56
  Router Priority: 1
  Link Local Address: FE80::C802:6FFF:FE16:8
  Number of Prefixes: 1
  Prefix Address: 2001:DB8:13::
  Prefix Length: 64, Options: None

R3 has two LSAs. One originated by R1 and the other by R3. It contains the link local address of each side plus the prefixes assigned to that interface itself. R1, in the same area, will have a different view as it has neighbours on two different links:

R1#show ospfv3 database | begin Type-8
		Link (Type-8) Link States (Area 0)

ADV Router       Age         Seq#        Link ID    Interface
 1.1.1.1         81          0x80000003  3          Fa0/1
 3.3.3.3         1110        0x80000001  2          Fa0/1
 1.1.1.1         1967        0x80000020  2          Fa0/0
 2.2.2.2         164         0x80000020  2          Fa0/0

I’ll now add a new router in the area, and connect it to the same segment that R1 and R3 is connected to. I’ll change the network type back to broadcast for this link:
OSPFv3 3 Demystifying the OSPFv3 database   Part 1
On a broadcast link, the DR will originate a Type2 LSA. This is one of the few LSAs that is near identical to it’s OSPFv2 counterpart. This LSA still has area flooding scope and hence R2 will also be able to see it:

R2#show ospfv3 database network

          OSPFv3 1 address-family ipv6 (router-id 2.2.2.2)

		Net Link States (Area 0)

  LS age: 368
  Options: (V6-Bit, E-Bit, R-bit, DC-Bit)
  LS Type: Network Links
  Link State ID: 2 (Interface ID of Designated Router)
  Advertising Router: 3.3.3.3
  LS Seq Number: 80000002
  Checksum: 0xF0D8
  Length: 36
	Attached Router: 3.3.3.3
	Attached Router: 1.1.1.1
	Attached Router: 7.7.7.7

R3 is the DR for the segment, and the LSA contains the router-ids of all three routers connected to that segment. Each of those three routers will still only originate a single Type8 on that link. So I would expect to see three Type8s on that link from R7′s perspective:

R7#show ospfv3 database | begin Type-8
		Link (Type-8) Link States (Area 0)

ADV Router       Age         Seq#        Link ID    Interface
 1.1.1.1         718         0x80000004  3          Fa0/0
 3.3.3.3         1922        0x80000001  2          Fa0/0
 7.7.7.7         505         0x80000001  2          Fa0/0

Recalculation

It’s clear from above that OSPFv3 separates IP address information from the topology LSAs. This is important for a number of reasons. In OSPFv2, if a router originated a new Type1 or Type2 LSA, it would cause all routers in the area to run SPF. If I changed the IP address of any OSPF link, that would cause SPF to run. If I added a secondary address to an OSPF link, SPF would run. In OSPFv3 the adding or changing of addresses does not cause the router to originate a new Type1. This means that addresses being changed will not cause SPF to run.

Take a look at R7′s current excecution count:

R7#show ospfv3 statistic | include algorithm
  Area 0: SPF algorithm executed 2 times

On R1 I’ll add an address to the loopback interface. This would cause SPF to run in OSPFv2:

R1(config)#int lo0
R1(config-if)#ipv6 address 2001:db8::11:11:11:11/128

What does R7 see?

R7#show ospfv3 statistic | include algorithm
  Area 0: SPF algorithm executed 2 times

No increase.

Let’s dig a little deeper in the LSAs to see what’s happened. The Type1 LSA originated by R1:

R7#show ospfv3 database router adv-router 1.1.1.1

          OSPFv3 1 address-family ipv6 (router-id 7.7.7.7)

		Router Link States (Area 0)

  LS age: 1160
  Options: (V6-Bit, E-Bit, R-bit, DC-Bit)
  LS Type: Router Links
  Link State ID: 0
  Advertising Router: 1.1.1.1
  LS Seq Number: 80000028
  Checksum: 0xF6AD
  Length: 56
  Number of Links: 2

    Link connected to: a Transit Network
      Link Metric: 1
      Local Interface ID: 3
      Neighbor (DR) Interface ID: 2
      Neighbor (DR) Router ID: 3.3.3.3

    Link connected to: another Router (point-to-point)
      Link Metric: 1
      Local Interface ID: 2
      Neighbor Interface ID: 2
      Neighbor Router ID: 2.2.2.2

The LSA age is 1160 seconds, even though I just added a new IPv6 address. i.e. no new Type1. If we look at the Type9 LSA from R1:

R7#show ospfv3 database prefix adv-router 1.1.1.1

          OSPFv3 1 address-family ipv6 (router-id 7.7.7.7)

		Intra Area Prefix Link States (Area 0)

  Routing Bit Set on this LSA
  LS age: 146
  LS Type: Intra-Area-Prefix-LSA
  Link State ID: 0
  Advertising Router: 1.1.1.1
  LS Seq Number: 8000002D
  Checksum: 0xADA5
  Length: 84
  Referenced LSA Type: 2001
  Referenced Link State ID: 0
  Referenced Advertising Router: 1.1.1.1
  Number of Prefixes: 3
  Prefix Address: 2001:DB8::1:1:1:1
  Prefix Length: 128, Options: LA, Metric: 0
  Prefix Address: 2001:DB8::11:11:11:11
  Prefix Length: 128, Options: LA, Metric: 0
  Prefix Address: 2001:DB8:12::
  Prefix Length: 64, Options: None, Metric: 1

There’s the new prefix we added. LSA age is lower so this is a new one. R7 already has the existing Type1 LSA so it knows about router-id 1.1.1.1 – It can therefore now work out the route to the new prefix with this Type9 LSA. It does not need to run SPF again as it has already run SPF on that Type1. R7 therefore has an intra-area route to that prefix:

R7#show ipv6 route 2001:db8::11:11:11:11
Routing entry for 2001:DB8::11:11:11:11/128
  Known via "ospf 1", distance 110, metric 1, type intra area
  Route count is 1/1, share count 0
  Routing paths:
    FE80::C800:6FFF:FE16:6, FastEthernet0/0
      Last updated 00:05:52 ago

SPF Delay – CCDE

SPF timers are usually one of those things that engineers don’t bother with. Hello/Dead timers are often adjusted, but not actual SPF timers themselves.

Different vendors, and even different platforms within vendors, can have dramatically different timers. Micro-loops can be even more pronounced when different vendors/platforms are involved.

SPF Timers

In OSPF, SPF is only run when certain conditions are met. One of those conditions is when a router originates a new type-1 LSA. If a router interface goes down, it will originate a new type-1 to let other routers in the area know about it. How soon after the interface goes down does the type-1 get sent? Once another router in the area receives that type-1, does it run SPF straight away? Does it flood the LSA before or after it runs SPF?
Micro-loops form when router’s FIBs do not agree on where the best path is. Two routers will bounce a packet backwards and forwards to each other until those routers agree on the forwarding path and have that path installed in their FIB.

The best way to understand this is to show the loop forming.

Let’s consider the following topology of five routers. The OSPF costs of each link is also displayed:
SPF Timers SPF Delay   CCDE

Most router interfaces have a cost of 50, while R3 has a second slower link with a cost of 200.

Under normal circumstances, any traffic from R1 to R5 with go through R2-R4.
SPF Timers2 SPF Delay   CCDE

R1#traceroute 10.0.0.5
Type escape sequence to abort.
Tracing the route to 10.0.0.5
VRF info: (vrf in name/id, vrf out name/id)
  1 192.168.12.2 12 msec 32 msec 16 msec
  2 192.168.24.4 44 msec 56 msec 16 msec
  3 192.168.45.5 68 msec 48 msec 48 msec

When the link between R2 and R4 fails, traffic should traverse the R2-R3-R4 links:
SPF Timers3 SPF Delay   CCDE
There are a number of milliseconds where this will not be the case.

In order to show how a micro-loop is formed, I’ll first need to artificially increase my SPF timers. This is because it’s very difficult to show an actual micro-loop simply with traceroute.
On R3 I’ll increase the wait time to run SPF after it receives an LSA to 10 seconds:

R3(config)#router ospf 1
R3(config-router)# timers throttle spf 10000 10000 10000

I’ll now break the link between R2 and R4 and run another traceroute from R1 to R5:

R2(config)#int gi2/0
R2(config-if)#shut
R1#traceroute 10.0.0.5
Type escape sequence to abort.
Tracing the route to 10.0.0.5
VRF info: (vrf in name/id, vrf out name/id)
  1 192.168.12.2 16 msec 16 msec 12 msec
  2  *  *
    192.168.23.3 36 msec
  3 192.168.23.2 40 msec 36 msec 68 msec
  4 192.168.23.3 44 msec 60 msec 60 msec
  5 192.168.23.2 56 msec 64 msec 60 msec
  6 192.168.23.3 100 msec 80 msec 80 msec
  7 192.168.23.2 80 msec 80 msec 84 msec
  8 192.168.23.3 80 msec 104 msec 104 msec
  9 192.168.23.2 100 msec 104 msec 100 msec
 10 192.168.23.3 128 msec 124 msec 124 msec
 11 192.168.23.2 132 msec 116 msec 124 msec
 12 192.168.23.3 152 msec 148 msec 148 msec
 13 192.168.23.2 144 msec 144 msec 148 msec
 14 192.168.23.3 152 msec
    192.168.45.5 112 msec 84 msec

Because R3 is delaying it’s SPF run until 10 seconds after it receives a relevant LSA, it still assumes the best path is through R2. R2 has run it’s SPF and it assumes the best path is through R3. This is the reason the packet bounces between both routers. The packet get to it’s destination only when R3 has run SPF and CEF updated.

Of course in the real world we don’t wait 10 seconds. But what are the actual timers? That depends a lot on which vendor and platform you’re running:

Vendor OS Initial SPF Delay (ms)
Cisco IOS & IOS-XE 5000
Cisco IOS-XR 50
Cisco NX-OS 200
Juniper Junos 200

The above list is of course not exhaustive.

The timers between vendors and platforms can be dramatically different. Even in an environment in when you are not cared about rapid convergence, it’s still important that your IGP routers all agree on their timers. Connecting an ASR1k to an ASR9k with default timers could cause traffic to loop for almost five seconds if left to the defaults. I would suggest you ensure all OSPF routers in an area, or all IS-IS routers in the same level, have identical timers.

Another option is to ensure the initial SPF delay run timer is set high enough so that LSA/LSP reaches all edges of the area/level. That way all router can run SPF at the same time and update their FIBs at the same time. The problem with this approach is that each router receives the LSA at different times. Even if they did receive them at exactly the same time, we are relying on the fact that all routers have 100% identical SPF and FIB-Update run times.

Further Reading

RFC 5715 – A Framework for Loop-Free Convergence
RFC 6976 – Framework for Loop-Free Convergence Using the Ordered Forwarding Information Base (oFIB) Approach

Splitting a module from a python app

My OSPF checker is getting a bit big. The majority of the code is the function that parses the OSPF output and returns the required values.

I’d like to continue to refine what it can pull out. I’d also like to check non-IOS devices like Junos and IOS-XR output.

A function can very easily be moved into a new file and then called as a module. The great thing about this is that others can use the same module in different applications of their own. I can also create a separate module per OS that I’m interested in. Each can be edited separately.

The IOS OSPF checker has now been split into it’s own module like so:

import re
import sys

def ospf_information(i):
    int_list = {}
    ospf = re.split(r'[\n](?=GigabitEthernet|FastEthernet|Serial|Tunnel|Loopback|Dialer|BVI|Vlan|Virtual-Access)',i)
    print(ospf)
    for o in ospf:
        properties = {}
        interface =  re.search(r'(GigabitEthernet|FastEthernet|Serial|Tunnel|Loopback|Dialer|BVI|Vlan|Virtual-Access)[0-9]{1,4}/?[0-9]{0,4}.
?[0-9]{0,4}/?[0-9]{0,3}/?[0-9]{0,3}/?[0-9]{0,3}:?[0-9]{0,3}',o)
        if not interface:
            continue
        interface = interface.group()
        ip = re.search(r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/\d{1,2})',o)
        if not ip:
            ip = re.search(r'Interface is unnumbered. Using address of [a-zA-Z]{1,10}[0-9]{1,5}/?[0-9]{0,5}.?[0-9]{0,5}',o)
            properties['IP'] = ip.group()
        else:
            properties['IP'] = ip.group()
        a = re.search(r'Area ([\s]{0,3}[0-9]{1,5})',o)
        properties['Area'] = a.group(1)
        n = re.search(r'Network Type ([\s]{0,3}[a-zA-Z_]{0,20})',o)
        properties['Net'] = n.group(1)
        c = re.search(r'Cost: ([0-9]{1,5})',o)
        properties['Cost'] = c.group(1)
        s = re.search(r'line protocol is[\s]([a-zA-Z]{1,4})',o)
        properties['Status'] = s.group(1)
        p = re.search(r'Passive',o)
        if p:
            properties['Neigh'] = "Passive Interface"
            properties['Adj'] = None
        else:
            ne = re.search(r'(?:Neighbor Count is )([0-9]{1,3})',o)
            if not ne:
                properties['Neigh'] = None
            else:
                properties['Neigh'] = ne.group(1)
            ad = re.search(r'(?:Adjacent neighbor count is )([0-9]{1,3})',o)
            if not ad:
                properties['Adj'] = None
            else:
                properties['Adj'] = ad.group(1)
        h = re.search(r'Hello ([0-9]{1,3})',o)
        if not h:
            properties['Hello'] = None
        else:
            properties['Hello'] = h.group(1)
        d = re.search(r'Dead ([0-9]{1,3})',o)
        if not d:
            properties['Dead'] = None
        else:
            properties['Dead'] = d.group(1)
        int_list[interface]=properties
    return int_list

if __name__ == "__main__":
    f = open(sys.argv[1])
    info = f.read()
    f.close()
    ospf = ospf_information(info)
    print("This device contains "+str(len(ospf))+" ospf enabled interfaces")
    print(ospf)

A couple of things to note here. The module now returns a dictionary. This allows any app using this module to easily extract whatever values it chooses instead of iterating through a list. The last section of code allows me to run the module directly against some raw router output directly to pull information out. This part is not run if calling as a module.

In my main application I now simply import the module and change how I call it slightly:

import ospfios
 ospf_int = ospfios.ospf_information(output)

I’ve started a preliminary Junos OSPF module which will return similar values:

import re
import sys

def ospf_information(i):
    int_list = {}
    ospf = re.split(r'[\n](?=ge|fe|lo|ae|et|fxp)',i)
    for o in ospf:
        properties = {}
        interface =  re.search(r'(ge|fe|lo|ae|et|fxp)([0-9]?)([-]?){0,1}[0-9]{1,5}/?[0-9]{0,5}/?[0-9]{0,5}/?[0-9]?[.][0-9]{1,5}',o)
        if not interface:
            continue
        interface = interface.group()
        ip = re.search(r'Address: (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})',o)
        properties['IP'] = ip.group(1)
        c = re.search(r'Cost: ([0-9]{1,5})',o)
        properties['Cost'] = c.group(1)
        ad = re.search(r'(?:Adj count: )([0-9]{1,3})',o)
        properties['Adj'] = ad.group(1)
        h = re.search(r'Hello: ([0-9]{1,3})',o)
        properties['Hello'] = h.group(1)
        d = re.search(r'Dead: ([0-9]{1,3})',o)
        properties['Dead'] = d.group(1)
        int_list[interface]=properties
    return int_list

if __name__ == "__main__":
    f = open(sys.argv[1])
    info = f.read()
    f.close()
    ospf = ospf_information(info)
    print("This device contains "+str(len(ospf))+" ospf enabled interfaces")
    print(ospf)

A quick run directly on a small Junos box:

darreno@Jumpbox:~/git/ospf_checker$ python3 ospfjunos.py junos.txt
This device contains 4 ospf enabled interfaces
{'ge-1/3/0.641': {'IP': '10.11.31.227', 'Cost': '10', 'Adj': '1', 'Hello': '10', 'Dead': '40'}, 'lo0.0': {'IP': '10.11.225.224', 'Cost': '0', 'Adj': '0', 'Hello': '10', 'Dead': '40'}, 'ge-0/0/0.643': {'IP': '10.11.31.90', 'Cost': '10', 'Adj': '1', 'Hello': '10', 'Dead': '40'}, 'ge-0/2/0.644': {'IP': '10.11.31.94', 'Cost': '10', 'Adj': '1', 'Hello': '10', 'Dead': '40'}}