mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-11-04 10:07:04 +00:00 
			
		
		
		
	ospf_apiserver * from listnode.  Remove unused variables.  Follows
        suggestion from Jay Fenlason.
		
	
			
		
			
				
	
	
		
			2656 lines
		
	
	
		
			66 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2656 lines
		
	
	
		
			66 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Server side of OSPF API.
 | 
						|
 * Copyright (C) 2001, 2002 Ralph Keller
 | 
						|
 *
 | 
						|
 * 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>
 | 
						|
 | 
						|
#ifdef SUPPORT_OSPF_API
 | 
						|
#ifndef HAVE_OPAQUE_LSA
 | 
						|
#error "Core Opaque-LSA module must be configured."
 | 
						|
#endif /* HAVE_OPAQUE_LSA */
 | 
						|
 | 
						|
#include "linklist.h"
 | 
						|
#include "prefix.h"
 | 
						|
#include "if.h"
 | 
						|
#include "table.h"
 | 
						|
#include "memory.h"
 | 
						|
#include "command.h"
 | 
						|
#include "vty.h"
 | 
						|
#include "stream.h"
 | 
						|
#include "log.h"
 | 
						|
#include "thread.h"
 | 
						|
#include "hash.h"
 | 
						|
#include "sockunion.h"		/* for inet_aton() */
 | 
						|
#include "buffer.h"
 | 
						|
 | 
						|
#include <sys/types.h>
 | 
						|
 | 
						|
#include "ospfd/ospfd.h"        /* for "struct thread_master" */
 | 
						|
#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"
 | 
						|
 | 
						|
#include "ospfd/ospf_api.h"
 | 
						|
#include "ospfd/ospf_apiserver.h"
 | 
						|
 | 
						|
/* This is an implementation of an API to the OSPF daemon that allows
 | 
						|
 * external applications to access the OSPF daemon through socket
 | 
						|
 * connections. The application can use this API to inject its own
 | 
						|
 * opaque LSAs and flood them to other OSPF daemons. Other OSPF
 | 
						|
 * daemons then receive these LSAs and inform applications through the
 | 
						|
 * API by sending a corresponding message. The application can also
 | 
						|
 * register to receive all LSA types (in addition to opaque types) and
 | 
						|
 * use this information to reconstruct the OSPF's LSDB. The OSPF
 | 
						|
 * daemon supports multiple applications concurrently.  */
 | 
						|
 | 
						|
/* List of all active connections. */
 | 
						|
struct list *apiserver_list;
 | 
						|
 | 
						|
/* -----------------------------------------------------------
 | 
						|
 * Functions to lookup interfaces
 | 
						|
 * -----------------------------------------------------------
 | 
						|
 */
 | 
						|
 | 
						|
struct ospf_interface *
 | 
						|
