mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-11-04 03:13:44 +00:00 
			
		
		
		
	This is largely a bulk-replace made with coccinelle. Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
		
			
				
	
	
		
			3763 lines
		
	
	
		
			102 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			3763 lines
		
	
	
		
			102 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * OSPF Link State Advertisement
 | 
						|
 * Copyright (C) 1999, 2000 Toshiaki Takada
 | 
						|
 *
 | 
						|
 * This file is part of GNU Zebra.
 | 
						|
 *
 | 
						|
 * GNU Zebra is free software; you can redistribute it and/or modify it
 | 
						|
 * under the terms of the GNU General Public License as published by the
 | 
						|
 * Free Software Foundation; either version 2, or (at your option) any
 | 
						|
 * later version.
 | 
						|
 *
 | 
						|
 * GNU Zebra is distributed in the hope that it will be useful, but
 | 
						|
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
 * General Public License for more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU General Public License
 | 
						|
 * along with GNU Zebra; see the file COPYING.  If not, write to the Free
 | 
						|
 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 | 
						|
 * 02111-1307, USA.
 | 
						|
 */
 | 
						|
 | 
						|
#include <zebra.h>
 | 
						|
 | 
						|
#include "monotime.h"
 | 
						|
#include "linklist.h"
 | 
						|
#include "prefix.h"
 | 
						|
#include "if.h"
 | 
						|
#include "table.h"
 | 
						|
#include "memory.h"
 | 
						|
#include "stream.h"
 | 
						|
#include "log.h"
 | 
						|
#include "thread.h"
 | 
						|
#include "hash.h"
 | 
						|
#include "sockunion.h"		/* for inet_aton() */
 | 
						|
#include "checksum.h"
 | 
						|
 | 
						|
#include "ospfd/ospfd.h"
 | 
						|
#include "ospfd/ospf_interface.h"
 | 
						|
#include "ospfd/ospf_ism.h"
 | 
						|
#include "ospfd/ospf_asbr.h"
 | 
						|
#include "ospfd/ospf_lsa.h"
 | 
						|
#include "ospfd/ospf_lsdb.h"
 | 
						|
#include "ospfd/ospf_neighbor.h"
 | 
						|
#include "ospfd/ospf_nsm.h"
 | 
						|
#include "ospfd/ospf_flood.h"
 | 
						|
#include "ospfd/ospf_packet.h"
 | 
						|
#include "ospfd/ospf_spf.h"
 | 
						|
#include "ospfd/ospf_dump.h"
 | 
						|
#include "ospfd/ospf_route.h"
 | 
						|
#include "ospfd/ospf_ase.h"
 | 
						|
#include "ospfd/ospf_zebra.h"
 | 
						|
 | 
						|
 | 
						|
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;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
struct timeval
 | 
						|
