0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-22 17:51:53 +00:00

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.
This commit is contained in:
Ondrej Zajicek 2024-04-04 18:37:26 +02:00
parent bc10975adb
commit 280daed57d
4 changed files with 63 additions and 1 deletions

View File

@ -217,7 +217,8 @@ neigh_find(struct proto *p, ip_addr a, struct iface *iface, uint flags)
struct ifa *addr = NULL; struct ifa *addr = NULL;
WALK_LIST(n, neigh_hash_table[h]) /* Search the cache */ 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; return n;
if (flags & NEF_IFACE) if (flags & NEF_IFACE)

View File

@ -252,6 +252,7 @@ struct ospf_proto
u32 last_vlink_id; /* Interface IDs for vlinks (starts at 0x80000000) */ u32 last_vlink_id; /* Interface IDs for vlinks (starts at 0x80000000) */
struct tbf log_pkt_tbf; /* TBF for packet messages */ struct tbf log_pkt_tbf; /* TBF for packet messages */
struct tbf log_lsa_tbf; /* TBF for LSA 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 struct ospf_area
@ -331,6 +332,7 @@ struct ospf_iface
struct top_hash_entry **flood_queue; /* LSAs queued for LSUPD */ struct top_hash_entry **flood_queue; /* LSAs queued for LSUPD */
u8 update_link_lsa; u8 update_link_lsa;
u8 update_net_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_used; /* The current number of LSAs in flood_queue */
u16 flood_queue_size; /* The maximum 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 */ int fadj; /* Number of fully adjacent neighbors */

View File

@ -2038,6 +2038,14 @@ again1:
{ {
neighbor *nbr = neigh_find(&p->p, nh->gw, nh->iface, neighbor *nbr = neigh_find(&p->p, nh->gw, nh->iface,
(nh->flags & RNF_ONLINK) ? NEF_ONLINK : 0); (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)) if (!nbr || (nbr->scope == SCOPE_HOST))
{ reset_ri(nf); break; } { reset_ri(nf); break; }
} }

View File

@ -1402,6 +1402,46 @@ lsab_put_prefix(struct ospf_proto *p, net_addr *n, u32 cost)
ospf3_put_prefix(buf, n, flags, 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 static void
prepare_link_lsa_body(struct ospf_proto *p, struct ospf_iface *ifa) 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++; i++;
} }
if (ospf_is_ip4(p) && ipa_zero(nh))
{
nh = p->loopback_addr;
ifa->loopback_addr_used = 1;
}
/* Filling the preallocated header */ /* Filling the preallocated header */
struct ospf_lsa_link *ll = p->lsab; struct ospf_lsa_link *ll = p->lsab;
ll->options = ifa->oa->options | (ifa->priority << 24); 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) WALK_LIST(ifa, p->iface_list)
{ {
if (ifa->type == OSPF_IT_VLINK) if (ifa->type == OSPF_IT_VLINK)
@ -1860,6 +1909,8 @@ ospf_update_topology(struct ospf_proto *p)
if (ifa->update_link_lsa) if (ifa->update_link_lsa)
{ {
ifa->loopback_addr_used = 0;
if ((ifa->state > OSPF_IS_LOOP) && !ifa->link_lsa_suppression) if ((ifa->state > OSPF_IS_LOOP) && !ifa->link_lsa_suppression)
ospf_originate_link_lsa(p, ifa); ospf_originate_link_lsa(p, ifa);
else else