diff options
Diffstat (limited to 'proto/ospf/topology.c')
-rw-r--r-- | proto/ospf/topology.c | 100 |
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) |