ospf_apiserver_if_lookup_by_addr (struct in_addr address)
 | 
						|
{
 | 
						|
  struct listnode *node;
 | 
						|
  struct ospf_interface *oi;
 | 
						|
  struct ospf *ospf;
 | 
						|
 | 
						|
  if (!(ospf = ospf_lookup ()))
 | 
						|
    return NULL;
 | 
						|
 | 
						|
  for (node = listhead (ospf->oiflist); node; nextnode (node))
 | 
						|
  LIST_LOOP (ospf->oiflist, oi, node)
 | 
						|
    if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
 | 
						|
      if (IPV4_ADDR_SAME (&address, &oi->address->u.prefix4))
 | 
						|
        return oi;
 | 
						|
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
struct ospf_interface *
 | 
						|
ospf_apiserver_if_lookup_by_ifp (struct interface *ifp)
 | 
						|
{
 | 
						|
  struct listnode *node;
 | 
						|
  struct ospf_interface *oi;
 | 
						|
  struct ospf *ospf;
 | 
						|
 | 
						|
  if (!(ospf = ospf_lookup ()));
 | 
						|
    return NULL;
 | 
						|
 | 
						|
  LIST_LOOP (ospf->oiflist, oi, node)
 | 
						|
    if (oi->ifp == ifp)
 | 
						|
      return oi;
 | 
						|
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
/* -----------------------------------------------------------
 | 
						|
 * Initialization
 | 
						|
 * -----------------------------------------------------------
 | 
						|
 */
 | 
						|
 | 
						|
unsigned short
 | 
						|
ospf_apiserver_getport (void)
 | 
						|
{
 | 
						|
  struct servent *sp = getservbyname ("ospfapi", "tcp");
 | 
						|
 | 
						|
  return sp ? ntohs (sp->s_port) : OSPF_API_SYNC_PORT;
 | 
						|
}
 | 
						|
 | 
						|
/* Initialize OSPF API module. Invoked from ospf_opaque_init() */
 | 
						|
int
 | 
						|
ospf_apiserver_init (void)
 | 
						|
{
 | 
						|
  int fd;
 | 
						|
  int rc = -1;
 | 
						|
 | 
						|
  /* Create new socket for synchronous messages. */
 | 
						|
  fd = ospf_apiserver_serv_sock_family (ospf_apiserver_getport (), AF_INET);
 | 
						|
 | 
						|
  if (fd < 0)
 | 
						|
    goto out;
 | 
						|
 | 
						|
  /* Schedule new thread that handles accepted connections. */
 | 
						|
  ospf_apiserver_event (OSPF_APISERVER_ACCEPT, fd, NULL);
 | 
						|
 | 
						|
  /* Initialize list that keeps track of all connections. */
 | 
						|
  apiserver_list = list_new ();
 | 
						|
 | 
						|
  /* Register opaque-independent call back functions. These functions
 | 
						|
     are invoked on ISM, NSM changes and LSA update and LSA deletes */
 | 
						|
  rc =
 | 
						|
    ospf_register_opaque_functab (0 /* all LSAs */, 
 | 
						|
				  0 /* all opaque types */,
 | 
						|
				  ospf_apiserver_new_if,
 | 
						|
				  ospf_apiserver_del_if,
 | 
						|
				  ospf_apiserver_ism_change,
 | 
						|
				  ospf_apiserver_nsm_change,
 | 
						|
				  NULL,
 | 
						|
				  NULL,
 | 
						|
				  NULL,
 | 
						|
				  NULL, /* ospf_apiserver_show_info */
 | 
						|
				  NULL, /* originator_func */
 | 
						|
				  NULL, /* ospf_apiserver_lsa_refresher */
 | 
						|
				  ospf_apiserver_lsa_update,
 | 
						|
				  ospf_apiserver_lsa_delete);
 | 
						|
  if (rc != 0)
 | 
						|
    {
 | 
						|
      zlog_warn ("ospf_apiserver_init: Failed to register opaque type [0/0]");
 | 
						|
    }
 | 
						|
 | 
						|
  rc = 0;
 | 
						|
 | 
						|
out:
 | 
						|
  return rc;
 | 
						|
}
 | 
						|
 | 
						|
/* Terminate OSPF API module. */
 | 
						|
void
 | 
						|
ospf_apiserver_term (void)
 | 
						|
{
 | 
						|
  struct ospf_apiserver *apiserv;
 | 
						|
 | 
						|
  /* Unregister wildcard [0/0] type */
 | 
						|
  ospf_delete_opaque_functab (0 /* all LSAs */, 
 | 
						|
			      0 /* all opaque types */);
 | 
						|
 | 
						|
  /*
 | 
						|
   * Free all client instances.  ospf_apiserver_free removes the node
 | 
						|
   * from the list, so we examine the head of the list anew each time.
 | 
						|
   */
 | 
						|
  while ( (apiserv = getdata (listhead (apiserver_list))) != NULL)
 | 
						|
    ospf_apiserver_free (apiserv);
 | 
						|
 | 
						|
  /* Free client list itself */
 | 
						|
  list_delete (apiserver_list);
 | 
						|
 | 
						|
  /* Free wildcard list */
 | 
						|
  /* XXX  */
 | 
						|
}
 | 
						|
 | 
						|
static struct ospf_apiserver *
 | 
						|
lookup_apiserver (u_char lsa_type, u_char opaque_type)
 | 
						|
{
 | 
						|
  struct listnode *n1, *n2;
 | 
						|
  struct registered_opaque_type *r;
 | 
						|
  struct ospf_apiserver *apiserv, *found = NULL;
 | 
						|
 | 
						|
  /* XXX: this approaches O(n**2) */
 | 
						|
  for (n1 = listhead (apiserver_list); n1; nextnode (n1))
 | 
						|
    {
 | 
						|
      apiserv = (struct ospf_apiserver *) getdata (n1);
 | 
						|
 | 
						|
      for (n2 = listhead (apiserv->opaque_types); n2; nextnode (n2))
 | 
						|
	{
 | 
						|
	  r = (struct registered_opaque_type *) getdata (n2);
 | 
						|
 | 
						|
          if (r->lsa_type == lsa_type && r->opaque_type == opaque_type)
 | 
						|
            {
 | 
						|
              found = apiserv;
 | 
						|
              goto out;
 | 
						|
            }
 | 
						|
	}
 | 
						|
    }
 | 
						|
out:
 | 
						|
  return found;
 | 
						|
}
 | 
						|
 | 
						|
static struct ospf_apiserver *
 | 
						|
lookup_apiserver_by_lsa (struct ospf_lsa *lsa)
 | 
						|
{
 | 
						|
  struct lsa_header *lsah = lsa->data;
 | 
						|
  struct ospf_apiserver *found = NULL;
 | 
						|
 | 
						|
  if (IS_OPAQUE_LSA (lsah->type))
 | 
						|
    {
 | 
						|
      found = lookup_apiserver (lsah->type,
 | 
						|
                                GET_OPAQUE_TYPE (ntohl (lsah->id.s_addr)));
 | 
						|
    }
 | 
						|
  return found;
 | 
						|
}
 | 
						|
 | 
						|
/* -----------------------------------------------------------
 | 
						|
 * Followings are functions to manage client connections.
 | 
						|
 * -----------------------------------------------------------
 | 
						|
 */
 | 
						|
static int
 | 
						|
ospf_apiserver_new_lsa_hook (struct ospf_lsa *lsa)
 | 
						|
{
 | 
						|
  if (IS_DEBUG_OSPF_EVENT)
 | 
						|
    zlog_debug ("API: Put LSA(%p)[%s] into reserve, total=%ld", lsa, dump_lsa_key (lsa), lsa->lsdb->total);
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
ospf_apiserver_del_lsa_hook (struct ospf_lsa *lsa)
 | 
						|
{
 | 
						|
  if (IS_DEBUG_OSPF_EVENT)
 | 
						|
    zlog_debug ("API: Get LSA(%p)[%s] from reserve, total=%ld", lsa, dump_lsa_key (lsa), lsa->lsdb->total);
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* Allocate new connection structure. */
 | 
						|
struct ospf_apiserver *
 | 
						|
ospf_apiserver_new (int fd_sync, int fd_async)
 | 
						|
{
 | 
						|
  struct ospf_apiserver *new =
 | 
						|
    XMALLOC (MTYPE_OSPF_APISERVER, sizeof (struct ospf_apiserver));
 | 
						|
 | 
						|
  new->filter =
 | 
						|
    XMALLOC (MTYPE_OSPF_APISERVER_MSGFILTER, sizeof (struct lsa_filter_type));
 | 
						|
 | 
						|
  new->fd_sync = fd_sync;
 | 
						|
  new->fd_async = fd_async;
 | 
						|
 | 
						|
  /* list of registered opaque types that application uses */
 | 
						|
  new->opaque_types = list_new ();
 | 
						|
 | 
						|
  /* Initialize temporary strage for LSA instances to be refreshed. */
 | 
						|
  memset (&new->reserve, 0, sizeof (struct ospf_lsdb));
 | 
						|
  ospf_lsdb_init (&new->reserve);
 | 
						|
 | 
						|
  new->reserve.new_lsa_hook = ospf_apiserver_new_lsa_hook; /* debug */
 | 
						|
  new->reserve.del_lsa_hook = ospf_apiserver_del_lsa_hook; /* debug */
 | 
						|
 | 
						|
  new->out_sync_fifo = msg_fifo_new ();
 | 
						|
  new->out_async_fifo = msg_fifo_new ();
 | 
						|
  new->t_sync_read = NULL;
 | 
						|
#ifdef USE_ASYNC_READ
 | 
						|
  new->t_async_read = NULL;
 | 
						|
#endif /* USE_ASYNC_READ */
 | 
						|
  new->t_sync_write = NULL;
 | 
						|
  new->t_async_write = NULL;
 | 
						|
 | 
						|
  new->filter->typemask = 0;	/* filter all LSAs */
 | 
						|
  new->filter->origin = ANY_ORIGIN;
 | 
						|
  new->filter->num_areas = 0;
 | 
						|
 | 
						|
  return new;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ospf_apiserver_event (enum event event, int fd,
 | 
						|
		      struct ospf_apiserver *apiserv)
 | 
						|
{
 | 
						|
  struct thread *apiserver_serv_thread;
 | 
						|
 | 
						|
  switch (event)
 | 
						|
    {
 | 
						|
    case OSPF_APISERVER_ACCEPT:
 | 
						|
      apiserver_serv_thread =
 | 
						|
	thread_add_read (master, ospf_apiserver_accept, apiserv, fd);
 | 
						|
      break;
 | 
						|
    case OSPF_APISERVER_SYNC_READ:
 | 
						|
      apiserv->t_sync_read =
 | 
						|
	thread_add_read (master, ospf_apiserver_read, apiserv, fd);
 | 
						|
      break;
 | 
						|
#ifdef USE_ASYNC_READ
 | 
						|
    case OSPF_APISERVER_ASYNC_READ:
 | 
						|
      apiserv->t_async_read =
 | 
						|
	thread_add_read (master, ospf_apiserver_read, apiserv, fd);
 | 
						|
      break;
 | 
						|
#endif /* USE_ASYNC_READ */
 | 
						|
    case OSPF_APISERVER_SYNC_WRITE:
 | 
						|
      if (!apiserv->t_sync_write)
 | 
						|
	{
 | 
						|
	  apiserv->t_sync_write =
 | 
						|
	    thread_add_write (master, ospf_apiserver_sync_write, apiserv, fd);
 | 
						|
	}
 | 
						|
      break;
 | 
						|
    case OSPF_APISERVER_ASYNC_WRITE:
 | 
						|
      if (!apiserv->t_async_write)
 | 
						|
	{
 | 
						|
	  apiserv->t_async_write =
 | 
						|
	    thread_add_write (master, ospf_apiserver_async_write, apiserv, fd);
 | 
						|
	}
 | 
						|
      break;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* Free instance. First unregister all opaque types used by
 | 
						|
   application, flush opaque LSAs injected by application 
 | 
						|
   from network and close connection. */
 | 
						|
void
 | 
						|
ospf_apiserver_free (struct ospf_apiserver *apiserv)
 | 
						|
{
 | 
						|
  struct listnode *node;
 | 
						|
 | 
						|
  /* Cancel read and write threads. */
 | 
						|
  if (apiserv->t_sync_read)
 | 
						|
    {
 | 
						|
      thread_cancel (apiserv->t_sync_read);
 | 
						|
    }
 | 
						|
#ifdef USE_ASYNC_READ
 | 
						|
  if (apiserv->t_async_read)
 | 
						|
    {
 | 
						|
      thread_cancel (apiserv->t_async_read);
 | 
						|
    }
 | 
						|
#endif /* USE_ASYNC_READ */
 | 
						|
  if (apiserv->t_sync_write)
 | 
						|
    {
 | 
						|
      thread_cancel (apiserv->t_sync_write);
 | 
						|
    }
 | 
						|
 | 
						|
  if (apiserv->t_async_write)
 | 
						|
    {
 | 
						|
      thread_cancel (apiserv->t_async_write);
 | 
						|
    }
 | 
						|
 | 
						|
  /* Unregister all opaque types that application registered 
 | 
						|
     and flush opaque LSAs if still in LSDB. */
 | 
						|
 | 
						|
  while ((node = listhead (apiserv->opaque_types)) != NULL)
 | 
						|
    {
 | 
						|
 | 
						|
      struct registered_opaque_type *regtype = node->data;
 | 
						|
 | 
						|
      ospf_apiserver_unregister_opaque_type (apiserv, regtype->lsa_type,
 | 
						|
					     regtype->opaque_type);
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
  /* Close connections to OSPFd. */
 | 
						|
  if (apiserv->fd_sync > 0)
 | 
						|
    {
 | 
						|
      close (apiserv->fd_sync);
 | 
						|
    }
 | 
						|
 | 
						|
  if (apiserv->fd_async > 0)
 | 
						|
    {
 | 
						|
      close (apiserv->fd_async);
 | 
						|
    }
 | 
						|
 | 
						|
  /* Free fifos */
 | 
						|
  msg_fifo_free (apiserv->out_sync_fifo);
 | 
						|
  msg_fifo_free (apiserv->out_async_fifo);
 | 
						|
 | 
						|
  /* Clear temporary strage for LSA instances to be refreshed. */
 | 
						|
  ospf_lsdb_delete_all (&apiserv->reserve);
 | 
						|
  ospf_lsdb_cleanup (&apiserv->reserve);
 | 
						|
 | 
						|
  /* Remove from the list of active clients. */
 | 
						|
  listnode_delete (apiserver_list, apiserv);
 | 
						|
 | 
						|
  if (IS_DEBUG_OSPF_EVENT)
 | 
						|
    zlog_debug ("API: Delete apiserv(%p), total#(%d)", apiserv, apiserver_list->count);
 | 
						|
 | 
						|
  /* And free instance. */
 | 
						|
  XFREE (MTYPE_OSPF_APISERVER, apiserv);
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
ospf_apiserver_read (struct thread *thread)
 | 
						|
{
 | 
						|
  struct ospf_apiserver *apiserv;
 | 
						|
  struct msg *msg;
 | 
						|
  int fd;
 | 
						|
  int rc = -1;
 | 
						|
  enum event event;
 | 
						|
 | 
						|
  apiserv = THREAD_ARG (thread);
 | 
						|
  fd = THREAD_FD (thread);
 | 
						|
 | 
						|
  if (fd == apiserv->fd_sync)
 | 
						|
    {
 | 
						|
      event = OSPF_APISERVER_SYNC_READ;
 | 
						|
      apiserv->t_sync_read = NULL;
 | 
						|
 | 
						|
      if (IS_DEBUG_OSPF_EVENT)
 | 
						|
        zlog_debug ("API: ospf_apiserver_read: Peer: %s/%u",
 | 
						|
                    inet_ntoa (apiserv->peer_sync.sin_addr),
 | 
						|
                    ntohs (apiserv->peer_sync.sin_port));
 | 
						|
    }
 | 
						|
#ifdef USE_ASYNC_READ
 | 
						|
  else if (fd == apiserv->fd_async)
 | 
						|
    {
 | 
						|
      event = OSPF_APISERVER_ASYNC_READ;
 | 
						|
      apiserv->t_async_read = NULL;
 | 
						|
 | 
						|
      if (IS_DEBUG_OSPF_EVENT)
 | 
						|
        zlog_debug ("API: ospf_apiserver_read: Peer: %s/%u",
 | 
						|
                    inet_ntoa (apiserv->peer_async.sin_addr),
 | 
						|
                    ntohs (apiserv->peer_async.sin_port));
 | 
						|
    }
 | 
						|
#endif /* USE_ASYNC_READ */
 | 
						|
  else
 | 
						|
    {
 | 
						|
      zlog_warn ("ospf_apiserver_read: Unknown fd(%d)", fd);
 | 
						|
      ospf_apiserver_free (apiserv);
 | 
						|
      goto out;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Read message from fd. */
 | 
						|
  msg = msg_read (fd);
 | 
						|
  if (msg == NULL)
 | 
						|
    {
 | 
						|
      zlog_warn
 | 
						|
	("ospf_apiserver_read: read failed on fd=%d, closing connection", fd);
 | 
						|
 | 
						|
      /* Perform cleanup. */
 | 
						|
      ospf_apiserver_free (apiserv);
 | 
						|
      goto out;
 | 
						|
    }
 | 
						|
 | 
						|
  if (IS_DEBUG_OSPF_EVENT)
 | 
						|
    msg_print (msg);
 | 
						|
 | 
						|
  /* Dispatch to corresponding message handler. */
 | 
						|
  rc = ospf_apiserver_handle_msg (apiserv, msg);
 | 
						|
 | 
						|
  /* Prepare for next message, add read thread. */
 | 
						|
  ospf_apiserver_event (event, fd, apiserv);
 | 
						|
 | 
						|
  msg_free (msg);
 | 
						|
 | 
						|
out:
 | 
						|
  return rc;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
ospf_apiserver_sync_write (struct thread *thread)
 | 
						|
{
 | 
						|
  struct ospf_apiserver *apiserv;
 | 
						|
  struct msg *msg;
 | 
						|
  int fd;
 | 
						|
  int rc = -1;
 | 
						|
 | 
						|
  apiserv = THREAD_ARG (thread);
 | 
						|
  assert (apiserv);
 | 
						|
  fd = THREAD_FD (thread);
 | 
						|
 | 
						|
  apiserv->t_sync_write = NULL;
 | 
						|
 | 
						|
  /* Sanity check */
 | 
						|
  if (fd != apiserv->fd_sync)
 | 
						|
    {
 | 
						|
      zlog_warn ("ospf_apiserver_sync_write: Unknown fd=%d", fd);
 | 
						|
      goto out;
 | 
						|
    }
 | 
						|
 | 
						|
  if (IS_DEBUG_OSPF_EVENT)
 | 
						|
    zlog_debug ("API: ospf_apiserver_sync_write: Peer: %s/%u",
 | 
						|
                inet_ntoa (apiserv->peer_sync.sin_addr),
 | 
						|
                ntohs (apiserv->peer_sync.sin_port));
 | 
						|
 | 
						|
  /* Check whether there is really a message in the fifo. */
 | 
						|
  msg = msg_fifo_pop (apiserv->out_sync_fifo);
 | 
						|
  if (!msg)
 | 
						|
    {
 | 
						|
      zlog_warn ("API: ospf_apiserver_sync_write: No message in Sync-FIFO?");
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
 | 
						|
  if (IS_DEBUG_OSPF_EVENT)
 | 
						|
    msg_print (msg);
 | 
						|
 | 
						|
  rc = msg_write (fd, msg);
 | 
						|
 | 
						|
  /* Once a message is dequeued, it should be freed anyway. */
 | 
						|
  msg_free (msg);
 | 
						|
 | 
						|
  if (rc < 0)
 | 
						|
    {
 | 
						|
      zlog_warn
 | 
						|
        ("ospf_apiserver_sync_write: write failed on fd=%d", fd);
 | 
						|
      goto out;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
  /* If more messages are in sync message fifo, schedule write thread. */
 | 
						|
  if (msg_fifo_head (apiserv->out_sync_fifo))
 | 
						|
    {
 | 
						|
      ospf_apiserver_event (OSPF_APISERVER_SYNC_WRITE, apiserv->fd_sync,
 | 
						|
                            apiserv);
 | 
						|
    }
 | 
						|
  
 | 
						|
 out:
 | 
						|
 | 
						|
  if (rc < 0)
 | 
						|
  {
 | 
						|
      /* Perform cleanup and disconnect with peer */
 | 
						|
      ospf_apiserver_free (apiserv);
 | 
						|
    }
 | 
						|
 | 
						|
  return rc;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
ospf_apiserver_async_write (struct thread *thread)
 | 
						|
{
 | 
						|
  struct ospf_apiserver *apiserv;
 | 
						|
  struct msg *msg;
 | 
						|
  int fd;
 | 
						|
  int rc = -1;
 | 
						|
 | 
						|
  apiserv = THREAD_ARG (thread);
 | 
						|
  assert (apiserv);
 | 
						|
  fd = THREAD_FD (thread);
 | 
						|
 | 
						|
  apiserv->t_async_write = NULL;
 | 
						|
 | 
						|
  /* Sanity check */
 | 
						|
  if (fd != apiserv->fd_async)
 | 
						|
    {
 | 
						|
      zlog_warn ("ospf_apiserver_async_write: Unknown fd=%d", fd);
 | 
						|
      goto out;
 | 
						|
    }
 | 
						|
 | 
						|
  if (IS_DEBUG_OSPF_EVENT)
 | 
						|
    zlog_debug ("API: ospf_apiserver_async_write: Peer: %s/%u",
 | 
						|
                inet_ntoa (apiserv->peer_async.sin_addr),
 | 
						|
                ntohs (apiserv->peer_async.sin_port));
 | 
						|
 | 
						|
  /* Check whether there is really a message in the fifo. */
 | 
						|
  msg = msg_fifo_pop (apiserv->out_async_fifo);
 | 
						|
  if (!msg)
 | 
						|
    {
 | 
						|
      zlog_warn ("API: ospf_apiserver_async_write: No message in Async-FIFO?");
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
 | 
						|
  if (IS_DEBUG_OSPF_EVENT)
 | 
						|
    msg_print (msg);
 | 
						|
 | 
						|
  rc = msg_write (fd, msg);
 | 
						|
 | 
						|
  /* Once a message is dequeued, it should be freed anyway. */
 | 
						|
  msg_free (msg);
 | 
						|
 | 
						|
  if (rc < 0)
 | 
						|
    {
 | 
						|
      zlog_warn
 | 
						|
        ("ospf_apiserver_async_write: write failed on fd=%d", fd);
 | 
						|
      goto out;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
  /* If more messages are in async message fifo, schedule write thread. */
 | 
						|
  if (msg_fifo_head (apiserv->out_async_fifo))
 | 
						|
    {
 | 
						|
      ospf_apiserver_event (OSPF_APISERVER_ASYNC_WRITE, apiserv->fd_async,
 | 
						|
                            apiserv);
 | 
						|
    }
 | 
						|
 | 
						|
 out:
 | 
						|
 | 
						|
  if (rc < 0)
 | 
						|
    {
 | 
						|
      /* Perform cleanup and disconnect with peer */
 | 
						|
      ospf_apiserver_free (apiserv);
 | 
						|
    }
 | 
						|
 | 
						|
  return rc;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
ospf_apiserver_serv_sock_family (unsigned short port, int family)
 | 
						|
{
 | 
						|
  union sockunion su;
 | 
						|
  int accept_sock;
 | 
						|
  int rc;
 | 
						|
 | 
						|
  memset (&su, 0, sizeof (union sockunion));
 | 
						|
  su.sa.sa_family = family;
 | 
						|
 | 
						|
  /* Make new socket */
 | 
						|
  accept_sock = sockunion_stream_socket (&su);
 | 
						|
  if (accept_sock < 0)
 | 
						|
    return accept_sock;
 | 
						|
 | 
						|
  /* This is a server, so reuse address and port */
 | 
						|
  sockopt_reuseaddr (accept_sock);
 | 
						|
  sockopt_reuseport (accept_sock);
 | 
						|
 | 
						|
  /* Bind socket to address and given port. */
 | 
						|
  rc = sockunion_bind (accept_sock, &su, port, NULL);
 | 
						|
  if (rc < 0)
 | 
						|
    {
 | 
						|
      close (accept_sock);	/* Close socket */
 | 
						|
      return rc;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Listen socket under queue length 3. */
 | 
						|
  rc = listen (accept_sock, 3);
 | 
						|
  if (rc < 0)
 | 
						|
    {
 | 
						|
      zlog_warn ("ospf_apiserver_serv_sock_family: listen: %s",
 | 
						|
                 safe_strerror (errno));
 | 
						|
      close (accept_sock);	/* Close socket */
 | 
						|
      return rc;
 | 
						|
    }
 | 
						|
  return accept_sock;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Accept connection request from external applications. For each
 | 
						|
   accepted connection allocate own connection instance. */
 | 
						|
int
 | 
						|
ospf_apiserver_accept (struct thread *thread)
 | 
						|
{
 | 
						|
  int accept_sock;
 | 
						|
  int new_sync_sock;
 | 
						|
  int new_async_sock;
 | 
						|
  union sockunion su;
 | 
						|
  struct ospf_apiserver *apiserv;
 | 
						|
  struct sockaddr_in peer_async;
 | 
						|
  struct sockaddr_in peer_sync;
 | 
						|
  int peerlen;
 | 
						|
  int ret;
 | 
						|
 | 
						|
  /* THREAD_ARG (thread) is NULL */
 | 
						|
  accept_sock = THREAD_FD (thread);
 | 
						|
 | 
						|
  /* Keep hearing on socket for further connections. */
 | 
						|
  ospf_apiserver_event (OSPF_APISERVER_ACCEPT, accept_sock, NULL);
 | 
						|
 | 
						|
  memset (&su, 0, sizeof (union sockunion));
 | 
						|
  /* Accept connection for synchronous messages */
 | 
						|
  new_sync_sock = sockunion_accept (accept_sock, &su);
 | 
						|
  if (new_sync_sock < 0)
 | 
						|
    {
 | 
						|
      zlog_warn ("ospf_apiserver_accept: accept: %s", safe_strerror (errno));
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Get port address and port number of peer to make reverse connection.
 | 
						|
     The reverse channel uses the port number of the peer port+1. */
 | 
						|
 | 
						|
  memset(&peer_sync, 0, sizeof(struct sockaddr_in));
 | 
						|
  peerlen = sizeof (struct sockaddr_in);
 | 
						|
 | 
						|
  ret = getpeername (new_sync_sock, (struct sockaddr *)&peer_sync, &peerlen);
 | 
						|
  if (ret < 0)
 | 
						|
    {
 | 
						|
      zlog_warn ("ospf_apiserver_accept: getpeername: %s", safe_strerror (errno));
 | 
						|
      close (new_sync_sock);
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
 | 
						|
  if (IS_DEBUG_OSPF_EVENT)
 | 
						|
    zlog_debug ("API: ospf_apiserver_accept: New peer: %s/%u",
 | 
						|
               inet_ntoa (peer_sync.sin_addr), ntohs (peer_sync.sin_port));
 | 
						|
 | 
						|
  /* Create new socket for asynchronous messages. */
 | 
						|
  peer_async = peer_sync;
 | 
						|
  peer_async.sin_port = htons(ntohs(peer_sync.sin_port) + 1);
 | 
						|
 | 
						|
  /* Check if remote port number to make reverse connection is valid one. */
 | 
						|
  if (ntohs (peer_async.sin_port) == ospf_apiserver_getport ())
 | 
						|
    {
 | 
						|
      zlog_warn ("API: ospf_apiserver_accept: Peer(%s/%u): Invalid async port number?",
 | 
						|
               inet_ntoa (peer_async.sin_addr), ntohs (peer_async.sin_port));
 | 
						|
      close (new_sync_sock);
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
 | 
						|
  new_async_sock = socket (AF_INET, SOCK_STREAM, 0);
 | 
						|
  if (new_async_sock < 0)
 | 
						|
    {
 | 
						|
      zlog_warn ("ospf_apiserver_accept: socket: %s", safe_strerror (errno));
 | 
						|
      close (new_sync_sock);
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
 | 
						|
  ret = connect (new_async_sock, (struct sockaddr *) &peer_async,
 | 
						|
		 sizeof (struct sockaddr_in));
 | 
						|
 | 
						|
  if (ret < 0)
 | 
						|
    {
 | 
						|
      zlog_warn ("ospf_apiserver_accept: connect: %s", safe_strerror (errno));
 | 
						|
      close (new_sync_sock);
 | 
						|
      close (new_async_sock);
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
 | 
						|
#ifdef USE_ASYNC_READ
 | 
						|
#else /* USE_ASYNC_READ */
 | 
						|
  /* Make the asynchronous channel write-only. */
 | 
						|
  ret = shutdown (new_async_sock, SHUT_RD);
 | 
						|
  if (ret < 0)
 | 
						|
    {
 | 
						|
      zlog_warn ("ospf_apiserver_accept: shutdown: %s", safe_strerror (errno));
 | 
						|
      close (new_sync_sock);
 | 
						|
      close (new_async_sock);
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
#endif /* USE_ASYNC_READ */
 | 
						|
 | 
						|
  /* Allocate new server-side connection structure */
 | 
						|
  apiserv = ospf_apiserver_new (new_sync_sock, new_async_sock);
 | 
						|
 | 
						|
  /* Add to active connection list */
 | 
						|
  listnode_add (apiserver_list, apiserv);
 | 
						|
  apiserv->peer_sync = peer_sync;
 | 
						|
  apiserv->peer_async = peer_async;
 | 
						|
 | 
						|
  /* And add read threads for new connection */
 | 
						|
  ospf_apiserver_event (OSPF_APISERVER_SYNC_READ, new_sync_sock, apiserv);
 | 
						|
#ifdef USE_ASYNC_READ
 | 
						|
  ospf_apiserver_event (OSPF_APISERVER_ASYNC_READ, new_async_sock, apiserv);
 | 
						|
#endif /* USE_ASYNC_READ */
 | 
						|
 | 
						|
  if (IS_DEBUG_OSPF_EVENT)
 | 
						|
    zlog_debug ("API: New apiserv(%p), total#(%d)", apiserv, apiserver_list->count);
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* -----------------------------------------------------------
 | 
						|
 * Send reply with return code to client application
 | 
						|
 * -----------------------------------------------------------
 | 
						|
 */
 | 
						|
 | 
						|
int
 | 
						|
ospf_apiserver_send_msg (struct ospf_apiserver *apiserv, struct msg *msg)
 | 
						|
{
 | 
						|
  struct msg_fifo *fifo;
 | 
						|
  struct msg *msg2;
 | 
						|
  enum event event;
 | 
						|
  int fd;
 | 
						|
 | 
						|
  switch (msg->hdr.msgtype)
 | 
						|
    {
 | 
						|
    case MSG_REPLY:
 | 
						|
      fifo = apiserv->out_sync_fifo;
 | 
						|
      fd = apiserv->fd_sync;
 | 
						|
      event = OSPF_APISERVER_SYNC_WRITE;
 | 
						|
      break;
 | 
						|
    case MSG_READY_NOTIFY:
 | 
						|
    case MSG_LSA_UPDATE_NOTIFY:
 | 
						|
    case MSG_LSA_DELETE_NOTIFY:
 | 
						|
    case MSG_NEW_IF:
 | 
						|
    case MSG_DEL_IF:
 | 
						|
    case MSG_ISM_CHANGE:
 | 
						|
    case MSG_NSM_CHANGE:
 | 
						|
      fifo = apiserv->out_async_fifo;
 | 
						|
      fd = apiserv->fd_async;
 | 
						|
      event = OSPF_APISERVER_ASYNC_WRITE;
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      zlog_warn ("ospf_apiserver_send_msg: Unknown message type %d",
 | 
						|
		 msg->hdr.msgtype);
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Make a copy of the message and put in the fifo. Once the fifo
 | 
						|
     gets drained by the write thread, the message will be freed. */
 | 
						|
  /* NB: Given "msg" is untouched in this function. */
 | 
						|
  msg2 = msg_dup (msg);
 | 
						|
 | 
						|
  /* Enqueue message into corresponding fifo queue */
 | 
						|
  msg_fifo_push (fifo, msg2);
 | 
						|
 | 
						|
  /* Schedule write thread */
 | 
						|
  ospf_apiserver_event (event, fd, apiserv);
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
ospf_apiserver_send_reply (struct ospf_apiserver *apiserv, u_int32_t seqnr,
 | 
						|
			   u_char rc)
 | 
						|
{
 | 
						|
  struct msg *msg = new_msg_reply (seqnr, rc);
 | 
						|
  int ret;
 | 
						|
 | 
						|
  if (!msg)
 | 
						|
    {
 | 
						|
      zlog_warn ("ospf_apiserver_send_reply: msg_new failed");
 | 
						|
#ifdef NOTYET
 | 
						|
      /* Cannot allocate new message. What should we do? */
 | 
						|
      ospf_apiserver_free (apiserv);
 | 
						|
#endif
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
 | 
						|
  ret = ospf_apiserver_send_msg (apiserv, msg);
 | 
						|
  msg_free (msg);
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* -----------------------------------------------------------
 | 
						|
 * Generic message dispatching handler function
 | 
						|
 * -----------------------------------------------------------
 | 
						|
 */
 | 
						|
 | 
						|
int
 | 
						|
ospf_apiserver_handle_msg (struct ospf_apiserver *apiserv, struct msg *msg)
 | 
						|
{
 | 
						|
  int rc;
 | 
						|
 | 
						|
  /* Call corresponding message handler function. */
 | 
						|
  switch (msg->hdr.msgtype)
 | 
						|
    {
 | 
						|
    case MSG_REGISTER_OPAQUETYPE:
 | 
						|
      rc = ospf_apiserver_handle_register_opaque_type (apiserv, msg);
 | 
						|
      break;
 | 
						|
    case MSG_UNREGISTER_OPAQUETYPE:
 | 
						|
      rc = ospf_apiserver_handle_unregister_opaque_type (apiserv, msg);
 | 
						|
      break;
 | 
						|
    case MSG_REGISTER_EVENT:
 | 
						|
      rc = ospf_apiserver_handle_register_event (apiserv, msg);
 | 
						|
      break;
 | 
						|
    case MSG_SYNC_LSDB:
 | 
						|
      rc = ospf_apiserver_handle_sync_lsdb (apiserv, msg);
 | 
						|
      break;
 | 
						|
    case MSG_ORIGINATE_REQUEST:
 | 
						|
      rc = ospf_apiserver_handle_originate_request (apiserv, msg);
 | 
						|
      break;
 | 
						|
    case MSG_DELETE_REQUEST:
 | 
						|
      rc = ospf_apiserver_handle_delete_request (apiserv, msg);
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      zlog_warn ("ospf_apiserver_handle_msg: Unknown message type: %d",
 | 
						|
		 msg->hdr.msgtype);
 | 
						|
      rc = -1;
 | 
						|
    }
 | 
						|
  return rc;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* -----------------------------------------------------------
 | 
						|
 * Following are functions for opaque type registration
 | 
						|
 * -----------------------------------------------------------
 | 
						|
 */
 | 
						|
 | 
						|
int
 | 
						|
ospf_apiserver_register_opaque_type (struct ospf_apiserver *apiserv,
 | 
						|
				     u_char lsa_type, u_char opaque_type)
 | 
						|
{
 | 
						|
  struct registered_opaque_type *regtype;
 | 
						|
  int (*originator_func) (void *arg);
 | 
						|
  int rc;
 | 
						|
 | 
						|
  switch (lsa_type)
 | 
						|
    {
 | 
						|
    case OSPF_OPAQUE_LINK_LSA:
 | 
						|
      originator_func = ospf_apiserver_lsa9_originator;
 | 
						|
      break;
 | 
						|
    case OSPF_OPAQUE_AREA_LSA:
 | 
						|
      originator_func = ospf_apiserver_lsa10_originator;
 | 
						|
      break;
 | 
						|
    case OSPF_OPAQUE_AS_LSA:
 | 
						|
      originator_func = ospf_apiserver_lsa11_originator;
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      zlog_warn ("ospf_apiserver_register_opaque_type: lsa_type(%d)",
 | 
						|
		 lsa_type);
 | 
						|
      return OSPF_API_ILLEGALLSATYPE;
 | 
						|
    }
 | 
						|
  
 | 
						|
 | 
						|
  /* Register opaque function table */
 | 
						|
  /* NB: Duplicated registration will be detected inside the function. */
 | 
						|
  rc =
 | 
						|
    ospf_register_opaque_functab (lsa_type, opaque_type,
 | 
						|
				  NULL, /* ospf_apiserver_new_if */
 | 
						|
				  NULL, /* ospf_apiserver_del_if */
 | 
						|
				  NULL, /* ospf_apiserver_ism_change */
 | 
						|
				  NULL, /* ospf_apiserver_nsm_change */
 | 
						|
				  NULL,
 | 
						|
				  NULL,
 | 
						|
				  NULL,
 | 
						|
				  ospf_apiserver_show_info,
 | 
						|
				  originator_func,
 | 
						|
				  ospf_apiserver_lsa_refresher,
 | 
						|
				  NULL, /* ospf_apiserver_lsa_update */
 | 
						|
				  NULL /* ospf_apiserver_lsa_delete */);
 | 
						|
 | 
						|
  if (rc != 0)
 | 
						|
    {
 | 
						|
      zlog_warn ("Failed to register opaque type [%d/%d]",
 | 
						|
		 lsa_type, opaque_type);
 | 
						|
      return OSPF_API_OPAQUETYPEINUSE;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Remember the opaque type that application registers so when
 | 
						|
     connection shuts down, we can flush all LSAs of this opaque
 | 
						|
     type. */
 | 
						|
 | 
						|
  regtype =
 | 
						|
    XMALLOC (MTYPE_OSPF_APISERVER, sizeof (struct registered_opaque_type));
 | 
						|
  memset (regtype, 0, sizeof (struct registered_opaque_type));
 | 
						|
  regtype->lsa_type = lsa_type;
 | 
						|
  regtype->opaque_type = opaque_type;
 | 
						|
 | 
						|
  /* Add to list of registered opaque types */
 | 
						|
  listnode_add (apiserv->opaque_types, regtype);
 | 
						|
 | 
						|
  if (IS_DEBUG_OSPF_EVENT)
 | 
						|
    zlog_debug ("API: Add LSA-type(%d)/Opaque-type(%d) into"
 | 
						|
               " apiserv(%p), total#(%d)", 
 | 
						|
               lsa_type, opaque_type, apiserv, 
 | 
						|
               listcount (apiserv->opaque_types));
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
ospf_apiserver_unregister_opaque_type (struct ospf_apiserver *apiserv,
 | 
						|
				       u_char lsa_type, u_char opaque_type)
 | 
						|
{
 | 
						|
  struct listnode *n1, *n1_next;
 | 
						|
  struct registered_opaque_type *regtype;
 | 
						|
 | 
						|
  for (n1 = listhead (apiserv->opaque_types); n1; n1 = n1_next)
 | 
						|
    {
 | 
						|
      n1_next = n1->next;
 | 
						|
      
 | 
						|
      regtype = (struct registered_opaque_type *) getdata(n1);
 | 
						|
 | 
						|
      /* Check if we really registered this opaque type */
 | 
						|
      if (regtype->lsa_type == lsa_type &&
 | 
						|
	  regtype->opaque_type == opaque_type)
 | 
						|
	{
 | 
						|
 | 
						|
	  /* Yes, we registered this opaque type. Flush
 | 
						|
	     all existing opaque LSAs of this type */
 | 
						|
 | 
						|
	  ospf_apiserver_flush_opaque_lsa (apiserv, lsa_type, opaque_type);
 | 
						|
	  ospf_delete_opaque_functab (lsa_type, opaque_type);
 | 
						|
 | 
						|
	  /* Remove from list of registered opaque types */
 | 
						|
	  listnode_delete (apiserv->opaque_types, regtype);
 | 
						|
 | 
						|
          if (IS_DEBUG_OSPF_EVENT)
 | 
						|
            zlog_debug ("API: Del LSA-type(%d)/Opaque-type(%d)"
 | 
						|
                       " from apiserv(%p), total#(%d)", 
 | 
						|
                       lsa_type, opaque_type, apiserv, 
 | 
						|
                       listcount (apiserv->opaque_types));
 | 
						|
 | 
						|
	  return 0;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  /* Opaque type is not registered */
 | 
						|
  zlog_warn ("Failed to unregister opaque type [%d/%d]",
 | 
						|
	     lsa_type, opaque_type);
 | 
						|
  return OSPF_API_OPAQUETYPENOTREGISTERED;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
apiserver_is_opaque_type_registered (struct ospf_apiserver *apiserv,
 | 
						|
				     u_char lsa_type, u_char opaque_type)
 | 
						|
{
 | 
						|
  struct listnode *node;
 | 
						|
  struct registered_opaque_type *regtype;
 | 
						|
 | 
						|
  /* XXX: how many types are there? if few, why not just a bitmap? */
 | 
						|
  LIST_LOOP (apiserv->opaque_types, regtype, node)
 | 
						|
    {
 | 
						|
      /* Check if we really registered this opaque type */
 | 
						|
      if (regtype->lsa_type == lsa_type &&
 | 
						|
	  regtype->opaque_type == opaque_type)
 | 
						|
	{
 | 
						|
	  /* Yes registered */
 | 
						|
	  return 1;
 | 
						|
	}
 | 
						|
    }
 | 
						|
  /* Not registered */
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
ospf_apiserver_handle_register_opaque_type (struct ospf_apiserver *apiserv,
 | 
						|
					    struct msg *msg)
 | 
						|
{
 | 
						|
  struct msg_register_opaque_type *rmsg;
 | 
						|
  u_char lsa_type;
 | 
						|
  u_char opaque_type;
 | 
						|
  int rc = 0;
 | 
						|
 | 
						|
  /* Extract parameters from register opaque type message */
 | 
						|
  rmsg = (struct msg_register_opaque_type *) STREAM_DATA (msg->s);
 | 
						|
 | 
						|
  lsa_type = rmsg->lsatype;
 | 
						|
  opaque_type = rmsg->opaquetype;
 | 
						|
 | 
						|
  rc = ospf_apiserver_register_opaque_type (apiserv, lsa_type, opaque_type);
 | 
						|
 | 
						|
  /* Send a reply back to client including return code */
 | 
						|
  rc = ospf_apiserver_send_reply (apiserv, ntohl (msg->hdr.msgseq), rc);
 | 
						|
  if (rc < 0)
 | 
						|
    goto out;
 | 
						|
 | 
						|
  /* Now inform application about opaque types that are ready */
 | 
						|
  switch (lsa_type)
 | 
						|
    {
 | 
						|
    case OSPF_OPAQUE_LINK_LSA:
 | 
						|
      ospf_apiserver_notify_ready_type9 (apiserv);
 | 
						|
      break;
 | 
						|
    case OSPF_OPAQUE_AREA_LSA:
 | 
						|
      ospf_apiserver_notify_ready_type10 (apiserv);
 | 
						|
      break;
 | 
						|
    case OSPF_OPAQUE_AS_LSA:
 | 
						|
      ospf_apiserver_notify_ready_type11 (apiserv);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
out:
 | 
						|
  return rc;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Notify specific client about all opaque types 9 that are ready. */
 | 
						|
void
 | 
						|
ospf_apiserver_notify_ready_type9 (struct ospf_apiserver *apiserv)
 | 
						|
{
 | 
						|
  struct listnode *node;
 | 
						|
  struct listnode *n2;
 | 
						|
  struct ospf *ospf;
 | 
						|
  struct ospf_interface *oi;
 | 
						|
  struct registered_opaque_type *r;
 | 
						|
 | 
						|
  ospf = ospf_lookup ();
 | 
						|
 | 
						|
  LIST_LOOP (ospf->oiflist, oi, node)
 | 
						|
    {
 | 
						|
      /* Check if this interface is indeed ready for type 9 */
 | 
						|
      if (!ospf_apiserver_is_ready_type9 (oi))
 | 
						|
	continue;
 | 
						|
 | 
						|
      /* Check for registered opaque type 9 types */
 | 
						|
      /* XXX: loop-de-loop - optimise me */
 | 
						|
      LIST_LOOP (apiserv->opaque_types, r, n2)
 | 
						|
	{
 | 
						|
	  struct msg *msg;
 | 
						|
 | 
						|
	  if (r->lsa_type == OSPF_OPAQUE_LINK_LSA)
 | 
						|
	    {
 | 
						|
 | 
						|
	      /* Yes, this opaque type is ready */
 | 
						|
	      msg = new_msg_ready_notify (0, OSPF_OPAQUE_LINK_LSA,
 | 
						|
					  r->opaque_type,
 | 
						|
					  oi->address->u.prefix4);
 | 
						|
	      if (!msg)
 | 
						|
		{
 | 
						|
		  zlog_warn ("apiserver_notify_ready_type9: msg_new failed");
 | 
						|
#ifdef NOTYET
 | 
						|
		  /* Cannot allocate new message. What should we do? */
 | 
						|
		  ospf_apiserver_free (apiserv);
 | 
						|
#endif
 | 
						|
		  goto out;
 | 
						|
		}
 | 
						|
	      ospf_apiserver_send_msg (apiserv, msg);
 | 
						|
	      msg_free (msg);
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
out:
 | 
						|
  return;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Notify specific client about all opaque types 10 that are ready. */
 | 
						|
void
 | 
						|
ospf_apiserver_notify_ready_type10 (struct ospf_apiserver *apiserv)
 | 
						|
{
 | 
						|
  struct listnode *node;
 | 
						|
  struct listnode *n2;
 | 
						|
  struct ospf *ospf;
 | 
						|
  struct ospf_area *area;
 | 
						|
  
 | 
						|
  ospf = ospf_lookup ();
 | 
						|
 | 
						|
  LIST_LOOP (ospf->areas, area, node)
 | 
						|
    {
 | 
						|
      struct registered_opaque_type *r;
 | 
						|
      
 | 
						|
      if (!ospf_apiserver_is_ready_type10 (area))
 | 
						|
	{
 | 
						|
	  continue;
 | 
						|
	}
 | 
						|
 | 
						|
      /* Check for registered opaque type 10 types */
 | 
						|
      /* XXX: loop in loop - optimise me */
 | 
						|
      LIST_LOOP (apiserv->opaque_types, r, n2)
 | 
						|
	{
 | 
						|
	  struct msg *msg;
 | 
						|
	  
 | 
						|
	  if (r->lsa_type == OSPF_OPAQUE_AREA_LSA)
 | 
						|
	    {
 | 
						|
	      /* Yes, this opaque type is ready */
 | 
						|
	      msg =
 | 
						|
		new_msg_ready_notify (0, OSPF_OPAQUE_AREA_LSA,
 | 
						|
				      r->opaque_type, area->area_id);
 | 
						|
	      if (!msg)
 | 
						|
		{
 | 
						|
		  zlog_warn ("apiserver_notify_ready_type10: msg_new failed");
 | 
						|
#ifdef NOTYET
 | 
						|
		  /* Cannot allocate new message. What should we do? */
 | 
						|
		  ospf_apiserver_free (apiserv);
 | 
						|
#endif
 | 
						|
		  goto out;
 | 
						|
		}
 | 
						|
	      ospf_apiserver_send_msg (apiserv, msg);
 | 
						|
	      msg_free (msg);
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
out:
 | 
						|
  return;
 | 
						|
}
 | 
						|
 | 
						|
/* Notify specific client about all opaque types 11 that are ready */
 | 
						|
void
 | 
						|
ospf_apiserver_notify_ready_type11 (struct ospf_apiserver *apiserv)
 | 
						|
{
 | 
						|
  struct listnode *node;
 | 
						|
  struct ospf *ospf;
 | 
						|
  struct registered_opaque_type *r;
 | 
						|
 | 
						|
  ospf = ospf_lookup ();
 | 
						|
 | 
						|
  /* Can type 11 be originated? */
 | 
						|
  if (!ospf_apiserver_is_ready_type11 (ospf))
 | 
						|
    goto out;
 | 
						|
 | 
						|
  /* Check for registered opaque type 11 types */
 | 
						|
  LIST_LOOP (apiserv->opaque_types, r, node)
 | 
						|
    {
 | 
						|
      struct msg *msg;
 | 
						|
      struct in_addr noarea_id = { 0L };
 | 
						|
 | 
						|
      if (r->lsa_type == OSPF_OPAQUE_AS_LSA)
 | 
						|
	{
 | 
						|
	  /* Yes, this opaque type is ready */
 | 
						|
	  msg = new_msg_ready_notify (0, OSPF_OPAQUE_AS_LSA,
 | 
						|
				      r->opaque_type, noarea_id);
 | 
						|
 | 
						|
	  if (!msg)
 | 
						|
	    {
 | 
						|
	      zlog_warn ("apiserver_notify_ready_type11: msg_new failed");
 | 
						|
#ifdef NOTYET
 | 
						|
	      /* Cannot allocate new message. What should we do? */
 | 
						|
	      ospf_apiserver_free (apiserv);
 | 
						|
#endif
 | 
						|
	      goto out;
 | 
						|
	    }
 | 
						|
	  ospf_apiserver_send_msg (apiserv, msg);
 | 
						|
	  msg_free (msg);
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
out:
 | 
						|
  return;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
ospf_apiserver_handle_unregister_opaque_type (struct ospf_apiserver *apiserv,
 | 
						|
					      struct msg *msg)
 | 
						|
{
 | 
						|
  struct msg_unregister_opaque_type *umsg;
 | 
						|
  u_char ltype;
 | 
						|
  u_char otype;
 | 
						|
  int rc = 0;
 | 
						|
 | 
						|
  /* Extract parameters from unregister opaque type message */
 | 
						|
  umsg = (struct msg_unregister_opaque_type *) STREAM_DATA (msg->s);
 | 
						|
 | 
						|
  ltype = umsg->lsatype;
 | 
						|
  otype = umsg->opaquetype;
 | 
						|
 | 
						|
  rc = ospf_apiserver_unregister_opaque_type (apiserv, ltype, otype);
 | 
						|
 | 
						|
  /* Send a reply back to client including return code */
 | 
						|
  rc = ospf_apiserver_send_reply (apiserv, ntohl (msg->hdr.msgseq), rc);
 | 
						|
 | 
						|
  return rc;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* -----------------------------------------------------------
 | 
						|
 * Following are functions for event (filter) registration.
 | 
						|
 * -----------------------------------------------------------
 | 
						|
 */
 | 
						|
int
 | 
						|
ospf_apiserver_handle_register_event (struct ospf_apiserver *apiserv,
 | 
						|
				      struct msg *msg)
 | 
						|
{
 | 
						|
  struct msg_register_event *rmsg;
 | 
						|
  int rc;
 | 
						|
  u_int32_t seqnum;
 | 
						|
 | 
						|
  rmsg = (struct msg_register_event *) STREAM_DATA (msg->s);
 | 
						|
 | 
						|
  /* Get request sequence number */
 | 
						|
  seqnum = msg_get_seq (msg);
 | 
						|
 | 
						|
  /* Free existing filter in apiserv. */
 | 
						|
  XFREE (MTYPE_OSPF_APISERVER_MSGFILTER, apiserv->filter);
 | 
						|
  /* Alloc new space for filter. */
 | 
						|
 | 
						|
  apiserv->filter = XMALLOC (MTYPE_OSPF_APISERVER_MSGFILTER,
 | 
						|
			     ntohs (msg->hdr.msglen));
 | 
						|
  if (apiserv->filter)
 | 
						|
    {
 | 
						|
      /* copy it over. */
 | 
						|
      memcpy (apiserv->filter, &rmsg->filter, ntohs (msg->hdr.msglen));
 | 
						|
      rc = OSPF_API_OK;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      rc = OSPF_API_NOMEMORY;
 | 
						|
    }
 | 
						|
  /* Send a reply back to client with return code */
 | 
						|
  rc = ospf_apiserver_send_reply (apiserv, seqnum, rc);
 | 
						|
  return rc;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* -----------------------------------------------------------
 | 
						|
 * Followings are functions for LSDB synchronization.
 | 
						|
 * -----------------------------------------------------------
 | 
						|
 */
 | 
						|
 | 
						|
int
 | 
						|
apiserver_sync_callback (struct ospf_lsa *lsa, void *p_arg, int int_arg)
 | 
						|
{
 | 
						|
  struct ospf_apiserver *apiserv;
 | 
						|
  int seqnum;
 | 
						|
  struct msg *msg;
 | 
						|
  struct param_t
 | 
						|
  {
 | 
						|
    struct ospf_apiserver *apiserv;
 | 
						|
    struct lsa_filter_type *filter;
 | 
						|
  }
 | 
						|
   *param;
 | 
						|
  int rc = -1;
 | 
						|
 | 
						|
  /* Sanity check */
 | 
						|
  assert (lsa->data);
 | 
						|
  assert (p_arg);
 | 
						|
 | 
						|
  param = (struct param_t *) p_arg;
 | 
						|
  apiserv = param->apiserv;
 | 
						|
  seqnum = (u_int32_t) int_arg;
 | 
						|
 | 
						|
  /* Check origin in filter. */
 | 
						|
  if ((param->filter->origin == ANY_ORIGIN) ||
 | 
						|
      (param->filter->origin == (lsa->flags & OSPF_LSA_SELF)))
 | 
						|
    {
 | 
						|
 | 
						|
      /* Default area for AS-External and Opaque11 LSAs */
 | 
						|
      struct in_addr area_id = { 0L };
 | 
						|
 | 
						|
      /* Default interface for non Opaque9 LSAs */
 | 
						|
      struct in_addr ifaddr = { 0L };
 | 
						|
 | 
						|
      if (lsa->area)
 | 
						|
	{
 | 
						|
	  area_id = lsa->area->area_id;
 | 
						|
	}
 | 
						|
      if (lsa->data->type == OSPF_OPAQUE_LINK_LSA)
 | 
						|
	{
 | 
						|
	  ifaddr = lsa->oi->address->u.prefix4;
 | 
						|
	}
 | 
						|
 | 
						|
      msg = new_msg_lsa_change_notify (MSG_LSA_UPDATE_NOTIFY,
 | 
						|
				       seqnum,
 | 
						|
				       ifaddr, area_id,
 | 
						|
				       lsa->flags & OSPF_LSA_SELF, lsa->data);
 | 
						|
      if (!msg)
 | 
						|
	{
 | 
						|
	  zlog_warn ("apiserver_sync_callback: new_msg_update failed");
 | 
						|
#ifdef NOTYET
 | 
						|
	  /* Cannot allocate new message. What should we do? */
 | 
						|
/*        ospf_apiserver_free (apiserv);*//* Do nothing here XXX */
 | 
						|
#endif
 | 
						|
	  goto out;
 | 
						|
	}
 | 
						|
 | 
						|
      /* Send LSA */
 | 
						|
      ospf_apiserver_send_msg (apiserv, msg);
 | 
						|
      msg_free (msg);
 | 
						|
    }
 | 
						|
  rc = 0;
 | 
						|
 | 
						|
out:
 | 
						|
  return rc;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
ospf_apiserver_handle_sync_lsdb (struct ospf_apiserver *apiserv,
 | 
						|
				 struct msg *msg)
 | 
						|
{
 | 
						|
  struct listnode *node;
 | 
						|
  u_int32_t seqnum;
 | 
						|
  int rc = 0;
 | 
						|
  struct msg_sync_lsdb *smsg;
 | 
						|
  struct param_t
 | 
						|
  {
 | 
						|
    struct ospf_apiserver *apiserv;
 | 
						|
    struct lsa_filter_type *filter;
 | 
						|
  }
 | 
						|
  param;
 | 
						|
  u_int16_t mask;
 | 
						|
  struct route_node *rn;
 | 
						|
  struct ospf_lsa *lsa;
 | 
						|
  struct ospf *ospf;
 | 
						|
  struct ospf_area *area;
 | 
						|
 | 
						|
  ospf = ospf_lookup ();
 | 
						|
 | 
						|
  /* Get request sequence number */
 | 
						|
  seqnum = msg_get_seq (msg);
 | 
						|
  /* Set sync msg. */
 | 
						|
  smsg = (struct msg_sync_lsdb *) STREAM_DATA (msg->s);
 | 
						|
 | 
						|
  /* Set parameter struct. */
 | 
						|
  param.apiserv = apiserv;
 | 
						|
  param.filter = &smsg->filter;
 | 
						|
 | 
						|
  /* Remember mask. */
 | 
						|
  mask = ntohs (smsg->filter.typemask);
 | 
						|
 | 
						|
  /* Iterate over all areas. */
 | 
						|
  LIST_LOOP (ospf->areas, area, node)
 | 
						|
    {
 | 
						|
      int i;
 | 
						|
      u_int32_t *area_id = NULL;
 | 
						|
 | 
						|
      /* Compare area_id with area_ids in sync request. */
 | 
						|
      if ((i = smsg->filter.num_areas) > 0)
 | 
						|
	{
 | 
						|
	  /* Let area_id point to the list of area IDs,
 | 
						|
	   * which is at the end of smsg->filter. */
 | 
						|
	  area_id = (u_int32_t *) (&smsg->filter + 1);
 | 
						|
	  while (i)
 | 
						|
	    {
 | 
						|
	      if (*area_id == area->area_id.s_addr)
 | 
						|
		{
 | 
						|
		  break;
 | 
						|
		}
 | 
						|
	      i--;
 | 
						|
	      area_id++;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  i = 1;
 | 
						|
	}
 | 
						|
 | 
						|
      /* If area was found, then i>0 here. */
 | 
						|
      if (i)
 | 
						|
	{
 | 
						|
	  /* Check msg type. */
 | 
						|
	  if (mask & Power2[OSPF_ROUTER_LSA])
 | 
						|
	    LSDB_LOOP (ROUTER_LSDB (area), rn, lsa)
 | 
						|
	      apiserver_sync_callback(lsa, (void *) ¶m, seqnum);
 | 
						|
	  if (mask & Power2[OSPF_NETWORK_LSA])
 | 
						|
            LSDB_LOOP (NETWORK_LSDB (area), rn, lsa)
 | 
						|
              apiserver_sync_callback(lsa, (void *) ¶m, seqnum);
 | 
						|
	  if (mask & Power2[OSPF_SUMMARY_LSA])
 | 
						|
            LSDB_LOOP (SUMMARY_LSDB (area), rn, lsa)
 | 
						|
              apiserver_sync_callback(lsa, (void *) ¶m, seqnum);
 | 
						|
	  if (mask & Power2[OSPF_ASBR_SUMMARY_LSA])
 | 
						|
            LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa)
 | 
						|
              apiserver_sync_callback(lsa, (void *) ¶m, seqnum);
 | 
						|
	  if (mask & Power2[OSPF_OPAQUE_LINK_LSA])
 | 
						|
            LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa)
 | 
						|
              apiserver_sync_callback(lsa, (void *) ¶m, seqnum);
 | 
						|
	  if (mask & Power2[OSPF_OPAQUE_AREA_LSA])
 | 
						|
            LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa)
 | 
						|
              apiserver_sync_callback(lsa, (void *) ¶m, seqnum);
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  /* For AS-external LSAs */
 | 
						|
  if (ospf->lsdb)
 | 
						|
    {
 | 
						|
      if (mask & Power2[OSPF_AS_EXTERNAL_LSA])
 | 
						|
	LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa)
 | 
						|
	  apiserver_sync_callback(lsa, (void *) ¶m, seqnum);
 | 
						|
    }
 | 
						|
 | 
						|
  /* For AS-external opaque LSAs */
 | 
						|
  if (ospf->lsdb)
 | 
						|
    {
 | 
						|
      if (mask & Power2[OSPF_OPAQUE_AS_LSA])
 | 
						|
	LSDB_LOOP (OPAQUE_AS_LSDB (ospf), rn, lsa)
 | 
						|
	  apiserver_sync_callback(lsa, (void *) ¶m, seqnum);
 | 
						|
    }
 | 
						|
 | 
						|
  /* Send a reply back to client with return code */
 | 
						|
  rc = ospf_apiserver_send_reply (apiserv, seqnum, rc);
 | 
						|
  return rc;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* -----------------------------------------------------------
 | 
						|
 * Followings are functions to originate or update LSA
 | 
						|
 * from an application.
 | 
						|
 * -----------------------------------------------------------
 | 
						|
 */
 | 
						|
 | 
						|
/* Create a new internal opaque LSA by taking prototype and filling in
 | 
						|
   missing fields such as age, sequence number, advertising router,
 | 
						|
   checksum and so on. The interface parameter is used for type 9
 | 
						|
   LSAs, area parameter for type 10. Type 11 LSAs do neither need area
 | 
						|
   nor interface. */
 | 
						|
 | 
						|
struct ospf_lsa *
 | 
						|
ospf_apiserver_opaque_lsa_new (struct ospf_area *area,
 | 
						|
			       struct ospf_interface *oi,
 | 
						|
			       struct lsa_header *protolsa)
 | 
						|
{
 | 
						|
  struct stream *s;
 | 
						|
  struct lsa_header *newlsa;
 | 
						|
  struct ospf_lsa *new = NULL;
 | 
						|
  u_char options = 0x0;
 | 
						|
  u_int16_t length;
 | 
						|
 | 
						|
  struct ospf *ospf;
 | 
						|
 | 
						|
  ospf = ospf_lookup();
 | 
						|
  assert(ospf);
 | 
						|
 | 
						|
  /* Create a stream for internal opaque LSA */
 | 
						|
  if ((s = stream_new (OSPF_MAX_LSA_SIZE)) == NULL)
 | 
						|
    {
 | 
						|
      zlog_warn ("ospf_apiserver_opaque_lsa_new: stream_new failed");
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
  newlsa = (struct lsa_header *) STREAM_DATA (s);
 | 
						|
 | 
						|
  /* XXX If this is a link-local LSA or an AS-external LSA, how do we
 | 
						|
     have to set options? */
 | 
						|
 | 
						|
  if (area)
 | 
						|
    {
 | 
						|
      options = LSA_OPTIONS_GET (area);
 | 
						|
      options |= LSA_OPTIONS_NSSA_GET (area);
 | 
						|
    }
 | 
						|
 | 
						|
  options |= OSPF_OPTION_O;	/* Don't forget to set option bit */
 | 
						|
 | 
						|
  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
 | 
						|
    {
 | 
						|
      zlog_debug ("LSA[Type%d:%s]: Creating an Opaque-LSA instance",
 | 
						|
		 protolsa->type, inet_ntoa (protolsa->id));
 | 
						|
    }
 | 
						|
 | 
						|
  /* Set opaque-LSA header fields. */
 | 
						|
  lsa_header_set (s, options, protolsa->type, protolsa->id, 
 | 
						|
                  ospf->router_id);
 | 
						|
 | 
						|
  /* Set opaque-LSA body fields. */
 | 
						|
  stream_put (s, ((u_char *) protolsa) + sizeof (struct lsa_header),
 | 
						|
	      ntohs (protolsa->length) - sizeof (struct lsa_header));
 | 
						|
 | 
						|
  /* Determine length of LSA. */
 | 
						|
  length = stream_get_endp (s);
 | 
						|
  newlsa->length = htons (length);
 | 
						|
 | 
						|
  /* Create OSPF LSA. */
 | 
						|
  if ((new = ospf_lsa_new ()) == NULL)
 | 
						|
    {
 | 
						|
      zlog_warn ("ospf_apiserver_opaque_lsa_new: ospf_lsa_new() ?");
 | 
						|
      stream_free (s);
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
  if ((new->data = ospf_lsa_data_new (length)) == NULL)
 | 
						|
    {
 | 
						|
      zlog_warn ("ospf_apiserver_opaque_lsa_new: ospf_lsa_data_new() ?");
 | 
						|
      ospf_lsa_unlock (new);
 | 
						|
      stream_free (s);
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
  new->area = area;
 | 
						|
  new->oi = oi;
 | 
						|
 | 
						|
  SET_FLAG (new->flags, OSPF_LSA_SELF);
 | 
						|
  memcpy (new->data, newlsa, length);
 | 
						|
  stream_free (s);
 | 
						|
 | 
						|
  return new;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
ospf_apiserver_is_ready_type9 (struct ospf_interface *oi)
 | 
						|
{
 | 
						|
  /* Type 9 opaque LSA can be originated if there is at least one
 | 
						|
     active opaque-capable neighbor attached to the outgoing
 | 
						|
     interface. */
 | 
						|
 | 
						|
  return (ospf_nbr_count_opaque_capable (oi) > 0);
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
ospf_apiserver_is_ready_type10 (struct ospf_area *area)
 | 
						|
{
 | 
						|
  /* Type 10 opaque LSA can be originated if there is at least one
 | 
						|
     interface belonging to the area that has an active opaque-capable
 | 
						|
     neighbor. */
 | 
						|
  struct listnode *node;
 | 
						|
  struct ospf_interface *oi;
 | 
						|
 | 
						|
  LIST_LOOP (area->oiflist, oi, node)
 | 
						|
    /* Is there an active neighbor attached to this interface? */
 | 
						|
    if (ospf_apiserver_is_ready_type9 (oi))
 | 
						|
      return 1;
 | 
						|
 | 
						|
  /* No active neighbor in area */
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
ospf_apiserver_is_ready_type11 (struct ospf *ospf)
 | 
						|
{
 | 
						|
  /* Type 11 opaque LSA can be originated if there is at least one interface
 | 
						|
     that has an active opaque-capable neighbor. */
 | 
						|
  struct listnode *node;
 | 
						|
  struct ospf_interface *oi;
 | 
						|
 | 
						|
  LIST_LOOP (ospf->oiflist, oi, node)
 | 
						|
    /* Is there an active neighbor attached to this interface? */
 | 
						|
    if (ospf_apiserver_is_ready_type9 (oi))
 | 
						|
      return 1;
 | 
						|
 | 
						|
  /* No active neighbor at all */
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
ospf_apiserver_handle_originate_request (struct ospf_apiserver *apiserv,
 | 
						|
					 struct msg *msg)
 | 
						|
{
 | 
						|
  struct msg_originate_request *omsg;
 | 
						|
  struct lsa_header *data;
 | 
						|
  struct ospf_lsa *new;
 | 
						|
  struct ospf_lsa *old;
 | 
						|
  struct ospf_area *area = NULL;
 | 
						|
  struct ospf_interface *oi = NULL;
 | 
						|
  struct ospf_lsdb *lsdb = NULL;
 | 
						|
  struct ospf *ospf;
 | 
						|
  int lsa_type, opaque_type;
 | 
						|
  int ready = 0;
 | 
						|
  int rc = 0;
 | 
						|
  
 | 
						|
  ospf = ospf_lookup();
 | 
						|
 | 
						|
  /* Extract opaque LSA data from message */
 | 
						|
  omsg = (struct msg_originate_request *) STREAM_DATA (msg->s);
 | 
						|
  data = &omsg->data;
 | 
						|
 | 
						|
  /* Determine interface for type9 or area for type10 LSAs. */
 | 
						|
  switch (data->type)
 | 
						|
    {
 | 
						|
    case OSPF_OPAQUE_LINK_LSA:
 | 
						|
      oi = ospf_apiserver_if_lookup_by_addr (omsg->ifaddr);
 | 
						|
      if (!oi)
 | 
						|
	{
 | 
						|
	  zlog_warn ("apiserver_originate: unknown interface %s",
 | 
						|
		     inet_ntoa (omsg->ifaddr));
 | 
						|
	  rc = OSPF_API_NOSUCHINTERFACE;
 | 
						|
	  goto out;
 | 
						|
	}
 | 
						|
      area = oi->area;
 | 
						|
      lsdb = area->lsdb;
 | 
						|
      break;
 | 
						|
    case OSPF_OPAQUE_AREA_LSA:
 | 
						|
      area = ospf_area_lookup_by_area_id (ospf, omsg->area_id);
 | 
						|
      if (!area)
 | 
						|
	{
 | 
						|
	  zlog_warn ("apiserver_originate: unknown area %s",
 | 
						|
		     inet_ntoa (omsg->area_id));
 | 
						|
	  rc = OSPF_API_NOSUCHAREA;
 | 
						|
	  goto out;
 | 
						|
	}
 | 
						|
      lsdb = area->lsdb;
 | 
						|
      break;
 | 
						|
    case OSPF_OPAQUE_AS_LSA:
 | 
						|
      lsdb = ospf->lsdb;
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      /* We can only handle opaque types here */
 | 
						|
      zlog_warn ("apiserver_originate: Cannot originate non-opaque LSA type %d",
 | 
						|
		 data->type);
 | 
						|
      rc = OSPF_API_ILLEGALLSATYPE;
 | 
						|
      goto out;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Check if we registered this opaque type */
 | 
						|
  lsa_type = data->type;
 | 
						|
  opaque_type = GET_OPAQUE_TYPE (ntohl (data->id.s_addr));
 | 
						|
 | 
						|
  if (!apiserver_is_opaque_type_registered (apiserv, lsa_type, opaque_type))
 | 
						|
    {
 | 
						|
      zlog_warn ("apiserver_originate: LSA-type(%d)/Opaque-type(%d): Not registered", lsa_type, opaque_type);
 | 
						|
      rc = OSPF_API_OPAQUETYPENOTREGISTERED;
 | 
						|
      goto out;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Make sure that the neighbors are ready before we can originate */
 | 
						|
  switch (data->type)
 | 
						|
    {
 | 
						|
    case OSPF_OPAQUE_LINK_LSA:
 | 
						|
      ready = ospf_apiserver_is_ready_type9 (oi);
 | 
						|
      break;
 | 
						|
    case OSPF_OPAQUE_AREA_LSA:
 | 
						|
      ready = ospf_apiserver_is_ready_type10 (area);
 | 
						|
      break;
 | 
						|
    case OSPF_OPAQUE_AS_LSA:
 | 
						|
      ready = ospf_apiserver_is_ready_type11 (ospf);
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
  if (!ready)
 | 
						|
    {
 | 
						|
      zlog_warn ("Neighbors not ready to originate type %d", data->type);
 | 
						|
      rc = OSPF_API_NOTREADY;
 | 
						|
      goto out;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Create OSPF's internal opaque LSA representation */
 | 
						|
  new = ospf_apiserver_opaque_lsa_new (area, oi, data);
 | 
						|
  if (!new)
 | 
						|
    {
 | 
						|
      rc = OSPF_API_NOMEMORY;	/* XXX */
 | 
						|
      goto out;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Determine if LSA is new or an update for an existing one. */
 | 
						|
  old = ospf_lsdb_lookup (lsdb, new);
 | 
						|
 | 
						|
  if (!old)
 | 
						|
    {
 | 
						|
      /* New LSA install in LSDB. */
 | 
						|
      rc = ospf_apiserver_originate1 (new);
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      /*
 | 
						|
       * Keep the new LSA instance in the "waiting place" until the next
 | 
						|
       * refresh timing. If several LSA update requests for the same LSID
 | 
						|
       * have issued by peer, the last one takes effect.
 | 
						|
       */
 | 
						|
      new->lsdb = &apiserv->reserve;
 | 
						|
      ospf_lsdb_add (&apiserv->reserve, new);
 | 
						|
 | 
						|
      /* Kick the scheduler function. */
 | 
						|
      ospf_opaque_lsa_refresh_schedule (old);
 | 
						|
    }
 | 
						|
 | 
						|
out:
 | 
						|
 | 
						|
  /* Send a reply back to client with return code */
 | 
						|
  rc = ospf_apiserver_send_reply (apiserv, ntohl (msg->hdr.msgseq), rc);
 | 
						|
  return rc;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* -----------------------------------------------------------
 | 
						|
 * Flood an LSA within its flooding scope. 
 | 
						|
 * -----------------------------------------------------------
 | 
						|
 */
 | 
						|
 | 
						|
/* XXX We can probably use ospf_flood_through instead of this function
 | 
						|
   but then we need the neighbor parameter. If we set nbr to 
 | 
						|
   NULL then ospf_flood_through crashes due to dereferencing NULL. */
 | 
						|
 | 
						|
void
 | 
						|
ospf_apiserver_flood_opaque_lsa (struct ospf_lsa *lsa)
 | 
						|
{
 | 
						|
  assert (lsa);
 | 
						|
 | 
						|
  switch (lsa->data->type)
 | 
						|
    {
 | 
						|
    case OSPF_OPAQUE_LINK_LSA:
 | 
						|
      /* Increment counters? XXX */
 | 
						|
 | 
						|
      /* Flood LSA through local network. */
 | 
						|
      ospf_flood_through_area (lsa->area, NULL /*nbr */ , lsa);
 | 
						|
      break;
 | 
						|
    case OSPF_OPAQUE_AREA_LSA:
 | 
						|
      /* Update LSA origination count. */
 | 
						|
      assert (lsa->area);
 | 
						|
      lsa->area->ospf->lsa_originate_count++;
 | 
						|
 | 
						|
      /* Flood LSA through area. */
 | 
						|
      ospf_flood_through_area (lsa->area, NULL /*nbr */ , lsa);
 | 
						|
      break;
 | 
						|
    case OSPF_OPAQUE_AS_LSA:
 | 
						|
      {
 | 
						|
	struct ospf *ospf;
 | 
						|
 | 
						|
	ospf = ospf_lookup();
 | 
						|
	assert(ospf);
 | 
						|
 | 
						|
	/* Increment counters? XXX */
 | 
						|
 | 
						|
	/* Flood LSA through AS. */
 | 
						|
	ospf_flood_through_as (ospf, NULL /*nbr */ , lsa);
 | 
						|
	break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
ospf_apiserver_originate1 (struct ospf_lsa *lsa)
 | 
						|
{
 | 
						|
  struct ospf *ospf;
 | 
						|
 | 
						|
  ospf = ospf_lookup();
 | 
						|
  assert(ospf);
 | 
						|
 | 
						|
  /* Install this LSA into LSDB. */
 | 
						|
  if (ospf_lsa_install (ospf, lsa->oi, lsa) == NULL)
 | 
						|
    {
 | 
						|
      zlog_warn ("ospf_apiserver_originate1: ospf_lsa_install failed");
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Flood LSA within scope */
 | 
						|
 | 
						|
#ifdef NOTYET
 | 
						|
  /*
 | 
						|
   * NB: Modified version of "ospf_flood_though ()" accepts NULL "inbr"
 | 
						|
   *     parameter, and thus it does not cause SIGSEGV error.
 | 
						|
   */
 | 
						|
  ospf_flood_through (NULL /*nbr */ , lsa);
 | 
						|
#else /* NOTYET */
 | 
						|
 | 
						|
  ospf_apiserver_flood_opaque_lsa (lsa);
 | 
						|
#endif /* NOTYET */
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Opaque LSAs of type 9 on a specific interface can now be
 | 
						|
   originated. Tell clients that registered type 9. */
 | 
						|
int
 | 
						|
ospf_apiserver_lsa9_originator (void *arg)
 | 
						|
{
 | 
						|
  struct ospf_interface *oi;
 | 
						|
 | 
						|
  oi = (struct ospf_interface *) arg;
 | 
						|
  if (listcount (apiserver_list) > 0) {
 | 
						|
    ospf_apiserver_clients_notify_ready_type9 (oi);
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
ospf_apiserver_lsa10_originator (void *arg)
 | 
						|
{
 | 
						|
  struct ospf_area *area;
 | 
						|
 | 
						|
  area = (struct ospf_area *) arg;
 | 
						|
  if (listcount (apiserver_list) > 0) {
 | 
						|
    ospf_apiserver_clients_notify_ready_type10 (area);
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
ospf_apiserver_lsa11_originator (void *arg)
 | 
						|
{
 | 
						|
  struct ospf *ospf;
 | 
						|
 | 
						|
  ospf = (struct ospf *) arg;
 | 
						|
  if (listcount (apiserver_list) > 0) {
 | 
						|
    ospf_apiserver_clients_notify_ready_type11 (ospf);
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Periodically refresh opaque LSAs so that they do not expire in
 | 
						|
   other routers. */
 | 
						|
void
 | 
						|
ospf_apiserver_lsa_refresher (struct ospf_lsa *lsa)
 | 
						|
{
 | 
						|
  struct ospf_apiserver *apiserv;
 | 
						|
  struct ospf_lsa *new = NULL;
 | 
						|
  struct ospf * ospf;
 | 
						|
 | 
						|
  ospf = ospf_lookup();
 | 
						|
  assert(ospf);
 | 
						|
 | 
						|
  apiserv = lookup_apiserver_by_lsa (lsa);
 | 
						|
  if (!apiserv)
 | 
						|
    {
 | 
						|
      zlog_warn ("ospf_apiserver_lsa_refresher: LSA[%s]: No apiserver?", dump_lsa_key (lsa));
 | 
						|
      lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); /* Flush it anyway. */
 | 
						|
    }
 | 
						|
 | 
						|
  if (IS_LSA_MAXAGE (lsa))
 | 
						|
    {
 | 
						|
      ospf_opaque_lsa_flush_schedule (lsa);
 | 
						|
      goto out;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Check if updated version of LSA instance has already prepared. */
 | 
						|
  new = ospf_lsdb_lookup (&apiserv->reserve, lsa);
 | 
						|
  if (!new)
 | 
						|
    {
 | 
						|
      /* This is a periodic refresh, driven by core OSPF mechanism. */
 | 
						|
      new = ospf_apiserver_opaque_lsa_new (lsa->area, lsa->oi, lsa->data);
 | 
						|
      if (!new)
 | 
						|
        {
 | 
						|
          zlog_warn ("ospf_apiserver_lsa_refresher: Cannot create a new LSA?");
 | 
						|
          goto out;
 | 
						|
        }
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      /* This is a forcible refresh, requested by OSPF-API client. */
 | 
						|
      ospf_lsdb_delete (&apiserv->reserve, new);
 | 
						|
      new->lsdb = NULL;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Increment sequence number */
 | 
						|
  new->data->ls_seqnum = lsa_seqnum_increment (lsa);
 | 
						|
 | 
						|
  /* New LSA is in same area. */
 | 
						|
  new->area = lsa->area;
 | 
						|
  SET_FLAG (new->flags, OSPF_LSA_SELF);
 | 
						|
 | 
						|
  /* Install LSA into LSDB. */
 | 
						|
  if (ospf_lsa_install (ospf, new->oi, new) == NULL)
 | 
						|
    {
 | 
						|
      zlog_warn ("ospf_apiserver_lsa_refresher: ospf_lsa_install failed");
 | 
						|
      ospf_lsa_unlock (new);
 | 
						|
      goto out;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Flood updated LSA through interface, area or AS */
 | 
						|
 | 
						|
#ifdef NOTYET
 | 
						|
  ospf_flood_through (NULL /*nbr */ , new);
 | 
						|
#endif /* NOTYET */
 | 
						|
  ospf_apiserver_flood_opaque_lsa (new);
 | 
						|
 | 
						|
  /* Debug logging. */
 | 
						|
  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
 | 
						|
    {
 | 
						|
      zlog_debug ("LSA[Type%d:%s]: Refresh Opaque LSA",
 | 
						|
		 new->data->type, inet_ntoa (new->data->id));
 | 
						|
      ospf_lsa_header_dump (new->data);
 | 
						|
    }
 | 
						|
 | 
						|
out:
 | 
						|
  return;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* -----------------------------------------------------------
 | 
						|
 * Followings are functions to delete LSAs
 | 
						|
 * -----------------------------------------------------------
 | 
						|
 */
 | 
						|
 | 
						|
int
 | 
						|
ospf_apiserver_handle_delete_request (struct ospf_apiserver *apiserv,
 | 
						|
				      struct msg *msg)
 | 
						|
{
 | 
						|
  struct msg_delete_request *dmsg;
 | 
						|
  struct ospf_lsa *old;
 | 
						|
  struct ospf_area *area = NULL;
 | 
						|
  struct in_addr id;
 | 
						|
  int lsa_type, opaque_type;
 | 
						|
  int rc = 0;
 | 
						|
  struct ospf * ospf;
 | 
						|
 | 
						|
  ospf = ospf_lookup();
 | 
						|
  assert(ospf);
 | 
						|
 | 
						|
  /* Extract opaque LSA from message */
 | 
						|
  dmsg = (struct msg_delete_request *) STREAM_DATA (msg->s);
 | 
						|
 | 
						|
  /* Lookup area for link-local and area-local opaque LSAs */
 | 
						|
  switch (dmsg->lsa_type)
 | 
						|
    {
 | 
						|
    case OSPF_OPAQUE_LINK_LSA:
 | 
						|
    case OSPF_OPAQUE_AREA_LSA:
 | 
						|
      area = ospf_area_lookup_by_area_id (ospf, dmsg->area_id);
 | 
						|
      if (!area)
 | 
						|
	{
 | 
						|
	  zlog_warn ("ospf_apiserver_lsa_delete: unknown area %s",
 | 
						|
		     inet_ntoa (dmsg->area_id));
 | 
						|
	  rc = OSPF_API_NOSUCHAREA;
 | 
						|
	  goto out;
 | 
						|
	}
 | 
						|
      break;
 | 
						|
    case OSPF_OPAQUE_AS_LSA:
 | 
						|
      /* AS-external opaque LSAs have no designated area */
 | 
						|
      area = NULL;
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      zlog_warn
 | 
						|
	("ospf_apiserver_lsa_delete: Cannot delete non-opaque LSA type %d",
 | 
						|
	 dmsg->lsa_type);
 | 
						|
      rc = OSPF_API_ILLEGALLSATYPE;
 | 
						|
      goto out;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Check if we registered this opaque type */
 | 
						|
  lsa_type = dmsg->lsa_type;
 | 
						|
  opaque_type = dmsg->opaque_type;
 | 
						|
 | 
						|
  if (!apiserver_is_opaque_type_registered (apiserv, lsa_type, opaque_type))
 | 
						|
    {
 | 
						|
      zlog_warn ("ospf_apiserver_lsa_delete: LSA-type(%d)/Opaque-type(%d): Not registered", lsa_type, opaque_type);
 | 
						|
      rc = OSPF_API_OPAQUETYPENOTREGISTERED;
 | 
						|
      goto out;
 | 
						|
    }
 | 
						|
 | 
						|
  /* opaque_id is in network byte order */
 | 
						|
  id.s_addr = htonl (SET_OPAQUE_LSID (dmsg->opaque_type,
 | 
						|
				      ntohl (dmsg->opaque_id)));
 | 
						|
 | 
						|
  /*
 | 
						|
   * Even if the target LSA has once scheduled to flush, it remains in
 | 
						|
   * the LSDB until it is finally handled by the maxage remover thread.
 | 
						|
   * Therefore, the lookup function below may return non-NULL result.
 | 
						|
   */
 | 
						|
  old = ospf_lsa_lookup (area, dmsg->lsa_type, id, ospf->router_id);
 | 
						|
  if (!old)
 | 
						|
    {
 | 
						|
      zlog_warn ("ospf_apiserver_lsa_delete: LSA[Type%d:%s] not in LSDB",
 | 
						|
		 dmsg->lsa_type, inet_ntoa (id));
 | 
						|
      rc = OSPF_API_NOSUCHLSA;
 | 
						|
      goto out;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Schedule flushing of LSA from LSDB */
 | 
						|
  /* NB: Multiple scheduling will produce a warning message, but harmless. */
 | 
						|
  ospf_opaque_lsa_flush_schedule (old);
 | 
						|
 | 
						|
out:
 | 
						|
 | 
						|
  /* Send reply back to client including return code */
 | 
						|
  rc = ospf_apiserver_send_reply (apiserv, ntohl (msg->hdr.msgseq), rc);
 | 
						|
  return rc;
 | 
						|
}
 | 
						|
 | 
						|
/* Flush self-originated opaque LSA */
 | 
						|
int
 | 
						|
apiserver_flush_opaque_type_callback (struct ospf_lsa *lsa,
 | 
						|
				      void *p_arg, int int_arg)
 | 
						|
{
 | 
						|
  struct param_t
 | 
						|
  {
 | 
						|
    struct ospf_apiserver *apiserv;
 | 
						|
    u_char lsa_type;
 | 
						|
    u_char opaque_type;
 | 
						|
  }
 | 
						|
   *param;
 | 
						|
 | 
						|
  /* Sanity check */
 | 
						|
  assert (lsa->data);
 | 
						|
  assert (p_arg);
 | 
						|
  param = (struct param_t *) p_arg;
 | 
						|
 | 
						|
  /* If LSA matches type and opaque type then delete it */
 | 
						|
  if (IS_LSA_SELF (lsa) && lsa->data->type == param->lsa_type
 | 
						|
      && GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)) == param->opaque_type)
 | 
						|
    {
 | 
						|
      ospf_opaque_lsa_flush_schedule (lsa);
 | 
						|
    }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* Delete self-originated opaque LSAs of a given opaque type. This
 | 
						|
   function is called when an application unregisters a given opaque
 | 
						|
   type or a connection to an application closes and all those opaque
 | 
						|
   LSAs need to be flushed the LSDB. */
 | 
						|
void
 | 
						|
ospf_apiserver_flush_opaque_lsa (struct ospf_apiserver *apiserv,
 | 
						|
				 u_char lsa_type, u_char opaque_type)
 | 
						|
{
 | 
						|
  struct param_t
 | 
						|
  {
 | 
						|
    struct ospf_apiserver *apiserv;
 | 
						|
    u_char lsa_type;
 | 
						|
    u_char opaque_type;
 | 
						|
  } param;
 | 
						|
  struct listnode *node;
 | 
						|
  struct ospf * ospf;
 | 
						|
  struct ospf_area *area;
 | 
						|
  
 | 
						|
  ospf = ospf_lookup();
 | 
						|
  assert(ospf);
 | 
						|
 | 
						|
  /* Set parameter struct. */
 | 
						|
  param.apiserv = apiserv;
 | 
						|
  param.lsa_type = lsa_type;
 | 
						|
  param.opaque_type = opaque_type;
 | 
						|
 | 
						|
  switch (lsa_type)
 | 
						|
    {
 | 
						|
      struct route_node *rn;
 | 
						|
      struct ospf_lsa *lsa;
 | 
						|
 | 
						|
    case OSPF_OPAQUE_LINK_LSA:
 | 
						|
      LIST_LOOP (ospf->areas, area, node)
 | 
						|
        LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa)
 | 
						|
          apiserver_flush_opaque_type_callback(lsa, (void *) ¶m, 0);
 | 
						|
      break;
 | 
						|
    case OSPF_OPAQUE_AREA_LSA:
 | 
						|
      LIST_LOOP (ospf->areas, area, node)
 | 
						|
        LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa)
 | 
						|
          apiserver_flush_opaque_type_callback(lsa, (void *) ¶m, 0);
 | 
						|
      break;
 | 
						|
    case OSPF_OPAQUE_AS_LSA:
 | 
						|
      LSDB_LOOP (OPAQUE_LINK_LSDB (ospf), rn, lsa)
 | 
						|
	apiserver_flush_opaque_type_callback(lsa, (void *) ¶m, 0);
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  return;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* -----------------------------------------------------------
 | 
						|
 * Followings are callback functions to handle opaque types 
 | 
						|
 * -----------------------------------------------------------
 | 
						|
 */
 | 
						|
 | 
						|
int
 | 
						|
ospf_apiserver_new_if (struct interface *ifp)
 | 
						|
{
 | 
						|
  struct ospf_interface *oi;
 | 
						|
 | 
						|
  /* For some strange reason it seems possible that we are invoked
 | 
						|
     with an interface that has no name. This seems to happen during
 | 
						|
     initialization. Return if this happens */
 | 
						|
 | 
						|
  if (ifp->name[0] == '\0') {
 | 
						|
    /* interface has empty name */
 | 
						|
    zlog_warn ("ospf_apiserver_new_if: interface has no name?");
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  /* zlog_warn for debugging */
 | 
						|
  zlog_warn ("ospf_apiserver_new_if");
 | 
						|
  zlog_warn ("ifp name=%s status=%d index=%d", ifp->name, ifp->status,
 | 
						|
	     ifp->ifindex);
 | 
						|
 | 
						|
  if (ifp->name[0] == '\0') {
 | 
						|
    /* interface has empty name */
 | 
						|
    zlog_warn ("ospf_apiserver_new_if: interface has no name?");
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  oi = ospf_apiserver_if_lookup_by_ifp (ifp);
 | 
						|
  
 | 
						|
  if (!oi) {
 | 
						|
    /* This interface is known to Zebra but not to OSPF daemon yet. */
 | 
						|
    zlog_warn ("ospf_apiserver_new_if: interface %s not known to OSPFd?", 
 | 
						|
	       ifp->name);
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  assert (oi);
 | 
						|
 | 
						|
  /* New interface added to OSPF, tell clients about it */
 | 
						|
  if (listcount (apiserver_list) > 0) {
 | 
						|
    ospf_apiserver_clients_notify_new_if (oi);
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
ospf_apiserver_del_if (struct interface *ifp)
 | 
						|
{
 | 
						|
  struct ospf_interface *oi;
 | 
						|
 | 
						|
  /* zlog_warn for debugging */
 | 
						|
  zlog_warn ("ospf_apiserver_del_if");
 | 
						|
  zlog_warn ("ifp name=%s status=%d index=%d\n", ifp->name, ifp->status,
 | 
						|
	     ifp->ifindex);
 | 
						|
 | 
						|
  oi = ospf_apiserver_if_lookup_by_ifp (ifp);
 | 
						|
 | 
						|
  if (!oi) {
 | 
						|
    /* This interface is known to Zebra but not to OSPF daemon
 | 
						|
       anymore. No need to tell clients about it */
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Interface deleted, tell clients about it */
 | 
						|
  if (listcount (apiserver_list) > 0) {
 | 
						|
    ospf_apiserver_clients_notify_del_if (oi);
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ospf_apiserver_ism_change (struct ospf_interface *oi, int old_state)
 | 
						|
{
 | 
						|
  /* Tell clients about interface change */
 | 
						|
 | 
						|
  /* zlog_warn for debugging */
 | 
						|
  zlog_warn ("ospf_apiserver_ism_change");
 | 
						|
  if (listcount (apiserver_list) > 0) {
 | 
						|
    ospf_apiserver_clients_notify_ism_change (oi);
 | 
						|
  }
 | 
						|
 | 
						|
  zlog_warn ("oi->ifp->name=%s", oi->ifp->name);
 | 
						|
  zlog_warn ("old_state=%d", old_state);
 | 
						|
  zlog_warn ("oi->state=%d", oi->state);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ospf_apiserver_nsm_change (struct ospf_neighbor *nbr, int old_status)
 | 
						|
{
 | 
						|
  /* Neighbor status changed, tell clients about it */
 | 
						|
  zlog_warn ("ospf_apiserver_nsm_change");
 | 
						|
  if (listcount (apiserver_list) > 0) {
 | 
						|
    ospf_apiserver_clients_notify_nsm_change (nbr);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ospf_apiserver_show_info (struct vty *vty, struct ospf_lsa *lsa)
 | 
						|
{
 | 
						|
  struct opaque_lsa
 | 
						|
  {
 | 
						|
    struct lsa_header header;
 | 
						|
    u_char data[1]; /* opaque data have variable length. This is start
 | 
						|
                       address */
 | 
						|
  };
 | 
						|
  struct opaque_lsa *olsa;
 | 
						|
  int opaquelen;
 | 
						|
 | 
						|
  olsa = (struct opaque_lsa *) lsa->data;
 | 
						|
 | 
						|
  if (VALID_OPAQUE_INFO_LEN (lsa->data))
 | 
						|
    opaquelen = ntohs (lsa->data->length) - OSPF_LSA_HEADER_SIZE;
 | 
						|
  else
 | 
						|
    opaquelen = 0;
 | 
						|
 | 
						|
  /* Output information about opaque LSAs */
 | 
						|
  if (vty != NULL)
 | 
						|
    {
 | 
						|
      int i;
 | 
						|
      vty_out (vty, "  Added using OSPF API: %u octets of opaque data %s%s",
 | 
						|
	       opaquelen,
 | 
						|
	       VALID_OPAQUE_INFO_LEN (lsa->data) ? "" : "(Invalid length?)",
 | 
						|
	       VTY_NEWLINE);
 | 
						|
      vty_out (vty, "  Opaque data: ");
 | 
						|
 | 
						|
      for (i = 0; i < opaquelen; i++)
 | 
						|
	{
 | 
						|
	  vty_out (vty, "0x%x ", olsa->data[i]);
 | 
						|
	}
 | 
						|
      vty_out (vty, "%s", VTY_NEWLINE);
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      int i;
 | 
						|
      zlog_debug ("    Added using OSPF API: %u octets of opaque data %s",
 | 
						|
		 opaquelen,
 | 
						|
		 VALID_OPAQUE_INFO_LEN (lsa->
 | 
						|
					data) ? "" : "(Invalid length?)");
 | 
						|
      zlog_debug ("    Opaque data: ");
 | 
						|
 | 
						|
      for (i = 0; i < opaquelen; i++)
 | 
						|
	{
 | 
						|
	  zlog_debug ("0x%x ", olsa->data[i]);
 | 
						|
	}
 | 
						|
      zlog_debug ("\n");
 | 
						|
    }
 | 
						|
  return;
 | 
						|
}
 | 
						|
 | 
						|
/* -----------------------------------------------------------
 | 
						|
 * Followings are functions to notify clients about events
 | 
						|
 * -----------------------------------------------------------
 | 
						|
 */
 | 
						|
 | 
						|
/* Send a message to all clients. This is useful for messages
 | 
						|
   that need to be notified to all clients (such as interface
 | 
						|
   changes) */
 | 
						|
 | 
						|
void
 | 
						|
ospf_apiserver_clients_notify_all (struct msg *msg)
 | 
						|
{
 | 
						|
  struct listnode *node;
 | 
						|
  struct ospf_apiserver *apiserv;
 | 
						|
 | 
						|
  /* Send message to all clients */
 | 
						|
  LIST_LOOP (apiserver_list, apiserv, node)
 | 
						|
    ospf_apiserver_send_msg (apiserv, msg);
 | 
						|
}
 | 
						|
 | 
						|
/* An interface is now ready to accept opaque LSAs. Notify all
 | 
						|
   clients that registered to use this opaque type */
 | 
						|
void
 | 
						|
ospf_apiserver_clients_notify_ready_type9 (struct ospf_interface *oi)
 | 
						|
{
 | 
						|
  struct listnode *node;
 | 
						|
  struct msg *msg;
 | 
						|
  struct ospf_apiserver *apiserv;
 | 
						|
 | 
						|
  assert (oi);
 | 
						|
  if (!oi->address)
 | 
						|
    {
 | 
						|
      zlog_warn ("Interface has no address?");
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
  if (!ospf_apiserver_is_ready_type9 (oi))
 | 
						|
    {
 | 
						|
      zlog_warn ("Interface not ready for type 9?");
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
  LIST_LOOP (apiserver_list, apiserv, node)
 | 
						|
    {
 | 
						|
      struct listnode *n2;
 | 
						|
      struct registered_opaque_type *r;
 | 
						|
 | 
						|
      LIST_LOOP (apiserv->opaque_types, r, n2)
 | 
						|
	{
 | 
						|
	  if (r->lsa_type == OSPF_OPAQUE_LINK_LSA)
 | 
						|
	    {
 | 
						|
	      msg = new_msg_ready_notify (0, OSPF_OPAQUE_LINK_LSA,
 | 
						|
					  r->opaque_type,
 | 
						|
					  oi->address->u.prefix4);
 | 
						|
	      if (!msg)
 | 
						|
		{
 | 
						|
		  zlog_warn
 | 
						|
		    ("ospf_apiserver_clients_notify_ready_type9: new_msg_ready_notify failed");
 | 
						|
#ifdef NOTYET
 | 
						|
		  /* Cannot allocate new message. What should we do? */
 | 
						|
		  ospf_apiserver_free (apiserv);
 | 
						|
#endif
 | 
						|
		  goto out;
 | 
						|
		}
 | 
						|
 | 
						|
	      ospf_apiserver_send_msg (apiserv, msg);
 | 
						|
	      msg_free (msg);
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
out:
 | 
						|
  return;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ospf_apiserver_clients_notify_ready_type10 (struct ospf_area *area)
 | 
						|
{
 | 
						|
  struct listnode *node;
 | 
						|
  struct msg *msg;
 | 
						|
  struct ospf_apiserver *apiserv;
 | 
						|
 | 
						|
  assert (area);
 | 
						|
 | 
						|
  if (!ospf_apiserver_is_ready_type10 (area))
 | 
						|
    {
 | 
						|
      zlog_warn ("Area not ready for type 10?");
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
  LIST_LOOP (apiserver_list, apiserv, node)
 | 
						|
    {
 | 
						|
      struct listnode *n2;
 | 
						|
      struct registered_opaque_type *r;
 | 
						|
 | 
						|
      LIST_LOOP (apiserv->opaque_types, r, n2)
 | 
						|
	{
 | 
						|
	  if (r->lsa_type == OSPF_OPAQUE_AREA_LSA)
 | 
						|
	    {
 | 
						|
	      msg = new_msg_ready_notify (0, OSPF_OPAQUE_AREA_LSA,
 | 
						|
					  r->opaque_type, area->area_id);
 | 
						|
	      if (!msg)
 | 
						|
		{
 | 
						|
		  zlog_warn
 | 
						|
		    ("ospf_apiserver_clients_notify_ready_type10: new_msg_ready_nofity failed");
 | 
						|
#ifdef NOTYET
 | 
						|
		  /* Cannot allocate new message. What should we do? */
 | 
						|
		  ospf_apiserver_free (apiserv);
 | 
						|
#endif
 | 
						|
                  goto out;
 | 
						|
		}
 | 
						|
 | 
						|
	      ospf_apiserver_send_msg (apiserv, msg);
 | 
						|
	      msg_free (msg);
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
out:
 | 
						|
  return;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void
 | 
						|
ospf_apiserver_clients_notify_ready_type11 (struct ospf *top)
 | 
						|
{
 | 
						|
  struct listnode *node;
 | 
						|
  struct msg *msg;
 | 
						|
  struct in_addr id_null = { 0L };
 | 
						|
  struct ospf_apiserver *apiserv;
 | 
						|
 | 
						|
  assert (top);
 | 
						|
 | 
						|
  if (!ospf_apiserver_is_ready_type11 (top))
 | 
						|
    {
 | 
						|
      zlog_warn ("AS not ready for type 11?");
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
  LIST_LOOP (apiserver_list, apiserv, node)
 | 
						|
    {
 | 
						|
      struct listnode *n2;
 | 
						|
      struct registered_opaque_type *r;
 | 
						|
 | 
						|
      LIST_LOOP (apiserv->opaque_types, r, n2)
 | 
						|
	{
 | 
						|
	  if (r->lsa_type == OSPF_OPAQUE_AS_LSA)
 | 
						|
	    {
 | 
						|
	      msg = new_msg_ready_notify (0, OSPF_OPAQUE_AS_LSA,
 | 
						|
					  r->opaque_type, id_null);
 | 
						|
	      if (!msg)
 | 
						|
		{
 | 
						|
		  zlog_warn
 | 
						|
		    ("ospf_apiserver_clients_notify_ready_type11: new_msg_ready_notify failed");
 | 
						|
#ifdef NOTYET
 | 
						|
		  /* Cannot allocate new message. What should we do? */
 | 
						|
		  ospf_apiserver_free (apiserv);
 | 
						|
#endif
 | 
						|
		  goto out;
 | 
						|
		}
 | 
						|
 | 
						|
	      ospf_apiserver_send_msg (apiserv, msg);
 | 
						|
	      msg_free (msg);
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
out:
 | 
						|
  return;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ospf_apiserver_clients_notify_new_if (struct ospf_interface *oi)
 | 
						|
{
 | 
						|
  struct msg *msg;
 | 
						|
 | 
						|
  msg = new_msg_new_if (0, oi->address->u.prefix4, oi->area->area_id);
 | 
						|
  if (msg != NULL)
 | 
						|
    {
 | 
						|
      ospf_apiserver_clients_notify_all (msg);
 | 
						|
      msg_free (msg);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ospf_apiserver_clients_notify_del_if (struct ospf_interface *oi)
 | 
						|
{
 | 
						|
  struct msg *msg;
 | 
						|
 | 
						|
  msg = new_msg_del_if (0, oi->address->u.prefix4);
 | 
						|
  if (msg != NULL)
 | 
						|
    {
 | 
						|
      ospf_apiserver_clients_notify_all (msg);
 | 
						|
      msg_free (msg);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ospf_apiserver_clients_notify_ism_change (struct ospf_interface *oi)
 | 
						|
{
 | 
						|
  struct msg *msg;
 | 
						|
  struct in_addr ifaddr = { 0L };
 | 
						|
  struct in_addr area_id = { 0L };
 | 
						|
 | 
						|
  assert (oi);
 | 
						|
  assert (oi->ifp);
 | 
						|
 | 
						|
  if (oi->address)
 | 
						|
    {
 | 
						|
      ifaddr = oi->address->u.prefix4;
 | 
						|
    }
 | 
						|
  if (oi->area)
 | 
						|
    {
 | 
						|
      area_id = oi->area->area_id;
 | 
						|
    }
 | 
						|
 | 
						|
  msg = new_msg_ism_change (0, ifaddr, area_id, oi->ifp->status);
 | 
						|
  if (!msg)
 | 
						|
    {
 | 
						|
      zlog_warn ("apiserver_clients_notify_ism_change: msg_new failed");
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
  ospf_apiserver_clients_notify_all (msg);
 | 
						|
  msg_free (msg);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ospf_apiserver_clients_notify_nsm_change (struct ospf_neighbor *nbr)
 | 
						|
{
 | 
						|
  struct msg *msg;
 | 
						|
  struct in_addr ifaddr = { 0L };
 | 
						|
  struct in_addr nbraddr = { 0L };
 | 
						|
 | 
						|
  assert (nbr);
 | 
						|
 | 
						|
  if (nbr->oi)
 | 
						|
    {
 | 
						|
      ifaddr = nbr->oi->address->u.prefix4;
 | 
						|
    }
 | 
						|
 | 
						|
  nbraddr = nbr->address.u.prefix4;
 | 
						|
 | 
						|
  msg = new_msg_nsm_change (0, ifaddr, nbraddr, nbr->router_id, nbr->state);
 | 
						|
  if (!msg)
 | 
						|
    {
 | 
						|
      zlog_warn ("apiserver_clients_notify_nsm_change: msg_new failed");
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
  ospf_apiserver_clients_notify_all (msg);
 | 
						|
  msg_free (msg);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
apiserver_clients_lsa_change_notify (u_char msgtype, struct ospf_lsa *lsa)
 | 
						|
{
 | 
						|
  struct msg *msg;
 | 
						|
  struct listnode *node;
 | 
						|
  struct ospf_apiserver *apiserv;
 | 
						|
 | 
						|
  /* Default area for AS-External and Opaque11 LSAs */
 | 
						|
  struct in_addr area_id = { 0L };
 | 
						|
 | 
						|
  /* Default interface for non Opaque9 LSAs */
 | 
						|
  struct in_addr ifaddr = { 0L };
 | 
						|
 | 
						|
  if (lsa->area)
 | 
						|
    {
 | 
						|
      area_id = lsa->area->area_id;
 | 
						|
    }
 | 
						|
  if (lsa->data->type == OSPF_OPAQUE_LINK_LSA)
 | 
						|
    {
 | 
						|
      assert (lsa->oi);
 | 
						|
      ifaddr = lsa->oi->address->u.prefix4;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Prepare message that can be sent to clients that have a matching
 | 
						|
     filter */
 | 
						|
  msg = new_msg_lsa_change_notify (msgtype, 0L,	/* no sequence number */
 | 
						|
				   ifaddr, area_id,
 | 
						|
				   lsa->flags & OSPF_LSA_SELF, lsa->data);
 | 
						|
  if (!msg)
 | 
						|
    {
 | 
						|
      zlog_warn ("apiserver_clients_lsa_change_notify: msg_new failed");
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Now send message to all clients with a matching filter */
 | 
						|
  LIST_LOOP (apiserver_list, apiserv, node)
 | 
						|
    {
 | 
						|
      struct lsa_filter_type *filter;
 | 
						|
      u_int16_t mask;
 | 
						|
      u_int32_t *area;
 | 
						|
      int i;
 | 
						|
 | 
						|
      /* Check filter for this client. */
 | 
						|
      filter = apiserv->filter;
 | 
						|
 | 
						|
      /* Check area IDs in case of non AS-E LSAs.
 | 
						|
       * If filter has areas (num_areas > 0),
 | 
						|
       * then one of the areas must match the area ID of this LSA. */
 | 
						|
 | 
						|
      i = filter->num_areas;
 | 
						|
      if ((lsa->data->type == OSPF_AS_EXTERNAL_LSA) ||
 | 
						|
	  (lsa->data->type == OSPF_OPAQUE_AS_LSA))
 | 
						|
	{
 | 
						|
	  i = 0;
 | 
						|
	}
 | 
						|
 | 
						|
      if (i > 0)
 | 
						|
	{
 | 
						|
	  area = (u_int32_t *) (filter + 1);
 | 
						|
	  while (i)
 | 
						|
	    {
 | 
						|
	      if (*area == area_id.s_addr)
 | 
						|
		{
 | 
						|
		  break;
 | 
						|
		}
 | 
						|
	      i--;
 | 
						|
	      area++;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  i = 1;
 | 
						|
	}
 | 
						|
 | 
						|
      if (i > 0)
 | 
						|
	{
 | 
						|
	  /* Area match. Check LSA type. */
 | 
						|
	  mask = ntohs (filter->typemask);
 | 
						|
 | 
						|
	  if (mask & Power2[lsa->data->type])
 | 
						|
	    {
 | 
						|
	      /* Type also matches. Check origin. */
 | 
						|
	      if ((filter->origin == ANY_ORIGIN) ||
 | 
						|
		  (filter->origin == IS_LSA_SELF (lsa)))
 | 
						|
		{
 | 
						|
		  ospf_apiserver_send_msg (apiserv, msg);
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
  /* Free message since it is not used anymore */
 | 
						|
  msg_free (msg);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* -------------------------------------------------------------
 | 
						|
 * Followings are hooks invoked when LSAs are updated or deleted
 | 
						|
 * -------------------------------------------------------------
 | 
						|
 */
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
apiserver_notify_clients_lsa (u_char msgtype, struct ospf_lsa *lsa)
 | 
						|
{
 | 
						|
  struct msg *msg;
 | 
						|
  /* default area for AS-External and Opaque11 LSAs */
 | 
						|
  struct in_addr area_id = { 0L };
 | 
						|
 | 
						|
  /* default interface for non Opaque9 LSAs */
 | 
						|
  struct in_addr ifaddr = { 0L };
 | 
						|
 | 
						|
  /* Only notify this update if the LSA's age is smaller than
 | 
						|
     MAXAGE. Otherwise clients would see LSA updates with max age just
 | 
						|
     before they are deleted from the LSDB. LSA delete messages have
 | 
						|
     MAXAGE too but should not be filtered. */
 | 
						|
  if (IS_LSA_MAXAGE(lsa) && (msgtype == MSG_LSA_UPDATE_NOTIFY)) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  if (lsa->area)
 | 
						|
    {
 | 
						|
      area_id = lsa->area->area_id;
 | 
						|
    }
 | 
						|
  if (lsa->data->type == OSPF_OPAQUE_LINK_LSA)
 | 
						|
    {
 | 
						|
      ifaddr = lsa->oi->address->u.prefix4;
 | 
						|
    }
 | 
						|
  msg = new_msg_lsa_change_notify (msgtype, 0L,	/* no sequence number */
 | 
						|
				   ifaddr, area_id,
 | 
						|
				   lsa->flags & OSPF_LSA_SELF, lsa->data);
 | 
						|
  if (!msg)
 | 
						|
    {
 | 
						|
      zlog_warn ("notify_clients_lsa: msg_new failed");
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
  /* Notify all clients that new LSA is added/updated */
 | 
						|
  apiserver_clients_lsa_change_notify (msgtype, lsa);
 | 
						|
 | 
						|
  /* Clients made their own copies of msg so we can free msg here */
 | 
						|
  msg_free (msg);
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
ospf_apiserver_lsa_update (struct ospf_lsa *lsa)
 | 
						|
{
 | 
						|
  return apiserver_notify_clients_lsa (MSG_LSA_UPDATE_NOTIFY, lsa);
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
ospf_apiserver_lsa_delete (struct ospf_lsa *lsa)
 | 
						|
{
 | 
						|
  return apiserver_notify_clients_lsa (MSG_LSA_DELETE_NOTIFY, lsa);
 | 
						|
}
 | 
						|
 | 
						|
#endif /* SUPPORT_OSPF_API */
 | 
						|
 |