summaryrefslogtreecommitdiff
path: root/proto/ospf/topology.c
diff options
context:
space:
mode:
Diffstat (limited to 'proto/ospf/topology.c')
-rw-r--r--proto/ospf/topology.c100
1 files changed, 95 insertions, 5 deletions
diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c
index 7d5deca0..efd03b54 100644
--- a/proto/ospf/topology.c
+++ b/proto/ospf/topology.c
@@ -83,7 +83,10 @@ ospf_install_lsa(struct ospf_proto *p, struct ospf_lsa_header *lsa, u32 type, u3
en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn, en->lsa.age);
if (change)
+ {
+ ospf_neigh_lsadb_changed(p, en);
ospf_schedule_rtcalc(p);
+ }
return en;
}
@@ -243,6 +246,7 @@ ospf_do_originate_lsa(struct ospf_proto *p, struct top_hash_entry *en, void *lsa
en->lsa.age = 0;
en->init_age = 0;
en->inst_time = current_time();
+ en->dirty = 0;
lsa_generate_checksum(&en->lsa, en->lsa_body);
OSPF_TRACE(D_EVENTS, "Originating LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x",
@@ -251,7 +255,10 @@ ospf_do_originate_lsa(struct ospf_proto *p, struct top_hash_entry *en, void *lsa
ospf_flood_lsa(p, en, NULL);
if (en->mode == LSA_M_BASIC)
+ {
+ ospf_neigh_lsadb_changed(p, en);
ospf_schedule_rtcalc(p);
+ }
return 1;
}
@@ -321,7 +328,8 @@ ospf_originate_lsa(struct ospf_proto *p, struct ospf_new_lsa *lsa)
if ((en->lsa.age < LSA_MAXAGE) &&
(lsa_length == en->lsa.length) &&
!memcmp(lsa_body, en->lsa_body, lsa_blen) &&
- (!ospf_is_v2(p) || (lsa->opts == lsa_get_options(&en->lsa))))
+ (!ospf_is_v2(p) || (lsa->opts == lsa_get_options(&en->lsa))) &&
+ !en->dirty)
goto drop;
lsa_body = lsab_flush(p);
@@ -433,7 +441,10 @@ ospf_flush_lsa(struct ospf_proto *p, struct top_hash_entry *en)
ospf_flood_lsa(p, en, NULL);
if (en->mode == LSA_M_BASIC)
+ {
+ ospf_neigh_lsadb_changed(p, en);
ospf_schedule_rtcalc(p);
+ }
en->mode = LSA_M_BASIC;
}
@@ -509,6 +520,12 @@ ospf_update_lsadb(struct ospf_proto *p)
continue;
}
+ if (en->dirty)
+ {
+ ospf_flush_lsa(p, en);
+ continue;
+ }
+
if ((en->lsa.rt == p->router_id) && (real_age >= LSREFRESHTIME))
{
ospf_refresh_lsa(p, en);
@@ -525,6 +542,16 @@ ospf_update_lsadb(struct ospf_proto *p)
}
}
+void
+ospf_mark_lsadb(struct ospf_proto *p)
+{
+ struct top_hash_entry *en;
+
+ /* Mark all local LSAs as dirty */
+ WALK_SLIST(en, p->lsal)
+ if (en->lsa.rt == p->router_id)
+ en->dirty = 1;
+}
static u32
ort_to_lsaid(struct ospf_proto *p, ort *nf)
@@ -1424,6 +1451,7 @@ prepare_prefix_rt_lsa_body(struct ospf_proto *p, struct ospf_area *oa)
struct ospf_config *cf = (struct ospf_config *) (p->p.cf);
struct ospf_iface *ifa;
struct ospf_lsa_prefix *lp;
+ uint max = ospf_is_ip4(p) ? IP4_MAX_PREFIX_LENGTH : IP6_MAX_PREFIX_LENGTH;
int host_addr = 0;
int net_lsa;
int i = 0;
@@ -1457,7 +1485,7 @@ prepare_prefix_rt_lsa_body(struct ospf_proto *p, struct ospf_area *oa)
(a->scope <= SCOPE_LINK))
continue;
- if (((a->prefix.pxlen < IP6_MAX_PREFIX_LENGTH) && net_lsa) ||
+ if (((a->prefix.pxlen < max) && net_lsa) ||
configured_stubnet(oa, a))
continue;
@@ -1465,8 +1493,13 @@ prepare_prefix_rt_lsa_body(struct ospf_proto *p, struct ospf_area *oa)
(ifa->state == OSPF_IS_LOOP) ||
(ifa->type == OSPF_IT_PTMP))
{
- net_addr_ip6 net = NET_ADDR_IP6(a->ip, IP6_MAX_PREFIX_LENGTH);
- lsab_put_prefix(p, (net_addr *) &net, 0);
+ net_addr net;
+ if (a->prefix.type == NET_IP4)
+ net_fill_ip4(&net, ipa_to_ip4(a->ip), IP4_MAX_PREFIX_LENGTH);
+ else
+ net_fill_ip6(&net, ipa_to_ip6(a->ip), IP6_MAX_PREFIX_LENGTH);
+
+ lsab_put_prefix(p, &net, 0);
host_addr = 1;
}
else
@@ -1482,7 +1515,7 @@ prepare_prefix_rt_lsa_body(struct ospf_proto *p, struct ospf_area *oa)
if (!sn->hidden)
{
lsab_put_prefix(p, &sn->prefix, sn->cost);
- if (sn->prefix.pxlen == IP6_MAX_PREFIX_LENGTH)
+ if (sn->prefix.pxlen == max)
host_addr = 1;
i++;
}
@@ -1670,6 +1703,59 @@ ospf_originate_prefix_net_lsa(struct ospf_proto *p, struct ospf_iface *ifa)
/*
+ * Grace LSA handling
+ * Type = LSA_T_GR, opaque type = LSA_OT_GR
+ */
+
+static inline void
+ospf_add_gr_period_tlv(struct ospf_proto *p, uint period)
+{
+ struct ospf_tlv *tlv = lsab_allocz(p, sizeof(struct ospf_tlv) + sizeof(u32));
+ tlv->type = LSA_GR_PERIOD;
+ tlv->length = 4;
+ tlv->data[0] = period;
+}
+
+static inline void
+ospf_add_gr_reason_tlv(struct ospf_proto *p, uint reason)
+{
+ struct ospf_tlv *tlv = lsab_allocz(p, sizeof(struct ospf_tlv) + sizeof(u32));
+ tlv->type = LSA_GR_REASON;
+ tlv->length = 1;
+ tlv->data[0] = reason << 24;
+}
+
+static inline void
+ospf_add_gr_address_tlv(struct ospf_proto *p, ip4_addr addr)
+{
+ struct ospf_tlv *tlv = lsab_allocz(p, sizeof(struct ospf_tlv) + sizeof(u32));
+ tlv->type = LSA_GR_ADDRESS;
+ tlv->length = 4;
+ tlv->data[0] = ip4_to_u32(addr);
+}
+
+void
+ospf_originate_gr_lsa(struct ospf_proto *p, struct ospf_iface *ifa)
+{
+ struct ospf_new_lsa lsa = {
+ .type = LSA_T_GR,
+ .dom = ifa->iface_id,
+ .id = ospf_is_v2(p) ? 0 : ifa->iface_id,
+ .ifa = ifa
+ };
+
+ ospf_add_gr_period_tlv(p, p->gr_time);
+ ospf_add_gr_reason_tlv(p, 0);
+
+ uint t = ifa->type;
+ if (ospf_is_v2(p) && ((t == OSPF_IT_BCAST) || (t == OSPF_IT_NBMA) || (t == OSPF_IT_PTMP)))
+ ospf_add_gr_address_tlv(p, ipa_to_ip4(ifa->addr->ip));
+
+ ospf_originate_lsa(p, &lsa);
+}
+
+
+/*
* Router Information LSA handling
* Type = LSA_T_RI_AREA, opaque type = LSA_OT_RI
*/
@@ -1712,6 +1798,10 @@ ospf_update_topology(struct ospf_proto *p)
struct ospf_area *oa;
struct ospf_iface *ifa;
+ /* No LSA reorigination during GR recovery */
+ if (p->gr_recovery)
+ return;
+
WALK_LIST(oa, p->area_list)
{
if (oa->update_rt_lsa)