/* Zebra daemon server routine. * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro * * 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 #include "prefix.h" #include "command.h" #include "if.h" #include "thread.h" #include "stream.h" #include "memory.h" #include "table.h" #include "rib.h" #include "network.h" #include "sockunion.h" #include "log.h" #include "zclient.h" #include "privs.h" #include "zebra/zserv.h" #include "zebra/router-id.h" #include "zebra/redistribute.h" #include "zebra/debug.h" #include "zebra/ipforward.h" /* Event list of zebra. */ enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE }; extern struct zebra_t zebrad; static void zebra_event (enum event event, int sock, struct zserv *client); extern struct zebra_privs_t zserv_privs; /* For logging of zebra meesages. */ static const char *zebra_command_str [] = { "NULL", "ZEBRA_INTERFACE_ADD", "ZEBRA_INTERFACE_DELETE", "ZEBRA_INTERFACE_ADDRESS_ADD", "ZEBRA_INTERFACE_ADDRESS_DELETE", "ZEBRA_INTERFACE_UP", "ZEBRA_INTERFACE_DOWN", "ZEBRA_IPV4_ROUTE_ADD", "ZEBRA_IPV4_ROUTE_DELETE", "ZEBRA_IPV6_ROUTE_ADD", "ZEBRA_IPV6_ROUTE_DELETE", "ZEBRA_REDISTRIBUTE_ADD", "ZEBRA_REDISTRIBUTE_DELETE", "ZEBRA_REDISTRIBUTE_DEFAULT_ADD", "ZEBRA_REDISTRIBUTE_DEFAULT_DELETE", "ZEBRA_IPV4_NEXTHOP_LOOKUP", "ZEBRA_IPV6_NEXTHOP_LOOKUP", "ZEBRA_IPV4_IMPORT_LOOKUP", "ZEBRA_IPV6_IMPORT_LOOKUP", "ZEBRA_ROUTER_ID_ADD", "ZEBRA_ROUTER_ID_DELETE", "ZEBRA_ROUTER_ID_UPDATE" }; struct zebra_message_queue { struct nsm_message_queue *next; struct nsm_message_queue *prev; u_char *buf; u_int16_t length; u_int16_t written; }; struct thread *t_write; struct fifo message_queue; int zebra_server_dequeue (struct thread *t) { int sock; int nbytes; struct zebra_message_queue *queue; sock = THREAD_FD (t); t_write = NULL; queue = (struct zebra_message_queue *) FIFO_HEAD (&message_queue); if (queue) { nbytes = write (sock, queue->buf + queue->written, queue->length - queue->written); if (nbytes <= 0) { if (errno != EAGAIN) return -1; } else if (nbytes != (queue->length - queue->written)) { queue->written += nbytes; } else { FIFO_DEL (queue); XFREE (MTYPE_TMP, queue->buf); XFREE (MTYPE_TMP, queue); } } if (FIFO_TOP (&message_queue)) THREAD_WRITE_ON (zebrad.master, t_write, zebra_server_dequeue, NULL, sock); return 0; } /* Enqueu message. */ void zebra_server_enqueue (int sock, u_char *buf, unsigned long length, unsigned long written) { struct zebra_message_queue *queue; queue = XCALLOC (MTYPE_TMP, sizeof (struct zebra_message_queue)); queue->buf = XMALLOC (MTYPE_TMP, length); memcpy (queue->buf, buf, length); queue->length = length; queue->written = written; FIFO_ADD (&message_queue, queue); THREAD_WRITE_ON (zebrad.master, t_write, zebra_server_dequeue, NULL, sock); } int zebra_server_send_message (int sock, u_char *buf, unsigned long length) { int nbytes; if (FIFO_TOP (&message_queue)) { zebra_server_enqueue (sock, buf, length, 0); return 0; } /* Send message. */ nbytes = write (sock, buf, length); if (nbytes <= 0) { if (errno == EAGAIN) zebra_server_enqueue (sock, buf, length, 0); else return -1; } /* It's clear that nbytes is positive at this point. */ else if ((unsigned) nbytes != length) zebra_server_enqueue (sock, buf, length, nbytes); return 0; } /* Interface is added. Send ZEBRA_INTERFACE_ADD to client. */ /* * This function is called in the following situations: * - in response to a 3-byte ZEBRA_INTERFACE_ADD request * from the client. * - at startup, when zebra figures out the available interfaces * - when an interface is added (where support for * RTM_IFANNOUNCE or AF_NETLINK sockets is available), or when * an interface is marked IFF_UP (i.e., an RTM_IFINFO message is * received) */ int zsend_interface_add (struct zserv *client, struct interface *ifp) { struct stream *s; /* Check this client need interface information. */ if (! client->ifinfo) return -1; s = client->obuf; stream_reset (s); /* Place holder for size. */ stream_putw (s, 0); /* Message type. */ stream_putc (s, ZEBRA_INTERFACE_ADD); /* Interface information. */ stream_put (s, ifp->name, INTERFACE_NAMSIZ); stream_putl (s, ifp->ifindex); stream_putc (s, ifp->status); stream_putl (s, ifp->flags); stream_putl (s, ifp->metric); stream_putl (s, ifp->mtu); stream_putl (s, ifp->mtu6); stream_putl (s, ifp->bandwidth); #ifdef HAVE_SOCKADDR_DL stream_put (s, &ifp->sdl, sizeof (ifp->sdl)); #else stream_putl (s, ifp->hw_addr_len); if (ifp->hw_addr_len) stream_put (s, ifp->hw_addr, ifp->hw_addr_len); #endif /* HAVE_SOCKADDR_DL */ /* Write packet size. */ stream_putw_at (s, 0, stream_get_endp (s)); zebra_server_send_message (client->sock, s->data, stream_get_endp (s)); return 0; } /* Interface deletion from zebra daemon. */ /* * This function is only called when support for * RTM_IFANNOUNCE or AF_NETLINK sockets (RTM_DELLINK message) * is available. It is not called on Solaris. */ #if (defined(RTM_IFANNOUNCE) || defined(HAVE_NETLINK)) int zsend_interface_delete (struct zserv *client, struct interface *ifp) { struct stream *s; /* Check this client need interface information. */ if (! client->ifinfo) return -1; s = client->obuf; stream_reset (s); /* Packet length placeholder. */ stream_putw (s, 0); /* Interface information. */ stream_putc (s, ZEBRA_INTERFACE_DELETE); stream_put (s, ifp->name, INTERFACE_NAMSIZ); stream_putl (s, ifp->ifindex); stream_putc (s, ifp->status); stream_putl (s, ifp->flags); stream_putl (s, ifp->metric); stream_putl (s, ifp->mtu); stream_putl (s, ifp->mtu6); stream_putl (s, ifp->bandwidth); /* Write packet length. */ stream_putw_at (s, 0, stream_get_endp (s)); zebra_server_send_message (client->sock, s->data, stream_get_endp (s)); return 0; } #endif /* (defined(RTM_IFANNOUNCE) || defined(HAVE_LINUX_RTNETLINK_H)) */ /* Interface address is added/deleted. Send ZEBRA_INTERFACE_ADDRESS_ADD or * ZEBRA_INTERFACE_ADDRESS_DELETE to the client. * * A ZEBRA_INTERFACE_ADDRESS_ADD is sent in the following situations: * - in response to a 3-byte ZEBRA_INTERFACE_ADD request * from the client, after the ZEBRA_INTERFACE_ADD has been * sent from zebra to the client * - redistribute new address info to all clients in the following situations * - at startup, when zebra figures out the available interfaces * - when an interface is added (where support for * RTM_IFANNOUNCE or AF_NETLINK sockets is available), or when * an interface is marked IFF_UP (i.e., an RTM_IFINFO message is * received) * - for the vty commands "ip address A.B.C.D/M [|