This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
age = ntohs (lsa->data->ls_age) + tv_floor (tv_sub (recent_relative_time (), lsa->tv_recv));
return age;}
/* Fletcher Checksum -- Refer to RFC1008. */
/* All the offsets are zero-based. The offsets in the RFC1008 are one-based. */u_int16_tospf_lsa_checksum (struct lsa_header *lsa){ u_char *buffer = (u_char *) &lsa->options; int options_offset = buffer - (u_char *) &lsa->ls_age; /* should be 2 */
/* Skip the AGE field */ u_int16_t len = ntohs(lsa->length) - options_offset;
/* Checksum offset starts from "options" field, not the beginning of the lsa_header struct. The offset is 14, rather than 16. */ int checksum_offset = (u_char *) &lsa->checksum - buffer;
/* kevinm: Clear the refresh_list, otherwise there are going to be problems when we try to remove the LSA from the queue (which it's not a member of.) XXX: Should we add the LSA to the refresh_list queue? */ new->refresh_list = -1;
/* router-LSA related functions. *//* Get router-LSA flags. */static u_charrouter_lsa_flags (struct ospf_area *area){ u_char flags;
flags = area->ospf->flags;
/* Set virtual link flag. */
if (ospf_full_virtual_nbrs (area)) SET_FLAG (flags, ROUTER_LSA_VIRTUAL); else /* Just sanity check */ UNSET_FLAG (flags, ROUTER_LSA_VIRTUAL);
/* Set Shortcut ABR behabiour flag. */ UNSET_FLAG (flags, ROUTER_LSA_SHORTCUT); if (area->ospf->abr_type == OSPF_ABR_SHORTCUT) if (!OSPF_IS_AREA_BACKBONE (area)) if ((area->shortcut_configured == OSPF_SHORTCUT_DEFAULT &&
/* ASBR can't exit in stub area. */ if (area->external_routing == OSPF_AREA_STUB) UNSET_FLAG (flags, ROUTER_LSA_EXTERNAL); /* If ASBR set External flag */ else if (IS_OSPF_ASBR (area->ospf)) SET_FLAG (flags, ROUTER_LSA_EXTERNAL);
/* Set ABR dependent flags */ if (IS_OSPF_ABR (area->ospf)) { SET_FLAG (flags, ROUTER_LSA_BORDER); /* If Area is NSSA and we are both ABR and unconditional translator, * set Nt bit to inform other routers. */ if ( (area->external_routing == OSPF_AREA_NSSA) && (area->NSSATranslatorRole == OSPF_NSSA_ROLE_ALWAYS)) SET_FLAG (flags, ROUTER_LSA_NT); } return flags;}
/* Lookup neighbor other than myself. And check neighbor count, Point-to-Point link must have only 1 neighbor. */struct ospf_neighbor *ospf_nbr_lookup_ptop (struct ospf_interface *oi){ struct ospf_neighbor *nbr = NULL; struct route_node *rn;
/* Search neighbor, there must be one of two nbrs. */ for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) if ((nbr = rn->info)) if (!IPV4_ADDR_SAME (&nbr->router_id, &oi->ospf->router_id))
if (nbr->state == NSM_Full) { route_unlock_node (rn); break; }
/* PtoP link must have only 1 neighbor. */ if (ospf_nbr_count (oi, 0) > 1)
zlog_warn ("Point-to-Point link has more than 1 neighobrs.");
return nbr;}
/* Determine cost of link, taking RFC3137 stub-router support into * consideration */static u_int16_tospf_link_cost (struct ospf_interface *oi){ /* RFC3137 stub router support */ if (!CHECK_FLAG (oi->area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED)) return oi->output_cost; else return OSPF_OUTPUT_COST_INFINITE;}
/* Set a link information. */static charlink_info_set (struct stream *s, struct in_addr id,
struct in_addr data, u_char type, u_char tos, u_int16_t cost){ /* LSA stream is initially allocated to OSPF_MAX_LSA_SIZE, suits * vast majority of cases. Some rare routers with lots of links need more. * we try accomodate those here. */ if (STREAM_WRITEABLE(s) < OSPF_ROUTER_LSA_LINK_SIZE) { size_t ret = OSPF_MAX_LSA_SIZE; /* Can we enlarge the stream still? */ if (STREAM_SIZE(s) == OSPF_MAX_LSA_SIZE) { /* we futz the size here for simplicity, really we need to account * for just: * IP Header - (sizeof (struct ip)) * OSPF Header - OSPF_HEADER_SIZE * LSA Header - OSPF_LSA_HEADER_SIZE * MD5 auth data, if MD5 is configured - OSPF_AUTH_MD5_SIZE. * * Simpler just to subtract OSPF_MAX_LSA_SIZE though. */ ret = stream_resize (s, OSPF_MAX_PACKET_SIZE - OSPF_MAX_LSA_SIZE); } if (ret == OSPF_MAX_LSA_SIZE) { zlog_warn ("%s: Out of space in LSA stream, left %zd, size %zd", __func__, STREAM_REMAIN (s), STREAM_SIZE (s)); return 0; } } /* TOS based routing is not supported. */ stream_put_ipv4 (s, id.s_addr); /* Link ID. */ stream_put_ipv4 (s, data.s_addr); /* Link Data. */
stream_putc (s, type); /* Link Type. */ stream_putc (s, tos); /* TOS = 0. */ stream_putw (s, cost); /* Link Cost. */ return 1;}
if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type1]: Set link Point-to-Point");
if ((nbr = ospf_nbr_lookup_ptop (oi))) if (nbr->state == NSM_Full) {
/* For unnumbered point-to-point networks, the Link Data field should specify the interface's MIB-II ifIndex value. */links += link_info_set (s, nbr->router_id, oi->address->u.prefix4,
LSA_LINK_TYPE_POINTOPOINT, 0, cost); }
/* Regardless of the state of the neighboring router, we must add a Type 3 link (stub network). N.B. Options 1 & 2 share basically the same logic. */ masklen2ip (oi->address->prefixlen, &mask); id.s_addr = CONNECTED_PREFIX(oi->connected)->u.prefix4.s_addr & mask.s_addr; links += link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0,
/* this function add for support point-to-multipoint ,see rfc2328 12.4.1.4.*//* from "edward rrr" <[email protected]> http://marc.theaimsgroup.com/?l=zebra&m=100739222210507&w=2 */static intlsa_link_ptomp_set (struct stream *s, struct ospf_interface *oi)
inline static voidospf_stub_router_check (struct ospf_area *area){ /* area must either be administratively configured to be stub * or startup-time stub-router must be configured and we must in a pre-stub * state. */ if (CHECK_FLAG (area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED)) { SET_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED); return; } /* not admin-stubbed, check whether startup stubbing is configured and * whether it's not been done yet */ if (CHECK_FLAG (area->stub_router_state, OSPF_AREA_WAS_START_STUB_ROUTED)) return; if (area->ospf->stub_router_startup_time == OSPF_STUB_ROUTER_UNCONFIGURED) { /* stub-router is hence done forever for this area, even if someone * tries configure it (take effect next restart). */ SET_FLAG (area->stub_router_state, OSPF_AREA_WAS_START_STUB_ROUTED); return; } /* startup stub-router configured and not yet done */ SET_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED); OSPF_AREA_TIMER_ON (area->t_stub_router, ospf_stub_router_timer, area->ospf->stub_router_startup_time);} /* Create new router-LSA. */static struct ospf_lsa *ospf_router_lsa_new (struct ospf_area *area){ struct ospf *ospf = area->ospf; struct stream *s; struct lsa_header *lsah; struct ospf_lsa *new; int length;
/* check whether stub-router is desired, and if this is the first * router LSA. */ ospf_stub_router_check (area); /* Create a stream for LSA. */ s = stream_new (OSPF_MAX_LSA_SIZE); /* Set LSA common header fields. */ lsa_header_set (s, LSA_OPTIONS_GET (area) | LSA_OPTIONS_NSSA_GET (area),
/* The network-LSA lists those routers that are fully adjacent to the Designated Router; each fully adjacent router is identified by its OSPF Router ID. The Designated Router includes itself in this list. RFC2328, Section 12.4.2 */
for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) if ((nbr = rn->info) != NULL) if (nbr->state == NSM_Full || nbr == oi->nbr_self)
/* If there are no neighbours on this network (the net is stub), the router does not originate network-LSA (see RFC 12.4.2) */ if (oi->full_nbrs == 0) return NULL; if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
if (id.s_addr == 0xffffffff) { /* Maybe Link State ID not available. */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type%d]: Link ID not available, can't originate", OSPF_SUMMARY_LSA); return NULL; }
if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type3]: Create summary-LSA instance");
/* Create new stream for LSA. */ s = stream_new (OSPF_MAX_LSA_SIZE); lsah = (struct lsa_header *) STREAM_DATA (s);
id = ospf_lsa_unique_id (area->ospf, area->lsdb, OSPF_SUMMARY_LSA, p);
if (id.s_addr == 0xffffffff) { /* Maybe Link State ID not available. */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type%d]: Link ID not available, can't originate", OSPF_SUMMARY_LSA); return NULL; } /* Create new summary-LSA instance. */ if ( !(new = ospf_summary_lsa_new (area, (struct prefix *) p, metric, id))) return NULL;
/* Instlal LSA to LSDB. */ new = ospf_lsa_install (area->ospf, NULL, new);
if (id.s_addr == 0xffffffff) { /* Maybe Link State ID not available. */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type%d]: Link ID not available, can't originate", OSPF_ASBR_SUMMARY_LSA); return NULL; }
if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type3]: Create summary-LSA instance");
/* Create new stream for LSA. */ s = stream_new (OSPF_MAX_LSA_SIZE); lsah = (struct lsa_header *) STREAM_DATA (s);
if (id.s_addr == 0xffffffff) { /* Maybe Link State ID not available. */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type%d]: Link ID not available, can't originate", OSPF_ASBR_SUMMARY_LSA); return NULL; } /* Create new summary-LSA instance. */ new = ospf_summary_asbr_lsa_new (area, (struct prefix *) p, metric, id); if (!new) return NULL;
/* Install LSA to LSDB. */ new = ospf_lsa_install (area->ospf, NULL, new); /* Update LSA origination count. */ area->ospf->lsa_originate_count++;
/* Flooding new LSA through area. */ ospf_flood_through_area (area, NULL, new);
if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("LSA[Type%d:%s]: Originate summary-ASBR-LSA %p",
/* Get nexthop for AS-external-LSAs. Return nexthop if its interface is connected, else 0*/static struct in_addrospf_external_lsa_nexthop_get (struct ospf *ospf, struct in_addr nexthop){ struct in_addr fwd; struct prefix nh; struct listnode *node; struct ospf_interface *oi;
fwd.s_addr = 0;
if (!nexthop.s_addr) return fwd;
/* Check whether nexthop is covered by OSPF network. */ nh.family = AF_INET; nh.u.prefix4 = nexthop; nh.prefixlen = IPV4_MAX_BITLEN; /* XXX/SCALE: If there were a lot of oi's on an ifp, then it'd be * better to make use of the per-ifp table of ois. */ for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) if (if_is_operative (oi->ifp)) if (oi->address->family == AF_INET) if (prefix_match (oi->address, &nh)) return nexthop;
/* Put type of external metric. */ stream_putc (s, (mtype == EXTERNAL_METRIC_TYPE_2 ? 0x80 : 0));
/* Put 0 metric. TOS metric is not supported. */ stream_put_ospf_metric (s, mvalue); /* Get forwarding address to nexthop if on the Connection List, else 0. */ fwd_addr = ospf_external_lsa_nexthop_get (ospf, ei->nexthop);
/* Put forwarding address. */ stream_put_ipv4 (s, fwd_addr.s_addr); /* Put route tag -- This value should be introduced from configuration. */ stream_putl (s, 0);}
if (ei == NULL) { if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
zlog_debug ("LSA[Type5]: External info is NULL, could not originated"); return NULL; }
if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type5]: Originate AS-external-LSA instance");
/* If old Link State ID is specified, refresh LSA with same ID. */ if (old_id) id = *old_id; /* Get Link State with unique ID. */ else
{ id = ospf_lsa_unique_id (ospf, ospf->lsdb, OSPF_AS_EXTERNAL_LSA, &ei->p); if (id.s_addr == 0xffffffff)
{ /* Maybe Link State ID not available. */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type5]: Link ID not available, can't originate"); return NULL;}
}
/* Create new stream for LSA. */ s = stream_new (OSPF_MAX_LSA_SIZE); lsah = (struct lsa_header *) STREAM_DATA (s);
/* Set LSA common header fields. */ lsa_header_set (s, OSPF_OPTION_E, OSPF_AS_EXTERNAL_LSA,
id, ospf->router_id);
/* Set AS-external-LSA body fields. */ ospf_external_lsa_body_set (s, ei, ospf);
/* LSA may be a Type-5 originated via translation of a Type-7 LSA * which originated from an NSSA area. In which case it should not be * flooded back to NSSA areas. */ if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) return; /* NSSA Originate or Refresh (If anyNSSA)
LSA is self-originated. And just installed as Type-5. Additionally, install as Type-7 LSDB for every attached NSSA.
P-Bit controls which ABR performs translation to outside world; If we are an ABR....do not set the P-bit, because we send the Type-5, not as the ABR Translator, but as the ASBR owner within the AS!
If we are NOT ABR, Flood through NSSA as Type-7 w/P-bit set. The elected ABR Translator will see the P-bit, Translate, and re-flood.
Later, ABR_TASK and P-bit will scan Type-7 LSDB and translate to Type-5's to non-NSSA Areas. (it will also attempt a re-install) */
for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) { /* Don't install Type-7 LSA's into nonNSSA area */ if (area->external_routing != OSPF_AREA_NSSA) continue;
/* make lsa duplicate, lock=1 */ new = ospf_lsa_dup (lsa); new->area = area; new->data->type = OSPF_AS_NSSA_LSA;
/* set P-bit if not ABR */ if (! IS_OSPF_ABR (ospf)) {
SET_FLAG(new->data->options, OSPF_OPTION_NP);
/* set non-zero FWD ADDR
draft-ietf-ospf-nssa-update-09.txt
if the network between the NSSA AS boundary router and the adjacent AS is advertised into OSPF as an internal OSPF route, the forwarding address should be the next op address as is cu currently done with type-5 LSAs. If the intervening network is not adversited into OSPF as an internal OSPF route and the type-7 LSA's P-bit is set a forwarding address should be selected from one of the router's active OSPF inteface addresses which belong to the NSSA. If no such addresses exist, then no type-7 LSA's with the P-bit set should originate from this router. */
/* kevinm: not updating lsa anymore, just new */ extlsa = (struct as_external_lsa *)(new->data);
if (extlsa->e[0].fwd_addr.s_addr == 0) extlsa->e[0].fwd_addr = ospf_get_nssa_ip(area); /* this NSSA area in ifp */
if (extlsa->e[0].fwd_addr.s_addr == 0) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("LSA[Type-7]: Could not build FWD-ADDR"); ospf_lsa_discard (new); return;
}}
/* install also as Type-7 */ ospf_lsa_install (ospf, NULL, new); /* Remove Old, Lock New = 2 */
/* will send each copy, lock=2+n */ ospf_flood_through_as (ospf, NULL, new); /* all attached NSSA's, no AS/STUBs */ }}
assert (type7->data); if (type5) assert (type5->data); assert (ospf->anyNSSA);
/* get required data according to what has been given */ if (type7 && type5 == NULL) { /* find the translated Type-5 for this Type-7 */ struct as_external_lsa *ext = (struct as_external_lsa *)(type7->data); struct prefix_ipv4 p = { .prefix = type7->data->id, .prefixlen = ip_masklen (ext->mask), .family = AF_INET, };
type5 = ospf_external_info_find_lsa (ospf, &p); } else if (type5 && type7 == NULL) { /* find the type-7 from which supplied type-5 was translated, * ie find first type-7 with same LSA Id. */ struct listnode *ln, *lnn; struct route_node *rn; struct ospf_lsa *lsa; struct ospf_area *area; for (ALL_LIST_ELEMENTS (ospf->areas, ln, lnn, area)) { if (area->external_routing != OSPF_AREA_NSSA && !type7) continue; LSDB_LOOP (NSSA_LSDB(area), rn, lsa) { if (lsa->data->id.s_addr == type5->data->id.s_addr) { type7 = lsa; break; } } } }
/* do we have type7? */ if (!type7) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_translated_nssa_refresh(): no Type-7 found for " "Type-5 LSA Id %s", inet_ntoa (type5->data->id)); return NULL; }
/* do we have valid translated type5? */
if (type5 == NULL || !CHECK_FLAG (type5->flags, OSPF_LSA_LOCAL_XLT) ) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_translated_nssa_refresh(): No translated Type-5 " "found for Type-7 with Id %s", inet_ntoa (type7->data->id)); return NULL; }
/* Delete LSA from neighbor retransmit-list. */ ospf_ls_retransmit_delete_nbr_as (ospf, type5); /* create new translated LSA */ if ( (new = ospf_lsa_translated_nssa_new (ospf, type7)) == NULL) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_translated_nssa_refresh(): Could not translate " "Type-7 for %s to Type-5", inet_ntoa (type7->data->id)); return NULL; }
if ( !(new = ospf_lsa_install (ospf, NULL, new)) ) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_translated_nssa_refresh(): Could not install " "translated LSA, Id %s", inet_ntoa (type7->data->id)); return NULL; } /* Flood LSA through area. */ ospf_flood_through_as (ospf, NULL, new);
/* Originate an AS-external-LSA, install and flood. */struct ospf_lsa *ospf_external_lsa_originate (struct ospf *ospf, struct external_info *ei){ struct ospf_lsa *new;
/* Added for NSSA project....
External LSAs are originated in ASBRs as usual, but for NSSA systems. there is the global Type-5 LSDB and a Type-7 LSDB installed for every area. The Type-7's are flooded to every IR and every ABR; We install the Type-5 LSDB so that the normal "refresh" code operates as usual, and flag them as not used during ASE calculations. The Type-7 LSDB is used for calculations. Each Type-7 has a Forwarding Address of non-zero.
If an ABR is the elected NSSA translator, following SPF and during the ABR task it will translate all the scanned Type-7's, with P-bit ON and not-self generated, and translate to Type-5's throughout the non-NSSA/STUB AS.
A difference in operation depends whether this ASBR is an ABR or not. If not an ABR, the P-bit is ON, to indicate that any elected NSSA-ABR can perform its translation.
If an ABR, the P-bit is OFF; No ABR will perform translation and this ASBR will flood the Type-5 LSA as usual.
For the case where this ASBR is not an ABR, the ASE calculations are based on the Type-5 LSDB; The Type-7 LSDB exists just to demonstrate to the user that there are LSA's that belong to any attached NSSA.
Finally, it just so happens that when the ABR is translating every Type-7 into Type-5, it installs it into the Type-5 LSDB as an approved Type-5 (translated from Type-7); at the end of translation if any Translated Type-5's remain unapproved, then they must be flushed from the AS.
*/ /* Check the AS-external-LSA should be originated. */ if (!ospf_redistribute_check (ospf, ei, NULL)) return NULL; /* Create new AS-external-LSA instance. */ if ((new = ospf_external_lsa_new (ospf, ei, NULL)) == NULL) { if (IS_DEBUG_OSPF_EVENT)
zlog_debug ("LSA[Type5:%s]: Could not originate AS-external-LSA", inet_ntoa (ei->p.prefix));
return NULL; }
/* Install newly created LSA into Type-5 LSDB, lock = 1. */ ospf_lsa_install (ospf, NULL, new);
/* Originate AS-external-LSA from external info with initial flag. */intospf_external_lsa_originate_timer (struct thread *thread){ struct ospf *ospf = THREAD_ARG (thread); struct route_node *rn; struct external_info *ei; struct route_table *rt; int type = THREAD_VAL (thread);
ospf->t_external_lsa = NULL;
/* Originate As-external-LSA from all type of distribute source. */ if ((rt = EXTERNAL_INFO (type))) for (rn = route_top (rt); rn; rn = route_next (rn)) if ((ei = rn->info) != NULL)
if (!is_prefix_default ((struct prefix_ipv4 *)&ei->p)) if (!ospf_external_lsa_originate (ospf, ei)) zlog_warn ("LSA: AS-external-LSA was not originated.");
if (ospf->default_originate == DEFAULT_ORIGINATE_ALWAYS) { /* If there is no default route via redistribute,
then originate AS-external-LSA with nexthop 0 (self). */ nexthop.s_addr = 0; ospf_external_info_add (DEFAULT_ROUTE, p, 0, nexthop); }
if ((ei = ospf_default_external_info (ospf))) ospf_external_lsa_originate (ospf, ei); return 0;}
/* Flush any NSSA LSAs for given prefix */voidospf_nssa_lsa_flush (struct ospf *ospf, struct prefix_ipv4 *p){ struct listnode *node, *nnode; struct ospf_lsa *lsa; struct ospf_area *area;
for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) { if (area->external_routing == OSPF_AREA_NSSA) { if (!(lsa = ospf_lsa_lookup (area, OSPF_AS_NSSA_LSA, p->prefix, ospf->router_id))) { if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("LSA: There is no such AS-NSSA-LSA %s/%d in LSDB", inet_ntoa (p->prefix), p->prefixlen); continue; }
if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("LSA: Flushing AS-external-LSA %s/%d",
inet_ntoa (p->prefix), p->prefixlen);
/* First lookup LSA from LSDB. */ if (!(lsa = ospf_external_info_find_lsa (ospf, p))) { if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
zlog_debug ("LSA: There is no such AS-external-LSA %s/%d in LSDB", inet_ntoa (p->prefix), p->prefixlen);
return; }
/* If LSA is selforiginated, not a translated LSA, and there is * NSSA area, flush Type-7 LSA's at first. */ if (IS_LSA_SELF(lsa) && (ospf->anyNSSA) && !(CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))) ospf_nssa_lsa_flush (ospf, p);
/* Sweep LSA from Link State Retransmit List. */ ospf_ls_retransmit_delete_nbr_as (ospf, lsa);
/* There must be no self-originated LSA in rtrs_external. */#if 0 /* Remove External route from Zebra. */ ospf_zebra_delete ((struct prefix_ipv4 *) p, &nexthop);#endif
if (!IS_LSA_MAXAGE (lsa)) { /* Unregister LSA from Refresh queue. */ ospf_refresher_unregister_lsa (ospf, lsa);
/* Flush AS-external-LSA through AS. */ ospf_lsa_flush_as (ospf, lsa); }
struct external_info *ei, int force){ struct ospf_lsa *new; int changed; /* Check the AS-external-LSA should be originated. */ if (!ospf_redistribute_check (ospf, ei, &changed)) { if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type%d:%s]: Could not be refreshed, " "redist check fail", lsa->data->type, inet_ntoa (lsa->data->id)); ospf_external_lsa_flush (ospf, ei->type, &ei->p,
ei->ifindex /*, ei->nexthop */); return NULL; }
if (!changed && !force) { if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type%d:%s]: Not refreshed, not changed/forced", lsa->data->type, inet_ntoa (lsa->data->id)); return NULL; }
/* Delete LSA from neighbor retransmit-list. */ ospf_ls_retransmit_delete_nbr_as (ospf, lsa);
/* Unregister AS-external-LSA from refresh-list. */ ospf_refresher_unregister_lsa (ospf, lsa);
new = ospf_external_lsa_new (ospf, ei, &lsa->data->id); if (new == NULL) { if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
zlog_debug ("LSA[Type%d:%s]: Could not be refreshed", lsa->data->type, inet_ntoa (lsa->data->id));
ospf_lsa_install (ospf, NULL, new); /* As type-5. */
/* Flood LSA through AS. */ ospf_flood_through_as (ospf, NULL, new);
/* If any attached NSSA, install as Type-7, flood to all NSSA Areas */ if (ospf->anyNSSA && !(CHECK_FLAG (new->flags, OSPF_LSA_LOCAL_XLT))) ospf_install_flood_nssa (ospf, new, ei); /* Install/Flood per new rules */
/* Register self-originated LSA to refresh queue. * Translated LSAs should not be registered, but refreshed upon * refresh of the Type-7 */ if ( !CHECK_FLAG (new->flags, OSPF_LSA_LOCAL_XLT) ) ospf_refresher_register_lsa (ospf, new);
/* Install router-LSA to an area. */static struct ospf_lsa *ospf_router_lsa_install (struct ospf *ospf, struct ospf_lsa *new, int rt_recalc){ struct ospf_area *area = new->area;
/* RFC 2328 Section 13.2 Router-LSAs and network-LSAs The entire routing table must be recalculated, starting with the shortest path calculations for each area (not just the area whose link-state database has changed). */
if (IS_LSA_SELF (new)) {
/* Only install LSA if it is originated/refreshed by us. * If LSA was received by flooding, the RECEIVED flag is set so do * not link the LSA */ if (CHECK_FLAG (new->flags, OSPF_LSA_RECEIVED))
/* Install network-LSA to an area. */static struct ospf_lsa *ospf_network_lsa_install (struct ospf *ospf,
struct ospf_interface *oi, struct ospf_lsa *new, int rt_recalc)
{
/* RFC 2328 Section 13.2 Router-LSAs and network-LSAs The entire routing table must be recalculated, starting with the shortest path calculations for each area (not just the area whose link-state database has changed). */ if (IS_LSA_SELF (new)) { /* We supposed that when LSA is originated by us, we pass the int
for which it was originated. If LSA was received by flooding, the RECEIVED flag is set, so we do not link the LSA to the int. */
if (CHECK_FLAG (new->flags, OSPF_LSA_RECEIVED))return new; /* ignore stale LSA */
/* Install summary-LSA to an area. */static struct ospf_lsa *ospf_summary_lsa_install (struct ospf *ospf, struct ospf_lsa *new,
int rt_recalc){ if (rt_recalc && !IS_LSA_SELF (new)) { /* RFC 2328 Section 13.2 Summary-LSAs
The best route to the destination described by the summary- LSA must be recalculated (see Section 16.5). If this destination is an AS boundary router, it may also be necessary to re-examine all the AS-external-LSAs.
if (IS_LSA_SELF (new)) ospf_refresher_register_lsa (ospf, new);
return new;}
/* Install ASBR-summary-LSA to an area. */static struct ospf_lsa *ospf_summary_asbr_lsa_install (struct ospf *ospf, struct ospf_lsa *new,
int rt_recalc){ if (rt_recalc && !IS_LSA_SELF (new)) { /* RFC 2328 Section 13.2 Summary-LSAs
The best route to the destination described by the summary- LSA must be recalculated (see Section 16.5). If this destination is an AS boundary router, it may also be necessary to re-examine all the AS-external-LSAs.
*/#if 0 /* These don't exist yet... */ ospf_summary_incremental_update(new); /* Isn't this done by the above call?
- RFC 2328 Section 16.5 implies it should be */ /* ospf_ase_calculate_schedule(); */#else /* #if 0 */ ospf_spf_calculate_schedule (ospf);#endif /* #if 0 */ }
/* register LSA to refresh-list. */ if (IS_LSA_SELF (new)) ospf_refresher_register_lsa (ospf, new);
int rt_recalc){ ospf_ase_register_external_lsa (new, ospf); /* If LSA is not self-originated, calculate an external route. */ if (rt_recalc) { /* RFC 2328 Section 13.2 AS-external-LSAs The best route to the destination described by the AS- external-LSA must be recalculated (see Section 16.6). */
if (!IS_LSA_SELF (new)) ospf_ase_incremental_update (ospf, new); }
if (new->data->type == OSPF_AS_NSSA_LSA) { /* There is no point to register selforiginate Type-7 LSA for * refreshing. We rely on refreshing Type-5 LSA's */ if (IS_LSA_SELF (new)) return new; else { /* Try refresh type-5 translated LSA for this LSA, if one exists. * New translations will be taken care of by the abr_task. */ ospf_translated_nssa_refresh (ospf, new, NULL); } }
/* Register self-originated LSA to refresh queue. * Leave Translated LSAs alone if NSSA is enabled */ if (IS_LSA_SELF (new) && !CHECK_FLAG (new->flags, OSPF_LSA_LOCAL_XLT ) ) ospf_refresher_register_lsa (ospf, new);
return new;}
voidospf_discard_from_db (struct ospf *ospf,
struct ospf_lsdb *lsdb, struct ospf_lsa *lsa){ struct ospf_lsa *old; if (!lsdb) { zlog_warn ("%s: Called with NULL lsdb!", __func__); if (!lsa) zlog_warn ("%s: and NULL LSA!", __func__); else zlog_warn ("LSA[Type%d:%s]: not associated with LSDB!", lsa->data->type, inet_ntoa (lsa->data->id)); return; } old = ospf_lsdb_lookup (lsdb, lsa);
if (!old) return;
if (old->refresh_list >= 0) ospf_refresher_unregister_lsa (ospf, old);
Installing a new LSA in the database, either as the result of
flooding or a newly self-originated LSA, may cause the OSPF routing table structure to be recalculated. The contents of the new LSA should be compared to the old instance, if present. If there is no difference, there is no need to recalculate the routing table. When comparing an LSA to its previous instance, the following are all considered to be differences in contents:
o The LSA's Options field has changed.
o One of the LSA instances has LS age set to MaxAge, and the other does not.
o The length field in the LSA header has changed.
o The body of the LSA (i.e., anything outside the 20-byte LSA header) has changed. Note that this excludes changes in LS Sequence Number and LS Checksum.
*/ /* Look up old LSA and determine if any SPF calculation or incremental update is needed */ old = ospf_lsdb_lookup (lsdb, lsa);
/* Do comparision and record if recalc needed. */ rt_recalc = 0; if ( old == NULL || ospf_lsa_different(old, lsa)) rt_recalc = 1;
/* Sequence number check (Section 14.1 of rfc 2328) "Premature aging is used when it is time for a self-originated LSA's sequence number field to wrap. At this point, the current LSA instance (having LS sequence number MaxSequenceNumber) must be prematurely aged and flushed from the routing domain before a new instance with sequence number equal to InitialSequenceNumber can be originated. " */
if (ntohl(lsa->data->ls_seqnum) - 1 == OSPF_MAX_SEQUENCE_NUMBER) { if (ospf_lsa_is_self_originated(ospf, lsa)) { lsa->data->ls_seqnum = htonl(OSPF_MAX_SEQUENCE_NUMBER); if (!IS_LSA_MAXAGE(lsa)) lsa->flags |= OSPF_LSA_PREMATURE_AGE; lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) { zlog_debug ("ospf_lsa_install() Premature Aging "
/* Do LSA specific installation process. */ switch (lsa->data->type) { case OSPF_ROUTER_LSA: new = ospf_router_lsa_install (ospf, lsa, rt_recalc); break; case OSPF_NETWORK_LSA: assert (oi); new = ospf_network_lsa_install (ospf, oi, lsa, rt_recalc); break; case OSPF_SUMMARY_LSA: new = ospf_summary_lsa_install (ospf, lsa, rt_recalc); break; case OSPF_ASBR_SUMMARY_LSA: new = ospf_summary_asbr_lsa_install (ospf, lsa, rt_recalc); break; case OSPF_AS_EXTERNAL_LSA: new = ospf_external_lsa_install (ospf, lsa, rt_recalc); break;#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: if (IS_LSA_SELF (lsa))
lsa->oi = oi; /* Specify outgoing ospf-interface for this LSA. */ else
; /* Incoming "oi" for this LSA has set at LSUpd reception. */ /* Fallthrough */ case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: new = ospf_opaque_lsa_install (lsa, rt_recalc); break;#endif /* HAVE_OPAQUE_LSA */ case OSPF_AS_NSSA_LSA: new = ospf_external_lsa_install (ospf, lsa, rt_recalc); default: /* type-6,8,9....nothing special */
break; }
if (new == NULL) return new; /* Installation failed, cannot proceed further -- endo. */
switch (lsa->data->type) { case OSPF_AS_EXTERNAL_LSA:#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA:#endif /* HAVE_OPAQUE_LSA */ case OSPF_AS_NSSA_LSA: zlog_debug ("LSA[%s]: Install %s", dump_lsa_key (new), LOOKUP (ospf_lsa_type_msg, new->data->type)); break; default:
strcpy (area_str, inet_ntoa (new->area->area_id)); zlog_debug ("LSA[%s]: Install %s to Area %s", dump_lsa_key (new), LOOKUP (ospf_lsa_type_msg, new->data->type), area_str); break; } }
/* If received LSA' ls_age is MaxAge, or lsa is being prematurely aged (it's getting flushed out of the area), set LSA on MaxAge LSA list. */ if ((lsa->flags & OSPF_LSA_PREMATURE_AGE) || (IS_LSA_MAXAGE (new) && !IS_LSA_SELF (new))) { if (IS_DEBUG_OSPF (lsa, LSA_INSTALL)) zlog_debug ("LSA[Type%d:%s]: Install LSA 0x%p, MaxAge", new->data->type, inet_ntoa (new->data->id), lsa); ospf_lsa_flush (ospf, lsa); }
if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("LSA[MaxAge]: remover Start");
reschedule = !ospf_check_nbr_status (ospf);
if (!reschedule) for (ALL_LIST_ELEMENTS (ospf->maxage_lsa, node, nnode, lsa)) { if (lsa->retransmit_counter > 0) { reschedule = 1; continue; } /* TODO: maybe convert this function to a work-queue */ if (thread_should_yield (thread)) OSPF_TIMER_ON (ospf->t_maxage, ospf_maxage_lsa_remover, 0); /* Remove LSA from the LSDB */ if (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF)) if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("LSA[Type%d:%s]: LSA 0x%lx is self-oririnated: ", lsa->data->type, inet_ntoa (lsa->data->id), (u_long)lsa);
if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("LSA[Type%d:%s]: MaxAge LSA removed from list", lsa->data->type, inet_ntoa (lsa->data->id));
if (CHECK_FLAG (lsa->flags, OSPF_LSA_PREMATURE_AGE)) { if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("originating new lsa for lsa 0x%p\n", lsa); ospf_lsa_refresh (ospf, lsa); }
/* A MaxAge LSA must be removed immediately from the router's link state database as soon as both a) it is no longer contained on any neighbor Link state retransmission lists and b) none of the router's neighbors are in states Exchange or Loading. */ if (reschedule) OSPF_TIMER_ON (ospf->t_maxage, ospf_maxage_lsa_remover, ospf->maxage_delay);
/* Add LSA onto the MaxAge list, and schedule for removal. * This does *not* lead to the LSA being flooded, that must be taken * care of elsewhere, see, e.g., ospf_lsa_flush* (which are callers of this * function). */voidospf_lsa_maxage (struct ospf *ospf, struct ospf_lsa *lsa){ /* When we saw a MaxAge LSA flooded to us, we put it on the list and schedule the MaxAge LSA remover. */
if (CHECK_FLAG(lsa->flags, OSPF_LSA_IN_MAXAGE)) { if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
static intospf_lsa_maxage_walker_remover (struct ospf *ospf, struct ospf_lsa *lsa){ /* Stay away from any Local Translated Type-7 LSAs */ if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) return 0;
if (IS_LSA_MAXAGE (lsa)) /* Self-originated LSAs should NOT time-out instead, they're flushed and submitted to the max_age list explicitly. */ if (!ospf_lsa_is_self_originated (ospf, lsa)) {
if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug("LSA[%s]: is MaxAge", dump_lsa_key (lsa));
switch (lsa->data->type) {#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: /* * As a general rule, whenever network topology has changed * (due to an LSA removal in this case), routing recalculation * should be triggered. However, this is not true for opaque * LSAs. Even if an opaque LSA instance is going to be removed * from the routing domain, it does not mean a change in network * topology, and thus, routing recalculation is not needed here. */ break;#endif /* HAVE_OPAQUE_LSA */ case OSPF_AS_EXTERNAL_LSA: case OSPF_AS_NSSA_LSA:
switch (type) { case OSPF_ROUTER_LSA: case OSPF_NETWORK_LSA: case OSPF_SUMMARY_LSA: case OSPF_ASBR_SUMMARY_LSA: case OSPF_AS_NSSA_LSA:#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA:#endif /* HAVE_OPAQUE_LSA */ return ospf_lsdb_lookup_by_id (area->lsdb, type, id, adv_router); case OSPF_AS_EXTERNAL_LSA:#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA:#endif /* HAVE_OPAQUE_LSA */ return ospf_lsdb_lookup_by_id (ospf->lsdb, type, id, adv_router); default:
switch (type) { case OSPF_ROUTER_LSA: return ospf_lsdb_lookup_by_id (area->lsdb, type, id, id); case OSPF_NETWORK_LSA: for (rn = route_top (NETWORK_LSDB (area)); rn; rn = route_next (rn))
if ((lsa = rn->info)) if (IPV4_ADDR_SAME (&lsa->data->id, &id)) { route_unlock_node (rn); return lsa; }
break; case OSPF_SUMMARY_LSA: case OSPF_ASBR_SUMMARY_LSA: /* Currently not used. */ assert (1); return ospf_lsdb_lookup_by_id (area->lsdb, type, id, id); case OSPF_AS_EXTERNAL_LSA: case OSPF_AS_NSSA_LSA:#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: /* Currently not used. */ break;#endif /* HAVE_OPAQUE_LSA */ default: break; }
#ifdef HAVE_OPAQUE_LSA /* * Strictly speaking, the LSA-ID field for Opaque-LSAs (type-9/10/11) * is redefined to have two subfields; opaque-type and opaque-id. * However, it is harmless to treat the two sub fields together, as if
* they two were forming a unique LSA-ID. */#endif /* HAVE_OPAQUE_LSA */
match = ospf_lsa_lookup (area, lsah->type, lsah->id, lsah->adv_router);
if (match == NULL) if (IS_DEBUG_OSPF (lsa, LSA) == OSPF_DEBUG_LSA) zlog_debug ("LSA[Type%d:%s]: Lookup by header, NO MATCH",
lsah->type, inet_ntoa (lsah->id));
return match;}
/* return +n, l1 is more recent. return -n, l2 is more recent. return 0, l1 and l2 is identical. */intospf_lsa_more_recent (struct ospf_lsa *l1, struct ospf_lsa *l2){ int r; int x, y;
if (l1 == NULL && l2 == NULL) return 0; if (l1 == NULL) return -1; if (l2 == NULL) return 1;
/* compare LS sequence number. */ x = (int) ntohl (l1->data->ls_seqnum); y = (int) ntohl (l2->data->ls_seqnum); if (x > y) return 1; if (x < y) return -1;
/* compare LS checksum. */ r = ntohs (l1->data->checksum) - ntohs (l2->data->checksum); if (r) return r;
/* compare LS age. */ if (IS_LSA_MAXAGE (l1) && !IS_LSA_MAXAGE (l2)) return 1; else if (!IS_LSA_MAXAGE (l1) && IS_LSA_MAXAGE (l2)) return -1;
/* compare LS age with MaxAgeDiff. */ if (LS_AGE (l1) - LS_AGE (l2) > OSPF_LSA_MAXAGE_DIFF) return -1; else if (LS_AGE (l2) - LS_AGE (l1) > OSPF_LSA_MAXAGE_DIFF) return 1;
/* LSAs are identical. */ return 0;
}
/* If two LSAs are different, return 1, otherwise return 0. */intospf_lsa_different (struct ospf_lsa *l1, struct ospf_lsa *l2){ char *p1, *p2; assert (l1); assert (l2); assert (l1->data); assert (l2->data);
if (l1->data->options != l2->data->options) return 1;
if (IS_LSA_MAXAGE (l1) && !IS_LSA_MAXAGE (l2)) return 1;
if (IS_LSA_MAXAGE (l2) && !IS_LSA_MAXAGE (l1)) return 1;
if (l1->data->length != l2->data->length) return 1;
if (l1->data->length == 0) return 1;
if (CHECK_FLAG ((l1->flags ^ l2->flags), OSPF_LSA_RECEIVED)) return 1; /* May be a stale LSA in the LSBD */
On non-broadcast networks, separateLink State Update packets must be sent, as unicasts, to each adjacent neighbor (i.e., those in state Exchange or greater). The destination IP addresses for these packets are the neighbors' IP addresses. */
/* * Make sure that the MaxAge LSA remover is executed immediately, * without conflicting to other threads. */ if (ospf->t_maxage != NULL) { OSPF_TIMER_OFF (ospf->t_maxage); thread_execute (master, ospf_maxage_lsa_remover, ospf, 0); }
return;}#endif /* ORIGINAL_CODING */
/* If there is self-originated LSA, then return 1, otherwise return 0. *//* An interface-independent version of ospf_lsa_is_self_originated */int ospf_lsa_is_self_originated (struct ospf *ospf, struct ospf_lsa *lsa){ struct listnode *node; struct ospf_interface *oi;
/* This LSA is already checked. */ if (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF_CHECKED)) return CHECK_FLAG (lsa->flags, OSPF_LSA_SELF);
/* Make sure LSA is self-checked. */ SET_FLAG (lsa->flags, OSPF_LSA_SELF_CHECKED);
/* AdvRouter and Router ID is the same. */ if (IPV4_ADDR_SAME (&lsa->data->adv_router, &ospf->router_id)) SET_FLAG (lsa->flags, OSPF_LSA_SELF);
/* LSA is router-LSA. */ else if (lsa->data->type == OSPF_ROUTER_LSA && IPV4_ADDR_SAME (&lsa->data->id, &ospf->router_id)) SET_FLAG (lsa->flags, OSPF_LSA_SELF);
/* LSA is network-LSA. Compare Link ID with all interfaces. */ else if (lsa->data->type == OSPF_NETWORK_LSA) for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) {
/* Ignore virtual link. */ if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
if (oi->address->family == AF_INET) if (IPV4_ADDR_SAME (&lsa->data->id, &oi->address->u.prefix4)) {
/* to make it easier later */SET_FLAG (lsa->flags, OSPF_LSA_SELF);return CHECK_FLAG (lsa->flags, OSPF_LSA_SELF);
} }
return CHECK_FLAG (lsa->flags, OSPF_LSA_SELF);}
/* Get unique Link State ID. */struct in_addrospf_lsa_unique_id (struct ospf *ospf,
switch (lsa->data->type) { /* Router and Network LSAs are processed differently. */ case OSPF_ROUTER_LSA: new = ospf_router_lsa_refresh (lsa); break; case OSPF_NETWORK_LSA: new = ospf_network_lsa_refresh (lsa); break; case OSPF_SUMMARY_LSA: new = ospf_summary_lsa_refresh (ospf, lsa); break; case OSPF_ASBR_SUMMARY_LSA: new = ospf_summary_asbr_lsa_refresh (ospf, lsa); break; case OSPF_AS_EXTERNAL_LSA: /* Translated from NSSA Type-5s are refreshed when * from refresh of Type-7 - do not refresh these directly. */ if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) break; ei = ospf_external_info_check (lsa); if (ei) new = ospf_external_lsa_refresh (ospf, lsa, ei, LSA_REFRESH_FORCE); else ospf_lsa_flush_as (ospf, lsa); break;#ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: new = ospf_opaque_lsa_refresh (lsa); break;#endif /* HAVE_OPAQUE_LSA */ default: break; } return new;}
intospf_lsa_refresh_walker (struct thread *t){ struct list *refresh_list; struct listnode *node, *nnode; struct ospf *ospf = THREAD_ARG (t); struct ospf_lsa *lsa; int i; struct list *lsa_to_refresh = list_new ();
if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) zlog_debug ("LSA[Refresh]:ospf_lsa_refresh_walker(): start");
i = ospf->lsa_refresh_queue.index; /* Note: if clock has jumped backwards, then time change could be negative, so we are careful to cast the expression to unsigned before taking modulus. */ ospf->lsa_refresh_queue.index = ((unsigned long)(ospf->lsa_refresh_queue.index +