diff --git a/doc/bird.sgml b/doc/bird.sgml index 18f3601b..0681bd53 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -1904,6 +1904,7 @@ on nonbroadcast networks. protocol ospf <name> { rfc1583compat <switch>; + stub router <switch>; tick <num>; ecmp <switch> [limit <num>]; area <id> { @@ -1983,6 +1984,15 @@ protocol ospf <name> { url="ftp://ftp.rfc-editor.org/in-notes/rfc1583.txt">. Default value is no. + stub router switch + This option configures the router to be a stub router, i.e., + a router that participates in the OSPF topology but does not + allow transit traffic. In OSPFv2, this is implemented by + advertising maximum metric for outgoing links, as suggested + by RFC 3137. + In OSPFv3, the stub router behavior is announced by clearing + the R-bit in the router LSA. Default value is no. + tick num The routing table calculation and clean-up of areas' databases is not performed when a single link state diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y index 2f1ee624..b43ef8a8 100644 --- a/proto/ospf/config.Y +++ b/proto/ospf/config.Y @@ -148,6 +148,7 @@ ospf_proto: ospf_proto_item: proto_item | RFC1583COMPAT bool { OSPF_CFG->rfc1583 = $2; } + | STUB ROUTER bool { OSPF_CFG->stub_router = $3; } | ECMP bool { OSPF_CFG->ecmp = $2 ? OSPF_DEFAULT_ECMP_LIMIT : 0; } | ECMP bool LIMIT expr { OSPF_CFG->ecmp = $2 ? $4 : 0; if ($4 < 0) cf_error("ECMP limit cannot be negative"); } | TICK expr { OSPF_CFG->tick = $2; if($2<=0) cf_error("Tick must be greater than zero"); } diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index bfd7777d..43e24805 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -164,7 +164,10 @@ ospf_area_add(struct proto_ospf *po, struct ospf_area_config *ac, int reconf) if (oa->areaid == 0) po->backbone = oa; - oa->options = ospf_is_v2(po) ? ac->type : (OPT_R | ac->type | OPT_V6); + if (ospf_is_v2(po)) + oa->options = ac->type; + else + oa->options = ac->type | OPT_V6 | (po->stub_router ? 0 : OPT_R); /* * Set E-bit for NSSA ABR routers. No need to explicitly call @@ -230,6 +233,7 @@ ospf_start(struct proto *p) po->router_id = proto_get_router_id(p->cf); po->last_vlink_id = 0x80000000; po->rfc1583 = c->rfc1583; + po->stub_router = c->stub_router; po->ebit = 0; po->ecmp = c->ecmp; po->tick = c->tick; @@ -678,7 +682,10 @@ ospf_area_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac) oa->ac = nac; // FIXME better area type reconfiguration - oa->options = ospf_is_v2(oa->po) ? nac->type : (OPT_R | nac->type | OPT_V6); + if (ospf_is_v2(po)) + oa->options = nac->type; + else + oa->options = nac->type | OPT_V6 | (oa->po->stub_router ? 0 : OPT_R); if (oa_is_nssa(oa) && (oa->po->areano > 1)) oa->po->ebit = 1; @@ -726,6 +733,7 @@ ospf_reconfigure(struct proto *p, struct proto_config *c) if (old->abr != new->abr) return 0; + po->stub_router = new->stub_router; po->ecmp = new->ecmp; po->tick = new->tick; po->disp_timer->recurrent = po->tick; @@ -819,6 +827,7 @@ ospf_sh(struct proto *p) cli_msg(-1014, "%s:", p->name); cli_msg(-1014, "RFC1583 compatibility: %s", (po->rfc1583 ? "enable" : "disabled")); + cli_msg(-1014, "Stub router: %s", (po->stub_router ? "Yes" : "No")); cli_msg(-1014, "RT scheduler tick: %d", po->tick); cli_msg(-1014, "Number of areas: %u", po->areano); cli_msg(-1014, "Number of LSAs in DB:\t%u", po->gr->hash_entries); diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index 90acc5c6..b5ecc435 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -72,6 +72,7 @@ struct ospf_config unsigned tick; byte ospf2; byte rfc1583; + byte stub_router; byte abr; byte ecmp; list area_list; /* list of struct ospf_area_config */ @@ -710,6 +711,7 @@ struct proto_ospf struct fib rtf; /* Routing table */ byte ospf2; /* OSPF v2 or v3 */ byte rfc1583; /* RFC1583 compatibility */ + byte stub_router; /* Do not forward transit traffic */ byte ebit; /* Did I originate any ext lsa? */ byte ecmp; /* Maximal number of nexthops in ECMP route, or 0 */ struct ospf_area *backbone; /* If exists */ diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index bf9b2adf..51fbf66c 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -332,6 +332,10 @@ spfa_process_rt(struct ospf_area *oa, struct top_hash_entry *act) ri_install_rt(oa, act->lsa.rt, &nf); } + /* Errata 2078 to RFC 5340 4.8.1 - skip links from non-routing nodes */ + if (ospf_is_v3(po) && (act != oa->rt) && !(rt->options & OPT_R)) + break; + /* Now process Rt links */ for (lsa_walk_rt_init(po, act, &rtl), i = 0; lsa_walk_rt(&rtl); i++) { @@ -1712,12 +1716,12 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par, return; if (ospf_is_v3(po) && (en->lsa_type == LSA_T_RT)) - { - /* In OSPFv3, check V6 and R flags */ - struct ospf_lsa_rt *rt = en->lsa_body; - if (!(rt->options & OPT_V6) || !(rt->options & OPT_R)) - return; - } + { + /* In OSPFv3, check V6 flag */ + struct ospf_lsa_rt *rt = en->lsa_body; + if (!(rt->options & OPT_V6)) + return; + } /* 16.1. (2c) */ if (en->color == INSPF) diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index f8637fdc..df7b63c6 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -219,6 +219,7 @@ prepare_rt2_lsa_body(struct proto_ospf *po, struct ospf_area *oa) WALK_LIST(ifa, po->iface_list) { int net_lsa = 0; + u32 link_cost = po->stub_router ? 0xffff : ifa->cost; if ((ifa->type == OSPF_IT_VLINK) && (ifa->voa == oa) && (!EMPTY_LIST(ifa->neigh_list))) @@ -249,7 +250,7 @@ prepare_rt2_lsa_body(struct proto_ospf *po, struct ospf_area *oa) * compatibility with some broken implementations that use * this address as a next-hop. */ - add_rt2_lsa_link(po, LSART_PTP, neigh->rid, ipa_to_u32(ifa->addr->ip), ifa->cost); + add_rt2_lsa_link(po, LSART_PTP, neigh->rid, ipa_to_u32(ifa->addr->ip), link_cost); i++; } break; @@ -258,7 +259,7 @@ prepare_rt2_lsa_body(struct proto_ospf *po, struct ospf_area *oa) case OSPF_IT_NBMA: if (bcast_net_active(ifa)) { - add_rt2_lsa_link(po, LSART_NET, ipa_to_u32(ifa->drip), ipa_to_u32(ifa->addr->ip), ifa->cost); + add_rt2_lsa_link(po, LSART_NET, ipa_to_u32(ifa->drip), ipa_to_u32(ifa->addr->ip), link_cost); i++; net_lsa = 1; } @@ -267,7 +268,7 @@ prepare_rt2_lsa_body(struct proto_ospf *po, struct ospf_area *oa) case OSPF_IT_VLINK: neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list); if ((!EMPTY_LIST(ifa->neigh_list)) && (neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff)) - add_rt2_lsa_link(po, LSART_VLNK, neigh->rid, ipa_to_u32(ifa->addr->ip), ifa->cost), i++; + add_rt2_lsa_link(po, LSART_VLNK, neigh->rid, ipa_to_u32(ifa->addr->ip), link_cost), i++; break; default: