OSPF: Basic support for DN-bit handling (RFC 4576)

External LSAs originated by OSPF routers with VPN-PE behavior enabled are
marked by DN flag and they are ignored by other OSPF routers with VPN-PE
enabled.
This commit is contained in:
Ondrej Zajicek (work) 2019-02-13 15:40:22 +01:00
parent 1e958e52d3
commit 4a3f5b3617
7 changed files with 38 additions and 13 deletions

View file

@ -199,7 +199,7 @@ CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN, VIRTUAL, CHECK, LINK, ONLY, BFD)
CF_KEYWORDS(RX, BUFFER, LARGE, NORMAL, STUBNET, HIDDEN, SUMMARY, TAG, EXTERNAL) CF_KEYWORDS(RX, BUFFER, LARGE, NORMAL, STUBNET, HIDDEN, SUMMARY, TAG, EXTERNAL)
CF_KEYWORDS(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT, NSSA, TRANSLATOR, STABILITY) CF_KEYWORDS(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT, NSSA, TRANSLATOR, STABILITY)
CF_KEYWORDS(GLOBAL, LSID, ROUTER, SELF, INSTANCE, REAL, NETMASK, TX, PRIORITY, LENGTH) CF_KEYWORDS(GLOBAL, LSID, ROUTER, SELF, INSTANCE, REAL, NETMASK, TX, PRIORITY, LENGTH)
CF_KEYWORDS(MERGE, LSA, SUPPRESSION, MULTICAST, RFC5838) CF_KEYWORDS(MERGE, LSA, SUPPRESSION, MULTICAST, RFC5838, VPN, PE)
%type <ld> lsadb_args %type <ld> lsadb_args
%type <i> ospf_variant ospf_af_mc nbma_eligible %type <i> ospf_variant ospf_af_mc nbma_eligible
@ -256,6 +256,7 @@ ospf_proto_item:
| ospf_channel { this_proto->net_type = $1->net_type; } | ospf_channel { this_proto->net_type = $1->net_type; }
| RFC1583COMPAT bool { OSPF_CFG->rfc1583 = $2; } | RFC1583COMPAT bool { OSPF_CFG->rfc1583 = $2; }
| RFC5838 bool { OSPF_CFG->af_ext = $2; if (!ospf_cfg_is_v3()) cf_error("RFC5838 option requires OSPFv3"); } | RFC5838 bool { OSPF_CFG->af_ext = $2; if (!ospf_cfg_is_v3()) cf_error("RFC5838 option requires OSPFv3"); }
| VPN PE bool { OSPF_CFG->vpn_pe = $3; }
| STUB ROUTER bool { OSPF_CFG->stub_router = $3; } | STUB ROUTER bool { OSPF_CFG->stub_router = $3; }
| ECMP bool { OSPF_CFG->ecmp = $2 ? OSPF_DEFAULT_ECMP_LIMIT : 0; } | ECMP bool { OSPF_CFG->ecmp = $2 ? OSPF_DEFAULT_ECMP_LIMIT : 0; }
| ECMP bool LIMIT expr { OSPF_CFG->ecmp = $2 ? $4 : 0; } | ECMP bool LIMIT expr { OSPF_CFG->ecmp = $2 ? $4 : 0; }

View file

@ -336,9 +336,10 @@ lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, int af, net_addr *net, u
{ {
if (ospf2) if (ospf2)
{ {
uint opts = lsa_get_options(&en->lsa);
struct ospf_lsa_sum2 *ls = en->lsa_body; struct ospf_lsa_sum2 *ls = en->lsa_body;
net_fill_ip4(net, ip4_from_u32(en->lsa.id & ls->netmask), u32_masklen(ls->netmask)); net_fill_ip4(net, ip4_from_u32(en->lsa.id & ls->netmask), u32_masklen(ls->netmask));
*pxopts = 0; *pxopts = (opts & OPT_DN) ? OPT_PX_DN : 0;
*metric = ls->metric & LSA_METRIC_MASK; *metric = ls->metric & LSA_METRIC_MASK;
} }
else else
@ -386,6 +387,7 @@ lsa_parse_ext(struct top_hash_entry *en, int ospf2, int af, struct ospf_lsa_ext_
rt->tag = ext->tag; rt->tag = ext->tag;
rt->propagate = lsa_get_options(&en->lsa) & OPT_P; rt->propagate = lsa_get_options(&en->lsa) & OPT_P;
rt->downwards = lsa_get_options(&en->lsa) & OPT_DN;
} }
else else
{ {
@ -402,6 +404,7 @@ lsa_parse_ext(struct top_hash_entry *en, int ospf2, int af, struct ospf_lsa_ext_
rt->tag = (ext->metric & LSA_EXT3_TBIT) ? *buf++ : 0; rt->tag = (ext->metric & LSA_EXT3_TBIT) ? *buf++ : 0;
rt->propagate = rt->pxopts & OPT_PX_P; rt->propagate = rt->pxopts & OPT_PX_P;
rt->downwards = rt->pxopts & OPT_PX_DN;
} }
} }

