From 2a0af925b83f699d126cf0e733a49c75ffd86033 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Mon, 10 May 2021 13:39:55 +0200 Subject: [PATCH] OSPF: Allow ifaces with host address as unnumbered PtP or PtMP ifaces Ifaces with host address (/32) were forced to be stubby, but now they can be used as PtP or PtMP. For these ifaces we need to: - Do not force stub mode - Accept packets from any IP as local - Accept any configured neighbor as local - Detect ifaces properly as unnumbered - Use ONLINK flag for nexthops --- proto/ospf/iface.c | 24 ++++++++++++------------ proto/ospf/ospf.h | 8 ++++++++ proto/ospf/packet.c | 2 +- proto/ospf/rt.c | 12 +++++++++--- 4 files changed, 30 insertions(+), 16 deletions(-) diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c index 666140b5..f38b8210 100644 --- a/proto/ospf/iface.c +++ b/proto/ospf/iface.c @@ -529,14 +529,14 @@ add_nbma_node(struct ospf_iface *ifa, struct nbma_node *src, int found) } static int -ospf_iface_stubby(struct ospf_iface_patt *ip, struct ifa *addr) +ospf_iface_stubby(struct ospf_iface_patt *ip, struct ifa *addr, int type) { /* vlink cannot be stub */ - if (ip->type == OSPF_IT_VLINK) + if (type == OSPF_IT_VLINK) return 0; - /* a host address */ - if (addr->flags & IA_HOST) + /* Host address on Broadcast/NBMA */ + if (((type == OSPF_IT_BCAST) || (type == OSPF_IT_NBMA)) && (addr->flags & IA_HOST)) return 1; /* a loopback iface */ @@ -584,7 +584,6 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i ifa->strictnbma = ip->strictnbma; ifa->waitint = ip->waitint; ifa->deadint = ip->deadint; - ifa->stub = ospf_iface_stubby(ip, addr); ifa->ioprob = OSPF_I_OK; ifa->check_link = ip->check_link; ifa->ecmp_weight = ip->ecmp_weight; @@ -598,18 +597,19 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i ifa->tx_length = ifa_tx_length(ifa); ifa->tx_hdrlen = ifa_tx_hdrlen(ifa); - ifa->ptp_netmask = !(addr->flags & IA_PEER); + ifa->ptp_netmask = !(addr->flags & (IA_HOST | IA_PEER)); if (ip->ptp_netmask < 2) ifa->ptp_netmask = ip->ptp_netmask; /* For compatibility, we may use ptp_address even for unnumbered links */ - ifa->ptp_address = !(addr->flags & IA_PEER) || (p->gr_mode != OSPF_GR_ABLE); + ifa->ptp_address = !(addr->flags & (IA_HOST | IA_PEER)) || (p->gr_mode != OSPF_GR_ABLE); if (ip->ptp_address < 2) ifa->ptp_address = ip->ptp_address; ifa->drip = ifa->bdrip = ospf_is_v2(p) ? IPA_NONE4 : IPA_NONE6; ifa->type = ospf_iface_classify(ip->type, addr); + ifa->stub = ospf_iface_stubby(ip, addr, ifa->type); /* Check validity of interface type */ int old_type = ifa->type; @@ -647,7 +647,7 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i should be used). Because OSPFv3 iface is not subnet-specific, there is no need for ipa_in_net() check */ - if (ospf_is_v2(p) && !ipa_in_netX(nb->ip, &addr->prefix)) + if (ospf_is_v2(p) && !ospf_ipa_local(nb->ip, addr)) continue; if (ospf_is_v3(p) && !ipa_is_link_local(nb->ip)) @@ -767,7 +767,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) if (old_type != new_type) return 0; - int new_stub = ospf_iface_stubby(new, ifa->addr); + int new_stub = ospf_iface_stubby(new, ifa->addr, new_type); if (ifa->stub != new_stub) return 0; @@ -929,7 +929,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) WALK_LIST(nb, new->nbma_list) { /* See related note in ospf_iface_new() */ - if (ospf_is_v2(p) && !ipa_in_netX(nb->ip, &ifa->addr->prefix)) + if (ospf_is_v2(p) && !ospf_ipa_local(nb->ip, ifa->addr)) continue; if (ospf_is_v3(p) && !ipa_is_link_local(nb->ip)) @@ -1011,7 +1011,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) /* PtP netmask */ int new_ptp_netmask = (new->ptp_netmask < 2) ? new->ptp_netmask : - !(ifa->addr->flags & IA_PEER); + !(ifa->addr->flags & (IA_HOST | IA_PEER)); if (ifa->ptp_netmask != new_ptp_netmask) { OSPF_TRACE(D_EVENTS, "Changing PtP netmask option of %s from %d to %d", @@ -1021,7 +1021,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) /* PtP address */ int new_ptp_address = (new->ptp_address < 2) ? new->ptp_address : - (!(ifa->addr->flags & IA_PEER) || (p->gr_mode != OSPF_GR_ABLE)); + (!(ifa->addr->flags & (IA_HOST | IA_PEER)) || (p->gr_mode != OSPF_GR_ABLE)); if (ifa->ptp_address != new_ptp_address) { /* Keep it silent for implicit changes */ diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index fd2347e5..3e704ae8 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -946,6 +946,14 @@ struct lsadb_show_data { #define EA_OSPF_ROUTER_ID EA_CODE(PROTOCOL_OSPF, 3) +/* + * For regular networks, neighbor address must match network prefix. + * For unnumbered networks, we consider every address local. + */ +static inline int ospf_ipa_local(ip_addr a, const struct ifa *addr) +{ return ipa_in_netX(a, &addr->prefix) || (addr->flags & IA_HOST); } + + /* ospf.c */ void ospf_schedule_rtcalc(struct ospf_proto *p); diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c index 15242318..d7e10f37 100644 --- a/proto/ospf/packet.c +++ b/proto/ospf/packet.c @@ -403,7 +403,7 @@ ospf_rx_hook(sock *sk, uint len) return 1; int src_local, dst_local, dst_mcast; - src_local = ipa_in_netX(sk->faddr, &ifa->addr->prefix); + src_local = ospf_ipa_local(sk->faddr, ifa->addr); dst_local = ipa_equal(sk->laddr, ifa->addr->ip); dst_mcast = ipa_equal(sk->laddr, ifa->all_routers) || ipa_equal(sk->laddr, ifa->des_routers); diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index b3e49a11..17f8be7f 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -1827,7 +1827,12 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en, return NULL; } - return new_nexthop(p, nh, ifa->iface, ifa->ecmp_weight); + struct nexthop *nhs = new_nexthop(p, nh, ifa->iface, ifa->ecmp_weight); + + if (ifa->addr->flags & IA_HOST) + nhs->flags = RNF_ONLINK; + + return nhs; } /* The third case - bcast or nbma neighbor */ @@ -2031,8 +2036,9 @@ again1: for (nh = nf->n.nhs; nh; nh = nh->next) if (ipa_nonzero(nh->gw)) { - neighbor *ng = neigh_find(&p->p, nh->gw, nh->iface, 0); - if (!ng || (ng->scope == SCOPE_HOST)) + neighbor *nbr = neigh_find(&p->p, nh->gw, nh->iface, + (nh->flags & RNF_ONLINK) ? NEF_ONLINK : 0); + if (!nbr || (nbr->scope == SCOPE_HOST)) { reset_ri(nf); break; } } }