diff options
Diffstat (limited to 'ospfd/ospf_lsa.c')
-rw-r--r-- | ospfd/ospf_lsa.c | 6436 |
1 files changed, 3187 insertions, 3249 deletions
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 835d321bb..68adf2e10 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -31,7 +31,7 @@ #include "log.h" #include "thread.h" #include "hash.h" -#include "sockunion.h" /* for inet_aton() */ +#include "sockunion.h" /* for inet_aton() */ #include "checksum.h" #include "ospfd/ospfd.h" @@ -51,1483 +51,1442 @@ #include "ospfd/ospf_zebra.h" -u_int32_t -get_metric (u_char *metric) +u_int32_t get_metric(u_char *metric) { - u_int32_t m; - m = metric[0]; - m = (m << 8) + metric[1]; - m = (m << 8) + metric[2]; - return m; + u_int32_t m; + m = metric[0]; + m = (m << 8) + metric[1]; + m = (m << 8) + metric[2]; + return m; } -struct timeval -int2tv (int a) +struct timeval int2tv(int a) { - struct timeval ret; + struct timeval ret; - ret.tv_sec = a; - ret.tv_usec = 0; + ret.tv_sec = a; + ret.tv_usec = 0; - return ret; + return ret; } -struct timeval -msec2tv (int a) +struct timeval msec2tv(int a) { - struct timeval ret; + struct timeval ret; - ret.tv_sec = a/1000; - ret.tv_usec = (a%1000) * 1000; + ret.tv_sec = a / 1000; + ret.tv_usec = (a % 1000) * 1000; - return ret; + return ret; } -int -ospf_lsa_refresh_delay (struct ospf_lsa *lsa) +int ospf_lsa_refresh_delay(struct ospf_lsa *lsa) { - struct timeval delta; - int delay = 0; + struct timeval delta; + int delay = 0; - if (monotime_since (&lsa->tv_orig, &delta) < OSPF_MIN_LS_INTERVAL * 1000LL) - { - struct timeval minv = msec2tv (OSPF_MIN_LS_INTERVAL); - timersub (&minv, &delta, &minv); + if (monotime_since(&lsa->tv_orig, &delta) + < OSPF_MIN_LS_INTERVAL * 1000LL) { + struct timeval minv = msec2tv(OSPF_MIN_LS_INTERVAL); + timersub(&minv, &delta, &minv); - /* TBD: remove padding to full sec, return timeval instead */ - delay = minv.tv_sec + !!minv.tv_usec; + /* TBD: remove padding to full sec, return timeval instead */ + delay = minv.tv_sec + !!minv.tv_usec; - if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) - zlog_debug ("LSA[Type%d:%s]: Refresh timer delay %d seconds", - lsa->data->type, inet_ntoa (lsa->data->id), delay); + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) + zlog_debug( + "LSA[Type%d:%s]: Refresh timer delay %d seconds", + lsa->data->type, inet_ntoa(lsa->data->id), + delay); - assert (delay > 0); - } + assert(delay > 0); + } - return delay; + return delay; } -int -get_age (struct ospf_lsa *lsa) +int get_age(struct ospf_lsa *lsa) { - struct timeval rel; + struct timeval rel; - monotime_since (&lsa->tv_recv, &rel); - return ntohs (lsa->data->ls_age) + rel.tv_sec; + monotime_since(&lsa->tv_recv, &rel); + return ntohs(lsa->data->ls_age) + rel.tv_sec; } /* Fletcher Checksum -- Refer to RFC1008. */ -/* All the offsets are zero-based. The offsets in the RFC1008 are +/* All the offsets are zero-based. The offsets in the RFC1008 are one-based. */ -u_int16_t -ospf_lsa_checksum (struct lsa_header *lsa) +u_int16_t ospf_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 */ + 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; + /* 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; + /* 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; - return fletcher_checksum(buffer, len, checksum_offset); + return fletcher_checksum(buffer, len, checksum_offset); } -int -ospf_lsa_checksum_valid (struct lsa_header *lsa) +int ospf_lsa_checksum_valid(struct lsa_header *lsa) { - u_char *buffer = (u_char *) &lsa->options; - int options_offset = buffer - (u_char *) &lsa->ls_age; /* should be 2 */ + 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; + /* Skip the AGE field */ + u_int16_t len = ntohs(lsa->length) - options_offset; - return(fletcher_checksum(buffer, len, FLETCHER_CHECKSUM_VALIDATE) == 0); + return (fletcher_checksum(buffer, len, FLETCHER_CHECKSUM_VALIDATE) + == 0); } - /* Create OSPF LSA. */ -struct ospf_lsa * -ospf_lsa_new () +struct ospf_lsa *ospf_lsa_new() { - struct ospf_lsa *new; + struct ospf_lsa *new; - new = XCALLOC (MTYPE_OSPF_LSA, sizeof (struct ospf_lsa)); + new = XCALLOC(MTYPE_OSPF_LSA, sizeof(struct ospf_lsa)); - new->flags = 0; - new->lock = 1; - new->retransmit_counter = 0; - monotime(&new->tv_recv); - new->tv_orig = new->tv_recv; - new->refresh_list = -1; - - return new; + new->flags = 0; + new->lock = 1; + new->retransmit_counter = 0; + monotime(&new->tv_recv); + new->tv_orig = new->tv_recv; + new->refresh_list = -1; + + return new; } /* Duplicate OSPF LSA. */ -struct ospf_lsa * -ospf_lsa_dup (struct ospf_lsa *lsa) +struct ospf_lsa *ospf_lsa_dup(struct ospf_lsa *lsa) { - struct ospf_lsa *new; + struct ospf_lsa *new; - if (lsa == NULL) - return NULL; + if (lsa == NULL) + return NULL; - new = XCALLOC (MTYPE_OSPF_LSA, sizeof (struct ospf_lsa)); + new = XCALLOC(MTYPE_OSPF_LSA, sizeof(struct ospf_lsa)); - memcpy (new, lsa, sizeof (struct ospf_lsa)); - UNSET_FLAG (new->flags, OSPF_LSA_DISCARD); - new->lock = 1; - new->retransmit_counter = 0; - new->data = ospf_lsa_data_dup (lsa->data); + memcpy(new, lsa, sizeof(struct ospf_lsa)); + UNSET_FLAG(new->flags, OSPF_LSA_DISCARD); + new->lock = 1; + new->retransmit_counter = 0; + new->data = ospf_lsa_data_dup(lsa->data); - /* 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; + /* 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; - if (IS_DEBUG_OSPF (lsa, LSA)) - zlog_debug ("LSA: duplicated %p (new: %p)", (void *)lsa, (void *)new); + if (IS_DEBUG_OSPF(lsa, LSA)) + zlog_debug("LSA: duplicated %p (new: %p)", (void *)lsa, + (void *)new); - return new; + return new; } /* Free OSPF LSA. */ -void -ospf_lsa_free (struct ospf_lsa *lsa) +void ospf_lsa_free(struct ospf_lsa *lsa) { - assert (lsa->lock == 0); - - if (IS_DEBUG_OSPF (lsa, LSA)) - zlog_debug ("LSA: freed %p", (void *)lsa); + assert(lsa->lock == 0); + + if (IS_DEBUG_OSPF(lsa, LSA)) + zlog_debug("LSA: freed %p", (void *)lsa); - /* Delete LSA data. */ - if (lsa->data != NULL) - ospf_lsa_data_free (lsa->data); + /* Delete LSA data. */ + if (lsa->data != NULL) + ospf_lsa_data_free(lsa->data); - assert (lsa->refresh_list < 0); + assert(lsa->refresh_list < 0); - memset (lsa, 0, sizeof (struct ospf_lsa)); - XFREE (MTYPE_OSPF_LSA, lsa); + memset(lsa, 0, sizeof(struct ospf_lsa)); + XFREE(MTYPE_OSPF_LSA, lsa); } /* Lock LSA. */ -struct ospf_lsa * -ospf_lsa_lock (struct ospf_lsa *lsa) +struct ospf_lsa *ospf_lsa_lock(struct ospf_lsa *lsa) { - lsa->lock++; - return lsa; + lsa->lock++; + return lsa; } /* Unlock LSA. */ -void -ospf_lsa_unlock (struct ospf_lsa **lsa) +void ospf_lsa_unlock(struct ospf_lsa **lsa) { - /* This is sanity check. */ - if (!lsa || !*lsa) - return; - - (*lsa)->lock--; + /* This is sanity check. */ + if (!lsa || !*lsa) + return; - assert ((*lsa)->lock >= 0); + (*lsa)->lock--; - if ((*lsa)->lock == 0) - { - assert (CHECK_FLAG ((*lsa)->flags, OSPF_LSA_DISCARD)); - ospf_lsa_free (*lsa); - *lsa = NULL; - } + assert((*lsa)->lock >= 0); + + if ((*lsa)->lock == 0) { + assert(CHECK_FLAG((*lsa)->flags, OSPF_LSA_DISCARD)); + ospf_lsa_free(*lsa); + *lsa = NULL; + } } /* Check discard flag. */ -void -ospf_lsa_discard (struct ospf_lsa *lsa) +void ospf_lsa_discard(struct ospf_lsa *lsa) { - if (!CHECK_FLAG (lsa->flags, OSPF_LSA_DISCARD)) - { - SET_FLAG (lsa->flags, OSPF_LSA_DISCARD); - ospf_lsa_unlock (&lsa); - } + if (!CHECK_FLAG(lsa->flags, OSPF_LSA_DISCARD)) { + SET_FLAG(lsa->flags, OSPF_LSA_DISCARD); + ospf_lsa_unlock(&lsa); + } } /* Create LSA data. */ -struct lsa_header * -ospf_lsa_data_new (size_t size) +struct lsa_header *ospf_lsa_data_new(size_t size) { - return XCALLOC (MTYPE_OSPF_LSA_DATA, size); + return XCALLOC(MTYPE_OSPF_LSA_DATA, size); } /* Duplicate LSA data. */ -struct lsa_header * -ospf_lsa_data_dup (struct lsa_header *lsah) +struct lsa_header *ospf_lsa_data_dup(struct lsa_header *lsah) { - struct lsa_header *new; + struct lsa_header *new; - new = ospf_lsa_data_new (ntohs (lsah->length)); - memcpy (new, lsah, ntohs (lsah->length)); + new = ospf_lsa_data_new(ntohs(lsah->length)); + memcpy(new, lsah, ntohs(lsah->length)); - return new; + return new; } /* Free LSA data. */ -void -ospf_lsa_data_free (struct lsa_header *lsah) +void ospf_lsa_data_free(struct lsa_header *lsah) { - if (IS_DEBUG_OSPF (lsa, LSA)) - zlog_debug ("LSA[Type%d:%s]: data freed %p", - lsah->type, inet_ntoa (lsah->id), (void *)lsah); + if (IS_DEBUG_OSPF(lsa, LSA)) + zlog_debug("LSA[Type%d:%s]: data freed %p", lsah->type, + inet_ntoa(lsah->id), (void *)lsah); - XFREE (MTYPE_OSPF_LSA_DATA, lsah); + XFREE(MTYPE_OSPF_LSA_DATA, lsah); } /* LSA general functions. */ -const char * -dump_lsa_key (struct ospf_lsa *lsa) +const char *dump_lsa_key(struct ospf_lsa *lsa) { - static char buf[] = { - "Type255,id(255.255.255.255),ar(255.255.255.255)" - }; - struct lsa_header *lsah; + static char buf[] = {"Type255,id(255.255.255.255),ar(255.255.255.255)"}; + struct lsa_header *lsah; - if (lsa != NULL && (lsah = lsa->data) != NULL) - { - char id[INET_ADDRSTRLEN], ar[INET_ADDRSTRLEN]; - strcpy (id, inet_ntoa (lsah->id)); - strcpy (ar, inet_ntoa (lsah->adv_router)); + if (lsa != NULL && (lsah = lsa->data) != NULL) { + char id[INET_ADDRSTRLEN], ar[INET_ADDRSTRLEN]; + strcpy(id, inet_ntoa(lsah->id)); + strcpy(ar, inet_ntoa(lsah->adv_router)); - sprintf (buf, "Type%d,id(%s),ar(%s)", lsah->type, id, ar); - } - else - strcpy (buf, "NULL"); + sprintf(buf, "Type%d,id(%s),ar(%s)", lsah->type, id, ar); + } else + strcpy(buf, "NULL"); - return buf; + return buf; } -u_int32_t -lsa_seqnum_increment (struct ospf_lsa *lsa) +u_int32_t lsa_seqnum_increment(struct ospf_lsa *lsa) { - u_int32_t seqnum; + u_int32_t seqnum; - seqnum = ntohl (lsa->data->ls_seqnum) + 1; + seqnum = ntohl(lsa->data->ls_seqnum) + 1; - return htonl (seqnum); + return htonl(seqnum); } -void -lsa_header_set (struct stream *s, u_char options, - u_char type, struct in_addr id, struct in_addr router_id) +void lsa_header_set(struct stream *s, u_char options, u_char type, + struct in_addr id, struct in_addr router_id) { - struct lsa_header *lsah; + struct lsa_header *lsah; - lsah = (struct lsa_header *) STREAM_DATA (s); + lsah = (struct lsa_header *)STREAM_DATA(s); - lsah->ls_age = htons (OSPF_LSA_INITIAL_AGE); - lsah->options = options; - lsah->type = type; - lsah->id = id; - lsah->adv_router = router_id; - lsah->ls_seqnum = htonl (OSPF_INITIAL_SEQUENCE_NUMBER); + lsah->ls_age = htons(OSPF_LSA_INITIAL_AGE); + lsah->options = options; + lsah->type = type; + lsah->id = id; + lsah->adv_router = router_id; + lsah->ls_seqnum = htonl(OSPF_INITIAL_SEQUENCE_NUMBER); - stream_forward_endp (s, OSPF_LSA_HEADER_SIZE); + stream_forward_endp(s, OSPF_LSA_HEADER_SIZE); } /* router-LSA related functions. */ /* Get router-LSA flags. */ -static u_char -router_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 && - area->ospf->backbone == NULL) || - area->shortcut_configured == OSPF_SHORTCUT_ENABLE) - SET_FLAG (flags, ROUTER_LSA_SHORTCUT); - - /* 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; +static u_char router_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 + && area->ospf->backbone == NULL) + || area->shortcut_configured + == OSPF_SHORTCUT_ENABLE) + SET_FLAG(flags, ROUTER_LSA_SHORTCUT); + + /* 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 *ospf_nbr_lookup_ptop(struct ospf_interface *oi) { - struct ospf_neighbor *nbr = NULL; - struct route_node *rn; + 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; - } + /* 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."); + /* 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; + return nbr; } /* Determine cost of link, taking RFC3137 stub-router support into * consideration */ -static u_int16_t -ospf_link_cost (struct ospf_interface *oi) +static u_int16_t ospf_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; + /* 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 char -link_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; +static char link_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; } /* Describe Point-to-Point link (Section 12.4.1.1). */ -static int -lsa_link_ptop_set (struct stream *s, struct ospf_interface *oi) -{ - int links = 0; - struct ospf_neighbor *nbr; - struct in_addr id, mask, data; - u_int16_t cost = ospf_link_cost (oi); - - 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) - { - if (CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED)) - { - /* For unnumbered point-to-point networks, the Link Data field - should specify the interface's MIB-II ifIndex value. */ - data.s_addr = htonl(oi->ifp->ifindex); - links += link_info_set (s, nbr->router_id, data, - LSA_LINK_TYPE_POINTOPOINT, 0, cost); - } - else - { - links += link_info_set (s, nbr->router_id, - oi->address->u.prefix4, - LSA_LINK_TYPE_POINTOPOINT, 0, cost); - } - } - - /* no need for a stub link for unnumbered interfaces */ - if (!CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED)) - { - /* 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, - oi->output_cost); - } - - return links; +static int lsa_link_ptop_set(struct stream *s, struct ospf_interface *oi) +{ + int links = 0; + struct ospf_neighbor *nbr; + struct in_addr id, mask, data; + u_int16_t cost = ospf_link_cost(oi); + + 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) { + if (CHECK_FLAG(oi->connected->flags, + ZEBRA_IFA_UNNUMBERED)) { + /* For unnumbered point-to-point networks, the + Link Data field + should specify the interface's MIB-II ifIndex + value. */ + data.s_addr = htonl(oi->ifp->ifindex); + links += link_info_set( + s, nbr->router_id, data, + LSA_LINK_TYPE_POINTOPOINT, 0, cost); + } else { + links += link_info_set( + s, nbr->router_id, + oi->address->u.prefix4, + LSA_LINK_TYPE_POINTOPOINT, 0, cost); + } + } + + /* no need for a stub link for unnumbered interfaces */ + if (!CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED)) { + /* 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, + oi->output_cost); + } + + return links; } /* Describe Broadcast Link. */ -static int -lsa_link_broadcast_set (struct stream *s, struct ospf_interface *oi) -{ - struct ospf_neighbor *dr; - struct in_addr id, mask; - u_int16_t cost = ospf_link_cost (oi); - - /* Describe Type 3 Link. */ - if (oi->state == ISM_Waiting) - { - if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) - zlog_debug ("LSA[Type1]: Interface %s is in state Waiting. " - "Adding stub interface", oi->ifp->name); - masklen2ip (oi->address->prefixlen, &mask); - id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr; - return link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, - oi->output_cost); - } - - dr = ospf_nbr_lookup_by_addr (oi->nbrs, &DR (oi)); - /* Describe Type 2 link. */ - if (dr && (dr->state == NSM_Full || - IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi))) && - ospf_nbr_count (oi, NSM_Full) > 0) - { - if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) - zlog_debug ("LSA[Type1]: Interface %s has a DR. " - "Adding transit interface", oi->ifp->name); - return link_info_set (s, DR (oi), oi->address->u.prefix4, - LSA_LINK_TYPE_TRANSIT, 0, cost); - } - /* Describe type 3 link. */ - else - { - if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) - zlog_debug ("LSA[Type1]: Interface %s has no DR. " - "Adding stub interface", oi->ifp->name); - masklen2ip (oi->address->prefixlen, &mask); - id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr; - return link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, - oi->output_cost); - } -} - -static int -lsa_link_loopback_set (struct stream *s, struct ospf_interface *oi) -{ - struct in_addr id, mask; - - /* Describe Type 3 Link. */ - if (oi->state != ISM_Loopback) - return 0; - - mask.s_addr = 0xffffffff; - id.s_addr = oi->address->u.prefix4.s_addr; - return link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, 0); +static int lsa_link_broadcast_set(struct stream *s, struct ospf_interface *oi) +{ + struct ospf_neighbor *dr; + struct in_addr id, mask; + u_int16_t cost = ospf_link_cost(oi); + + /* Describe Type 3 Link. */ + if (oi->state == ISM_Waiting) { + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) + zlog_debug( + "LSA[Type1]: Interface %s is in state Waiting. " + "Adding stub interface", + oi->ifp->name); + masklen2ip(oi->address->prefixlen, &mask); + id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr; + return link_info_set(s, id, mask, LSA_LINK_TYPE_STUB, 0, + oi->output_cost); + } + + dr = ospf_nbr_lookup_by_addr(oi->nbrs, &DR(oi)); + /* Describe Type 2 link. */ + if (dr && (dr->state == NSM_Full + || IPV4_ADDR_SAME(&oi->address->u.prefix4, &DR(oi))) + && ospf_nbr_count(oi, NSM_Full) > 0) { + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) + zlog_debug( + "LSA[Type1]: Interface %s has a DR. " + "Adding transit interface", + oi->ifp->name); + return link_info_set(s, DR(oi), oi->address->u.prefix4, + LSA_LINK_TYPE_TRANSIT, 0, cost); + } + /* Describe type 3 link. */ + else { + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) + zlog_debug( + "LSA[Type1]: Interface %s has no DR. " + "Adding stub interface", + oi->ifp->name); + masklen2ip(oi->address->prefixlen, &mask); + id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr; + return link_info_set(s, id, mask, LSA_LINK_TYPE_STUB, 0, + oi->output_cost); + } +} + +static int lsa_link_loopback_set(struct stream *s, struct ospf_interface *oi) +{ + struct in_addr id, mask; + + /* Describe Type 3 Link. */ + if (oi->state != ISM_Loopback) + return 0; + + mask.s_addr = 0xffffffff; + id.s_addr = oi->address->u.prefix4.s_addr; + return link_info_set(s, id, mask, LSA_LINK_TYPE_STUB, 0, 0); } /* Describe Virtual Link. */ -static int -lsa_link_virtuallink_set (struct stream *s, struct ospf_interface *oi) +static int lsa_link_virtuallink_set(struct stream *s, struct ospf_interface *oi) { - struct ospf_neighbor *nbr; - u_int16_t cost = ospf_link_cost (oi); + struct ospf_neighbor *nbr; + u_int16_t cost = ospf_link_cost(oi); - if (oi->state == ISM_PointToPoint) - if ((nbr = ospf_nbr_lookup_ptop (oi))) - if (nbr->state == NSM_Full) - { - return link_info_set (s, nbr->router_id, oi->address->u.prefix4, - LSA_LINK_TYPE_VIRTUALLINK, 0, cost); - } + if (oi->state == ISM_PointToPoint) + if ((nbr = ospf_nbr_lookup_ptop(oi))) + if (nbr->state == NSM_Full) { + return link_info_set(s, nbr->router_id, + oi->address->u.prefix4, + LSA_LINK_TYPE_VIRTUALLINK, + 0, cost); + } - return 0; + return 0; } #define lsa_link_nbma_set(S,O) lsa_link_broadcast_set (S, O) -/* this function add for support point-to-multipoint ,see rfc2328 +/* this function add for support point-to-multipoint ,see rfc2328 12.4.1.4.*/ /* from "edward rrr" <edward_rrr@hotmail.com> http://marc.theaimsgroup.com/?l=zebra&m=100739222210507&w=2 */ -static int -lsa_link_ptomp_set (struct stream *s, struct ospf_interface *oi) -{ - int links = 0; - struct route_node *rn; - struct ospf_neighbor *nbr = NULL; - struct in_addr id, mask; - u_int16_t cost = ospf_link_cost (oi); - - mask.s_addr = 0xffffffff; - id.s_addr = oi->address->u.prefix4.s_addr; - links += link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, 0); - - if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) - zlog_debug ("PointToMultipoint: running ptomultip_set"); - - /* Search neighbor, */ - for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) - if ((nbr = rn->info) != NULL) - /* Ignore myself. */ - if (!IPV4_ADDR_SAME (&nbr->router_id, &oi->ospf->router_id)) - if (nbr->state == NSM_Full) - - { - links += link_info_set (s, nbr->router_id, oi->address->u.prefix4, - LSA_LINK_TYPE_POINTOPOINT, 0, cost); - if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) - zlog_debug ("PointToMultipoint: set link to %s", - inet_ntoa(oi->address->u.prefix4)); - } - - return links; +static int lsa_link_ptomp_set(struct stream *s, struct ospf_interface *oi) +{ + int links = 0; + struct route_node *rn; + struct ospf_neighbor *nbr = NULL; + struct in_addr id, mask; + u_int16_t cost = ospf_link_cost(oi); + + mask.s_addr = 0xffffffff; + id.s_addr = oi->address->u.prefix4.s_addr; + links += link_info_set(s, id, mask, LSA_LINK_TYPE_STUB, 0, 0); + + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) + zlog_debug("PointToMultipoint: running ptomultip_set"); + + /* Search neighbor, */ + for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) + if ((nbr = rn->info) != NULL) + /* Ignore myself. */ + if (!IPV4_ADDR_SAME(&nbr->router_id, + &oi->ospf->router_id)) + if (nbr->state == NSM_Full) + + { + links += link_info_set( + s, nbr->router_id, + oi->address->u.prefix4, + LSA_LINK_TYPE_POINTOPOINT, 0, + cost); + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) + zlog_debug( + "PointToMultipoint: set link to %s", + inet_ntoa( + oi->address->u + .prefix4)); + } + + return links; } /* Set router-LSA link information. */ -static int -router_lsa_link_set (struct stream *s, struct ospf_area *area) -{ - struct listnode *node; - struct ospf_interface *oi; - int links = 0; - - for (ALL_LIST_ELEMENTS_RO (area->oiflist, node, oi)) - { - struct interface *ifp = oi->ifp; - - /* Check interface is up, OSPF is enable. */ - if (if_is_operative (ifp)) - { - if (oi->state != ISM_Down) - { - oi->lsa_pos_beg = links; - /* Describe each link. */ - switch (oi->type) - { - case OSPF_IFTYPE_POINTOPOINT: - links += lsa_link_ptop_set (s, oi); - break; - case OSPF_IFTYPE_BROADCAST: - links += lsa_link_broadcast_set (s, oi); - break; - case OSPF_IFTYPE_NBMA: - links += lsa_link_nbma_set (s, oi); - break; - case OSPF_IFTYPE_POINTOMULTIPOINT: - links += lsa_link_ptomp_set (s, oi); - break; - case OSPF_IFTYPE_VIRTUALLINK: - links += lsa_link_virtuallink_set (s, oi); - break; - case OSPF_IFTYPE_LOOPBACK: - links += lsa_link_loopback_set (s, oi); +static int router_lsa_link_set(struct stream *s, struct ospf_area *area) +{ + struct listnode *node; + struct ospf_interface *oi; + int links = 0; + + for (ALL_LIST_ELEMENTS_RO(area->oiflist, node, oi)) { + struct interface *ifp = oi->ifp; + + /* Check interface is up, OSPF is enable. */ + if (if_is_operative(ifp)) { + if (oi->state != ISM_Down) { + oi->lsa_pos_beg = links; + /* Describe each link. */ + switch (oi->type) { + case OSPF_IFTYPE_POINTOPOINT: + links += lsa_link_ptop_set(s, oi); + break; + case OSPF_IFTYPE_BROADCAST: + links += lsa_link_broadcast_set(s, oi); + break; + case OSPF_IFTYPE_NBMA: + links += lsa_link_nbma_set(s, oi); + break; + case OSPF_IFTYPE_POINTOMULTIPOINT: + links += lsa_link_ptomp_set(s, oi); + break; + case OSPF_IFTYPE_VIRTUALLINK: + links += + lsa_link_virtuallink_set(s, oi); + break; + case OSPF_IFTYPE_LOOPBACK: + links += lsa_link_loopback_set(s, oi); + } + oi->lsa_pos_end = links; + } } - oi->lsa_pos_end = links; - } } - } - return links; + return links; } /* Set router-LSA body. */ -static void -ospf_router_lsa_body_set (struct stream *s, struct ospf_area *area) -{ - unsigned long putp; - u_int16_t cnt; - - /* Set flags. */ - stream_putc (s, router_lsa_flags (area)); - - /* Set Zero fields. */ - stream_putc (s, 0); - - /* Keep pointer to # links. */ - putp = stream_get_endp(s); - - /* Forward word */ - stream_putw(s, 0); - - /* Set all link information. */ - cnt = router_lsa_link_set (s, area); - - /* Set # of links here. */ - stream_putw_at (s, putp, cnt); -} - -static int -ospf_stub_router_timer (struct thread *t) -{ - struct ospf_area *area = THREAD_ARG (t); - - area->t_stub_router = NULL; - - SET_FLAG (area->stub_router_state, OSPF_AREA_WAS_START_STUB_ROUTED); - - /* clear stub route state and generate router-lsa refresh, don't - * clobber an administratively set stub-router state though. - */ - if (CHECK_FLAG (area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED)) - return 0; - - UNSET_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED); - - ospf_router_lsa_update_area (area); - - return 0; -} - -static void -ospf_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); -} - +static void ospf_router_lsa_body_set(struct stream *s, struct ospf_area *area) +{ + unsigned long putp; + u_int16_t cnt; + + /* Set flags. */ + stream_putc(s, router_lsa_flags(area)); + + /* Set Zero fields. */ + stream_putc(s, 0); + + /* Keep pointer to # links. */ + putp = stream_get_endp(s); + + /* Forward word */ + stream_putw(s, 0); + + /* Set all link information. */ + cnt = router_lsa_link_set(s, area); + + /* Set # of links here. */ + stream_putw_at(s, putp, cnt); +} + +static int ospf_stub_router_timer(struct thread *t) +{ + struct ospf_area *area = THREAD_ARG(t); + + area->t_stub_router = NULL; + + SET_FLAG(area->stub_router_state, OSPF_AREA_WAS_START_STUB_ROUTED); + + /* clear stub route state and generate router-lsa refresh, don't + * clobber an administratively set stub-router state though. + */ + if (CHECK_FLAG(area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED)) + return 0; + + UNSET_FLAG(area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED); + + ospf_router_lsa_update_area(area); + + return 0; +} + +static void ospf_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; - - if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) - zlog_debug ("LSA[Type1]: Create router-LSA instance"); - - /* 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), - OSPF_ROUTER_LSA, ospf->router_id, ospf->router_id); - - /* Set router-LSA body fields. */ - ospf_router_lsa_body_set (s, area); - - /* Set length. */ - length = stream_get_endp (s); - lsah = (struct lsa_header *) STREAM_DATA (s); - lsah->length = htons (length); - - /* Now, create OSPF LSA instance. */ - if ( (new = ospf_lsa_new ()) == NULL) - { - zlog_err ("%s: Unable to create new lsa", __func__); - return NULL; - } - - new->area = area; - SET_FLAG (new->flags, OSPF_LSA_SELF | OSPF_LSA_SELF_CHECKED); - - /* Copy LSA data to store, discard stream. */ - new->data = ospf_lsa_data_new (length); - memcpy (new->data, lsah, length); - stream_free (s); - - return new; +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; + + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) + zlog_debug("LSA[Type1]: Create router-LSA instance"); + + /* 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), + OSPF_ROUTER_LSA, ospf->router_id, ospf->router_id); + + /* Set router-LSA body fields. */ + ospf_router_lsa_body_set(s, area); + + /* Set length. */ + length = stream_get_endp(s); + lsah = (struct lsa_header *)STREAM_DATA(s); + lsah->length = htons(length); + + /* Now, create OSPF LSA instance. */ + if ((new = ospf_lsa_new()) == NULL) { + zlog_err("%s: Unable to create new lsa", __func__); + return NULL; + } + + new->area = area; + SET_FLAG(new->flags, OSPF_LSA_SELF | OSPF_LSA_SELF_CHECKED); + + /* Copy LSA data to store, discard stream. */ + new->data = ospf_lsa_data_new(length); + memcpy(new->data, lsah, length); + stream_free(s); + + return new; } /* Originate Router-LSA. */ -static struct ospf_lsa * -ospf_router_lsa_originate (struct ospf_area *area) +static struct ospf_lsa *ospf_router_lsa_originate(struct ospf_area *area) { - struct ospf_lsa *new; - - /* Create new router-LSA instance. */ - if ( (new = ospf_router_lsa_new (area)) == NULL) - { - zlog_err ("%s: ospf_router_lsa_new returned NULL", __func__); - return NULL; - } + struct ospf_lsa *new; - /* Sanity check. */ - if (new->data->adv_router.s_addr == 0) - { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("LSA[Type1]: AdvRouter is 0, discard"); - ospf_lsa_discard (new); - return NULL; - } + /* Create new router-LSA instance. */ + if ((new = ospf_router_lsa_new(area)) == NULL) { + zlog_err("%s: ospf_router_lsa_new returned NULL", __func__); + return NULL; + } + + /* Sanity check. */ + if (new->data->adv_router.s_addr == 0) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("LSA[Type1]: AdvRouter is 0, discard"); + ospf_lsa_discard(new); + return NULL; + } - /* Install LSA to LSDB. */ - new = ospf_lsa_install (area->ospf, NULL, new); + /* Install LSA to LSDB. */ + new = ospf_lsa_install(area->ospf, NULL, new); - /* Update LSA origination count. */ - area->ospf->lsa_originate_count++; + /* Update LSA origination count. */ + area->ospf->lsa_originate_count++; - /* Flooding new LSA through area. */ - ospf_flood_through_area (area, NULL, new); + /* 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 router-LSA %p", - new->data->type, inet_ntoa (new->data->id), (void *)new); - ospf_lsa_header_dump (new->data); - } + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) { + zlog_debug("LSA[Type%d:%s]: Originate router-LSA %p", + new->data->type, inet_ntoa(new->data->id), + (void *)new); + ospf_lsa_header_dump(new->data); + } - return new; + return new; } /* Refresh router-LSA. */ -static struct ospf_lsa * -ospf_router_lsa_refresh (struct ospf_lsa *lsa) -{ - struct ospf_area *area = lsa->area; - struct ospf_lsa *new; - - /* Sanity check. */ - assert (lsa->data); +static struct ospf_lsa *ospf_router_lsa_refresh(struct ospf_lsa *lsa) +{ + struct ospf_area *area = lsa->area; + struct ospf_lsa *new; + + /* Sanity check. */ + assert(lsa->data); - /* Delete LSA from neighbor retransmit-list. */ - ospf_ls_retransmit_delete_nbr_area (area, lsa); + /* Delete LSA from neighbor retransmit-list. */ + ospf_ls_retransmit_delete_nbr_area(area, lsa); - /* Unregister LSA from refresh-list */ - ospf_refresher_unregister_lsa (area->ospf, lsa); - - /* Create new router-LSA instance. */ - if ( (new = ospf_router_lsa_new (area)) == NULL) - { - zlog_err ("%s: ospf_router_lsa_new returned NULL", __func__); - return NULL; - } - - new->data->ls_seqnum = lsa_seqnum_increment (lsa); + /* Unregister LSA from refresh-list */ + ospf_refresher_unregister_lsa(area->ospf, lsa); - ospf_lsa_install (area->ospf, NULL, new); + /* Create new router-LSA instance. */ + if ((new = ospf_router_lsa_new(area)) == NULL) { + zlog_err("%s: ospf_router_lsa_new returned NULL", __func__); + return NULL; + } + + new->data->ls_seqnum = lsa_seqnum_increment(lsa); - /* Flood LSA through area. */ - ospf_flood_through_area (area, NULL, new); + ospf_lsa_install(area->ospf, NULL, new); - /* Debug logging. */ - if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) - { - zlog_debug ("LSA[Type%d:%s]: router-LSA refresh", - new->data->type, inet_ntoa (new->data->id)); - ospf_lsa_header_dump (new->data); - } + /* Flood LSA through area. */ + ospf_flood_through_area(area, NULL, new); + + /* Debug logging. */ + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) { + zlog_debug("LSA[Type%d:%s]: router-LSA refresh", + new->data->type, inet_ntoa(new->data->id)); + ospf_lsa_header_dump(new->data); + } - return NULL; + return NULL; } -int -ospf_router_lsa_update_area (struct ospf_area *area) +int ospf_router_lsa_update_area(struct ospf_area *area) { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("[router-LSA]: (router-LSA area update)"); + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("[router-LSA]: (router-LSA area update)"); - /* Now refresh router-LSA. */ - if (area->router_lsa_self) - ospf_lsa_refresh (area->ospf, area->router_lsa_self); - /* Newly originate router-LSA. */ - else - ospf_router_lsa_originate (area); + /* Now refresh router-LSA. */ + if (area->router_lsa_self) + ospf_lsa_refresh(area->ospf, area->router_lsa_self); + /* Newly originate router-LSA. */ + else + ospf_router_lsa_originate(area); - return 0; + return 0; } -int -ospf_router_lsa_update (struct ospf *ospf) +int ospf_router_lsa_update(struct ospf *ospf) { - struct listnode *node, *nnode; - struct ospf_area *area; + struct listnode *node, *nnode; + struct ospf_area *area; - if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) - zlog_debug ("Timer[router-LSA Update]: (timer expire)"); + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) + zlog_debug("Timer[router-LSA Update]: (timer expire)"); - for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) - { - struct ospf_lsa *lsa = area->router_lsa_self; - struct router_lsa *rl; - const char *area_str; + for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) { + struct ospf_lsa *lsa = area->router_lsa_self; + struct router_lsa *rl; + const char *area_str; - /* Keep Area ID string. */ - area_str = AREA_NAME (area); + /* Keep Area ID string. */ + area_str = AREA_NAME(area); - /* If LSA not exist in this Area, originate new. */ - if (lsa == NULL) - { - if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) - zlog_debug("LSA[Type1]: Create router-LSA for Area %s", area_str); + /* If LSA not exist in this Area, originate new. */ + if (lsa == NULL) { + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) + zlog_debug( + "LSA[Type1]: Create router-LSA for Area %s", + area_str); - ospf_router_lsa_originate (area); - } - /* If router-ID is changed, Link ID must change. - First flush old LSA, then originate new. */ - else if (!IPV4_ADDR_SAME (&lsa->data->id, &ospf->router_id)) - { - if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) - zlog_debug("LSA[Type%d:%s]: Refresh router-LSA for Area %s", - lsa->data->type, inet_ntoa (lsa->data->id), area_str); - ospf_refresher_unregister_lsa (ospf, lsa); - ospf_lsa_flush_area (lsa, area); - ospf_lsa_unlock (&area->router_lsa_self); - area->router_lsa_self = NULL; - - /* Refresh router-LSA, (not install) and flood through area. */ - ospf_router_lsa_update_area (area); - } - else - { - rl = (struct router_lsa *) lsa->data; - /* Refresh router-LSA, (not install) and flood through area. */ - if (rl->flags != ospf->flags) - ospf_router_lsa_update_area (area); + ospf_router_lsa_originate(area); + } + /* If router-ID is changed, Link ID must change. + First flush old LSA, then originate new. */ + else if (!IPV4_ADDR_SAME(&lsa->data->id, &ospf->router_id)) { + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) + zlog_debug( + "LSA[Type%d:%s]: Refresh router-LSA for Area %s", + lsa->data->type, + inet_ntoa(lsa->data->id), area_str); + ospf_refresher_unregister_lsa(ospf, lsa); + ospf_lsa_flush_area(lsa, area); + ospf_lsa_unlock(&area->router_lsa_self); + area->router_lsa_self = NULL; + + /* Refresh router-LSA, (not install) and flood through + * area. */ + ospf_router_lsa_update_area(area); + } else { + rl = (struct router_lsa *)lsa->data; + /* Refresh router-LSA, (not install) and flood through + * area. */ + if (rl->flags != ospf->flags) + ospf_router_lsa_update_area(area); + } } - } - return 0; + return 0; } /* network-LSA related functions. */ /* Originate Network-LSA. */ -static void -ospf_network_lsa_body_set (struct stream *s, struct ospf_interface *oi) +static void ospf_network_lsa_body_set(struct stream *s, + struct ospf_interface *oi) { - struct in_addr mask; - struct route_node *rn; - struct ospf_neighbor *nbr; + struct in_addr mask; + struct route_node *rn; + struct ospf_neighbor *nbr; - masklen2ip (oi->address->prefixlen, &mask); - stream_put_ipv4 (s, mask.s_addr); + masklen2ip(oi->address->prefixlen, &mask); + stream_put_ipv4(s, mask.s_addr); - /* 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 */ + /* 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) - stream_put_ipv4 (s, nbr->router_id.s_addr); + 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) + stream_put_ipv4(s, nbr->router_id.s_addr); } -static struct ospf_lsa * -ospf_network_lsa_new (struct ospf_interface *oi) -{ - struct stream *s; - struct ospf_lsa *new; - struct lsa_header *lsah; - struct ospf_if_params *oip; - int length; - - /* 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)) - zlog_debug ("LSA[Type2]: Create network-LSA instance"); - - /* Create new stream for LSA. */ - s = stream_new (OSPF_MAX_LSA_SIZE); - lsah = (struct lsa_header *) STREAM_DATA (s); - - lsa_header_set (s, (OPTIONS (oi) | LSA_OPTIONS_GET (oi->area)), - OSPF_NETWORK_LSA, DR (oi), oi->ospf->router_id); - - /* Set network-LSA body fields. */ - ospf_network_lsa_body_set (s, oi); - - /* Set length. */ - length = stream_get_endp (s); - lsah->length = htons (length); - - /* Create OSPF LSA instance. */ - if ( (new = ospf_lsa_new ()) == NULL) - { - zlog_err ("%s: ospf_lsa_new returned NULL", __func__); - return NULL; - } - - new->area = oi->area; - SET_FLAG (new->flags, OSPF_LSA_SELF | OSPF_LSA_SELF_CHECKED); - - /* Copy LSA to store. */ - new->data = ospf_lsa_data_new (length); - memcpy (new->data, lsah, length); - stream_free (s); - - /* Remember prior network LSA sequence numbers, even if we stop - * originating one for this oi, to try avoid re-originating LSAs with a - * prior sequence number, and thus speed up adjency forming & convergence. - */ - if ((oip = ospf_lookup_if_params (oi->ifp, oi->address->u.prefix4))) - { - new->data->ls_seqnum = oip->network_lsa_seqnum; - new->data->ls_seqnum = lsa_seqnum_increment (new); - } - else - { - oip = ospf_get_if_params (oi->ifp, oi->address->u.prefix4); - ospf_if_update_params (oi->ifp, oi->address->u.prefix4); - } - oip->network_lsa_seqnum = new->data->ls_seqnum; - - return new; +static struct ospf_lsa *ospf_network_lsa_new(struct ospf_interface *oi) +{ + struct stream *s; + struct ospf_lsa *new; + struct lsa_header *lsah; + struct ospf_if_params *oip; + int length; + + /* 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)) + zlog_debug("LSA[Type2]: Create network-LSA instance"); + + /* Create new stream for LSA. */ + s = stream_new(OSPF_MAX_LSA_SIZE); + lsah = (struct lsa_header *)STREAM_DATA(s); + + lsa_header_set(s, (OPTIONS(oi) | LSA_OPTIONS_GET(oi->area)), + OSPF_NETWORK_LSA, DR(oi), oi->ospf->router_id); + + /* Set network-LSA body fields. */ + ospf_network_lsa_body_set(s, oi); + + /* Set length. */ + length = stream_get_endp(s); + lsah->length = htons(length); + + /* Create OSPF LSA instance. */ + if ((new = ospf_lsa_new()) == NULL) { + zlog_err("%s: ospf_lsa_new returned NULL", __func__); + return NULL; + } + + new->area = oi->area; + SET_FLAG(new->flags, OSPF_LSA_SELF | OSPF_LSA_SELF_CHECKED); + + /* Copy LSA to store. */ + new->data = ospf_lsa_data_new(length); + memcpy(new->data, lsah, length); + stream_free(s); + + /* Remember prior network LSA sequence numbers, even if we stop + * originating one for this oi, to try avoid re-originating LSAs with a + * prior sequence number, and thus speed up adjency forming & + * convergence. + */ + if ((oip = ospf_lookup_if_params(oi->ifp, oi->address->u.prefix4))) { + new->data->ls_seqnum = oip->network_lsa_seqnum; + new->data->ls_seqnum = lsa_seqnum_increment(new); + } else { + oip = ospf_get_if_params(oi->ifp, oi->address->u.prefix4); + ospf_if_update_params(oi->ifp, oi->address->u.prefix4); + } + oip->network_lsa_seqnum = new->data->ls_seqnum; + + return new; } /* Originate network-LSA. */ -void -ospf_network_lsa_update (struct ospf_interface *oi) +void ospf_network_lsa_update(struct ospf_interface *oi) { - struct ospf_lsa *new; - - if (oi->network_lsa_self != NULL) - { - ospf_lsa_refresh (oi->ospf, oi->network_lsa_self); - return; - } - - /* Create new network-LSA instance. */ - new = ospf_network_lsa_new (oi); - if (new == NULL) - return; + struct ospf_lsa *new; - /* Install LSA to LSDB. */ - new = ospf_lsa_install (oi->ospf, oi, new); + if (oi->network_lsa_self != NULL) { + ospf_lsa_refresh(oi->ospf, oi->network_lsa_self); + return; + } + + /* Create new network-LSA instance. */ + new = ospf_network_lsa_new(oi); + if (new == NULL) + return; - /* Update LSA origination count. */ - oi->ospf->lsa_originate_count++; + /* Install LSA to LSDB. */ + new = ospf_lsa_install(oi->ospf, oi, new); - /* Flooding new LSA through area. */ - ospf_flood_through_area (oi->area, NULL, new); + /* Update LSA origination count. */ + oi->ospf->lsa_originate_count++; - if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) - { - zlog_debug ("LSA[Type%d:%s]: Originate network-LSA %p", - new->data->type, inet_ntoa (new->data->id), (void *)new); - ospf_lsa_header_dump (new->data); - } + /* Flooding new LSA through area. */ + ospf_flood_through_area(oi->area, NULL, new); + + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) { + zlog_debug("LSA[Type%d:%s]: Originate network-LSA %p", + new->data->type, inet_ntoa(new->data->id), + (void *)new); + ospf_lsa_header_dump(new->data); + } - return; + return; } -static struct ospf_lsa * -ospf_network_lsa_refresh (struct ospf_lsa *lsa) -{ - struct ospf_area *area = lsa->area; - struct ospf_lsa *new, *new2; - struct ospf_if_params *oip; - struct ospf_interface *oi; - - assert (lsa->data); - - /* Retrieve the oi for the network LSA */ - oi = ospf_if_lookup_by_local_addr (area->ospf, NULL, lsa->data->id); - if (oi == NULL) - { - if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) - { - zlog_debug ("LSA[Type%d:%s]: network-LSA refresh: " - "no oi found, ick, ignoring.", - lsa->data->type, inet_ntoa (lsa->data->id)); - ospf_lsa_header_dump (lsa->data); - } - return NULL; - } - /* Delete LSA from neighbor retransmit-list. */ - ospf_ls_retransmit_delete_nbr_area (area, lsa); - - /* Unregister LSA from refresh-list */ - ospf_refresher_unregister_lsa (area->ospf, lsa); - - /* Create new network-LSA instance. */ - new = ospf_network_lsa_new (oi); - if (new == NULL) - return NULL; - - oip = ospf_lookup_if_params (oi->ifp, oi->address->u.prefix4); - assert (oip != NULL); - oip->network_lsa_seqnum = new->data->ls_seqnum = lsa_seqnum_increment (lsa); - - new2 = ospf_lsa_install (area->ospf, oi, new); - - assert (new2 == new); - - /* Flood LSA through aera. */ - ospf_flood_through_area (area, NULL, new); - - if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) - { - zlog_debug ("LSA[Type%d:%s]: network-LSA refresh", - new->data->type, inet_ntoa (new->data->id)); - ospf_lsa_header_dump (new->data); - } - - return new; -} - -static void -stream_put_ospf_metric (struct stream *s, u_int32_t metric_value) -{ - u_int32_t metric; - char *mp; - - /* Put 0 metric. TOS metric is not supported. */ - metric = htonl (metric_value); - mp = (char *) &metric; - mp++; - stream_put (s, mp, 3); +static struct ospf_lsa *ospf_network_lsa_refresh(struct ospf_lsa *lsa) +{ + struct ospf_area *area = lsa->area; + struct ospf_lsa *new, *new2; + struct ospf_if_params *oip; + struct ospf_interface *oi; + + assert(lsa->data); + + /* Retrieve the oi for the network LSA */ + oi = ospf_if_lookup_by_local_addr(area->ospf, NULL, lsa->data->id); + if (oi == NULL) { + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) { + zlog_debug( + "LSA[Type%d:%s]: network-LSA refresh: " + "no oi found, ick, ignoring.", + lsa->data->type, inet_ntoa(lsa->data->id)); + ospf_lsa_header_dump(lsa->data); + } + return NULL; + } + /* Delete LSA from neighbor retransmit-list. */ + ospf_ls_retransmit_delete_nbr_area(area, lsa); + + /* Unregister LSA from refresh-list */ + ospf_refresher_unregister_lsa(area->ospf, lsa); + + /* Create new network-LSA instance. */ + new = ospf_network_lsa_new(oi); + if (new == NULL) + return NULL; + + oip = ospf_lookup_if_params(oi->ifp, oi->address->u.prefix4); + assert(oip != NULL); + oip->network_lsa_seqnum = new->data->ls_seqnum = + lsa_seqnum_increment(lsa); + + new2 = ospf_lsa_install(area->ospf, oi, new); + + assert(new2 == new); + + /* Flood LSA through aera. */ + ospf_flood_through_area(area, NULL, new); + + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) { + zlog_debug("LSA[Type%d:%s]: network-LSA refresh", + new->data->type, inet_ntoa(new->data->id)); + ospf_lsa_header_dump(new->data); + } + + return new; +} + +static void stream_put_ospf_metric(struct stream *s, u_int32_t metric_value) +{ + u_int32_t metric; + char *mp; + + /* Put 0 metric. TOS metric is not supported. */ + metric = htonl(metric_value); + mp = (char *)&metric; + mp++; + stream_put(s, mp, 3); } /* summary-LSA related functions. */ -static void -ospf_summary_lsa_body_set (struct stream *s, struct prefix *p, - u_int32_t metric) +static void ospf_summary_lsa_body_set(struct stream *s, struct prefix *p, + u_int32_t metric) { - struct in_addr mask; + struct in_addr mask; - masklen2ip (p->prefixlen, &mask); + masklen2ip(p->prefixlen, &mask); - /* Put Network Mask. */ - stream_put_ipv4 (s, mask.s_addr); + /* Put Network Mask. */ + stream_put_ipv4(s, mask.s_addr); - /* Set # TOS. */ - stream_putc (s, (u_char) 0); + /* Set # TOS. */ + stream_putc(s, (u_char)0); - /* Set metric. */ - stream_put_ospf_metric (s, metric); + /* Set metric. */ + stream_put_ospf_metric(s, metric); } -static struct ospf_lsa * -ospf_summary_lsa_new (struct ospf_area *area, struct prefix *p, - u_int32_t metric, struct in_addr id) +static struct ospf_lsa *ospf_summary_lsa_new(struct ospf_area *area, + struct prefix *p, u_int32_t metric, + struct in_addr id) { - struct stream *s; - struct ospf_lsa *new; - struct lsa_header *lsah; - int length; + struct stream *s; + struct ospf_lsa *new; + struct lsa_header *lsah; + int length; - 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 (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"); + 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); + /* Create new stream for LSA. */ + s = stream_new(OSPF_MAX_LSA_SIZE); + lsah = (struct lsa_header *)STREAM_DATA(s); - lsa_header_set (s, LSA_OPTIONS_GET (area), OSPF_SUMMARY_LSA, - id, area->ospf->router_id); + lsa_header_set(s, LSA_OPTIONS_GET(area), OSPF_SUMMARY_LSA, id, + area->ospf->router_id); - /* Set summary-LSA body fields. */ - ospf_summary_lsa_body_set (s, p, metric); + /* Set summary-LSA body fields. */ + ospf_summary_lsa_body_set(s, p, metric); - /* Set length. */ - length = stream_get_endp (s); - lsah->length = htons (length); + /* Set length. */ + length = stream_get_endp(s); + lsah->length = htons(length); - /* Create OSPF LSA instance. */ - new = ospf_lsa_new (); - new->area = area; - SET_FLAG (new->flags, OSPF_LSA_SELF | OSPF_LSA_SELF_CHECKED); + /* Create OSPF LSA instance. */ + new = ospf_lsa_new(); + new->area = area; + SET_FLAG(new->flags, OSPF_LSA_SELF | OSPF_LSA_SELF_CHECKED); - /* Copy LSA to store. */ - new->data = ospf_lsa_data_new (length); - memcpy (new->data, lsah, length); - stream_free (s); + /* Copy LSA to store. */ + new->data = ospf_lsa_data_new(length); + memcpy(new->data, lsah, length); + stream_free(s); - return new; + return new; } /* Originate Summary-LSA. */ -struct ospf_lsa * -ospf_summary_lsa_originate (struct prefix_ipv4 *p, u_int32_t metric, - struct ospf_area *area) -{ - struct ospf_lsa *new; - struct in_addr id; - - 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); - - /* 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-LSA %p", - new->data->type, inet_ntoa (new->data->id), (void *)new); - ospf_lsa_header_dump (new->data); - } - - return new; -} - -static struct ospf_lsa* -ospf_summary_lsa_refresh (struct ospf *ospf, struct ospf_lsa *lsa) -{ - struct ospf_lsa *new; - struct summary_lsa *sl; - struct prefix p; - - /* Sanity check. */ - assert (lsa->data); - - sl = (struct summary_lsa *)lsa->data; - p.prefixlen = ip_masklen (sl->mask); - new = ospf_summary_lsa_new (lsa->area, &p, GET_METRIC (sl->metric), - sl->header.id); - - if (!new) - return NULL; - - new->data->ls_seqnum = lsa_seqnum_increment (lsa); - - ospf_lsa_install (ospf, NULL, new); - - /* Flood LSA through AS. */ - ospf_flood_through_area (new->area, NULL, new); - - /* Debug logging. */ - if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) - { - zlog_debug ("LSA[Type%d:%s]: summary-LSA refresh", - new->data->type, inet_ntoa (new->data->id)); - ospf_lsa_header_dump (new->data); - } - - return new; +struct ospf_lsa *ospf_summary_lsa_originate(struct prefix_ipv4 *p, + u_int32_t metric, + struct ospf_area *area) +{ + struct ospf_lsa *new; + struct in_addr id; + + 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); + + /* 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-LSA %p", + new->data->type, inet_ntoa(new->data->id), + (void *)new); + ospf_lsa_header_dump(new->data); + } + + return new; +} + +static struct ospf_lsa *ospf_summary_lsa_refresh(struct ospf *ospf, + struct ospf_lsa *lsa) +{ + struct ospf_lsa *new; + struct summary_lsa *sl; + struct prefix p; + + /* Sanity check. */ + assert(lsa->data); + + sl = (struct summary_lsa *)lsa->data; + p.prefixlen = ip_masklen(sl->mask); + new = ospf_summary_lsa_new(lsa->area, &p, GET_METRIC(sl->metric), + sl->header.id); + + if (!new) + return NULL; + + new->data->ls_seqnum = lsa_seqnum_increment(lsa); + + ospf_lsa_install(ospf, NULL, new); + + /* Flood LSA through AS. */ + ospf_flood_through_area(new->area, NULL, new); + + /* Debug logging. */ + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) { + zlog_debug("LSA[Type%d:%s]: summary-LSA refresh", + new->data->type, inet_ntoa(new->data->id)); + ospf_lsa_header_dump(new->data); + } + + return new; } /* summary-ASBR-LSA related functions. */ -static void -ospf_summary_asbr_lsa_body_set (struct stream *s, struct prefix *p, - u_int32_t metric) +static void ospf_summary_asbr_lsa_body_set(struct stream *s, struct prefix *p, + u_int32_t metric) { - /* Put Network Mask. */ - stream_put_ipv4 (s, (u_int32_t) 0); + /* Put Network Mask. */ + stream_put_ipv4(s, (u_int32_t)0); - /* Set # TOS. */ - stream_putc (s, (u_char) 0); + /* Set # TOS. */ + stream_putc(s, (u_char)0); - /* Set metric. */ - stream_put_ospf_metric (s, metric); + /* Set metric. */ + stream_put_ospf_metric(s, metric); } -static struct ospf_lsa * -ospf_summary_asbr_lsa_new (struct ospf_area *area, struct prefix *p, - u_int32_t metric, struct in_addr id) +static struct ospf_lsa *ospf_summary_asbr_lsa_new(struct ospf_area *area, + struct prefix *p, + u_int32_t metric, + struct in_addr id) { - struct stream *s; - struct ospf_lsa *new; - struct lsa_header *lsah; - int length; + struct stream *s; + struct ospf_lsa *new; + struct lsa_header *lsah; + int length; - 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 (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"); + 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); + /* Create new stream for LSA. */ + s = stream_new(OSPF_MAX_LSA_SIZE); + lsah = (struct lsa_header *)STREAM_DATA(s); - lsa_header_set (s, LSA_OPTIONS_GET (area), OSPF_ASBR_SUMMARY_LSA, - id, area->ospf->router_id); + lsa_header_set(s, LSA_OPTIONS_GET(area), OSPF_ASBR_SUMMARY_LSA, id, + area->ospf->router_id); - /* Set summary-LSA body fields. */ - ospf_summary_asbr_lsa_body_set (s, p, metric); + /* Set summary-LSA body fields. */ + ospf_summary_asbr_lsa_body_set(s, p, metric); - /* Set length. */ - length = stream_get_endp (s); - lsah->length = htons (length); + /* Set length. */ + length = stream_get_endp(s); + lsah->length = htons(length); - /* Create OSPF LSA instance. */ - new = ospf_lsa_new (); - new->area = area; - SET_FLAG (new->flags, OSPF_LSA_SELF | OSPF_LSA_SELF_CHECKED); + /* Create OSPF LSA instance. */ + new = ospf_lsa_new(); + new->area = area; + SET_FLAG(new->flags, OSPF_LSA_SELF | OSPF_LSA_SELF_CHECKED); - /* Copy LSA to store. */ - new->data = ospf_lsa_data_new (length); - memcpy (new->data, lsah, length); - stream_free (s); + /* Copy LSA to store. */ + new->data = ospf_lsa_data_new(length); + memcpy(new->data, lsah, length); + stream_free(s); - return new; + return new; } /* Originate summary-ASBR-LSA. */ -struct ospf_lsa * -ospf_summary_asbr_lsa_originate (struct prefix_ipv4 *p, u_int32_t metric, - struct ospf_area *area) -{ - struct ospf_lsa *new; - struct in_addr id; - - id = ospf_lsa_unique_id (area->ospf, area->lsdb, OSPF_ASBR_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_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", - new->data->type, inet_ntoa (new->data->id), (void *)new); - ospf_lsa_header_dump (new->data); - } - - return new; -} - -static struct ospf_lsa* -ospf_summary_asbr_lsa_refresh (struct ospf *ospf, struct ospf_lsa *lsa) -{ - struct ospf_lsa *new; - struct summary_lsa *sl; - struct prefix p; - - /* Sanity check. */ - assert (lsa->data); - - sl = (struct summary_lsa *)lsa->data; - p.prefixlen = ip_masklen (sl->mask); - new = ospf_summary_asbr_lsa_new (lsa->area, &p, GET_METRIC (sl->metric), - sl->header.id); - if (!new) - return NULL; - - new->data->ls_seqnum = lsa_seqnum_increment (lsa); +struct ospf_lsa *ospf_summary_asbr_lsa_originate(struct prefix_ipv4 *p, + u_int32_t metric, + struct ospf_area *area) +{ + struct ospf_lsa *new; + struct in_addr id; + + id = ospf_lsa_unique_id(area->ospf, area->lsdb, OSPF_ASBR_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_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); - ospf_lsa_install (ospf, NULL, new); - - /* Flood LSA through area. */ - ospf_flood_through_area (new->area, NULL, new); + /* Update LSA origination count. */ + area->ospf->lsa_originate_count++; - if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) - { - zlog_debug ("LSA[Type%d:%s]: summary-ASBR-LSA refresh", - new->data->type, inet_ntoa (new->data->id)); - ospf_lsa_header_dump (new->data); - } + /* Flooding new LSA through area. */ + ospf_flood_through_area(area, NULL, new); - return new; + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) { + zlog_debug("LSA[Type%d:%s]: Originate summary-ASBR-LSA %p", + new->data->type, inet_ntoa(new->data->id), + (void *)new); + ospf_lsa_header_dump(new->data); + } + + return new; +} + +static struct ospf_lsa *ospf_summary_asbr_lsa_refresh(struct ospf *ospf, + struct ospf_lsa *lsa) +{ + struct ospf_lsa *new; + struct summary_lsa *sl; + struct prefix p; + + /* Sanity check. */ + assert(lsa->data); + + sl = (struct summary_lsa *)lsa->data; + p.prefixlen = ip_masklen(sl->mask); + new = ospf_summary_asbr_lsa_new(lsa->area, &p, GET_METRIC(sl->metric), + sl->header.id); + if (!new) + return NULL; + + new->data->ls_seqnum = lsa_seqnum_increment(lsa); + + ospf_lsa_install(ospf, NULL, new); + + /* Flood LSA through area. */ + ospf_flood_through_area(new->area, NULL, new); + + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) { + zlog_debug("LSA[Type%d:%s]: summary-ASBR-LSA refresh", + new->data->type, inet_ntoa(new->data->id)); + ospf_lsa_header_dump(new->data); + } + + return new; } /* AS-external-LSA related functions. */ /* Get nexthop for AS-external-LSAs. Return nexthop if its interface is connected, else 0*/ -static struct in_addr -ospf_external_lsa_nexthop_get (struct ospf *ospf, struct in_addr nexthop) +static struct in_addr ospf_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; + struct in_addr fwd; + struct prefix nh; + struct listnode *node; + struct ospf_interface *oi; + + fwd.s_addr = 0; - fwd.s_addr = 0; + if (!nexthop.s_addr) + return fwd; - 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; - /* 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; + /* 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; - return fwd; + return fwd; } /* NSSA-external-LSA related functions. */ /* Get 1st IP connection for Forward Addr */ -struct in_addr -ospf_get_ip_from_ifp (struct ospf_interface *oi) +struct in_addr ospf_get_ip_from_ifp(struct ospf_interface *oi) { - struct in_addr fwd; + struct in_addr fwd; - fwd.s_addr = 0; + fwd.s_addr = 0; - if (if_is_operative (oi->ifp)) - return oi->address->u.prefix4; - - return fwd; + if (if_is_operative(oi->ifp)) + return oi->address->u.prefix4; + + return fwd; } /* Get 1st IP connection for Forward Addr */ -struct in_addr -ospf_get_nssa_ip (struct ospf_area *area) -{ - struct in_addr fwd; - struct in_addr best_default; - struct listnode *node; - struct ospf_interface *oi; - - fwd.s_addr = 0; - best_default.s_addr = 0; - - for (ALL_LIST_ELEMENTS_RO (area->ospf->oiflist, node, oi)) - { - if (if_is_operative (oi->ifp)) - if (oi->area->external_routing == OSPF_AREA_NSSA) - if (oi->address && oi->address->family == AF_INET) - { - if (best_default.s_addr == 0) - best_default = oi->address->u.prefix4; - if (oi->area == area) - return oi->address->u.prefix4; - } - } - if (best_default.s_addr != 0) - return best_default; +struct in_addr ospf_get_nssa_ip(struct ospf_area *area) +{ + struct in_addr fwd; + struct in_addr best_default; + struct listnode *node; + struct ospf_interface *oi; + + fwd.s_addr = 0; + best_default.s_addr = 0; + + for (ALL_LIST_ELEMENTS_RO(area->ospf->oiflist, node, oi)) { + if (if_is_operative(oi->ifp)) + if (oi->area->external_routing == OSPF_AREA_NSSA) + if (oi->address + && oi->address->family == AF_INET) { + if (best_default.s_addr == 0) + best_default = + oi->address->u.prefix4; + if (oi->area == area) + return oi->address->u.prefix4; + } + } + if (best_default.s_addr != 0) + return best_default; - if (best_default.s_addr != 0) - return best_default; + if (best_default.s_addr != 0) + return best_default; - return fwd; + return fwd; } #define DEFAULT_DEFAULT_METRIC 20 @@ -1536,841 +1495,840 @@ ospf_get_nssa_ip (struct ospf_area *area) #define DEFAULT_METRIC_TYPE EXTERNAL_METRIC_TYPE_2 -int -metric_type (struct ospf *ospf, u_char src, u_short instance) +int metric_type(struct ospf *ospf, u_char src, u_short instance) { - struct ospf_redist *red; + struct ospf_redist *red; - red = ospf_redist_lookup(ospf, src, instance); + red = ospf_redist_lookup(ospf, src, instance); - return ((!red || red->dmetric.type < 0) ? - DEFAULT_METRIC_TYPE : red->dmetric.type); + return ((!red || red->dmetric.type < 0) ? DEFAULT_METRIC_TYPE + : red->dmetric.type); } -int -metric_value (struct ospf *ospf, u_char src, u_short instance) +int metric_value(struct ospf *ospf, u_char src, u_short instance) { - struct ospf_redist *red; + struct ospf_redist *red; - red = ospf_redist_lookup(ospf, src, instance); - if (!red || red->dmetric.value < 0) - { - if (src == DEFAULT_ROUTE) - { - if (ospf->default_originate == DEFAULT_ORIGINATE_ZEBRA) - return DEFAULT_DEFAULT_ORIGINATE_METRIC; - else - return DEFAULT_DEFAULT_ALWAYS_METRIC; + red = ospf_redist_lookup(ospf, src, instance); + if (!red || red->dmetric.value < 0) { + if (src == DEFAULT_ROUTE) { + if (ospf->default_originate == DEFAULT_ORIGINATE_ZEBRA) + return DEFAULT_DEFAULT_ORIGINATE_METRIC; + else + return DEFAULT_DEFAULT_ALWAYS_METRIC; + } else if (ospf->default_metric < 0) + return DEFAULT_DEFAULT_METRIC; + else + return ospf->default_metric; } - else if (ospf->default_metric < 0) - return DEFAULT_DEFAULT_METRIC; - else - return ospf->default_metric; - } - return red->dmetric.value; + return red->dmetric.value; } /* Set AS-external-LSA body. */ -static void -ospf_external_lsa_body_set (struct stream *s, struct external_info *ei, - struct ospf *ospf) -{ - struct prefix_ipv4 *p = &ei->p; - struct in_addr mask, fwd_addr; - u_int32_t mvalue; - int mtype; - int type; - u_short instance; - - /* Put Network Mask. */ - masklen2ip (p->prefixlen, &mask); - stream_put_ipv4 (s, mask.s_addr); - - /* If prefix is default, specify DEFAULT_ROUTE. */ - type = is_prefix_default (&ei->p) ? DEFAULT_ROUTE : ei->type; - instance = is_prefix_default (&ei->p) ? 0 : ei->instance; - - mtype = (ROUTEMAP_METRIC_TYPE (ei) != -1) ? - ROUTEMAP_METRIC_TYPE (ei) : metric_type (ospf, type, instance); - - mvalue = (ROUTEMAP_METRIC (ei) != -1) ? - ROUTEMAP_METRIC (ei) : metric_value (ospf, type, instance); - - /* 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 */ - stream_putl (s, ei->tag); +static void ospf_external_lsa_body_set(struct stream *s, + struct external_info *ei, + struct ospf *ospf) +{ + struct prefix_ipv4 *p = &ei->p; + struct in_addr mask, fwd_addr; + u_int32_t mvalue; + int mtype; + int type; + u_short instance; + + /* Put Network Mask. */ + masklen2ip(p->prefixlen, &mask); + stream_put_ipv4(s, mask.s_addr); + + /* If prefix is default, specify DEFAULT_ROUTE. */ + type = is_prefix_default(&ei->p) ? DEFAULT_ROUTE : ei->type; + instance = is_prefix_default(&ei->p) ? 0 : ei->instance; + + mtype = (ROUTEMAP_METRIC_TYPE(ei) != -1) + ? ROUTEMAP_METRIC_TYPE(ei) + : metric_type(ospf, type, instance); + + mvalue = (ROUTEMAP_METRIC(ei) != -1) + ? ROUTEMAP_METRIC(ei) + : metric_value(ospf, type, instance); + + /* 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 */ + stream_putl(s, ei->tag); } /* Create new external-LSA. */ -static struct ospf_lsa * -ospf_external_lsa_new (struct ospf *ospf, - struct external_info *ei, struct in_addr *old_id) -{ - struct stream *s; - struct lsa_header *lsah; - struct ospf_lsa *new; - struct in_addr id; - int length; - - if (ei == NULL) - { - if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) - zlog_debug ("LSA[Type5]: External info is NULL, can't originate"); - 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); - - /* Set length. */ - length = stream_get_endp (s); - lsah->length = htons (length); - - /* Now, create OSPF LSA instance. */ - new = ospf_lsa_new (); - new->area = NULL; - SET_FLAG (new->flags, OSPF_LSA_SELF | OSPF_LSA_APPROVED | OSPF_LSA_SELF_CHECKED); - - /* Copy LSA data to store, discard stream. */ - new->data = ospf_lsa_data_new (length); - memcpy (new->data, lsah, length); - stream_free (s); - - return new; +static struct ospf_lsa *ospf_external_lsa_new(struct ospf *ospf, + struct external_info *ei, + struct in_addr *old_id) +{ + struct stream *s; + struct lsa_header *lsah; + struct ospf_lsa *new; + struct in_addr id; + int length; + + if (ei == NULL) { + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) + zlog_debug( + "LSA[Type5]: External info is NULL, can't originate"); + 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); + + /* Set length. */ + length = stream_get_endp(s); + lsah->length = htons(length); + + /* Now, create OSPF LSA instance. */ + new = ospf_lsa_new(); + new->area = NULL; + SET_FLAG(new->flags, + OSPF_LSA_SELF | OSPF_LSA_APPROVED | OSPF_LSA_SELF_CHECKED); + + /* Copy LSA data to store, discard stream. */ + new->data = ospf_lsa_data_new(length); + memcpy(new->data, lsah, length); + stream_free(s); + + return new; } /* As Type-7 */ -static void -ospf_install_flood_nssa (struct ospf *ospf, - struct ospf_lsa *lsa, struct external_info *ei) -{ - struct ospf_lsa *new; - struct as_external_lsa *extlsa; - struct ospf_area *area; - struct listnode *node, *nnode; - - /* 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 */ - } +static void ospf_install_flood_nssa(struct ospf *ospf, struct ospf_lsa *lsa, + struct external_info *ei) +{ + struct ospf_lsa *new; + struct as_external_lsa *extlsa; + struct ospf_area *area; + struct listnode *node, *nnode; + + /* 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 */ + } } -static struct ospf_lsa * -ospf_lsa_translated_nssa_new (struct ospf *ospf, - struct ospf_lsa *type7) -{ - - struct ospf_lsa *new; - struct as_external_lsa *ext, *extnew; - struct external_info ei; - - ext = (struct as_external_lsa *)(type7->data); - - /* need external_info struct, fill in bare minimum */ - ei.p.family = AF_INET; - ei.p.prefix = type7->data->id; - ei.p.prefixlen = ip_masklen (ext->mask); - ei.type = ZEBRA_ROUTE_OSPF; - ei.nexthop = ext->header.adv_router; - ei.route_map_set.metric = -1; - ei.route_map_set.metric_type = -1; - ei.tag = 0; - - if ( (new = ospf_external_lsa_new (ospf, &ei, &type7->data->id)) == NULL) - { - if (IS_DEBUG_OSPF_NSSA) - zlog_debug ("ospf_nssa_translate_originate(): Could not originate " - "Translated Type-5 for %s", - inet_ntoa (ei.p.prefix)); - return NULL; - } - - extnew = (struct as_external_lsa *)(new->data); - - /* copy over Type-7 data to new */ - extnew->e[0].tos = ext->e[0].tos; - extnew->e[0].route_tag = ext->e[0].route_tag; - extnew->e[0].fwd_addr.s_addr = ext->e[0].fwd_addr.s_addr; - new->data->ls_seqnum = type7->data->ls_seqnum; - - /* add translated flag, checksum and lock new lsa */ - SET_FLAG (new->flags, OSPF_LSA_LOCAL_XLT); /* Translated from 7 */ - new = ospf_lsa_lock (new); - - return new; +static struct ospf_lsa *ospf_lsa_translated_nssa_new(struct ospf *ospf, + struct ospf_lsa *type7) +{ + + struct ospf_lsa *new; + struct as_external_lsa *ext, *extnew; + struct external_info ei; + + ext = (struct as_external_lsa *)(type7->data); + + /* need external_info struct, fill in bare minimum */ + ei.p.family = AF_INET; + ei.p.prefix = type7->data->id; + ei.p.prefixlen = ip_masklen(ext->mask); + ei.type = ZEBRA_ROUTE_OSPF; + ei.nexthop = ext->header.adv_router; + ei.route_map_set.metric = -1; + ei.route_map_set.metric_type = -1; + ei.tag = 0; + + if ((new = ospf_external_lsa_new(ospf, &ei, &type7->data->id)) + == NULL) { + if (IS_DEBUG_OSPF_NSSA) + zlog_debug( + "ospf_nssa_translate_originate(): Could not originate " + "Translated Type-5 for %s", + inet_ntoa(ei.p.prefix)); + return NULL; + } + + extnew = (struct as_external_lsa *)(new->data); + + /* copy over Type-7 data to new */ + extnew->e[0].tos = ext->e[0].tos; + extnew->e[0].route_tag = ext->e[0].route_tag; + extnew->e[0].fwd_addr.s_addr = ext->e[0].fwd_addr.s_addr; + new->data->ls_seqnum = type7->data->ls_seqnum; + + /* add translated flag, checksum and lock new lsa */ + SET_FLAG(new->flags, OSPF_LSA_LOCAL_XLT); /* Translated from 7 */ + new = ospf_lsa_lock(new); + + return new; } /* Originate Translated Type-5 for supplied Type-7 NSSA LSA */ -struct ospf_lsa * -ospf_translated_nssa_originate (struct ospf *ospf, struct ospf_lsa *type7) -{ - struct ospf_lsa *new; - struct as_external_lsa *extnew; - - /* we cant use ospf_external_lsa_originate() as we need to set - * the OSPF_LSA_LOCAL_XLT flag, must originate by hand - */ - - if ( (new = ospf_lsa_translated_nssa_new (ospf, type7)) == NULL) - { - if (IS_DEBUG_OSPF_NSSA) - zlog_debug ("ospf_translated_nssa_originate(): Could not translate " - "Type-7, Id %s, to Type-5", - inet_ntoa (type7->data->id)); - return NULL; - } - - extnew = (struct as_external_lsa *)new; - - if (IS_DEBUG_OSPF_NSSA) - { - zlog_debug ("ospf_translated_nssa_originate(): " - "translated Type 7, installed:"); - ospf_lsa_header_dump (new->data); - zlog_debug (" Network mask: %d",ip_masklen (extnew->mask)); - zlog_debug (" Forward addr: %s", inet_ntoa (extnew->e[0].fwd_addr)); - } - - if ( (new = ospf_lsa_install (ospf, NULL, new)) == NULL) - { - if (IS_DEBUG_OSPF_NSSA) - zlog_debug ("ospf_lsa_translated_nssa_originate(): " - "Could not install LSA " - "id %s", inet_ntoa (type7->data->id)); - return NULL; - } - - ospf->lsa_originate_count++; - ospf_flood_through_as (ospf, NULL, new); - - return new; +struct ospf_lsa *ospf_translated_nssa_originate(struct ospf *ospf, + struct ospf_lsa *type7) +{ + struct ospf_lsa *new; + struct as_external_lsa *extnew; + + /* we cant use ospf_external_lsa_originate() as we need to set + * the OSPF_LSA_LOCAL_XLT flag, must originate by hand + */ + + if ((new = ospf_lsa_translated_nssa_new(ospf, type7)) == NULL) { + if (IS_DEBUG_OSPF_NSSA) + zlog_debug( + "ospf_translated_nssa_originate(): Could not translate " + "Type-7, Id %s, to Type-5", + inet_ntoa(type7->data->id)); + return NULL; + } + + extnew = (struct as_external_lsa *)new; + + if (IS_DEBUG_OSPF_NSSA) { + zlog_debug( + "ospf_translated_nssa_originate(): " + "translated Type 7, installed:"); + ospf_lsa_header_dump(new->data); + zlog_debug(" Network mask: %d", ip_masklen(extnew->mask)); + zlog_debug(" Forward addr: %s", + inet_ntoa(extnew->e[0].fwd_addr)); + } + + if ((new = ospf_lsa_install(ospf, NULL, new)) == NULL) { + if (IS_DEBUG_OSPF_NSSA) + zlog_debug( + "ospf_lsa_translated_nssa_originate(): " + "Could not install LSA " + "id %s", + inet_ntoa(type7->data->id)); + return NULL; + } + + ospf->lsa_originate_count++; + ospf_flood_through_as(ospf, NULL, new); + + return new; } /* Refresh Translated from NSSA AS-external-LSA. */ -struct ospf_lsa * -ospf_translated_nssa_refresh (struct ospf *ospf, struct ospf_lsa *type7, - struct ospf_lsa *type5) -{ - struct ospf_lsa *new = NULL; - - /* Sanity checks. */ - assert (type7 || type5); - if (!(type7 || type5)) - return NULL; - if (type7) - 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); - - return new; -} - -int -is_prefix_default (struct prefix_ipv4 *p) -{ - struct prefix_ipv4 q; - - q.family = AF_INET; - q.prefix.s_addr = 0; - q.prefixlen = 0; - - return prefix_same ((struct prefix *) p, (struct prefix *) &q); +struct ospf_lsa *ospf_translated_nssa_refresh(struct ospf *ospf, + struct ospf_lsa *type7, + struct ospf_lsa *type5) +{ + struct ospf_lsa *new = NULL; + + /* Sanity checks. */ + assert(type7 || type5); + if (!(type7 || type5)) + return NULL; + if (type7) + 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); + + return new; +} + +int is_prefix_default(struct prefix_ipv4 *p) +{ + struct prefix_ipv4 q; + + q.family = AF_INET; + q.prefix.s_addr = 0; + q.prefixlen = 0; + + return prefix_same((struct prefix *)p, (struct prefix *)&q); } /* 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); - - /* Update LSA origination count. */ - ospf->lsa_originate_count++; - - /* Flooding new LSA. only to AS (non-NSSA/STUB) */ - ospf_flood_through_as (ospf, NULL, new); - - /* If there is any attached NSSA, do special handling */ - if (ospf->anyNSSA && - /* stay away from translated LSAs! */ - !(CHECK_FLAG (new->flags, OSPF_LSA_LOCAL_XLT))) - ospf_install_flood_nssa (ospf, new, ei); /* Install/Flood Type-7 to all NSSAs */ - - /* Debug logging. */ - if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) - { - zlog_debug ("LSA[Type%d:%s]: Originate AS-external-LSA %p", - new->data->type, inet_ntoa (new->data->id), (void *)new); - ospf_lsa_header_dump (new->data); - } - - return new; +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); + + /* Update LSA origination count. */ + ospf->lsa_originate_count++; + + /* Flooding new LSA. only to AS (non-NSSA/STUB) */ + ospf_flood_through_as(ospf, NULL, new); + + /* If there is any attached NSSA, do special handling */ + if (ospf->anyNSSA && + /* stay away from translated LSAs! */ + !(CHECK_FLAG(new->flags, OSPF_LSA_LOCAL_XLT))) + ospf_install_flood_nssa( + ospf, new, ei); /* Install/Flood Type-7 to all NSSAs */ + + /* Debug logging. */ + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) { + zlog_debug("LSA[Type%d:%s]: Originate AS-external-LSA %p", + new->data->type, inet_ntoa(new->data->id), + (void *)new); + ospf_lsa_header_dump(new->data); + } + + return new; } /* Originate AS-external-LSA from external info with initial flag. */ -int -ospf_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); - struct list *ext_list; - struct listnode *node; - struct ospf_external *ext; - - ospf->t_external_lsa = NULL; - - ext_list = om->external[type]; - if (!ext_list) - return 0; - - for (ALL_LIST_ELEMENTS_RO(ext_list, node, ext)) - /* Originate As-external-LSA from all type of distribute source. */ - if ((rt = ext->external_info)) - 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."); - - return 0; -} - -static struct external_info * -ospf_default_external_info (struct ospf *ospf) -{ - int type; - struct route_node *rn; - struct prefix_ipv4 p; - - p.family = AF_INET; - p.prefix.s_addr = 0; - p.prefixlen = 0; - - /* First, lookup redistributed default route. */ - for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) - { - struct list *ext_list; - struct listnode *node; - struct ospf_external *ext; - - if (type == ZEBRA_ROUTE_OSPF) - continue; - - ext_list = om->external[type]; - if (!ext_list) - continue; - - for (ALL_LIST_ELEMENTS_RO(ext_list, node, ext)) - { - rn = route_node_lookup (ext->external_info, (struct prefix *) &p); - if (rn != NULL) - { - route_unlock_node (rn); - assert (rn->info); - if (ospf_redistribute_check (ospf, rn->info, NULL)) - return rn->info; - } - } - } - - return NULL; -} - -int -ospf_default_originate_timer (struct thread *thread) -{ - struct prefix_ipv4 p; - struct in_addr nexthop; - struct external_info *ei; - struct ospf *ospf; - - ospf = THREAD_ARG (thread); - - p.family = AF_INET; - p.prefix.s_addr = 0; - p.prefixlen = 0; - - 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, 0, p, 0, nexthop, 0); - } - - if ((ei = ospf_default_external_info (ospf))) - ospf_external_lsa_originate (ospf, ei); - - return 0; +int ospf_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); + struct list *ext_list; + struct listnode *node; + struct ospf_external *ext; + + ospf->t_external_lsa = NULL; + + ext_list = om->external[type]; + if (!ext_list) + return 0; + + for (ALL_LIST_ELEMENTS_RO(ext_list, node, ext)) + /* Originate As-external-LSA from all type of distribute source. + */ + if ((rt = ext->external_info)) + 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."); + + return 0; +} + +static struct external_info *ospf_default_external_info(struct ospf *ospf) +{ + int type; + struct route_node *rn; + struct prefix_ipv4 p; + + p.family = AF_INET; + p.prefix.s_addr = 0; + p.prefixlen = 0; + + /* First, lookup redistributed default route. */ + for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) { + struct list *ext_list; + struct listnode *node; + struct ospf_external *ext; + + if (type == ZEBRA_ROUTE_OSPF) + continue; + + ext_list = om->external[type]; + if (!ext_list) + continue; + + for (ALL_LIST_ELEMENTS_RO(ext_list, node, ext)) { + rn = route_node_lookup(ext->external_info, + (struct prefix *)&p); + if (rn != NULL) { + route_unlock_node(rn); + assert(rn->info); + if (ospf_redistribute_check(ospf, rn->info, + NULL)) + return rn->info; + } + } + } + + return NULL; +} + +int ospf_default_originate_timer(struct thread *thread) +{ + struct prefix_ipv4 p; + struct in_addr nexthop; + struct external_info *ei; + struct ospf *ospf; + + ospf = THREAD_ARG(thread); + + p.family = AF_INET; + p.prefix.s_addr = 0; + p.prefixlen = 0; + + 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, 0, p, 0, nexthop, 0); + } + + if ((ei = ospf_default_external_info(ospf))) + ospf_external_lsa_originate(ospf, ei); + + return 0; } /* Flush any NSSA LSAs for given prefix */ -void -ospf_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; - } - ospf_ls_retransmit_delete_nbr_area (area, lsa); - if (!IS_LSA_MAXAGE (lsa)) - { - ospf_refresher_unregister_lsa (ospf, lsa); - ospf_lsa_flush_area (lsa, area); - } - } - } +void ospf_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; + } + ospf_ls_retransmit_delete_nbr_area(area, lsa); + if (!IS_LSA_MAXAGE(lsa)) { + ospf_refresher_unregister_lsa(ospf, lsa); + ospf_lsa_flush_area(lsa, area); + } + } + } } /* Flush an AS-external-LSA from LSDB and routing domain. */ -void -ospf_external_lsa_flush (struct ospf *ospf, - u_char type, struct prefix_ipv4 *p, - ifindex_t ifindex /*, struct in_addr nexthop */) -{ - struct ospf_lsa *lsa; - - 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. */ +void ospf_external_lsa_flush(struct ospf *ospf, u_char type, + struct prefix_ipv4 *p, + ifindex_t ifindex /*, struct in_addr nexthop */) +{ + struct ospf_lsa *lsa; + + 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); - } - - if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) - zlog_debug ("ospf_external_lsa_flush(): stop"); -} - -void -ospf_external_lsa_refresh_default (struct ospf *ospf) -{ - struct prefix_ipv4 p; - struct external_info *ei; - struct ospf_lsa *lsa; - - p.family = AF_INET; - p.prefixlen = 0; - p.prefix.s_addr = 0; - - ei = ospf_default_external_info (ospf); - lsa = ospf_external_info_find_lsa (ospf, &p); - - if (ei) - { - if (lsa) - { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("LSA[Type5:0.0.0.0]: Refresh AS-external-LSA %p", - (void *)lsa); - ospf_external_lsa_refresh (ospf, lsa, ei, LSA_REFRESH_FORCE); - } - else - { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("LSA[Type5:0.0.0.0]: Originate AS-external-LSA"); - ospf_external_lsa_originate (ospf, ei); - } - } - else - { - if (lsa) - { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("LSA[Type5:0.0.0.0]: Flush AS-external-LSA"); - ospf_refresher_unregister_lsa (ospf, lsa); - ospf_lsa_flush_as (ospf, lsa); - } - } -} - -void -ospf_external_lsa_refresh_type (struct ospf *ospf, u_char type, u_short instance, - int force) -{ - struct route_node *rn; - struct external_info *ei; - struct ospf_external *ext; - - if (type != DEFAULT_ROUTE) - if ((ext = ospf_external_lookup(type, instance)) && - EXTERNAL_INFO (ext)) - /* Refresh each redistributed AS-external-LSAs. */ - for (rn = route_top (EXTERNAL_INFO (ext)); rn; rn = route_next (rn)) - if ((ei = rn->info)) - if (!is_prefix_default (&ei->p)) - { - struct ospf_lsa *lsa; - - if ((lsa = ospf_external_info_find_lsa (ospf, &ei->p))) - ospf_external_lsa_refresh (ospf, lsa, ei, force); - else - ospf_external_lsa_originate (ospf, ei); - } + 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); + } + + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug("ospf_external_lsa_flush(): stop"); +} + +void ospf_external_lsa_refresh_default(struct ospf *ospf) +{ + struct prefix_ipv4 p; + struct external_info *ei; + struct ospf_lsa *lsa; + + p.family = AF_INET; + p.prefixlen = 0; + p.prefix.s_addr = 0; + + ei = ospf_default_external_info(ospf); + lsa = ospf_external_info_find_lsa(ospf, &p); + + if (ei) { + if (lsa) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug( + "LSA[Type5:0.0.0.0]: Refresh AS-external-LSA %p", + (void *)lsa); + ospf_external_lsa_refresh(ospf, lsa, ei, + LSA_REFRESH_FORCE); + } else { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug( + "LSA[Type5:0.0.0.0]: Originate AS-external-LSA"); + ospf_external_lsa_originate(ospf, ei); + } + } else { + if (lsa) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug( + "LSA[Type5:0.0.0.0]: Flush AS-external-LSA"); + ospf_refresher_unregister_lsa(ospf, lsa); + ospf_lsa_flush_as(ospf, lsa); + } + } +} + +void ospf_external_lsa_refresh_type(struct ospf *ospf, u_char type, + u_short instance, int force) +{ + struct route_node *rn; + struct external_info *ei; + struct ospf_external *ext; + + if (type != DEFAULT_ROUTE) + if ((ext = ospf_external_lookup(type, instance)) + && EXTERNAL_INFO(ext)) + /* Refresh each redistributed AS-external-LSAs. */ + for (rn = route_top(EXTERNAL_INFO(ext)); rn; + rn = route_next(rn)) + if ((ei = rn->info)) + if (!is_prefix_default(&ei->p)) { + struct ospf_lsa *lsa; + + if ((lsa = ospf_external_info_find_lsa( + ospf, &ei->p))) + ospf_external_lsa_refresh( + ospf, lsa, ei, + force); + else + ospf_external_lsa_originate( + ospf, ei); + } } /* Refresh AS-external-LSA. */ -struct ospf_lsa * -ospf_external_lsa_refresh (struct ospf *ospf, struct ospf_lsa *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)); - return NULL; - } - - new->data->ls_seqnum = lsa_seqnum_increment (lsa); - - 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); - - /* Debug logging. */ - if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) - { - zlog_debug ("LSA[Type%d:%s]: AS-external-LSA refresh", - new->data->type, inet_ntoa (new->data->id)); - ospf_lsa_header_dump (new->data); - } - - return new; +struct ospf_lsa *ospf_external_lsa_refresh(struct ospf *ospf, + struct ospf_lsa *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)); + return NULL; + } + + new->data->ls_seqnum = lsa_seqnum_increment(lsa); + + 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); + + /* Debug logging. */ + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) { + zlog_debug("LSA[Type%d:%s]: AS-external-LSA refresh", + new->data->type, inet_ntoa(new->data->id)); + ospf_lsa_header_dump(new->data); + } + + return new; } @@ -2378,114 +2336,109 @@ ospf_external_lsa_refresh (struct ospf *ospf, struct ospf_lsa *lsa, /* Install router-LSA to an area. */ static struct ospf_lsa * -ospf_router_lsa_install (struct ospf *ospf, struct ospf_lsa *new, - int rt_recalc) +ospf_router_lsa_install(struct ospf *ospf, struct ospf_lsa *new, int rt_recalc) { - struct ospf_area *area = new->area; + 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). - */ + /* 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)) - { + 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)) - return new; /* ignore stale LSA */ + /* 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)) + return new; /* ignore stale LSA */ - /* Set self-originated router-LSA. */ - ospf_lsa_unlock (&area->router_lsa_self); - area->router_lsa_self = ospf_lsa_lock (new); + /* Set self-originated router-LSA. */ + ospf_lsa_unlock(&area->router_lsa_self); + area->router_lsa_self = ospf_lsa_lock(new); - ospf_refresher_register_lsa (ospf, new); - } - if (rt_recalc) - ospf_spf_calculate_schedule (ospf, SPF_FLAG_ROUTER_LSA_INSTALL); - return new; + ospf_refresher_register_lsa(ospf, new); + } + if (rt_recalc) + ospf_spf_calculate_schedule(ospf, SPF_FLAG_ROUTER_LSA_INSTALL); + return new; } -#define OSPF_INTERFACE_TIMER_ON(T,F,V) \ - if (!(T)) \ - (T) = thread_add_timer (master, (F), oi, (V)) +#define OSPF_INTERFACE_TIMER_ON(T, F, V) \ + if (!(T)) \ + (T) = thread_add_timer(master, (F), oi, (V)) /* 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 */ - - ospf_lsa_unlock (&oi->network_lsa_self); - oi->network_lsa_self = ospf_lsa_lock (new); - ospf_refresher_register_lsa (ospf, new); - } - if (rt_recalc) - ospf_spf_calculate_schedule (ospf, SPF_FLAG_NETWORK_LSA_INSTALL); - - return new; +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 */ + + ospf_lsa_unlock(&oi->network_lsa_self); + oi->network_lsa_self = ospf_lsa_lock(new); + ospf_refresher_register_lsa(ospf, new); + } + if (rt_recalc) + ospf_spf_calculate_schedule(ospf, SPF_FLAG_NETWORK_LSA_INSTALL); + + return new; } /* 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. - */ +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 0 /* This doesn't exist yet... */ ospf_summary_incremental_update(new); */ -#else /* #if 0 */ - ospf_spf_calculate_schedule (ospf, SPF_FLAG_SUMMARY_LSA_INSTALL); +#else /* #if 0 */ + ospf_spf_calculate_schedule(ospf, SPF_FLAG_SUMMARY_LSA_INSTALL); #endif /* #if 0 */ - - } + } - if (IS_LSA_SELF (new)) - ospf_refresher_register_lsa (ospf, new); + if (IS_LSA_SELF(new)) + ospf_refresher_register_lsa(ospf, new); - return 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. - */ +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); @@ -2493,428 +2446,421 @@ ospf_summary_asbr_lsa_install (struct ospf *ospf, struct ospf_lsa *new, - RFC 2328 Section 16.5 implies it should be */ /* ospf_ase_calculate_schedule(); */ #else /* #if 0 */ - ospf_spf_calculate_schedule (ospf, SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL); + ospf_spf_calculate_schedule(ospf, + SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL); #endif /* #if 0 */ - } + } - /* register LSA to refresh-list. */ - if (IS_LSA_SELF (new)) - ospf_refresher_register_lsa (ospf, new); + /* register LSA to refresh-list. */ + if (IS_LSA_SELF(new)) + ospf_refresher_register_lsa(ospf, new); - return new; + return new; } /* Install AS-external-LSA. */ -static struct ospf_lsa * -ospf_external_lsa_install (struct ospf *ospf, struct ospf_lsa *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; -} - -void -ospf_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); - - switch (old->data->type) - { - case OSPF_AS_EXTERNAL_LSA: - ospf_ase_unregister_external_lsa (old, ospf); - ospf_ls_retransmit_delete_nbr_as (ospf, old); - break; - case OSPF_OPAQUE_AS_LSA: - ospf_ls_retransmit_delete_nbr_as (ospf, old); - break; - case OSPF_AS_NSSA_LSA: - ospf_ls_retransmit_delete_nbr_area (old->area, old); - ospf_ase_unregister_external_lsa (old, ospf); - break; - default: - ospf_ls_retransmit_delete_nbr_area (old->area, old); - break; - } - - ospf_lsa_maxage_delete (ospf, old); - ospf_lsa_discard (old); -} - -struct ospf_lsa * -ospf_lsa_install (struct ospf *ospf, struct ospf_interface *oi, - struct ospf_lsa *lsa) -{ - struct ospf_lsa *new = NULL; - struct ospf_lsa *old = NULL; - struct ospf_lsdb *lsdb = NULL; - int rt_recalc; - - /* Set LSDB. */ - switch (lsa->data->type) - { - /* kevinm */ - case OSPF_AS_NSSA_LSA: - if (lsa->area) - lsdb = lsa->area->lsdb; - else - lsdb = ospf->lsdb; - break; - case OSPF_AS_EXTERNAL_LSA: - case OSPF_OPAQUE_AS_LSA: - lsdb = ospf->lsdb; - break; - default: - lsdb = lsa->area->lsdb; - break; - } - - assert (lsdb); - - /* RFC 2328 13.2. Installing LSAs in the database - - 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 " - "lsa 0x%p, seqnum 0x%x", - (void *)lsa, ntohl(lsa->data->ls_seqnum)); - ospf_lsa_header_dump (lsa->data); - } - } - else - { - if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) - { - zlog_debug ("ospf_lsa_install() got an lsa with seq 0x80000000 " - "that was not self originated. Ignoring\n"); - ospf_lsa_header_dump (lsa->data); - } - return old; - } - } - - /* discard old LSA from LSDB */ - if (old != NULL) - ospf_discard_from_db (ospf, lsdb, lsa); - - /* Calculate Checksum if self-originated?. */ - if (IS_LSA_SELF (lsa)) - ospf_lsa_checksum (lsa->data); - - /* Insert LSA to LSDB. */ - ospf_lsdb_add (lsdb, lsa); - lsa->lsdb = lsdb; - - /* 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; - 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; - 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. */ - - /* Debug logs. */ - if (IS_DEBUG_OSPF (lsa, LSA_INSTALL)) - { - char area_str[INET_ADDRSTRLEN]; - - switch (lsa->data->type) - { - case OSPF_AS_EXTERNAL_LSA: - case OSPF_OPAQUE_AS_LSA: - case OSPF_AS_NSSA_LSA: - zlog_debug ("LSA[%s]: Install %s", - dump_lsa_key (new), - lookup_msg(ospf_lsa_type_msg, new->data->type, NULL)); - 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_msg(ospf_lsa_type_msg, new->data->type, NULL), 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 (IS_LSA_MAXAGE (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), - (void *)lsa); - ospf_lsa_maxage (ospf, lsa); - } - - return new; -} - - -int -ospf_check_nbr_status (struct ospf *ospf) -{ - struct listnode *node, *nnode; - struct ospf_interface *oi; - - for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi)) - { - struct route_node *rn; - struct ospf_neighbor *nbr; - - if (ospf_if_is_enable (oi)) - for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) - if ((nbr = rn->info) != NULL) - if (nbr->state == NSM_Exchange || nbr->state == NSM_Loading) - { - route_unlock_node (rn); - return 0; - } - } - - return 1; -} - - - -static int -ospf_maxage_lsa_remover (struct thread *thread) -{ - struct ospf *ospf = THREAD_ARG (thread); - struct ospf_lsa *lsa; - struct route_node *rn; - int reschedule = 0; - - ospf->t_maxage = NULL; - - if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) - zlog_debug ("LSA[MaxAge]: remover Start"); - - reschedule = !ospf_check_nbr_status (ospf); - - if (!reschedule) - for (rn = route_top(ospf->maxage_lsa); rn; rn = route_next(rn)) - { - if ((lsa = rn->info) == NULL) - { - continue; - } - - /* There is at least one neighbor from which we still await an ack - * for that LSA, so we are not allowed to remove it from our lsdb yet - * as per RFC 2328 section 14 para 4 a) */ - 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); - route_unlock_node(rn); /* route_top/route_next */ - return 0; - } - - /* Remove LSA from the LSDB */ - if (IS_LSA_SELF (lsa)) - if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) - zlog_debug ("LSA[Type%d:%s]: LSA 0x%lx is self-originated: ", - 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", (void *)lsa); - ospf_lsa_refresh (ospf, lsa); - } - - /* Remove from lsdb. */ - if (lsa->lsdb) - { - ospf_discard_from_db (ospf, lsa->lsdb, lsa); - ospf_lsdb_delete (lsa->lsdb, lsa); - } - else - zlog_warn ("%s: LSA[Type%d:%s]: No associated LSDB!", __func__, - lsa->data->type, inet_ntoa (lsa->data->id)); - } - - /* 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); - - return 0; -} - -void -ospf_lsa_maxage_delete (struct ospf *ospf, struct ospf_lsa *lsa) -{ - struct route_node *rn; - struct prefix_ptr lsa_prefix; - - lsa_prefix.family = 0; - lsa_prefix.prefixlen = sizeof(lsa_prefix.prefix) * CHAR_BIT; - lsa_prefix.prefix = (uintptr_t) lsa; - - if ((rn = route_node_lookup(ospf->maxage_lsa, - (struct prefix *)&lsa_prefix))) - { - if (rn->info == lsa) - { - UNSET_FLAG(lsa->flags, OSPF_LSA_IN_MAXAGE); - ospf_lsa_unlock (&lsa); /* maxage_lsa */ - rn->info = NULL; - route_unlock_node (rn); /* unlock node because lsa is deleted */ - } - route_unlock_node (rn); /* route_node_lookup */ - } +static struct ospf_lsa *ospf_external_lsa_install(struct ospf *ospf, + struct ospf_lsa *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; +} + +void ospf_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); + + switch (old->data->type) { + case OSPF_AS_EXTERNAL_LSA: + ospf_ase_unregister_external_lsa(old, ospf); + ospf_ls_retransmit_delete_nbr_as(ospf, old); + break; + case OSPF_OPAQUE_AS_LSA: + ospf_ls_retransmit_delete_nbr_as(ospf, old); + break; + case OSPF_AS_NSSA_LSA: + ospf_ls_retransmit_delete_nbr_area(old->area, old); + ospf_ase_unregister_external_lsa(old, ospf); + break; + default: + ospf_ls_retransmit_delete_nbr_area(old->area, old); + break; + } + + ospf_lsa_maxage_delete(ospf, old); + ospf_lsa_discard(old); +} + +struct ospf_lsa *ospf_lsa_install(struct ospf *ospf, struct ospf_interface *oi, + struct ospf_lsa *lsa) +{ + struct ospf_lsa *new = NULL; + struct ospf_lsa *old = NULL; + struct ospf_lsdb *lsdb = NULL; + int rt_recalc; + + /* Set LSDB. */ + switch (lsa->data->type) { + /* kevinm */ + case OSPF_AS_NSSA_LSA: + if (lsa->area) + lsdb = lsa->area->lsdb; + else + lsdb = ospf->lsdb; + break; + case OSPF_AS_EXTERNAL_LSA: + case OSPF_OPAQUE_AS_LSA: + lsdb = ospf->lsdb; + break; + default: + lsdb = lsa->area->lsdb; + break; + } + + assert(lsdb); + + /* RFC 2328 13.2. Installing LSAs in the database + + 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 " + "lsa 0x%p, seqnum 0x%x", + (void *)lsa, + ntohl(lsa->data->ls_seqnum)); + ospf_lsa_header_dump(lsa->data); + } + } else { + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) { + zlog_debug( + "ospf_lsa_install() got an lsa with seq 0x80000000 " + "that was not self originated. Ignoring\n"); + ospf_lsa_header_dump(lsa->data); + } + return old; + } + } + + /* discard old LSA from LSDB */ + if (old != NULL) + ospf_discard_from_db(ospf, lsdb, lsa); + + /* Calculate Checksum if self-originated?. */ + if (IS_LSA_SELF(lsa)) + ospf_lsa_checksum(lsa->data); + + /* Insert LSA to LSDB. */ + ospf_lsdb_add(lsdb, lsa); + lsa->lsdb = lsdb; + + /* 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; + 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; + 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. */ + + /* Debug logs. */ + if (IS_DEBUG_OSPF(lsa, LSA_INSTALL)) { + char area_str[INET_ADDRSTRLEN]; + + switch (lsa->data->type) { + case OSPF_AS_EXTERNAL_LSA: + case OSPF_OPAQUE_AS_LSA: + case OSPF_AS_NSSA_LSA: + zlog_debug("LSA[%s]: Install %s", dump_lsa_key(new), + lookup_msg(ospf_lsa_type_msg, + new->data->type, NULL)); + 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_msg(ospf_lsa_type_msg, + new->data->type, NULL), + 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 (IS_LSA_MAXAGE(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), + (void *)lsa); + ospf_lsa_maxage(ospf, lsa); + } + + return new; +} + + +int ospf_check_nbr_status(struct ospf *ospf) +{ + struct listnode *node, *nnode; + struct ospf_interface *oi; + + for (ALL_LIST_ELEMENTS(ospf->oiflist, node, nnode, oi)) { + struct route_node *rn; + struct ospf_neighbor *nbr; + + if (ospf_if_is_enable(oi)) + for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) + if ((nbr = rn->info) != NULL) + if (nbr->state == NSM_Exchange + || nbr->state == NSM_Loading) { + route_unlock_node(rn); + return 0; + } + } + + return 1; +} + + +static int ospf_maxage_lsa_remover(struct thread *thread) +{ + struct ospf *ospf = THREAD_ARG(thread); + struct ospf_lsa *lsa; + struct route_node *rn; + int reschedule = 0; + + ospf->t_maxage = NULL; + + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug("LSA[MaxAge]: remover Start"); + + reschedule = !ospf_check_nbr_status(ospf); + + if (!reschedule) + for (rn = route_top(ospf->maxage_lsa); rn; + rn = route_next(rn)) { + if ((lsa = rn->info) == NULL) { + continue; + } + + /* There is at least one neighbor from which we still + * await an ack + * for that LSA, so we are not allowed to remove it from + * our lsdb yet + * as per RFC 2328 section 14 para 4 a) */ + 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); + route_unlock_node( + rn); /* route_top/route_next */ + return 0; + } + + /* Remove LSA from the LSDB */ + if (IS_LSA_SELF(lsa)) + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug( + "LSA[Type%d:%s]: LSA 0x%lx is self-originated: ", + 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", + (void *)lsa); + ospf_lsa_refresh(ospf, lsa); + } + + /* Remove from lsdb. */ + if (lsa->lsdb) { + ospf_discard_from_db(ospf, lsa->lsdb, lsa); + ospf_lsdb_delete(lsa->lsdb, lsa); + } else + zlog_warn( + "%s: LSA[Type%d:%s]: No associated LSDB!", + __func__, lsa->data->type, + inet_ntoa(lsa->data->id)); + } + + /* 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); + + return 0; +} + +void ospf_lsa_maxage_delete(struct ospf *ospf, struct ospf_lsa *lsa) +{ + struct route_node *rn; + struct prefix_ptr lsa_prefix; + + lsa_prefix.family = 0; + lsa_prefix.prefixlen = sizeof(lsa_prefix.prefix) * CHAR_BIT; + lsa_prefix.prefix = (uintptr_t)lsa; + + if ((rn = route_node_lookup(ospf->maxage_lsa, + (struct prefix *)&lsa_prefix))) { + if (rn->info == lsa) { + UNSET_FLAG(lsa->flags, OSPF_LSA_IN_MAXAGE); + ospf_lsa_unlock(&lsa); /* maxage_lsa */ + rn->info = NULL; + route_unlock_node( + rn); /* unlock node because lsa is deleted */ + } + route_unlock_node(rn); /* route_node_lookup */ + } } /* Add LSA onto the MaxAge list, and schedule for removal. @@ -2922,841 +2868,833 @@ ospf_lsa_maxage_delete (struct ospf *ospf, struct ospf_lsa *lsa) * care of elsewhere, see, e.g., ospf_lsa_flush* (which are callers of this * function). */ -void -ospf_lsa_maxage (struct ospf *ospf, struct ospf_lsa *lsa) -{ - struct prefix_ptr lsa_prefix; - struct route_node *rn; - - /* 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)) - zlog_debug ("LSA[Type%d:%s]: %p already exists on MaxAge LSA list", - lsa->data->type, inet_ntoa (lsa->data->id), (void *)lsa); - return; - } - - lsa_prefix.family = 0; - lsa_prefix.prefixlen = sizeof(lsa_prefix.prefix) * CHAR_BIT; - lsa_prefix.prefix = (uintptr_t) lsa; - - if ((rn = route_node_get (ospf->maxage_lsa, - (struct prefix *)&lsa_prefix)) != NULL) - { - if (rn->info != NULL) - { - if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) - zlog_debug ("LSA[%s]: found LSA (%p) in table for LSA %p %d", - dump_lsa_key (lsa), rn->info, (void *)lsa, - lsa_prefix.prefixlen); - route_unlock_node (rn); - } - else - { - rn->info = ospf_lsa_lock(lsa); - SET_FLAG(lsa->flags, OSPF_LSA_IN_MAXAGE); - } - } - else - { - zlog_err("Unable to allocate memory for maxage lsa\n"); - assert(0); - } - - if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) - zlog_debug ("LSA[%s]: MaxAge LSA remover scheduled.", dump_lsa_key (lsa)); - - OSPF_TIMER_ON (ospf->t_maxage, ospf_maxage_lsa_remover, - ospf->maxage_delay); -} - -static int -ospf_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) - { - 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; - case OSPF_AS_EXTERNAL_LSA: - case OSPF_AS_NSSA_LSA: - ospf_ase_incremental_update (ospf, lsa); - break; - default: - ospf_spf_calculate_schedule (ospf, SPF_FLAG_MAXAGE); - break; - } - ospf_lsa_maxage (ospf, lsa); - } - - if (IS_LSA_MAXAGE (lsa) && !ospf_lsa_is_self_originated (ospf, lsa)) - if (LS_AGE (lsa) > OSPF_LSA_MAXAGE + 30) - printf ("Eek! Shouldn't happen!\n"); - - return 0; +void ospf_lsa_maxage(struct ospf *ospf, struct ospf_lsa *lsa) +{ + struct prefix_ptr lsa_prefix; + struct route_node *rn; + + /* 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)) + zlog_debug( + "LSA[Type%d:%s]: %p already exists on MaxAge LSA list", + lsa->data->type, inet_ntoa(lsa->data->id), + (void *)lsa); + return; + } + + lsa_prefix.family = 0; + lsa_prefix.prefixlen = sizeof(lsa_prefix.prefix) * CHAR_BIT; + lsa_prefix.prefix = (uintptr_t)lsa; + + if ((rn = route_node_get(ospf->maxage_lsa, + (struct prefix *)&lsa_prefix)) + != NULL) { + if (rn->info != NULL) { + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug( + "LSA[%s]: found LSA (%p) in table for LSA %p %d", + dump_lsa_key(lsa), rn->info, + (void *)lsa, lsa_prefix.prefixlen); + route_unlock_node(rn); + } else { + rn->info = ospf_lsa_lock(lsa); + SET_FLAG(lsa->flags, OSPF_LSA_IN_MAXAGE); + } + } else { + zlog_err("Unable to allocate memory for maxage lsa\n"); + assert(0); + } + + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug("LSA[%s]: MaxAge LSA remover scheduled.", + dump_lsa_key(lsa)); + + OSPF_TIMER_ON(ospf->t_maxage, ospf_maxage_lsa_remover, + ospf->maxage_delay); +} + +static int ospf_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) { + 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; + case OSPF_AS_EXTERNAL_LSA: + case OSPF_AS_NSSA_LSA: + ospf_ase_incremental_update(ospf, lsa); + break; + default: + ospf_spf_calculate_schedule(ospf, + SPF_FLAG_MAXAGE); + break; + } + ospf_lsa_maxage(ospf, lsa); + } + + if (IS_LSA_MAXAGE(lsa) && !ospf_lsa_is_self_originated(ospf, lsa)) + if (LS_AGE(lsa) > OSPF_LSA_MAXAGE + 30) + printf("Eek! Shouldn't happen!\n"); + + return 0; } /* Periodical check of MaxAge LSA. */ -int -ospf_lsa_maxage_walker (struct thread *thread) -{ - struct ospf *ospf = THREAD_ARG (thread); - struct route_node *rn; - struct ospf_lsa *lsa; - struct ospf_area *area; - struct listnode *node, *nnode; - - ospf->t_maxage_walker = NULL; - - for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) - { - LSDB_LOOP (ROUTER_LSDB (area), rn, lsa) - ospf_lsa_maxage_walker_remover (ospf, lsa); - LSDB_LOOP (NETWORK_LSDB (area), rn, lsa) - ospf_lsa_maxage_walker_remover (ospf, lsa); - LSDB_LOOP (SUMMARY_LSDB (area), rn, lsa) - ospf_lsa_maxage_walker_remover (ospf, lsa); - LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa) - ospf_lsa_maxage_walker_remover (ospf, lsa); - LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa) - ospf_lsa_maxage_walker_remover (ospf, lsa); - LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa) - ospf_lsa_maxage_walker_remover (ospf, lsa); - LSDB_LOOP (NSSA_LSDB (area), rn, lsa) - ospf_lsa_maxage_walker_remover (ospf, lsa); - } - - /* for AS-external-LSAs. */ - if (ospf->lsdb) - { - LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa) - ospf_lsa_maxage_walker_remover (ospf, lsa); - LSDB_LOOP (OPAQUE_AS_LSDB (ospf), rn, lsa) - ospf_lsa_maxage_walker_remover (ospf, lsa); - } - - OSPF_TIMER_ON (ospf->t_maxage_walker, ospf_lsa_maxage_walker, - OSPF_LSA_MAXAGE_CHECK_INTERVAL); - return 0; -} - -struct ospf_lsa * -ospf_lsa_lookup_by_prefix (struct ospf_lsdb *lsdb, u_char type, - struct prefix_ipv4 *p, struct in_addr router_id) -{ - struct ospf_lsa *lsa; - struct in_addr mask, id; - struct lsa_header_mask - { - struct lsa_header header; - struct in_addr mask; - } *hmask; - - lsa = ospf_lsdb_lookup_by_id (lsdb, type, p->prefix, router_id); - if (lsa == NULL) - return NULL; - - masklen2ip (p->prefixlen, &mask); - - hmask = (struct lsa_header_mask *) lsa->data; - - if (mask.s_addr != hmask->mask.s_addr) - { - id.s_addr = p->prefix.s_addr | (~mask.s_addr); - lsa = ospf_lsdb_lookup_by_id (lsdb, type, id, router_id); - if (!lsa) - return NULL; - } - - return lsa; -} - -struct ospf_lsa * -ospf_lsa_lookup (struct ospf_area *area, u_int32_t type, - struct in_addr id, struct in_addr adv_router) -{ - struct ospf *ospf = ospf_lookup(); - assert(ospf); - - switch (type) - { - case OSPF_ROUTER_LSA: - case OSPF_NETWORK_LSA: - case OSPF_SUMMARY_LSA: - case OSPF_ASBR_SUMMARY_LSA: - case OSPF_AS_NSSA_LSA: - case OSPF_OPAQUE_LINK_LSA: - case OSPF_OPAQUE_AREA_LSA: - return ospf_lsdb_lookup_by_id (area->lsdb, type, id, adv_router); - case OSPF_AS_EXTERNAL_LSA: - case OSPF_OPAQUE_AS_LSA: - return ospf_lsdb_lookup_by_id (ospf->lsdb, type, id, adv_router); - default: - break; - } - - return NULL; -} - -struct ospf_lsa * -ospf_lsa_lookup_by_id (struct ospf_area *area, u_int32_t type, - struct in_addr id) -{ - struct ospf_lsa *lsa; - struct route_node *rn; - - 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: - case OSPF_OPAQUE_LINK_LSA: - case OSPF_OPAQUE_AREA_LSA: - case OSPF_OPAQUE_AS_LSA: - /* Currently not used. */ - break; - default: - break; - } - - return NULL; -} - -struct ospf_lsa * -ospf_lsa_lookup_by_header (struct ospf_area *area, struct lsa_header *lsah) -{ - struct ospf_lsa *match; - - /* - * 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. - */ - - 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; +int ospf_lsa_maxage_walker(struct thread *thread) +{ + struct ospf *ospf = THREAD_ARG(thread); + struct route_node *rn; + struct ospf_lsa *lsa; + struct ospf_area *area; + struct listnode *node, *nnode; + + ospf->t_maxage_walker = NULL; + + for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) { + LSDB_LOOP(ROUTER_LSDB(area), rn, lsa) + ospf_lsa_maxage_walker_remover(ospf, lsa); + LSDB_LOOP(NETWORK_LSDB(area), rn, lsa) + ospf_lsa_maxage_walker_remover(ospf, lsa); + LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa) + ospf_lsa_maxage_walker_remover(ospf, lsa); + LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa) + ospf_lsa_maxage_walker_remover(ospf, lsa); + LSDB_LOOP(OPAQUE_AREA_LSDB(area), rn, lsa) + ospf_lsa_maxage_walker_remover(ospf, lsa); + LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa) + ospf_lsa_maxage_walker_remover(ospf, lsa); + LSDB_LOOP(NSSA_LSDB(area), rn, lsa) + ospf_lsa_maxage_walker_remover(ospf, lsa); + } + + /* for AS-external-LSAs. */ + if (ospf->lsdb) { + LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa) + ospf_lsa_maxage_walker_remover(ospf, lsa); + LSDB_LOOP(OPAQUE_AS_LSDB(ospf), rn, lsa) + ospf_lsa_maxage_walker_remover(ospf, lsa); + } + + OSPF_TIMER_ON(ospf->t_maxage_walker, ospf_lsa_maxage_walker, + OSPF_LSA_MAXAGE_CHECK_INTERVAL); + return 0; +} + +struct ospf_lsa *ospf_lsa_lookup_by_prefix(struct ospf_lsdb *lsdb, u_char type, + struct prefix_ipv4 *p, + struct in_addr router_id) +{ + struct ospf_lsa *lsa; + struct in_addr mask, id; + struct lsa_header_mask { + struct lsa_header header; + struct in_addr mask; + } * hmask; + + lsa = ospf_lsdb_lookup_by_id(lsdb, type, p->prefix, router_id); + if (lsa == NULL) + return NULL; + + masklen2ip(p->prefixlen, &mask); + + hmask = (struct lsa_header_mask *)lsa->data; + + if (mask.s_addr != hmask->mask.s_addr) { + id.s_addr = p->prefix.s_addr | (~mask.s_addr); + lsa = ospf_lsdb_lookup_by_id(lsdb, type, id, router_id); + if (!lsa) + return NULL; + } + + return lsa; +} + +struct ospf_lsa *ospf_lsa_lookup(struct ospf_area *area, u_int32_t type, + struct in_addr id, struct in_addr adv_router) +{ + struct ospf *ospf = ospf_lookup(); + assert(ospf); + + switch (type) { + case OSPF_ROUTER_LSA: + case OSPF_NETWORK_LSA: + case OSPF_SUMMARY_LSA: + case OSPF_ASBR_SUMMARY_LSA: + case OSPF_AS_NSSA_LSA: + case OSPF_OPAQUE_LINK_LSA: + case OSPF_OPAQUE_AREA_LSA: + return ospf_lsdb_lookup_by_id(area->lsdb, type, id, adv_router); + case OSPF_AS_EXTERNAL_LSA: + case OSPF_OPAQUE_AS_LSA: + return ospf_lsdb_lookup_by_id(ospf->lsdb, type, id, adv_router); + default: + break; + } + + return NULL; +} + +struct ospf_lsa *ospf_lsa_lookup_by_id(struct ospf_area *area, u_int32_t type, + struct in_addr id) +{ + struct ospf_lsa *lsa; + struct route_node *rn; + + 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: + case OSPF_OPAQUE_LINK_LSA: + case OSPF_OPAQUE_AREA_LSA: + case OSPF_OPAQUE_AS_LSA: + /* Currently not used. */ + break; + default: + break; + } + + return NULL; +} + +struct ospf_lsa *ospf_lsa_lookup_by_header(struct ospf_area *area, + struct lsa_header *lsah) +{ + struct ospf_lsa *match; + + /* + * 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. + */ + + 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. */ -int -ospf_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; +int ospf_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. */ -int -ospf_lsa_different (struct ospf_lsa *l1, struct ospf_lsa *l2) +int ospf_lsa_different(struct ospf_lsa *l1, struct ospf_lsa *l2) { - char *p1, *p2; - assert (l1); - assert (l2); - assert (l1->data); - assert (l2->data); + char *p1, *p2; + assert(l1); + assert(l2); + assert(l1->data); + assert(l2->data); - if (l1->data->options != l2->data->options) - return 1; + if (l1->data->options != l2->data->options) + return 1; - if (IS_LSA_MAXAGE (l1) && !IS_LSA_MAXAGE (l2)) - 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 (IS_LSA_MAXAGE(l2) && !IS_LSA_MAXAGE(l1)) + return 1; - if (l1->data->length != l2->data->length) - return 1; + if (l1->data->length != l2->data->length) + return 1; - if (l1->data->length == 0) - 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 */ + if (CHECK_FLAG((l1->flags ^ l2->flags), OSPF_LSA_RECEIVED)) + return 1; /* May be a stale LSA in the LSBD */ - assert ( ntohs(l1->data->length) > OSPF_LSA_HEADER_SIZE); + assert(ntohs(l1->data->length) > OSPF_LSA_HEADER_SIZE); - p1 = (char *) l1->data; - p2 = (char *) l2->data; + p1 = (char *)l1->data; + p2 = (char *)l2->data; - if (memcmp (p1 + OSPF_LSA_HEADER_SIZE, p2 + OSPF_LSA_HEADER_SIZE, - ntohs( l1->data->length ) - OSPF_LSA_HEADER_SIZE) != 0) - return 1; + if (memcmp(p1 + OSPF_LSA_HEADER_SIZE, p2 + OSPF_LSA_HEADER_SIZE, + ntohs(l1->data->length) - OSPF_LSA_HEADER_SIZE) + != 0) + return 1; - return 0; + return 0; } #ifdef ORIGINAL_CODING -void -ospf_lsa_flush_self_originated (struct ospf_neighbor *nbr, - struct ospf_lsa *self, - struct ospf_lsa *new) -{ - u_int32_t seqnum; - - /* Adjust LS Sequence Number. */ - seqnum = ntohl (new->data->ls_seqnum) + 1; - self->data->ls_seqnum = htonl (seqnum); - - /* Recalculate LSA checksum. */ - ospf_lsa_checksum (self->data); - - /* Reflooding LSA. */ - /* RFC2328 Section 13.3 - On non-broadcast networks, separate Link 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. */ - if (nbr->oi->type == OSPF_IFTYPE_NBMA) - { - struct route_node *rn; - struct ospf_neighbor *onbr; - - for (rn = route_top (nbr->oi->nbrs); rn; rn = route_next (rn)) - if ((onbr = rn->info) != NULL) - if (onbr != nbr->oi->nbr_self && onbr->status >= NSM_Exchange) - ospf_ls_upd_send_lsa (onbr, self, OSPF_SEND_PACKET_DIRECT); - } - else - ospf_ls_upd_send_lsa (nbr, self, OSPF_SEND_PACKET_INDIRECT); - - if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) - zlog_debug ("LSA[Type%d:%s]: Flush self-originated LSA", - self->data->type, inet_ntoa (self->data->id)); -} -#else /* ORIGINAL_CODING */ -int -ospf_lsa_flush_schedule (struct ospf *ospf, struct ospf_lsa *lsa) -{ - if (lsa == NULL || !IS_LSA_SELF (lsa)) - return 0; - - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("LSA[Type%d:%s]: Schedule self-originated LSA to FLUSH", lsa->data->type, inet_ntoa (lsa->data->id)); - - /* Force given lsa's age to MaxAge. */ - lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); - - switch (lsa->data->type) - { - /* Opaque wants to be notified of flushes */ - case OSPF_OPAQUE_LINK_LSA: - case OSPF_OPAQUE_AREA_LSA: - case OSPF_OPAQUE_AS_LSA: - ospf_opaque_lsa_refresh (lsa); - break; - default: - ospf_refresher_unregister_lsa (ospf, lsa); - ospf_lsa_flush (ospf, lsa); - break; - } - - return 0; -} - -void -ospf_flush_self_originated_lsas_now (struct ospf *ospf) -{ - struct listnode *node, *nnode; - struct listnode *node2, *nnode2; - struct ospf_area *area; - struct ospf_interface *oi; - struct ospf_lsa *lsa; - struct route_node *rn; - int need_to_flush_ase = 0; - - for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) - { - if ((lsa = area->router_lsa_self) != NULL) - { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("LSA[Type%d:%s]: Schedule self-originated LSA to FLUSH", - lsa->data->type, inet_ntoa (lsa->data->id)); - - ospf_refresher_unregister_lsa (ospf, lsa); - ospf_lsa_flush_area (lsa, area); - ospf_lsa_unlock (&area->router_lsa_self); - area->router_lsa_self = NULL; - } - - for (ALL_LIST_ELEMENTS (area->oiflist, node2, nnode2, oi)) - { - if ((lsa = oi->network_lsa_self) != NULL - && oi->state == ISM_DR - && oi->full_nbrs > 0) - { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("LSA[Type%d:%s]: Schedule self-originated LSA to FLUSH", - lsa->data->type, inet_ntoa (lsa->data->id)); - - ospf_refresher_unregister_lsa (ospf, oi->network_lsa_self); - ospf_lsa_flush_area (oi->network_lsa_self, area); - ospf_lsa_unlock (&oi->network_lsa_self); - oi->network_lsa_self = NULL; - } - - if (oi->type != OSPF_IFTYPE_VIRTUALLINK - && area->external_routing == OSPF_AREA_DEFAULT) - need_to_flush_ase = 1; - } - - LSDB_LOOP (SUMMARY_LSDB (area), rn, lsa) - ospf_lsa_flush_schedule (ospf, lsa); - LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa) - ospf_lsa_flush_schedule (ospf, lsa); - LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa) - ospf_lsa_flush_schedule (ospf, lsa); - LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa) - ospf_lsa_flush_schedule (ospf, lsa); - } - - if (need_to_flush_ase) - { - LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa) - ospf_lsa_flush_schedule (ospf, lsa); - LSDB_LOOP (OPAQUE_AS_LSDB (ospf), rn, lsa) - ospf_lsa_flush_schedule (ospf, lsa); - } - - /* - * 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; +void ospf_lsa_flush_self_originated(struct ospf_neighbor *nbr, + struct ospf_lsa *self, struct ospf_lsa *new) +{ + u_int32_t seqnum; + + /* Adjust LS Sequence Number. */ + seqnum = ntohl(new->data->ls_seqnum) + 1; + self->data->ls_seqnum = htonl(seqnum); + + /* Recalculate LSA checksum. */ + ospf_lsa_checksum(self->data); + + /* Reflooding LSA. */ + /* RFC2328 Section 13.3 + On non-broadcast networks, separate Link 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. */ + if (nbr->oi->type == OSPF_IFTYPE_NBMA) { + struct route_node *rn; + struct ospf_neighbor *onbr; + + for (rn = route_top(nbr->oi->nbrs); rn; rn = route_next(rn)) + if ((onbr = rn->info) != NULL) + if (onbr != nbr->oi->nbr_self + && onbr->status >= NSM_Exchange) + ospf_ls_upd_send_lsa( + onbr, self, + OSPF_SEND_PACKET_DIRECT); + } else + ospf_ls_upd_send_lsa(nbr, self, OSPF_SEND_PACKET_INDIRECT); + + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) + zlog_debug("LSA[Type%d:%s]: Flush self-originated LSA", + self->data->type, inet_ntoa(self->data->id)); +} +#else /* ORIGINAL_CODING */ +int ospf_lsa_flush_schedule(struct ospf *ospf, struct ospf_lsa *lsa) +{ + if (lsa == NULL || !IS_LSA_SELF(lsa)) + return 0; + + if (IS_DEBUG_OSPF_EVENT) + zlog_debug( + "LSA[Type%d:%s]: Schedule self-originated LSA to FLUSH", + lsa->data->type, inet_ntoa(lsa->data->id)); + + /* Force given lsa's age to MaxAge. */ + lsa->data->ls_age = htons(OSPF_LSA_MAXAGE); + + switch (lsa->data->type) { + /* Opaque wants to be notified of flushes */ + case OSPF_OPAQUE_LINK_LSA: + case OSPF_OPAQUE_AREA_LSA: + case OSPF_OPAQUE_AS_LSA: + ospf_opaque_lsa_refresh(lsa); + break; + default: + ospf_refresher_unregister_lsa(ospf, lsa); + ospf_lsa_flush(ospf, lsa); + break; + } + + return 0; +} + +void ospf_flush_self_originated_lsas_now(struct ospf *ospf) +{ + struct listnode *node, *nnode; + struct listnode *node2, *nnode2; + struct ospf_area *area; + struct ospf_interface *oi; + struct ospf_lsa *lsa; + struct route_node *rn; + int need_to_flush_ase = 0; + + for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) { + if ((lsa = area->router_lsa_self) != NULL) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug( + "LSA[Type%d:%s]: Schedule self-originated LSA to FLUSH", + lsa->data->type, + inet_ntoa(lsa->data->id)); + + ospf_refresher_unregister_lsa(ospf, lsa); + ospf_lsa_flush_area(lsa, area); + ospf_lsa_unlock(&area->router_lsa_self); + area->router_lsa_self = NULL; + } + + for (ALL_LIST_ELEMENTS(area->oiflist, node2, nnode2, oi)) { + if ((lsa = oi->network_lsa_self) != NULL + && oi->state == ISM_DR && oi->full_nbrs > 0) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug( + "LSA[Type%d:%s]: Schedule self-originated LSA to FLUSH", + lsa->data->type, + inet_ntoa(lsa->data->id)); + + ospf_refresher_unregister_lsa( + ospf, oi->network_lsa_self); + ospf_lsa_flush_area(oi->network_lsa_self, area); + ospf_lsa_unlock(&oi->network_lsa_self); + oi->network_lsa_self = NULL; + } + + if (oi->type != OSPF_IFTYPE_VIRTUALLINK + && area->external_routing == OSPF_AREA_DEFAULT) + need_to_flush_ase = 1; + } + + LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa) + ospf_lsa_flush_schedule(ospf, lsa); + LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa) + ospf_lsa_flush_schedule(ospf, lsa); + LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa) + ospf_lsa_flush_schedule(ospf, lsa); + LSDB_LOOP(OPAQUE_AREA_LSDB(area), rn, lsa) + ospf_lsa_flush_schedule(ospf, lsa); + } + + if (need_to_flush_ase) { + LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa) + ospf_lsa_flush_schedule(ospf, lsa); + LSDB_LOOP(OPAQUE_AS_LSDB(ospf), rn, lsa) + ospf_lsa_flush_schedule(ospf, lsa); + } + + /* + * 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 IS_LSA_SELF (lsa); - - /* 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 IS_LSA_SELF (lsa); - } - } - - return IS_LSA_SELF (lsa); +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 IS_LSA_SELF(lsa); + + /* 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 IS_LSA_SELF(lsa); + } + } + + return IS_LSA_SELF(lsa); } /* Get unique Link State ID. */ -struct in_addr -ospf_lsa_unique_id (struct ospf *ospf, - struct ospf_lsdb *lsdb, u_char type, struct prefix_ipv4 *p) -{ - struct ospf_lsa *lsa; - struct in_addr mask, id; - - id = p->prefix; - - /* Check existence of LSA instance. */ - lsa = ospf_lsdb_lookup_by_id (lsdb, type, id, ospf->router_id); - if (lsa) - { - struct as_external_lsa *al = (struct as_external_lsa *) lsa->data; - if (ip_masklen (al->mask) == p->prefixlen) - { - if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) - zlog_debug ("ospf_lsa_unique_id(): " - "Can't get Link State ID for %s/%d", - inet_ntoa (p->prefix), p->prefixlen); - /* id.s_addr = 0; */ - id.s_addr = 0xffffffff; - return id; - } - /* Masklen differs, then apply wildcard mask to Link State ID. */ - else - { - masklen2ip (p->prefixlen, &mask); - - id.s_addr = p->prefix.s_addr | (~mask.s_addr); - lsa = ospf_lsdb_lookup_by_id (ospf->lsdb, type, - id, ospf->router_id); - if (lsa) - { - if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) - zlog_debug ("ospf_lsa_unique_id(): " - "Can't get Link State ID for %s/%d", - inet_ntoa (p->prefix), p->prefixlen); - /* id.s_addr = 0; */ - id.s_addr = 0xffffffff; - return id; - } - } - } - - return id; +struct in_addr ospf_lsa_unique_id(struct ospf *ospf, struct ospf_lsdb *lsdb, + u_char type, struct prefix_ipv4 *p) +{ + struct ospf_lsa *lsa; + struct in_addr mask, id; + + id = p->prefix; + + /* Check existence of LSA instance. */ + lsa = ospf_lsdb_lookup_by_id(lsdb, type, id, ospf->router_id); + if (lsa) { + struct as_external_lsa *al = + (struct as_external_lsa *)lsa->data; + if (ip_masklen(al->mask) == p->prefixlen) { + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) + zlog_debug( + "ospf_lsa_unique_id(): " + "Can't get Link State ID for %s/%d", + inet_ntoa(p->prefix), p->prefixlen); + /* id.s_addr = 0; */ + id.s_addr = 0xffffffff; + return id; + } + /* Masklen differs, then apply wildcard mask to Link State ID. + */ + else { + masklen2ip(p->prefixlen, &mask); + + id.s_addr = p->prefix.s_addr | (~mask.s_addr); + lsa = ospf_lsdb_lookup_by_id(ospf->lsdb, type, id, + ospf->router_id); + if (lsa) { + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) + zlog_debug( + "ospf_lsa_unique_id(): " + "Can't get Link State ID for %s/%d", + inet_ntoa(p->prefix), + p->prefixlen); + /* id.s_addr = 0; */ + id.s_addr = 0xffffffff; + return id; + } + } + } + + return id; } #define LSA_ACTION_FLOOD_AREA 1 #define LSA_ACTION_FLUSH_AREA 2 -struct lsa_action -{ - u_char action; - struct ospf_area *area; - struct ospf_lsa *lsa; +struct lsa_action { + u_char action; + struct ospf_area *area; + struct ospf_lsa *lsa; }; -static int -ospf_lsa_action (struct thread *t) +static int ospf_lsa_action(struct thread *t) { - struct lsa_action *data; + struct lsa_action *data; - data = THREAD_ARG (t); + data = THREAD_ARG(t); - if (IS_DEBUG_OSPF (lsa, LSA) == OSPF_DEBUG_LSA) - zlog_debug ("LSA[Action]: Performing scheduled LSA action: %d", - data->action); + if (IS_DEBUG_OSPF(lsa, LSA) == OSPF_DEBUG_LSA) + zlog_debug("LSA[Action]: Performing scheduled LSA action: %d", + data->action); - switch (data->action) - { - case LSA_ACTION_FLOOD_AREA: - ospf_flood_through_area (data->area, NULL, data->lsa); - break; - case LSA_ACTION_FLUSH_AREA: - ospf_lsa_flush_area (data->lsa, data->area); - break; - } + switch (data->action) { + case LSA_ACTION_FLOOD_AREA: + ospf_flood_through_area(data->area, NULL, data->lsa); + break; + case LSA_ACTION_FLUSH_AREA: + ospf_lsa_flush_area(data->lsa, data->area); + break; + } - ospf_lsa_unlock (&data->lsa); /* Message */ - XFREE (MTYPE_OSPF_MESSAGE, data); - return 0; + ospf_lsa_unlock(&data->lsa); /* Message */ + XFREE(MTYPE_OSPF_MESSAGE, data); + return 0; } -void -ospf_schedule_lsa_flood_area (struct ospf_area *area, struct ospf_lsa *lsa) +void ospf_schedule_lsa_flood_area(struct ospf_area *area, struct ospf_lsa *lsa) { - struct lsa_action *data; + struct lsa_action *data; - data = XCALLOC (MTYPE_OSPF_MESSAGE, sizeof (struct lsa_action)); - data->action = LSA_ACTION_FLOOD_AREA; - data->area = area; - data->lsa = ospf_lsa_lock (lsa); /* Message / Flood area */ + data = XCALLOC(MTYPE_OSPF_MESSAGE, sizeof(struct lsa_action)); + data->action = LSA_ACTION_FLOOD_AREA; + data->area = area; + data->lsa = ospf_lsa_lock(lsa); /* Message / Flood area */ - thread_add_event(master, ospf_lsa_action, data, 0, NULL); + thread_add_event(master, ospf_lsa_action, data, 0, NULL); } -void -ospf_schedule_lsa_flush_area (struct ospf_area *area, struct ospf_lsa *lsa) +void ospf_schedule_lsa_flush_area(struct ospf_area *area, struct ospf_lsa *lsa) { - struct lsa_action *data; + struct lsa_action *data; - data = XCALLOC (MTYPE_OSPF_MESSAGE, sizeof (struct lsa_action)); - data->action = LSA_ACTION_FLUSH_AREA; - data->area = area; - data->lsa = ospf_lsa_lock (lsa); /* Message / Flush area */ + data = XCALLOC(MTYPE_OSPF_MESSAGE, sizeof(struct lsa_action)); + data->action = LSA_ACTION_FLUSH_AREA; + data->area = area; + data->lsa = ospf_lsa_lock(lsa); /* Message / Flush area */ - thread_add_event(master, ospf_lsa_action, data, 0, NULL); + thread_add_event(master, ospf_lsa_action, data, 0, NULL); } /* LSA Refreshment functions. */ -struct ospf_lsa * -ospf_lsa_refresh (struct ospf *ospf, struct ospf_lsa *lsa) -{ - struct external_info *ei; - struct ospf_lsa *new = NULL; - assert (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF)); - assert (IS_LSA_SELF (lsa)); - assert (lsa->lock > 0); - - 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; - case OSPF_OPAQUE_LINK_LSA: - case OSPF_OPAQUE_AREA_LSA: - case OSPF_OPAQUE_AS_LSA: - new = ospf_opaque_lsa_refresh (lsa); - break; - default: - break; - } - return new; -} - -void -ospf_refresher_register_lsa (struct ospf *ospf, struct ospf_lsa *lsa) -{ - u_int16_t index, current_index; - - assert (lsa->lock > 0); - assert (IS_LSA_SELF (lsa)); - - if (lsa->refresh_list < 0) - { - int delay; - int min_delay = OSPF_LS_REFRESH_TIME - (2 * OSPF_LS_REFRESH_JITTER); - int max_delay = OSPF_LS_REFRESH_TIME - OSPF_LS_REFRESH_JITTER; - - /* We want to refresh the LSA within OSPF_LS_REFRESH_TIME which is - * 1800s. Use jitter so that we send the LSA sometime between 1680s - * and 1740s. - */ - delay = (random() % (max_delay - min_delay)) + min_delay; - - current_index = ospf->lsa_refresh_queue.index + (monotime(NULL) - - ospf->lsa_refresher_started)/OSPF_LSA_REFRESHER_GRANULARITY; - - index = (current_index + delay/OSPF_LSA_REFRESHER_GRANULARITY) - % (OSPF_LSA_REFRESHER_SLOTS); - - if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) - zlog_debug ("LSA[Refresh:Type%d:%s]: age %d, added to index %d", - lsa->data->type, inet_ntoa (lsa->data->id), LS_AGE (lsa), index); - - if (!ospf->lsa_refresh_queue.qs[index]) - ospf->lsa_refresh_queue.qs[index] = list_new (); - - listnode_add (ospf->lsa_refresh_queue.qs[index], - ospf_lsa_lock (lsa)); /* lsa_refresh_queue */ - lsa->refresh_list = index; - - if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) - zlog_debug ("LSA[Refresh:Type%d:%s]: ospf_refresher_register_lsa(): " - "setting refresh_list on lsa %p (slod %d)", - lsa->data->type, inet_ntoa (lsa->data->id), (void *)lsa, index); - } -} - -void -ospf_refresher_unregister_lsa (struct ospf *ospf, struct ospf_lsa *lsa) -{ - assert (lsa->lock > 0); - assert (IS_LSA_SELF (lsa)); - if (lsa->refresh_list >= 0) - { - struct list *refresh_list = ospf->lsa_refresh_queue.qs[lsa->refresh_list]; - listnode_delete (refresh_list, lsa); - if (!listcount (refresh_list)) - { - list_free (refresh_list); - ospf->lsa_refresh_queue.qs[lsa->refresh_list] = NULL; - } - ospf_lsa_unlock (&lsa); /* lsa_refresh_queue */ - lsa->refresh_list = -1; - } -} - -int -ospf_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 + - (monotime(NULL) - ospf->lsa_refresher_started) - / OSPF_LSA_REFRESHER_GRANULARITY)) - % OSPF_LSA_REFRESHER_SLOTS; - - if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) - zlog_debug ("LSA[Refresh]: ospf_lsa_refresh_walker(): next index %d", - ospf->lsa_refresh_queue.index); - - for (;i != ospf->lsa_refresh_queue.index; - i = (i + 1) % OSPF_LSA_REFRESHER_SLOTS) - { - if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) - zlog_debug ("LSA[Refresh]: ospf_lsa_refresh_walker(): " - "refresh index %d", i); - - refresh_list = ospf->lsa_refresh_queue.qs [i]; - - assert (i >= 0); - - ospf->lsa_refresh_queue.qs [i] = NULL; - - if (refresh_list) - { - for (ALL_LIST_ELEMENTS (refresh_list, node, nnode, lsa)) - { - if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) - zlog_debug ("LSA[Refresh:Type%d:%s]: ospf_lsa_refresh_walker(): " - "refresh lsa %p (slot %d)", - lsa->data->type, inet_ntoa (lsa->data->id), (void *)lsa, i); - - assert (lsa->lock > 0); - list_delete_node (refresh_list, node); - lsa->refresh_list = -1; - listnode_add (lsa_to_refresh, lsa); - } - list_free (refresh_list); - } - } - - ospf->t_lsa_refresher = NULL; - thread_add_timer(master, ospf_lsa_refresh_walker, ospf, ospf->lsa_refresh_interval, - &ospf->t_lsa_refresher); - ospf->lsa_refresher_started = monotime(NULL); - - for (ALL_LIST_ELEMENTS (lsa_to_refresh, node, nnode, lsa)) - { - ospf_lsa_refresh (ospf, lsa); - assert (lsa->lock > 0); - ospf_lsa_unlock (&lsa); /* lsa_refresh_queue & temp for lsa_to_refresh*/ - } - - list_delete (lsa_to_refresh); - - if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) - zlog_debug ("LSA[Refresh]: ospf_lsa_refresh_walker(): end"); - - return 0; +struct ospf_lsa *ospf_lsa_refresh(struct ospf *ospf, struct ospf_lsa *lsa) +{ + struct external_info *ei; + struct ospf_lsa *new = NULL; + assert(CHECK_FLAG(lsa->flags, OSPF_LSA_SELF)); + assert(IS_LSA_SELF(lsa)); + assert(lsa->lock > 0); + + 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; + case OSPF_OPAQUE_LINK_LSA: + case OSPF_OPAQUE_AREA_LSA: + case OSPF_OPAQUE_AS_LSA: + new = ospf_opaque_lsa_refresh(lsa); + break; + default: + break; + } + return new; } +void ospf_refresher_register_lsa(struct ospf *ospf, struct ospf_lsa *lsa) +{ + u_int16_t index, current_index; + + assert(lsa->lock > 0); + assert(IS_LSA_SELF(lsa)); + + if (lsa->refresh_list < 0) { + int delay; + int min_delay = + OSPF_LS_REFRESH_TIME - (2 * OSPF_LS_REFRESH_JITTER); + int max_delay = OSPF_LS_REFRESH_TIME - OSPF_LS_REFRESH_JITTER; + + /* We want to refresh the LSA within OSPF_LS_REFRESH_TIME which + * is + * 1800s. Use jitter so that we send the LSA sometime between + * 1680s + * and 1740s. + */ + delay = (random() % (max_delay - min_delay)) + min_delay; + + current_index = ospf->lsa_refresh_queue.index + + (monotime(NULL) - ospf->lsa_refresher_started) + / OSPF_LSA_REFRESHER_GRANULARITY; + + index = (current_index + delay / OSPF_LSA_REFRESHER_GRANULARITY) + % (OSPF_LSA_REFRESHER_SLOTS); + + if (IS_DEBUG_OSPF(lsa, LSA_REFRESH)) + zlog_debug( + "LSA[Refresh:Type%d:%s]: age %d, added to index %d", + lsa->data->type, inet_ntoa(lsa->data->id), + LS_AGE(lsa), index); + + if (!ospf->lsa_refresh_queue.qs[index]) + ospf->lsa_refresh_queue.qs[index] = list_new(); + + listnode_add(ospf->lsa_refresh_queue.qs[index], + ospf_lsa_lock(lsa)); /* lsa_refresh_queue */ + lsa->refresh_list = index; + + if (IS_DEBUG_OSPF(lsa, LSA_REFRESH)) + zlog_debug( + "LSA[Refresh:Type%d:%s]: ospf_refresher_register_lsa(): " + "setting refresh_list on lsa %p (slod %d)", + lsa->data->type, inet_ntoa(lsa->data->id), + (void *)lsa, index); + } +} + +void ospf_refresher_unregister_lsa(struct ospf *ospf, struct ospf_lsa *lsa) +{ + assert(lsa->lock > 0); + assert(IS_LSA_SELF(lsa)); + if (lsa->refresh_list >= 0) { + struct list *refresh_list = + ospf->lsa_refresh_queue.qs[lsa->refresh_list]; + listnode_delete(refresh_list, lsa); + if (!listcount(refresh_list)) { + list_free(refresh_list); + ospf->lsa_refresh_queue.qs[lsa->refresh_list] = NULL; + } + ospf_lsa_unlock(&lsa); /* lsa_refresh_queue */ + lsa->refresh_list = -1; + } +} + +int ospf_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 + + (monotime(NULL) + - ospf->lsa_refresher_started) + / OSPF_LSA_REFRESHER_GRANULARITY)) + % OSPF_LSA_REFRESHER_SLOTS; + + if (IS_DEBUG_OSPF(lsa, LSA_REFRESH)) + zlog_debug( + "LSA[Refresh]: ospf_lsa_refresh_walker(): next index %d", + ospf->lsa_refresh_queue.index); + + for (; i != ospf->lsa_refresh_queue.index; + i = (i + 1) % OSPF_LSA_REFRESHER_SLOTS) { + if (IS_DEBUG_OSPF(lsa, LSA_REFRESH)) + zlog_debug( + "LSA[Refresh]: ospf_lsa_refresh_walker(): " + "refresh index %d", + i); + + refresh_list = ospf->lsa_refresh_queue.qs[i]; + + assert(i >= 0); + + ospf->lsa_refresh_queue.qs[i] = NULL; + + if (refresh_list) { + for (ALL_LIST_ELEMENTS(refresh_list, node, nnode, + lsa)) { + if (IS_DEBUG_OSPF(lsa, LSA_REFRESH)) + zlog_debug( + "LSA[Refresh:Type%d:%s]: ospf_lsa_refresh_walker(): " + "refresh lsa %p (slot %d)", + lsa->data->type, + inet_ntoa(lsa->data->id), + (void *)lsa, i); + + assert(lsa->lock > 0); + list_delete_node(refresh_list, node); + lsa->refresh_list = -1; + listnode_add(lsa_to_refresh, lsa); + } + list_free(refresh_list); + } + } + + ospf->t_lsa_refresher = NULL; + thread_add_timer(master, ospf_lsa_refresh_walker, ospf, + ospf->lsa_refresh_interval, &ospf->t_lsa_refresher); + ospf->lsa_refresher_started = monotime(NULL); + + for (ALL_LIST_ELEMENTS(lsa_to_refresh, node, nnode, lsa)) { + ospf_lsa_refresh(ospf, lsa); + assert(lsa->lock > 0); + ospf_lsa_unlock( + &lsa); /* lsa_refresh_queue & temp for lsa_to_refresh*/ + } + + list_delete(lsa_to_refresh); + + if (IS_DEBUG_OSPF(lsa, LSA_REFRESH)) + zlog_debug("LSA[Refresh]: ospf_lsa_refresh_walker(): end"); + + return 0; +} |