View file

@ -92,6 +92,7 @@
* - RFC 2328 - main OSPFv2 standard * - RFC 2328 - main OSPFv2 standard
* - RFC 5340 - main OSPFv3 standard * - RFC 5340 - main OSPFv3 standard
* - RFC 3101 - OSPFv2 NSSA areas * - RFC 3101 - OSPFv2 NSSA areas
* - RFC 4576 - OSPFv2 VPN loop prevention
* - RFC 5250 - OSPFv2 Opaque LSAs * - RFC 5250 - OSPFv2 Opaque LSAs
* - RFC 5709 - OSPFv2 HMAC-SHA Cryptographic Authentication * - RFC 5709 - OSPFv2 HMAC-SHA Cryptographic Authentication
* - RFC 5838 - OSPFv3 Support of Address Families * - RFC 5838 - OSPFv3 Support of Address Families
@ -243,6 +244,7 @@ ospf_start(struct proto *P)
p->merge_external = c->merge_external; p->merge_external = c->merge_external;
p->instance_id = c->instance_id; p->instance_id = c->instance_id;
p->asbr = c->asbr; p->asbr = c->asbr;
p->vpn_pe = c->vpn_pe;
p->ecmp = c->ecmp; p->ecmp = c->ecmp;
p->tick = c->tick; p->tick = c->tick;
p->disp_timer = tm_new_init(P->pool, ospf_disp, p, p->tick S, 0); p->disp_timer = tm_new_init(P->pool, ospf_disp, p, p->tick S, 0);
@ -657,6 +659,9 @@ ospf_reconfigure(struct proto *P, struct proto_config *CF)
if (old->abr != new->abr) if (old->abr != new->abr)
return 0; return 0;
if (old->vpn_pe != new->vpn_pe)
return 0;
if ((p->af_ext != new->af_ext) || (p->af_mc != new->af_mc)) if ((p->af_ext != new->af_ext) || (p->af_mc != new->af_mc))
return 0; return 0;

View file

@ -96,6 +96,7 @@ struct ospf_config
u8 instance_id_set; u8 instance_id_set;
u8 abr; u8 abr;
u8 asbr; u8 asbr;
u8 vpn_pe;
int ecmp; int ecmp;
list area_list; /* list of area configs (struct ospf_area_config) */ list area_list; /* list of area configs (struct ospf_area_config) */
list vlink_list; /* list of configured vlinks (struct ospf_iface_patt) */ list vlink_list; /* list of configured vlinks (struct ospf_iface_patt) */
@ -225,6 +226,7 @@ struct ospf_proto
u8 merge_external; /* Should i merge external routes? */ u8 merge_external; /* Should i merge external routes? */
u8 instance_id; /* Differentiate between more OSPF instances */ u8 instance_id; /* Differentiate between more OSPF instances */
u8 asbr; /* May i originate any ext/NSSA lsa? */ u8 asbr; /* May i originate any ext/NSSA lsa? */
u8 vpn_pe; /* Should we do VPN PE specific behavior (RFC 4577)? */
u8 ecmp; /* Maximal number of nexthops in ECMP route, or 0 */ u8 ecmp; /* Maximal number of nexthops in ECMP route, or 0 */
u64 csn64; /* Last used cryptographic sequence number */ u64 csn64; /* Last used cryptographic sequence number */
struct ospf_area *backbone; /* If exists */ struct ospf_area *backbone; /* If exists */
@ -467,6 +469,7 @@ struct ospf_neighbor
#define OPT_R 0x0010 /* OSPFv3, originator is active router */ #define OPT_R 0x0010 /* OSPFv3, originator is active router */
#define OPT_DC 0x0020 /* Related to demand circuits, not used */ #define OPT_DC 0x0020 /* Related to demand circuits, not used */
#define OPT_O 0x0040 /* OSPFv2 Opaque LSA (RFC 5250) */ #define OPT_O 0x0040 /* OSPFv2 Opaque LSA (RFC 5250) */
#define OPT_DN 0x0080 /* OSPFv2 VPN loop prevention (RFC 4576)*/
#define OPT_AF 0x0100 /* OSPFv3 Address Families (RFC 5838) */ #define OPT_AF 0x0100 /* OSPFv3 Address Families (RFC 5838) */
#define OPT_L_V3 0x0200 /* OSPFv3, link-local signaling */ #define OPT_L_V3 0x0200 /* OSPFv3, link-local signaling */
#define OPT_AT 0x0400 /* OSPFv3, authentication trailer */ #define OPT_AT 0x0400 /* OSPFv3, authentication trailer */
@ -736,7 +739,7 @@ struct ospf_lsa_ext_local
{ {
net_addr net; net_addr net;
ip_addr fwaddr; ip_addr fwaddr;
u32 metric, ebit, fbit, tag, propagate; u32 metric, ebit, fbit, tag, propagate, downwards;
u8 pxopts; u8 pxopts;
}; };