int2tv (int a)
 | 
						|
{
 | 
						|
  struct timeval ret;
 | 
						|
 | 
						|
  ret.tv_sec = a;
 | 
						|
  ret.tv_usec = 0;
 | 
						|
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
struct timeval
 | 
						|
msec2tv (int a)
 | 
						|
{
 | 
						|
  struct timeval ret;
 | 
						|
 | 
						|
  ret.tv_sec = a/1000;
 | 
						|
  ret.tv_usec = (a%1000) * 1000;
 | 
						|
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
ospf_lsa_refresh_delay (struct ospf_lsa *lsa)
 | 
						|
{
 | 
						|
  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);
 | 
						|
 | 
						|
      /* 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);
 | 
						|
 | 
						|
      assert (delay > 0);
 | 
						|
    }
 | 
						|
 | 
						|
  return delay;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
get_age (struct ospf_lsa *lsa)
 | 
						|
{
 | 
						|
  struct timeval rel;
 | 
						|
 | 
						|
  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 
 | 
						|
   one-based. */
 | 
						|
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 */
 | 
						|
 | 
						|
  /* 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;
 | 
						|
 | 
						|
  return fletcher_checksum(buffer, len, checksum_offset);
 | 
						|
}
 | 
						|
 | 
						|
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 */
 | 
						|
 | 
						|
  /* Skip the AGE field */
 | 
						|
  u_int16_t len = ntohs(lsa->length) - options_offset;
 | 
						|
 | 
						|
  return(fletcher_checksum(buffer, len, FLETCHER_CHECKSUM_VALIDATE) == 0);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/* Create OSPF LSA. */
 | 
						|
struct ospf_lsa *
 | 
						|
ospf_lsa_new ()
 | 
						|
{
 | 
						|
  struct ospf_lsa *new;
 | 
						|
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
/* Duplicate OSPF LSA. */
 | 
						|
struct ospf_lsa *
 | 
						|
ospf_lsa_dup (struct ospf_lsa *lsa)
 | 
						|
{
 | 
						|
  struct ospf_lsa *new;
 | 
						|
 | 
						|
  if (lsa == NULL)
 | 
						|
    return NULL;
 | 
						|
 | 
						|
  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);
 | 
						|
 | 
						|
  /* 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);
 | 
						|
 | 
						|
  return new;
 | 
						|
}
 | 
						|
 | 
						|
/* Free OSPF 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);
 | 
						|
 | 
						|
  /* Delete LSA data. */
 | 
						|
  if (lsa->data != NULL)
 | 
						|
    ospf_lsa_data_free (lsa->data);
 | 
						|
 | 
						|
  assert (lsa->refresh_list < 0);
 | 
						|
 | 
						|
  memset (lsa, 0, sizeof (struct ospf_lsa)); 
 | 
						|
  XFREE (MTYPE_OSPF_LSA, lsa);
 | 
						|
}
 | 
						|
 | 
						|
/* Lock LSA. */
 | 
						|
struct ospf_lsa *
 | 
						|
ospf_lsa_lock (struct ospf_lsa *lsa)
 | 
						|
{
 | 
						|
  lsa->lock++;
 | 
						|
  return lsa;
 | 
						|
}
 | 
						|
 | 
						|
/* Unlock LSA. */
 | 
						|
void
 | 
						|
ospf_lsa_unlock (struct ospf_lsa **lsa)
 | 
						|
{
 | 
						|
  /* This is sanity check. */
 | 
						|
  if (!lsa || !*lsa)
 | 
						|
    return;
 | 
						|
  
 | 
						|
  (*lsa)->lock--;
 | 
						|
 | 
						|
  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)
 | 
						|
{
 | 
						|
  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)
 | 
						|
{
 | 
						|
  return XCALLOC (MTYPE_OSPF_LSA_DATA, size);
 | 
						|
}
 | 
						|
 | 
						|
/* Duplicate LSA data. */
 | 
						|
struct lsa_header *
 | 
						|
ospf_lsa_data_dup (struct lsa_header *lsah)
 | 
						|
{
 | 
						|
  struct lsa_header *new;
 | 
						|
 | 
						|
  new = ospf_lsa_data_new (ntohs (lsah->length));
 | 
						|
  memcpy (new, lsah, ntohs (lsah->length));
 | 
						|
 | 
						|
  return new;
 | 
						|
}
 | 
						|
 | 
						|
/* Free LSA data. */
 | 
						|
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);
 | 
						|
 | 
						|
  XFREE (MTYPE_OSPF_LSA_DATA, lsah);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* LSA general functions. */
 | 
						|
 | 
						|
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;
 | 
						|
 | 
						|
  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");
 | 
						|
 | 
						|
  return buf;
 | 
						|
}
 | 
						|
 | 
						|
u_int32_t
 | 
						|
lsa_seqnum_increment (struct ospf_lsa *lsa)
 | 
						|
{
 | 
						|
  u_int32_t seqnum;
 | 
						|
 | 
						|
  seqnum = ntohl (lsa->data->ls_seqnum) + 1;
 | 
						|
 | 
						|
  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)
 | 
						|
{
 | 
						|
  struct lsa_header *lsah;
 | 
						|
 | 
						|
  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);
 | 
						|
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
/* Lookup neighbor other than myself.
 | 
						|
   And check neighbor count,
 | 
						|
   Point-to-Point link must have only 1 neighbor. */
 | 
						|
struct ospf_neighbor *
 | 
						|
ospf_nbr_lookup_ptop (struct ospf_interface *oi)
 | 
						|
{
 | 
						|
  struct ospf_neighbor *nbr = NULL;
 | 
						|
  struct route_node *rn;
 | 
						|
 | 
						|
  /* Search neighbor, there must be one of two nbrs. */
 | 
						|
  for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
 | 
						|
    if ((nbr = rn->info))
 | 
						|
      if (!IPV4_ADDR_SAME (&nbr->router_id, &oi->ospf->router_id))
 | 
						|
	if (nbr->state == NSM_Full)
 | 
						|
	  {
 | 
						|
	    route_unlock_node (rn);
 | 
						|
	    break;
 | 
						|
	  }
 | 
						|
 | 
						|
  /* PtoP link must have only 1 neighbor. */
 | 
						|
  if (ospf_nbr_count (oi, 0) > 1)
 | 
						|
    zlog_warn ("Point-to-Point link has more than 1 neighobrs.");
 | 
						|
 | 
						|
  return nbr;
 | 
						|
}
 | 
						|
 | 
						|
/* Determine cost of link, taking RFC3137 stub-router support into
 | 
						|
 * consideration
 | 
						|
 */
 | 
						|
static u_int16_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;
 | 
						|
}
 | 
						|
 | 
						|
/* 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;
 | 
						|
}
 | 
						|
 | 
						|
/* 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;
 | 
						|
}
 | 
						|
 | 
						|
/* 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);
 | 
						|
}
 | 
						|
 | 
						|
/* Describe Virtual Link. */
 | 
						|
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);
 | 
						|
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
#define lsa_link_nbma_set(S,O)  lsa_link_broadcast_set (S, O)
 | 
						|
 | 
						|
/* 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;
 | 
						|
}
 | 
						|
 | 
						|
/* 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); 
 | 
						|
		}
 | 
						|
	      oi->lsa_pos_end = 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);
 | 
						|
}
 | 
						|
 
 | 
						|
/* 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;
 | 
						|
}
 | 
						|
 | 
						|
/* Originate Router-LSA. */
 | 
						|
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;
 | 
						|
    }
 | 
						|
 | 
						|
  /* 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);
 | 
						|
 | 
						|
  /* 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 router-LSA %p",
 | 
						|
		 new->data->type, inet_ntoa (new->data->id), (void *)new);
 | 
						|
      ospf_lsa_header_dump (new->data);
 | 
						|
    }
 | 
						|
 | 
						|
  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);
 | 
						|
 | 
						|
  /* 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);
 | 
						|
 | 
						|
  ospf_lsa_install (area->ospf, NULL, new);
 | 
						|
 | 
						|
  /* 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;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
ospf_router_lsa_update_area (struct ospf_area *area)
 | 
						|
{
 | 
						|
  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);
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
ospf_router_lsa_update (struct ospf *ospf)
 | 
						|
{
 | 
						|
  struct listnode *node, *nnode;
 | 
						|
  struct ospf_area *area;
 | 
						|
 | 
						|
  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;
 | 
						|
 | 
						|
      /* 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);
 | 
						|
 | 
						|
	  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;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* network-LSA related functions. */
 | 
						|
