diff --git a/doc/bird.sgml b/doc/bird.sgml
index 136ff251..e8ccd430 100644
--- a/doc/bird.sgml
+++ b/doc/bird.sgml
@@ -1195,8 +1195,13 @@ protocol ospf <name> {
<prefix>;
<prefix> hidden;
}
- interface <interface pattern>
- {
+ stubnet <prefix>;
+ stubnet <prefix> {
+ hidden <switch>;
+ summary <switch>;
+ cost <num>;
+ }
+ interface <interface pattern> {
cost <num>;
stub <switch>;
hello <num>;
@@ -1223,8 +1228,7 @@ protocol ospf <name> {
<ip> eligible;
};
};
- virtual link <id>
- {
+ virtual link <id> {
hello <num>;
retransmit <num>;
wait <num>;
@@ -1265,6 +1269,24 @@ protocol ospf <name> {
Definition of area IP ranges. This is used in summary lsa origination.
Hidden networks are not propagated into other areas.
+ stubnet
+ Stub networks are networks that are not transit networks
+ between OSPF routers. They are also propagated through an
+ OSPF area as a part of a link state database. By default,
+ BIRD generates a stub network record for each primary network
+ address on each OSPF interface that does not have any OSPF
+ neighbors, and also for each non-primary network address on
+ each OSPF interface. This option allows to alter a set of
+ stub networks propagated by this router.
+
+ Each instance of this option adds a stub network with given
+ network prefix to the set of propagated stub network, unless
+ option interface pattern
Defines that the specified interfaces belong to the area being defined.
See [ common option for detailed description.
diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y
index 7f7d6a31..0f688a7e 100644
--- a/proto/ospf/config.Y
+++ b/proto/ospf/config.Y
@@ -18,6 +18,7 @@ CF_DEFINES
static struct ospf_area_config *this_area;
static struct nbma_node *this_nbma;
static struct area_net_config *this_pref;
+static struct ospf_stubnet_config *this_stubnet;
static void
finish_iface_config(struct ospf_iface_patt *ip)
@@ -38,7 +39,7 @@ CF_KEYWORDS(NEIGHBORS, RFC1583COMPAT, STUB, TICK, COST, RETRANSMIT)
CF_KEYWORDS(HELLO, TRANSMIT, PRIORITY, DEAD, NONBROADCAST, POINTOPOINT, TYPE)
CF_KEYWORDS(NONE, SIMPLE, AUTHENTICATION, STRICT, CRYPTOGRAPHIC)
CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN, VIRTUAL, LINK)
-CF_KEYWORDS(RX, BUFFER, LARGE, NORMAL)
+CF_KEYWORDS(RX, BUFFER, LARGE, NORMAL, STUBNET, HIDDEN, SUMMARY)
%type opttext
@@ -75,6 +76,7 @@ ospf_area_start: AREA idval '{' {
init_list(&this_area->patt_list);
init_list(&this_area->vlink_list);
init_list(&this_area->net_list);
+ init_list(&this_area->stubnet_list);
}
;
@@ -90,10 +92,36 @@ ospf_area_item:
STUB COST expr { this_area->stub = $3 ; if($3<=0) cf_error("Stub cost must be greater than zero"); }
| STUB bool {if($2) { if(!this_area->stub) this_area->stub=DEFAULT_STUB_COST;}else{ this_area->stub=0;}}
| NETWORKS '{' pref_list '}'
+ | STUBNET ospf_stubnet
| INTERFACE ospf_iface
| ospf_vlink
;
+ospf_stubnet:
+ ospf_stubnet_start '{' ospf_stubnet_opts '}'
+ | ospf_stubnet_start
+ ;
+
+ospf_stubnet_start:
+ prefix {
+ this_stubnet = cfg_allocz(sizeof(struct stubnet_config));
+ add_tail(&this_area->stubnet_list, NODE this_stubnet);
+ this_stubnet->px = $1;
+ this_stubnet->cost = COST_D;
+ }
+ ;
+
+ospf_stubnet_opts:
+ /* empty */
+ | ospf_stubnet_opts ospf_stubnet_item ';'
+ ;
+
+ospf_stubnet_item:
+ HIDDEN bool { this_stubnet->hidden = $2; }
+ | SUMMARY bool { this_stubnet->summary = $2; }
+ | COST expr { this_stubnet->cost = $2; }
+ ;
+
ospf_vlink:
ospf_vlink_start '{' ospf_vlink_opts '}' { finish_iface_config(OSPF_PATT); }
| ospf_vlink_start
diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c
index 4ad6ef46..c9b5f430 100644
--- a/proto/ospf/ospf.c
+++ b/proto/ospf/ospf.c
@@ -148,6 +148,7 @@ ospf_start(struct proto *p)
oa = mb_allocz(p->pool, sizeof(struct ospf_area));
add_tail(&po->area_list, NODE oa);
po->areano++;
+ oa->ac = ac;
oa->stub = ac->stub;
oa->areaid = ac->areaid;
oa->rt = NULL;
@@ -629,9 +630,31 @@ ospf_reconfigure(struct proto *p, struct proto_config *c)
if (!oa)
return 0;
+ oa->ac = newac;
oa->stub = newac->stub;
if (newac->stub && (oa->areaid == 0)) oa->stub = 0;
+ /* Check stubnet_list */
+ struct ospf_stubnet_config *oldsn = HEAD(oldac->stubnet_list);
+ struct ospf_stubnet_config *newsn = HEAD(newac->stubnet_list);
+
+ while (((NODE(oldsn))->next != NULL) && ((NODE(newsn))->next != NULL))
+ {
+ if (!ipa_equal(oldsn->px.addr, newsn->px.addr) ||
+ (oldsn->px.len != newsn->px.len) ||
+ (oldsn->hidden != newsn->hidden) ||
+ (oldsn->summary != newsn->summary) ||
+ (oldsn->cost != newsn->cost))
+ break;
+
+ oldsn = (struct ospf_stubnet_config *)(NODE(oldsn))->next;
+ newsn = (struct ospf_stubnet_config *)(NODE(newsn))->next;
+ }
+
+ /* If there is no change, both pointers should be NULL */
+ if (((NODE(oldsn))->next) != ((NODE(newsn))->next))
+ schedule_rt_lsa(oa);
+
/* Change net_list */
FIB_WALK(&oa->net_fib, nf) /* First check if some networks are deleted */
{
diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h
index 71f99d34..23f21b8e 100644
--- a/proto/ospf/ospf.h
+++ b/proto/ospf/ospf.h
@@ -99,6 +99,14 @@ struct area_net
u32 metric;
};
+struct ospf_stubnet_config
+{
+ node n;
+ struct prefix px;
+ int hidden, summary;
+ u32 cost;
+};
+
struct ospf_area_config
{
node n;
@@ -107,6 +115,7 @@ struct ospf_area_config
list patt_list;
list vlink_list;
list net_list;
+ list stubnet_list;
};
struct obits
@@ -523,6 +532,7 @@ struct ospf_area
{
node n;
u32 areaid;
+ struct ospf_area_config *ac; /* Related area config */
int origrt; /* Rt lsa origination scheduled? */
struct top_hash_entry *rt; /* My own router LSA */
list cand; /* List of candidates for RT calc. */
diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c
index 18100f7e..371856f9 100644
--- a/proto/ospf/topology.c
+++ b/proto/ospf/topology.c
@@ -52,6 +52,25 @@ lsab_flush(struct proto_ospf *po)
return r;
}
+static int
+configured_stubnet(struct ospf_area *oa, struct ifa *a)
+{
+ struct ospf_stubnet_config *sn;
+ WALK_LIST(sn, oa->ac->stubnet_list)
+ {
+ if (sn->summary)
+ {
+ if (ipa_in_net(a->prefix, sn->px.addr, sn->px.len) && (a->pxlen >= sn->px.len))
+ return 1;
+ }
+ else
+ {
+ if (ipa_equal(a->prefix, sn->px.addr) && (a->pxlen == sn->px.len))
+ return 1;
+ }
+ }
+ return 0;
+}
static void *
originate_rt_lsa_body(struct ospf_area *oa, u16 * length)
@@ -163,9 +182,11 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 * length)
{
if (((a == ifa->iface->addr) && master) ||
(a->flags & IA_SECONDARY) ||
- (a->flags & IA_UNNUMBERED))
+ (a->flags & IA_UNNUMBERED) ||
+ configured_stubnet(oa, a))
continue;
+
ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link));
ln->type = LSART_STUB;
ln->id = ipa_to_u32(a->prefix);
@@ -176,6 +197,19 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 * length)
}
}
+ struct ospf_stubnet_config *sn;
+ WALK_LIST(sn, oa->ac->stubnet_list)
+ if (!sn->hidden)
+ {
+ ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link));
+ ln->type = LSART_STUB;
+ ln->id = ipa_to_u32(sn->px.addr);
+ ln->data = ipa_to_u32(ipa_mkmask(sn->px.len));
+ ln->metric = sn->cost;
+ ln->notos = 0;
+ i++;
+ }
+
rt = po->lsab;
rt->links = i;
rt->veb.bit.v = bitv;
]