View file

@ -782,6 +782,10 @@ ospf_rt_sum(struct ospf_area *oa)
if (pxopts & OPT_PX_NU) if (pxopts & OPT_PX_NU)
continue; continue;
/* RFC 4576 4 - do not use LSAs with DN-bit on PE-routers */
if (p->vpn_pe && (pxopts & OPT_PX_DN))
continue;
options = 0; options = 0;
type = ORT_NET; type = ORT_NET;
} }
@ -879,6 +883,10 @@ ospf_rt_sum_tr(struct ospf_area *oa)
if (pxopts & OPT_PX_NU) if (pxopts & OPT_PX_NU)
continue; continue;
/* RFC 4576 4 - do not use LSAs with DN-bit on PE-routers */
if (p->vpn_pe && (pxopts & OPT_PX_DN))
continue;
re = fib_find(&p->rtf, &net); re = fib_find(&p->rtf, &net);
} }
else // en->lsa_type == LSA_T_SUM_RT else // en->lsa_type == LSA_T_SUM_RT
@ -1104,11 +1112,11 @@ check_nssa_lsa(struct ospf_proto *p, ort *nf)
/* RFC 3101 3.2 (3) - originate the aggregated address range */ /* RFC 3101 3.2 (3) - originate the aggregated address range */
if (anet && anet->active && !anet->hidden && oa->translate) if (anet && anet->active && !anet->hidden && oa->translate)
ospf_originate_ext_lsa(p, NULL, nf, LSA_M_RTCALC, anet->metric, ospf_originate_ext_lsa(p, NULL, nf, LSA_M_RTCALC, anet->metric,
(anet->metric & LSA_EXT3_EBIT), IPA_NONE, anet->tag, 0); (anet->metric & LSA_EXT3_EBIT), IPA_NONE, anet->tag, 0, 0);
/* RFC 3101 3.2 (2) - originate the same network */ /* RFC 3101 3.2 (2) - originate the same network */
else if (decide_nssa_lsa(p, nf, &rt)) else if (decide_nssa_lsa(p, nf, &rt))
ospf_originate_ext_lsa(p, NULL, nf, LSA_M_RTCALC, rt.metric, rt.ebit, rt.fwaddr, rt.tag, 0); ospf_originate_ext_lsa(p, NULL, nf, LSA_M_RTCALC, rt.metric, rt.ebit, rt.fwaddr, rt.tag, 0, 0);
} }
/* RFC 2328 16.7. p2 - find new/lost vlink endpoints */ /* RFC 2328 16.7. p2 - find new/lost vlink endpoints */
@ -1238,7 +1246,7 @@ ospf_rt_abr1(struct ospf_proto *p)
if (oa_is_nssa(oa) && oa->ac->default_nssa) if (oa_is_nssa(oa) && oa->ac->default_nssa)
ospf_originate_ext_lsa(p, oa, default_nf, LSA_M_RTCALC, oa->ac->default_cost, ospf_originate_ext_lsa(p, oa, default_nf, LSA_M_RTCALC, oa->ac->default_cost,
(oa->ac->default_cost & LSA_EXT3_EBIT), IPA_NONE, 0, 0); (oa->ac->default_cost & LSA_EXT3_EBIT), IPA_NONE, 0, 0, 0);
/* RFC 2328 16.4. (3) - precompute preferred ASBR entries */ /* RFC 2328 16.4. (3) - precompute preferred ASBR entries */
if (oa_is_ext(oa)) if (oa_is_ext(oa))
@ -1474,6 +1482,10 @@ ospf_ext_spf(struct ospf_proto *p)
if (rt.pxopts & OPT_PX_NU) if (rt.pxopts & OPT_PX_NU)
continue; continue;
/* RFC 4576 4 - do not use LSAs with DN-bit on PE-routers */
if (p->vpn_pe && rt.downwards)
continue;
/* 16.4. (3) */ /* 16.4. (3) */
/* If there are more areas, we already precomputed preferred ASBR /* If there are more areas, we already precomputed preferred ASBR
entries in ospf_rt_abr1() and stored them in the backbone entries in ospf_rt_abr1() and stored them in the backbone

View file

@ -1097,7 +1097,7 @@ prepare_ext2_lsa_body(struct ospf_proto *p, uint pxlen,
static inline void static inline void
prepare_ext3_lsa_body(struct ospf_proto *p, ort *nf, prepare_ext3_lsa_body(struct ospf_proto *p, ort *nf,
u32 metric, u32 ebit, ip_addr fwaddr, u32 tag, int pbit) u32 metric, u32 ebit, ip_addr fwaddr, u32 tag, int pbit, int dn)
{ {
struct ospf_lsa_ext3 *ext; struct ospf_lsa_ext3 *ext;
int bsize = sizeof(struct ospf_lsa_ext3) int bsize = sizeof(struct ospf_lsa_ext3)
@ -1109,7 +1109,8 @@ prepare_ext3_lsa_body(struct ospf_proto *p, ort *nf,
ext->metric = metric & LSA_METRIC_MASK; ext->metric = metric & LSA_METRIC_MASK;
u32 *buf = ext->rest; u32 *buf = ext->rest;
buf = ospf3_put_prefix(buf, nf->fn.addr, pbit ? OPT_PX_P : 0, 0); uint flags = (pbit ? OPT_PX_P : 0) | (dn ? OPT_PX_DN : 0);
buf = ospf3_put_prefix(buf, nf->fn.addr, flags, 0);
if (ebit) if (ebit)
ext->metric |= LSA_EXT3_EBIT; ext->metric |= LSA_EXT3_EBIT;
@ -1147,21 +1148,21 @@ prepare_ext3_lsa_body(struct ospf_proto *p, ort *nf,
*/ */
void void
ospf_originate_ext_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, u8 mode, ospf_originate_ext_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, u8 mode,
u32 metric, u32 ebit, ip_addr fwaddr, u32 tag, int pbit) u32 metric, u32 ebit, ip_addr fwaddr, u32 tag, int pbit, int dn)
{ {
struct ospf_new_lsa lsa = { struct ospf_new_lsa lsa = {
.type = oa ? LSA_T_NSSA : LSA_T_EXT, .type = oa ? LSA_T_NSSA : LSA_T_EXT,
.mode = mode, /* LSA_M_EXPORT or LSA_M_RTCALC */ .mode = mode, /* LSA_M_EXPORT or LSA_M_RTCALC */
.dom = oa ? oa->areaid : 0, .dom = oa ? oa->areaid : 0,
.id = ort_to_lsaid(p, nf), .id = ort_to_lsaid(p, nf),
.opts = oa ? (pbit ? OPT_P : 0) : OPT_E, .opts = (oa ? (pbit ? OPT_P : 0) : OPT_E) | (dn ? OPT_DN : 0),
.nf = nf .nf = nf
}; };
if (ospf_is_v2(p)) if (ospf_is_v2(p))
prepare_ext2_lsa_body(p, nf->fn.addr->pxlen, metric, ebit, fwaddr, tag); prepare_ext2_lsa_body(p, nf->fn.addr->pxlen, metric, ebit, fwaddr, tag);
else else
prepare_ext3_lsa_body(p, nf, metric, ebit, fwaddr, tag, oa && pbit); prepare_ext3_lsa_body(p, nf, metric, ebit, fwaddr, tag, oa && pbit, dn);
ospf_originate_lsa(p, &lsa); ospf_originate_lsa(p, &lsa);
} }
@ -1337,7 +1338,7 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte
} }
nf = fib_get(&p->rtf, n->n.addr); nf = fib_get(&p->rtf, n->n.addr);
ospf_originate_ext_lsa(p, oa, nf, LSA_M_EXPORT, metric, ebit, fwd, tag, 1); ospf_originate_ext_lsa(p, oa, nf, LSA_M_EXPORT, metric, ebit, fwd, tag, 1, p->vpn_pe);
nf->external_rte = 1; nf->external_rte = 1;
} }

View file

@ -186,7 +186,7 @@ static inline void ospf_flush2_lsa(struct ospf_proto *p, struct top_hash_entry *
void ospf_originate_sum_net_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, int metric); void ospf_originate_sum_net_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, int metric);
void ospf_originate_sum_rt_lsa(struct ospf_proto *p, struct ospf_area *oa, u32 drid, int metric, u32 options); void ospf_originate_sum_rt_lsa(struct ospf_proto *p, struct ospf_area *oa, u32 drid, int metric, u32 options);
void ospf_originate_ext_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, u8 mode, u32 metric, u32 ebit, ip_addr fwaddr, u32 tag, int pbit); void ospf_originate_ext_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, u8 mode, u32 metric, u32 ebit, ip_addr fwaddr, u32 tag, int pbit, int dn);
void ospf_rt_notify(struct proto *P, struct channel *ch, net *n, rte *new, rte *old); void ospf_rt_notify(struct proto *P, struct channel *ch, net *n, rte *new, rte *old);
void ospf_update_topology(struct ospf_proto *p); void ospf_update_topology(struct ospf_proto *p);