/* Originate Network-LSA. */
 | 
						|
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;
 | 
						|
 | 
						|
  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 */
 | 
						|
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
/* Originate network-LSA. */
 | 
						|
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;
 | 
						|
 | 
						|
  /* Install LSA to LSDB. */
 | 
						|
  new = ospf_lsa_install (oi->ospf, oi, new);
 | 
						|
 | 
						|
  /* Update LSA origination count. */
 | 
						|
  oi->ospf->lsa_originate_count++;
 | 
						|
 | 
						|
  /* 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;
 | 
						|
}
 | 
						|
 | 
						|
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)
 | 
						|
{
 | 
						|
  struct in_addr mask;
 | 
						|
 | 
						|
  masklen2ip (p->prefixlen, &mask);
 | 
						|
 | 
						|
  /* Put Network Mask. */
 | 
						|
  stream_put_ipv4 (s, mask.s_addr);
 | 
						|
 | 
						|
  /* Set # TOS. */
 | 
						|
  stream_putc (s, (u_char) 0);
 | 
						|
 | 
						|
  /* 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)
 | 
						|
{
 | 
						|
  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 (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);
 | 
						|
 | 
						|
  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 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);
 | 
						|
 | 
						|
  /* Copy LSA to store. */
 | 
						|
  new->data = ospf_lsa_data_new (length);
 | 
						|
  memcpy (new->data, lsah, length);
 | 
						|
  stream_free (s);
 | 
						|
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* summary-ASBR-LSA related functions. */
 | 
						|
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);
 | 
						|
 | 
						|
  /* Set # TOS. */
 | 
						|
  stream_putc (s, (u_char) 0);
 | 
						|
 | 
						|
  /* 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)
 | 
						|
{
 | 
						|
  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 (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);
 | 
						|
 | 
						|
  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 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);
 | 
						|
 | 
						|
  /* Copy LSA to store. */
 | 
						|
  new->data = ospf_lsa_data_new (length);
 | 
						|
  memcpy (new->data, lsah, length);
 | 
						|
  stream_free (s);
 | 
						|
 | 
						|
  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);
 | 
						|
 | 
						|
  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)
 | 
						|
{
 | 
						|
  struct in_addr fwd;
 | 
						|
  struct prefix nh;
 | 
						|
  struct listnode *node;
 | 
						|
  struct ospf_interface *oi;
 | 
						|
 | 
						|
  fwd.s_addr = 0;
 | 
						|
 | 
						|
  if (!nexthop.s_addr)
 | 
						|
    return fwd;
 | 
						|
 | 
						|
  /* Check whether nexthop is covered by OSPF network. */
 | 
						|
  nh.family = AF_INET;
 | 
						|
  nh.u.prefix4 = nexthop;
 | 
						|
  nh.prefixlen = IPV4_MAX_BITLEN;
 | 
						|
  
 | 
						|
  /* XXX/SCALE: If there were a lot of oi's on an ifp, then it'd be
 | 
						|
   * better to make use of the per-ifp table of ois.
 | 
						|
   */
 | 
						|
  for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi))
 | 
						|
    if (if_is_operative (oi->ifp))
 | 
						|
      if (oi->address->family == AF_INET)
 | 
						|
        if (prefix_match (oi->address, &nh))
 | 
						|
          return nexthop;
 | 
						|
 | 
						|
  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 fwd;
 | 
						|
 | 
						|
  fwd.s_addr = 0;
 | 
						|
 | 
						|
  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;
 | 
						|
 | 
						|
  if (best_default.s_addr != 0)
 | 
						|
    return best_default;
 | 
						|
 | 
						|
  return fwd;
 | 
						|
}
 | 
						|
 | 
						|
#define DEFAULT_DEFAULT_METRIC	             20
 | 
						|
#define DEFAULT_DEFAULT_ORIGINATE_METRIC     10
 | 
						|
#define DEFAULT_DEFAULT_ALWAYS_METRIC	      1
 | 
						|
 | 
						|
#define DEFAULT_METRIC_TYPE		     EXTERNAL_METRIC_TYPE_2
 | 
						|
 | 
						|
int
 | 
						|
metric_type (struct ospf *ospf, u_char src, u_short instance)
 | 
						|
{
 | 
						|
  struct ospf_redist *red;
 | 
						|
 | 
						|
  red = ospf_redist_lookup(ospf, src, instance);
 | 
						|
 | 
						|
  return ((!red || red->dmetric.type < 0) ?
 | 
						|
	  DEFAULT_METRIC_TYPE : red->dmetric.type);
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
metric_value (struct ospf *ospf, u_char src, u_short instance)
 | 
						|
{
 | 
						|
  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;
 | 
						|
	}
 | 
						|
      else if (ospf->default_metric < 0)
 | 
						|
	return DEFAULT_DEFAULT_METRIC;
 | 
						|
      else
 | 
						|
	return ospf->default_metric;
 | 
						|
    }
 | 
						|
 | 
						|
  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);
 | 
						|
}
 | 
						|
 | 
						|
