diff options
author | Ondrej Zajicek <santiago@crfreenet.org> | 2024-04-04 18:37:26 +0200 |
---|---|---|
committer | Ondrej Zajicek <santiago@crfreenet.org> | 2024-04-04 18:37:26 +0200 |
commit | 280daed57d061eb1ebc89013637c683fe23465e8 (patch) | |
tree | 91b4a338b2d3a986ee2ceddb48558c98a0cfc679 | |
parent | bc10975adbb0aef772496f334dd0bbd23251c1d8 (diff) |
OSPF: Allow loopback nexthop in OSPFv3-IPv4
In OSPFv3-IPv4 there is no requirement that link-local next hop announced
in Link-LSA must be in interface address range. Therefore, for interfaces
that do not have IPv4 address we can use some loopback IP address and
announce it as a next hop. Also we should accept such address.
-rw-r--r-- | nest/neighbor.c | 3 | ||||
-rw-r--r-- | proto/ospf/ospf.h | 2 | ||||
-rw-r--r-- | proto/ospf/rt.c | 8 | ||||
-rw-r--r-- | proto/ospf/topology.c | 51 |
4 files changed, 63 insertions, 1 deletions
diff --git a/nest/neighbor.c b/nest/neighbor.c index 2c2d3adf..63c07f83 100644 --- a/nest/neighbor.c +++ b/nest/neighbor.c @@ -217,7 +217,8 @@ neigh_find(struct proto *p, ip_addr a, struct iface *iface, uint flags) struct ifa *addr = NULL; WALK_LIST(n, neigh_hash_table[h]) /* Search the cache */ - if ((n->proto == p) && ipa_equal(n->addr, a) && (n->ifreq == iface)) + if ((n->proto == p) && ipa_equal(n->addr, a) && (n->ifreq == iface) && + ((n->flags & NEF_ONLINK) == (flags & NEF_ONLINK))) return n; if (flags & NEF_IFACE) diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index 3e704ae8..4949f173 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -252,6 +252,7 @@ struct ospf_proto u32 last_vlink_id; /* Interface IDs for vlinks (starts at 0x80000000) */ struct tbf log_pkt_tbf; /* TBF for packet messages */ struct tbf log_lsa_tbf; /* TBF for LSA messages */ + ip_addr loopback_addr; /* IP address used as common next hop (in OSPFv3-IPv4) */ }; struct ospf_area @@ -331,6 +332,7 @@ struct ospf_iface struct top_hash_entry **flood_queue; /* LSAs queued for LSUPD */ u8 update_link_lsa; u8 update_net_lsa; + u8 loopback_addr_used; /* The Link-LSA depends on p->loopback_addr */ u16 flood_queue_used; /* The current number of LSAs in flood_queue */ u16 flood_queue_size; /* The maximum number of LSAs in flood_queue */ int fadj; /* Number of fully adjacent neighbors */ diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index 471bb586..d7753ce0 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -2038,6 +2038,14 @@ again1: { neighbor *nbr = neigh_find(&p->p, nh->gw, nh->iface, (nh->flags & RNF_ONLINK) ? NEF_ONLINK : 0); + + /* According to RFC 5838 2.5 Direct Interface Address */ + if (ospf_is_v3(p) && !nbr && ipa_is_ip4(nh->gw)) + { + nh->flags |= RNF_ONLINK; + nbr = neigh_find(&p->p, nh->gw, nh->iface, NEF_ONLINK); + } + if (!nbr || (nbr->scope == SCOPE_HOST)) { reset_ri(nf); break; } } diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index 9fe68264..78022423 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -1402,6 +1402,46 @@ lsab_put_prefix(struct ospf_proto *p, net_addr *n, u32 cost) ospf3_put_prefix(buf, n, flags, cost); } +static inline void +update_loopback_addr(struct ospf_proto *p) +{ + ip_addr old_addr = p->loopback_addr; + ip_addr best_addr = IPA_NONE; + int best_pref = 0; + + struct ospf_iface *ifa; + WALK_LIST(ifa, p->iface_list) + { + if (ifa->type == OSPF_IT_VLINK) + continue; + + struct ifa *a; + WALK_LIST(a, ifa->iface->addrs) + { + if ((a->prefix.type != ospf_get_af(p)) || + (a->flags & IA_SECONDARY) || + (a->scope <= SCOPE_LINK)) + continue; + + int pref = (a->flags & IA_HOST) ? 3 : (ifa->stub ? 2 : 1); + if ((pref > best_pref) || ((pref == best_pref) && ipa_equal(a->ip, old_addr))) + { + best_addr = a->ip; + best_pref = pref; + } + } + } + + if (ipa_equal(best_addr, old_addr)) + return; + + p->loopback_addr = best_addr; + + WALK_LIST(ifa, p->iface_list) + if (ifa->loopback_addr_used) + ospf_notify_link_lsa(ifa); +} + static void prepare_link_lsa_body(struct ospf_proto *p, struct ospf_iface *ifa) { @@ -1427,6 +1467,12 @@ prepare_link_lsa_body(struct ospf_proto *p, struct ospf_iface *ifa) i++; } + if (ospf_is_ip4(p) && ipa_zero(nh)) + { + nh = p->loopback_addr; + ifa->loopback_addr_used = 1; + } + /* Filling the preallocated header */ struct ospf_lsa_link *ll = p->lsab; ll->options = ifa->oa->options | (ifa->priority << 24); @@ -1853,6 +1899,9 @@ ospf_update_topology(struct ospf_proto *p) } } + if (ospf_is_v3(p) && ospf_is_ip4(p)) + update_loopback_addr(p); + WALK_LIST(ifa, p->iface_list) { if (ifa->type == OSPF_IT_VLINK) @@ -1860,6 +1909,8 @@ ospf_update_topology(struct ospf_proto *p) if (ifa->update_link_lsa) { + ifa->loopback_addr_used = 0; + if ((ifa->state > OSPF_IS_LOOP) && !ifa->link_lsa_suppression) ospf_originate_link_lsa(p, ifa); else |