123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746 |
- /*
- * Client side of OSPF API.
- * Copyright (C) 2001, 2002, 2003 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>
- #include <lib/version.h>
- #include "getopt.h"
- #include "thread.h"
- #include "prefix.h"
- #include "linklist.h"
- #include "if.h"
- #include "vector.h"
- #include "vty.h"
- #include "command.h"
- #include "filter.h"
- #include "stream.h"
- #include "log.h"
- #include "memory.h"
- #include "ospfd/ospfd.h"
- #include "ospfd/ospf_interface.h"
- #include "ospfd/ospf_asbr.h"
- #include "ospfd/ospf_lsa.h"
- #include "ospfd/ospf_opaque.h"
- #include "ospfd/ospf_lsdb.h"
- #include "ospfd/ospf_neighbor.h"
- #include "ospfd/ospf_dump.h"
- #include "ospfd/ospf_zebra.h"
- #include "ospfd/ospf_api.h"
- #include "ospf_apiclient.h"
- /* Backlog for listen */
- #define BACKLOG 5
- /* -----------------------------------------------------------
- * Forward declarations
- * -----------------------------------------------------------
- */
- void ospf_apiclient_handle_reply (struct ospf_apiclient *oclient,
- struct msg *msg);
- void ospf_apiclient_handle_update_notify (struct ospf_apiclient *oclient,
- struct msg *msg);
- void ospf_apiclient_handle_delete_notify (struct ospf_apiclient *oclient,
- struct msg *msg);
- /* -----------------------------------------------------------
- * Initialization
- * -----------------------------------------------------------
- */
- static unsigned short
- ospf_apiclient_getport (void)
- {
- struct servent *sp = getservbyname ("ospfapi", "tcp");
- return sp ? ntohs (sp->s_port) : OSPF_API_SYNC_PORT;
- }
- /* -----------------------------------------------------------
- * Followings are functions for connection management
- * -----------------------------------------------------------
- */
- struct ospf_apiclient *
- ospf_apiclient_connect (char *host, int syncport)
- {
- struct sockaddr_in myaddr_sync;
- struct sockaddr_in myaddr_async;
- struct sockaddr_in peeraddr;
- struct hostent *hp;
- struct ospf_apiclient *new;
- int size = 0;
- unsigned int peeraddrlen;
- int async_server_sock;
- int fd1, fd2;
- int ret;
- int on = 1;
- /* There are two connections between the client and the server.
- First the client opens a connection for synchronous requests/replies
- to the server. The server will accept this connection and
- as a reaction open a reverse connection channel for
- asynchronous messages. */
- async_server_sock = socket (AF_INET, SOCK_STREAM, 0);
- if (async_server_sock < 0)
- {
- fprintf (stderr,
- "ospf_apiclient_connect: creating async socket failed\n");
- return NULL;
- }
- /* Prepare socket for asynchronous messages */
- /* Initialize async address structure */
- memset (&myaddr_async, 0, sizeof (struct sockaddr_in));
- myaddr_async.sin_family = AF_INET;
- myaddr_async.sin_addr.s_addr = htonl (INADDR_ANY);
- myaddr_async.sin_port = htons (syncport+1);
- size = sizeof (struct sockaddr_in);
- #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
- myaddr_async.sin_len = size;
- #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
- /* This is a server socket, reuse addr and port */
- ret = setsockopt (async_server_sock, SOL_SOCKET,
- SO_REUSEADDR, (void *) &on, sizeof (on));
- if (ret < 0)
- {
- fprintf (stderr, "ospf_apiclient_connect: SO_REUSEADDR failed\n");
- close (async_server_sock);
- return NULL;
- }
- #ifdef SO_REUSEPORT
- ret = setsockopt (async_server_sock, SOL_SOCKET, SO_REUSEPORT,
- (void *) &on, sizeof (on));
- if (ret < 0)
- {
- fprintf (stderr, "ospf_apiclient_connect: SO_REUSEPORT failed\n");
- close (async_server_sock);
- return NULL;
- }
- #endif /* SO_REUSEPORT */
- /* Bind socket to address structure */
- ret = bind (async_server_sock, (struct sockaddr *) &myaddr_async, size);
- if (ret < 0)
- {
- fprintf (stderr, "ospf_apiclient_connect: bind async socket failed\n");
- close (async_server_sock);
- return NULL;
- }
- /* Wait for reverse channel connection establishment from server */
- ret = listen (async_server_sock, BACKLOG);
- if (ret < 0)
- {
- fprintf (stderr, "ospf_apiclient_connect: listen: %s\n", safe_strerror (errno));
- close (async_server_sock);
- return NULL;
- }
- /* Make connection for synchronous requests and connect to server */
- /* Resolve address of server */
- hp = gethostbyname (host);
- if (!hp)
- {
- fprintf (stderr, "ospf_apiclient_connect: no such host %s\n", host);
- close (async_server_sock);
- return NULL;
- }
- fd1 = socket (AF_INET, SOCK_STREAM, 0);
- if (fd1 < 0)
- {
- fprintf (stderr,
- "ospf_apiclient_connect: creating sync socket failed\n");
- return NULL;
- }
- /* Reuse addr and port */
- ret = setsockopt (fd1, SOL_SOCKET,
- SO_REUSEADDR, (void *) &on, sizeof (on));
- if (ret < 0)
- {
- fprintf (stderr, "ospf_apiclient_connect: SO_REUSEADDR failed\n");
- close (fd1);
- return NULL;
- }
- #ifdef SO_REUSEPORT
- ret = setsockopt (fd1, SOL_SOCKET, SO_REUSEPORT,
- (void *) &on, sizeof (on));
- if (ret < 0)
- {
- fprintf (stderr, "ospf_apiclient_connect: SO_REUSEPORT failed\n");
- close (fd1);
- return NULL;
- }
- #endif /* SO_REUSEPORT */
- /* Bind sync socket to address structure. This is needed since we
- want the sync port number on a fixed port number. The reverse
- async channel will be at this port+1 */
- memset (&myaddr_sync, 0, sizeof (struct sockaddr_in));
- myaddr_sync.sin_family = AF_INET;
- myaddr_sync.sin_port = htons (syncport);
- #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
- myaddr_sync.sin_len = sizeof (struct sockaddr_in);
- #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
- ret = bind (fd1, (struct sockaddr *) &myaddr_sync, size);
- if (ret < 0)
- {
- fprintf (stderr, "ospf_apiclient_connect: bind sync socket failed\n");
- close (fd1);
- return NULL;
- }
- /* Prepare address structure for connect */
- memcpy (&myaddr_sync.sin_addr, hp->h_addr, hp->h_length);
- myaddr_sync.sin_family = AF_INET;
- myaddr_sync.sin_port = htons(ospf_apiclient_getport ());
- #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
- myaddr_sync.sin_len = sizeof (struct sockaddr_in);
- #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
- /* Now establish synchronous channel with OSPF daemon */
- ret = connect (fd1, (struct sockaddr *) &myaddr_sync,
- sizeof (struct sockaddr_in));
- if (ret < 0)
- {
- fprintf (stderr, "ospf_apiclient_connect: sync connect failed\n");
- close (async_server_sock);
- close (fd1);
- return NULL;
- }
- /* Accept reverse connection */
- peeraddrlen = sizeof (struct sockaddr_in);
- memset (&peeraddr, 0, peeraddrlen);
- fd2 =
- accept (async_server_sock, (struct sockaddr *) &peeraddr, &peeraddrlen);
- if (fd2 < 0)
- {
- fprintf (stderr, "ospf_apiclient_connect: accept async failed\n");
- close (async_server_sock);
- close (fd1);
- return NULL;
- }
- /* Server socket is not needed anymore since we are not accepting more
- connections */
- close (async_server_sock);
- /* Create new client-side instance */
- new = XCALLOC (MTYPE_OSPF_APICLIENT, sizeof (struct ospf_apiclient));
- /* Initialize socket descriptors for sync and async channels */
- new->fd_sync = fd1;
- new->fd_async = fd2;
- return new;
- }
- int
- ospf_apiclient_close (struct ospf_apiclient *oclient)
- {
- if (oclient->fd_sync >= 0)
- {
- close (oclient->fd_sync);
- }
- if (oclient->fd_async >= 0)
- {
- close (oclient->fd_async);
- }
- /* Free client structure */
- XFREE (MTYPE_OSPF_APICLIENT, oclient);
- return 0;
- }
- /* -----------------------------------------------------------
- * Followings are functions to send a request to OSPFd
- * -----------------------------------------------------------
- */
- /* Send synchronous request, wait for reply */
- static int
- ospf_apiclient_send_request (struct ospf_apiclient *oclient, struct msg *msg)
- {
- u_int32_t reqseq;
- struct msg_reply *msgreply;
- int rc;
- /* NB: Given "msg" is freed inside this function. */
- /* Remember the sequence number of the request */
- reqseq = ntohl (msg->hdr.msgseq);
- /* Write message to OSPFd */
- rc = msg_write (oclient->fd_sync, msg);
- msg_free (msg);
- if (rc < 0)
- {
- return -1;
- }
- /* Wait for reply *//* NB: New "msg" is allocated by "msg_read()". */
- msg = msg_read (oclient->fd_sync);
- if (!msg)
- return -1;
- assert (msg->hdr.msgtype == MSG_REPLY);
- assert (ntohl (msg->hdr.msgseq) == reqseq);
- msgreply = (struct msg_reply *) STREAM_DATA (msg->s);
- rc = msgreply->errcode;
- msg_free (msg);
- return rc;
- }
- /* -----------------------------------------------------------
- * Helper functions
- * -----------------------------------------------------------
- */
- static u_int32_t
- ospf_apiclient_get_seqnr (void)
- {
- static u_int32_t seqnr = MIN_SEQ;
- u_int32_t tmp;
- tmp = seqnr;
- /* Increment sequence number */
- if (seqnr < MAX_SEQ)
- {
- seqnr++;
- }
- else
- {
- seqnr = MIN_SEQ;
- }
- return tmp;
- }
- /* -----------------------------------------------------------
- * API to access OSPF daemon by client applications.
- * -----------------------------------------------------------
- */
- /*
- * Synchronous request to register opaque type.
- */
- int
- ospf_apiclient_register_opaque_type (struct ospf_apiclient *cl,
- u_char ltype, u_char otype)
- {
- struct msg *msg;
- int rc;
- /* just put 1 as a sequence number. */
- msg = new_msg_register_opaque_type (ospf_apiclient_get_seqnr (),
- ltype, otype);
- if (!msg)
- {
- fprintf (stderr, "new_msg_register_opaque_type failed\n");
- return -1;
- }
- rc = ospf_apiclient_send_request (cl, msg);
- return rc;
- }
- /*
- * Synchronous request to synchronize with OSPF's LSDB.
- * Two steps required: register_event in order to get
- * dynamic updates and LSDB_Sync.
- */
- int
- ospf_apiclient_sync_lsdb (struct ospf_apiclient *oclient)
- {
- struct msg *msg;
- int rc;
- struct lsa_filter_type filter;
- filter.typemask = 0xFFFF; /* all LSAs */
- filter.origin = ANY_ORIGIN;
- filter.num_areas = 0; /* all Areas. */
- msg = new_msg_register_event (ospf_apiclient_get_seqnr (), &filter);
- if (!msg)
- {
- fprintf (stderr, "new_msg_register_event failed\n");
- return -1;
- }
- rc = ospf_apiclient_send_request (oclient, msg);
- if (rc != 0)
- goto out;
- msg = new_msg_sync_lsdb (ospf_apiclient_get_seqnr (), &filter);
- if (!msg)
- {
- fprintf (stderr, "new_msg_sync_lsdb failed\n");
- return -1;
- }
- rc = ospf_apiclient_send_request (oclient, msg);
- out:
- return rc;
- }
- /*
- * Synchronous request to originate or update an LSA.
- */
- int
- ospf_apiclient_lsa_originate (struct ospf_apiclient *oclient,
- struct in_addr ifaddr,
- struct in_addr area_id,
- u_char lsa_type,
- u_char opaque_type, u_int32_t opaque_id,
- void *opaquedata, int opaquelen)
- {
- struct msg *msg;
- int rc;
- u_char buf[OSPF_MAX_LSA_SIZE];
- struct lsa_header *lsah;
- u_int32_t tmp;
- /* We can only originate opaque LSAs */
- if (!IS_OPAQUE_LSA (lsa_type))
- {
- fprintf (stderr, "Cannot originate non-opaque LSA type %d\n", lsa_type);
- return OSPF_API_ILLEGALLSATYPE;
- }
- /* Make a new LSA from parameters */
- lsah = (struct lsa_header *) buf;
- lsah->ls_age = 0;
- lsah->options = 0;
- lsah->type = lsa_type;
- tmp = SET_OPAQUE_LSID (opaque_type, opaque_id);
- lsah->id.s_addr = htonl (tmp);
- lsah->adv_router.s_addr = 0;
- lsah->ls_seqnum = 0;
- lsah->checksum = 0;
- lsah->length = htons (sizeof (struct lsa_header) + opaquelen);
- memcpy (((u_char *) lsah) + sizeof (struct lsa_header), opaquedata,
- opaquelen);
- msg = new_msg_originate_request (ospf_apiclient_get_seqnr (),
- ifaddr, area_id, lsah);
- if (!msg)
- {
- fprintf (stderr, "new_msg_originate_request failed\n");
- return OSPF_API_NOMEMORY;
- }
- rc = ospf_apiclient_send_request (oclient, msg);
- return rc;
- }
- int
- ospf_apiclient_lsa_delete (struct ospf_apiclient *oclient,
- struct in_addr area_id, u_char lsa_type,
- u_char opaque_type, u_int32_t opaque_id)
- {
- struct msg *msg;
- int rc;
- /* Only opaque LSA can be deleted */
- if (!IS_OPAQUE_LSA (lsa_type))
- {
- fprintf (stderr, "Cannot delete non-opaque LSA type %d\n", lsa_type);
- return OSPF_API_ILLEGALLSATYPE;
- }
- /* opaque_id is in host byte order and will be converted
- * to network byte order by new_msg_delete_request */
- msg = new_msg_delete_request (ospf_apiclient_get_seqnr (),
- area_id, lsa_type, opaque_type, opaque_id);
- rc = ospf_apiclient_send_request (oclient, msg);
- return rc;
- }
- /* -----------------------------------------------------------
- * Followings are handlers for messages from OSPF daemon
- * -----------------------------------------------------------
- */
- static void
- ospf_apiclient_handle_ready (struct ospf_apiclient *oclient, struct msg *msg)
- {
- struct msg_ready_notify *r;
- r = (struct msg_ready_notify *) STREAM_DATA (msg->s);
- /* Invoke registered callback function. */
- if (oclient->ready_notify)
- {
- (oclient->ready_notify) (r->lsa_type, r->opaque_type, r->addr);
- }
- }
- static void
- ospf_apiclient_handle_new_if (struct ospf_apiclient *oclient, struct msg *msg)
- {
- struct msg_new_if *n;
- n = (struct msg_new_if *) STREAM_DATA (msg->s);
- /* Invoke registered callback function. */
- if (oclient->new_if)
- {
- (oclient->new_if) (n->ifaddr, n->area_id);
- }
- }
- static void
- ospf_apiclient_handle_del_if (struct ospf_apiclient *oclient, struct msg *msg)
- {
- struct msg_del_if *d;
- d = (struct msg_del_if *) STREAM_DATA (msg->s);
- /* Invoke registered callback function. */
- if (oclient->del_if)
- {
- (oclient->del_if) (d->ifaddr);
- }
- }
- static void
- ospf_apiclient_handle_ism_change (struct ospf_apiclient *oclient,
- struct msg *msg)
- {
- struct msg_ism_change *m;
- m = (struct msg_ism_change *) STREAM_DATA (msg->s);
- /* Invoke registered callback function. */
- if (oclient->ism_change)
- {
- (oclient->ism_change) (m->ifaddr, m->area_id, m->status);
- }
- }
- static void
- ospf_apiclient_handle_nsm_change (struct ospf_apiclient *oclient,
- struct msg *msg)
- {
- struct msg_nsm_change *m;
- m = (struct msg_nsm_change *) STREAM_DATA (msg->s);
- /* Invoke registered callback function. */
- if (oclient->nsm_change)
- {
- (oclient->nsm_change) (m->ifaddr, m->nbraddr, m->router_id, m->status);
- }
- }
- static void
- ospf_apiclient_handle_lsa_update (struct ospf_apiclient *oclient,
- struct msg *msg)
- {
- struct msg_lsa_change_notify *cn;
- struct lsa_header *lsa;
- int lsalen;
- cn = (struct msg_lsa_change_notify *) STREAM_DATA (msg->s);
- /* Extract LSA from message */
- lsalen = ntohs (cn->data.length);
- lsa = XMALLOC (MTYPE_OSPF_APICLIENT, lsalen);
- if (!lsa)
- {
- fprintf (stderr, "LSA update: Cannot allocate memory for LSA\n");
- return;
- }
- memcpy (lsa, &(cn->data), lsalen);
- /* Invoke registered update callback function */
- if (oclient->update_notify)
- {
- (oclient->update_notify) (cn->ifaddr, cn->area_id,
- cn->is_self_originated, lsa);
- }
- /* free memory allocated by ospf apiclient library */
- XFREE (MTYPE_OSPF_APICLIENT, lsa);
- }
- static void
- ospf_apiclient_handle_lsa_delete (struct ospf_apiclient *oclient,
- struct msg *msg)
- {
- struct msg_lsa_change_notify *cn;
- struct lsa_header *lsa;
- int lsalen;
- cn = (struct msg_lsa_change_notify *) STREAM_DATA (msg->s);
- /* Extract LSA from message */
- lsalen = ntohs (cn->data.length);
- lsa = XMALLOC (MTYPE_OSPF_APICLIENT, lsalen);
- if (!lsa)
- {
- fprintf (stderr, "LSA delete: Cannot allocate memory for LSA\n");
- return;
- }
- memcpy (lsa, &(cn->data), lsalen);
- /* Invoke registered update callback function */
- if (oclient->delete_notify)
- {
- (oclient->delete_notify) (cn->ifaddr, cn->area_id,
- cn->is_self_originated, lsa);
- }
- /* free memory allocated by ospf apiclient library */
- XFREE (MTYPE_OSPF_APICLIENT, lsa);
- }
- static void
- ospf_apiclient_msghandle (struct ospf_apiclient *oclient, struct msg *msg)
- {
- /* Call message handler function. */
- switch (msg->hdr.msgtype)
- {
- case MSG_READY_NOTIFY:
- ospf_apiclient_handle_ready (oclient, msg);
- break;
- case MSG_NEW_IF:
- ospf_apiclient_handle_new_if (oclient, msg);
- break;
- case MSG_DEL_IF:
- ospf_apiclient_handle_del_if (oclient, msg);
- break;
- case MSG_ISM_CHANGE:
- ospf_apiclient_handle_ism_change (oclient, msg);
- break;
- case MSG_NSM_CHANGE:
- ospf_apiclient_handle_nsm_change (oclient, msg);
- break;
- case MSG_LSA_UPDATE_NOTIFY:
- ospf_apiclient_handle_lsa_update (oclient, msg);
- break;
- case MSG_LSA_DELETE_NOTIFY:
- ospf_apiclient_handle_lsa_delete (oclient, msg);
- break;
- default:
- fprintf (stderr, "ospf_apiclient_read: Unknown message type: %d\n",
- msg->hdr.msgtype);
- break;
- }
- }
- /* -----------------------------------------------------------
- * Callback handler registration
- * -----------------------------------------------------------
- */
- void
- ospf_apiclient_register_callback (struct ospf_apiclient *oclient,
- void (*ready_notify) (u_char lsa_type,
- u_char opaque_type,
- struct in_addr addr),
- void (*new_if) (struct in_addr ifaddr,
- struct in_addr area_id),
- void (*del_if) (struct in_addr ifaddr),
- void (*ism_change) (struct in_addr ifaddr,
- struct in_addr area_id,
- u_char status),
- void (*nsm_change) (struct in_addr ifaddr,
- struct in_addr nbraddr,
- struct in_addr
- router_id,
- u_char status),
- void (*update_notify) (struct in_addr
- ifaddr,
- struct in_addr
- area_id,
- u_char self_origin,
- struct lsa_header *
- lsa),
- void (*delete_notify) (struct in_addr
- ifaddr,
- struct in_addr
- area_id,
- u_char self_origin,
- struct lsa_header *
- lsa))
- {
- assert (oclient);
- assert (update_notify);
- /* Register callback function */
- oclient->ready_notify = ready_notify;
- oclient->new_if = new_if;
- oclient->del_if = del_if;
- oclient->ism_change = ism_change;
- oclient->nsm_change = nsm_change;
- oclient->update_notify = update_notify;
- oclient->delete_notify = delete_notify;
- }
- /* -----------------------------------------------------------
- * Asynchronous message handling
- * -----------------------------------------------------------
- */
- int
- ospf_apiclient_handle_async (struct ospf_apiclient *oclient)
- {
- struct msg *msg;
- /* Get a message */
- msg = msg_read (oclient->fd_async);
- if (!msg)
- {
- /* Connection broke down */
- return -1;
- }
- /* Handle message */
- ospf_apiclient_msghandle (oclient, msg);
- /* Don't forget to free this message */
- msg_free (msg);
- return 0;
- }
|