/* 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;
 | 
						|
}
 | 
						|
 | 
						|
/* 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 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;
 | 
						|
}
 | 
						|
 | 
						|
/* 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);
 | 
						|
}
 | 
						|
 | 
						|
/* 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;
 | 
						|
}
 | 
						|
 | 
						|
/* 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;
 | 
						|
}
 | 
						|
 | 
						|
/* 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);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* 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. */
 | 
						|
#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);
 | 
						|
	    }
 | 
						|
}
 | 
						|
 | 
						|
/* 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;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* LSA installation functions. */
 | 
						|
 | 
						|
/* Install router-LSA to an area. */
 | 
						|
static struct ospf_lsa *
 | 
						|
ospf_router_lsa_install (struct ospf *ospf, struct ospf_lsa *new,
 | 
						|
                         int rt_recalc)
 | 
						|
{
 | 
						|
  struct ospf_area *area = new->area;
 | 
						|
 | 
						|
  /* RFC 2328 Section 13.2 Router-LSAs and network-LSAs
 | 
						|
     The entire routing table must be recalculated, starting with
 | 
						|
     the shortest path calculations for each area (not just the
 | 
						|
     area whose link-state database has changed). 
 | 
						|
  */
 | 
						|
 | 
						|
  if (IS_LSA_SELF (new))
 | 
						|
    {
 | 
						|
 | 
						|
      /* Only install LSA if it is originated/refreshed by us.
 | 
						|
       * If LSA was received by flooding, the RECEIVED flag is set so do
 | 
						|
       * not link the LSA */
 | 
						|
      if (CHECK_FLAG (new->flags, OSPF_LSA_RECEIVED))
 | 
						|
	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);
 | 
						|
 | 
						|
      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))
 | 
						|
 | 
						|
/* 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;
 | 
						|
}
 | 
						|
 | 
						|
/* Install summary-LSA to an area. */
 | 
						|
static struct ospf_lsa *
 | 
						|
