Hello,
OSPFv2 is right to treat a Network LSA as self-originated when its Link State ID is one of our interface addresses, even if another router advertised it (RFC 2328 13.4). The next step is wrong. If this router is not originating that LSA, it should be flushed at MaxAge. Instead, when a copy younger than MaxAge is already in the local LSDB, BIRD refreshes it and leaves the other router's ID in the Advertising Router field. The two routers then exchange that same LSA continuously, one at age 0 and the other at age 3600.
This is in proto/ospf/lsupd.c, in ospf_receive_lsupd(), at the 13.(5f) / 13.4 check, and in ospf_advance_lsa() in proto/ospf/topology.c. It is present in BIRD 2.0.8. The same check is still in current master as of 29 Sep 2026. This is not a security issue.
The receive check is:
lsa.rt == router_id OR (OSPFv2 AND type is Network AND ospf_addr_is_local())
ospf_addr_is_local() walks every OSPF interface in the area and compares the Link State ID with the interface address. A match calls ospf_advance_lsa().
That function has two branches. If the local copy exists and its age is still under MaxAge, it does only this:
sequence = received sequence + 1 age = 0
It does not change the Advertising Router. It then floods that copy. The log line is printed only in this branch:
Advancing LSA: Type: 2002, Id: 10.0.0.1, Rt: 192.0.2.1, Seq: 80000002
If there is no local copy, or the local copy is already MaxAge, the same function installs the received LSA at MaxAge and floods that. That second branch is the flush. The loop needs the first branch, so it needs a young copy to still be present.
How the two routers keep it going
Call the router named on the LSA R1 (192.0.2.1). Call the router that now has the address R2 (192.0.2.2). The Link State ID is 10.0.0.1.
  1. R1 no longer has 10.0.0.1. The LSA still carries R1's router id, so R1 takes the self-originated path. Its copy is MaxAge, so it floods age 3600.
  2. R2 still has 10.0.0.1, so it also takes the self-originated path. Its copy is younger than MaxAge, so it sets age 0 and sequence plus 1, leaves the Advertising Router as 192.0.2.1, and floods that.
  3. R1 receives a newer copy that still carries its own router id. Its local copy is MaxAge, so it floods age 3600 again.
Each pass is limited by MinLSArrival. A normal Network LSA refresh is 1800 seconds. SPF runs on every pass.
How to reproduce
Two routers, one OSPFv2 area, broadcast interfaces. No customer network is involved. These addresses are only an example.
R1 router id 192.0.2.1 R2 router id 192.0.2.2 A broadcast link on which R1 is DR, interface address 10.0.0.1/30 R1 has a full neighbor, so it originates: type 2002, id 10.0.0.1, advertising router 192.0.2.1
While that LSA is still in R2's LSDB and its age is under 3600:
  1. Configure 10.0.0.1/30 on R2, on an OSPF interface in the same area.
  2. After that, delete 10.0.0.1/30 from R1.
R2 must already hold a copy younger than MaxAge at step 2. That is the copy it will advance.
When this will not show up
The flush sticks if the address is deleted on R1 first, and R2 is given 10.0.0.1 only after that Network LSA is age 3600 or gone from R2. There is then no young copy to advance.
Deleting 10.0.0.1/30 on R1 and configuring the same address back on R1 does not start the loop. A point-to-point link does not originate a Network LSA, so it does not hit this either.
Suggested fix
For a Network LSA whose Advertising Router is not the local router id, use the flush that ospf_advance_lsa() already uses when the local copy is missing or MaxAge. Do that even if a young copy exists. A Network LSA this router really originated (lsa.rt == router_id) should still advance as it does today.
Against current master, inside the existing self-originated block:
OSPF_TRACE(D_EVENTS, "Received unexpected self-originated LSA"); if ((lsa_type == LSA_T_NET) && (lsa.rt != p->router_id)) { lsa.age = LSA_MAXAGE; en = ospf_install_lsa(p, &lsa, lsa_type, lsa_domain, body); ospf_flood_lsa(p, en, NULL); continue; } ospf_advance_lsa(p, en, &lsa, lsa_type, lsa_domain, body); continue;
I can send this as a patch against master if that is useful.
Thanks,
Shariq Faran