ospf_summary_lsa_install (struct ospf *ospf, struct ospf_lsa *new,
 | 
						|
			  int rt_recalc)
 | 
						|
{
 | 
						|
  if (rt_recalc && !IS_LSA_SELF (new))
 | 
						|
    {
 | 
						|
      /* RFC 2328 Section 13.2 Summary-LSAs
 | 
						|
	 The best route to the destination described by the summary-
 | 
						|
	 LSA must be recalculated (see Section 16.5).  If this
 | 
						|
	 destination is an AS boundary router, it may also be
 | 
						|
	 necessary to re-examine all the AS-external-LSAs.
 | 
						|
      */
 | 
						|
 | 
						|
#if 0
 | 
						|
      /* This doesn't exist yet... */
 | 
						|
      ospf_summary_incremental_update(new); */
 | 
						|
#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);
 | 
						|
 | 
						|
  return new;
 | 
						|
}
 | 
						|
 | 
						|
/* Install ASBR-summary-LSA to an area. */
 | 
						|
static struct ospf_lsa *
 | 
						|
ospf_summary_asbr_lsa_install (struct ospf *ospf, struct ospf_lsa *new,
 | 
						|
			       int rt_recalc)
 | 
						|
{
 | 
						|
  if (rt_recalc && !IS_LSA_SELF (new))
 | 
						|
    {
 | 
						|
      /* RFC 2328 Section 13.2 Summary-LSAs
 | 
						|
	 The best route to the destination described by the summary-
 | 
						|
	 LSA must be recalculated (see Section 16.5).  If this
 | 
						|
	 destination is an AS boundary router, it may also be
 | 
						|
	 necessary to re-examine all the AS-external-LSAs.
 | 
						|
      */
 | 
						|
#if 0
 | 
						|
      /* These don't exist yet... */
 | 
						|
      ospf_summary_incremental_update(new);
 | 
						|
      /* Isn't this done by the above call? 
 | 
						|
	 - RFC 2328 Section 16.5 implies it should be */
 | 
						|
      /* ospf_ase_calculate_schedule(); */
 | 
						|
#else  /* #if 0 */
 | 
						|
      ospf_spf_calculate_schedule (ospf, 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);
 | 
						|
 | 
						|
  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 (ospf_lsa_type_msg, new->data->type));
 | 
						|
          break;
 | 
						|
        default:
 | 
						|
	  strcpy (area_str, inet_ntoa (new->area->area_id));
 | 
						|
          zlog_debug ("LSA[%s]: Install %s to Area %s",
 | 
						|
                 dump_lsa_key (new),
 | 
						|
                 LOOKUP (ospf_lsa_type_msg, new->data->type), area_str);
 | 
						|
          break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
  /* 
 | 
						|
     If received LSA' ls_age is MaxAge, or lsa is being prematurely aged
 | 
						|
     (it's getting flushed out of the area), set LSA on MaxAge LSA list. 
 | 
						|
   */
 | 
						|
  if (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.
 | 
						|
 * This does *not* lead to the LSA being flooded, that must be taken
 | 
						|
 * care of elsewhere, see, e.g., ospf_lsa_flush* (which are callers of this
 | 
						|
 * function).
 | 
						|
 */
 | 
						|
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;
 | 
						|
}
 | 
						|
 | 
						|
/* 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;
 | 
						|
}
 | 
						|
 | 
						|
/* If two LSAs are different, return 1, otherwise return 0. */
 | 
						|
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);
 | 
						|
 | 
						|
  if (l1->data->options != l2->data->options)
 | 
						|
    return 1;
 | 
						|
 | 
						|
  if (IS_LSA_MAXAGE (l1) && !IS_LSA_MAXAGE (l2))
 | 
						|
    return 1;
 | 
						|
 | 
						|
  if (IS_LSA_MAXAGE (l2) && !IS_LSA_MAXAGE (l1))
 | 
						|
    return 1;
 | 
						|
 | 
						|
  if (l1->data->length != l2->data->length)
 | 
						|
    return 1;
 | 
						|
 | 
						|
  if (l1->data->length ==  0)
 | 
						|
    return 1;
 | 
						|
 | 
						|
  if (CHECK_FLAG ((l1->flags ^ l2->flags), OSPF_LSA_RECEIVED))
 | 
						|
    return 1; /* May be a stale LSA in the LSBD */
 | 
						|
 | 
						|
  assert ( ntohs(l1->data->length) > OSPF_LSA_HEADER_SIZE);
 | 
						|
 | 
						|
  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;
 | 
						|
 | 
						|
  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;
 | 
						|
}
 | 
						|
#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);
 | 
						|
}
 | 
						|
 | 
						|
/* 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;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#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;
 | 
						|
};
 | 
						|
 | 
						|
static int
 | 
						|
ospf_lsa_action (struct thread *t)
 | 
						|
{
 | 
						|
  struct lsa_action *data;
 | 
						|
 | 
						|
  data = THREAD_ARG (t);
 | 
						|
 | 
						|
  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;
 | 
						|
    }
 | 
						|
 | 
						|
  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)
 | 
						|
{
 | 
						|
  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 */
 | 
						|
 | 
						|
  thread_add_event (master, ospf_lsa_action, data, 0);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ospf_schedule_lsa_flush_area (struct ospf_area *area, struct ospf_lsa *lsa)
 | 
						|
{
 | 
						|
  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 */
 | 
						|
 | 
						|
  thread_add_event (master, ospf_lsa_action, data, 0);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* 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 = thread_add_timer (master, ospf_lsa_refresh_walker,
 | 
						|
					   ospf, ospf->lsa_refresh_interval);
 | 
						|
  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;
 | 
						|
}
 | 
						|
 |