/* 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 this program; see the file COPYING; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "prefix.h" #include "command.h" #include "if.h" #include "thread.h" #include "stream.h" #include "memory.h" #include "zebra_memory.h" #include "table.h" #include "rib.h" #include "network.h" #include "sockunion.h" #include "log.h" #include "zclient.h" #include "privs.h" #include "network.h" #include "buffer.h" #include "nexthop.h" #include "vrf.h" #include "zebra/zserv.h" #include "zebra/zebra_ns.h" #include "zebra/zebra_vrf.h" #include "zebra/router-id.h" #include "zebra/redistribute.h" #include "zebra/debug.h" #include "zebra/ipforward.h" #include "zebra/zebra_rnh.h" #include "zebra/rt_netlink.h" #include "zebra/interface.h" #include "zebra/zebra_ptm.h" #include "zebra/rtadv.h" #include "zebra/zebra_mpls.h" #include "zebra/zebra_mroute.h" #include "zebra/label_manager.h" #include "zebra/zebra_vxlan.h" #include "zebra/rt.h" /* Event list of zebra. */ enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE }; static void zebra_event(enum event event, int sock, struct zserv *client); extern struct zebra_privs_t zserv_privs; static void zebra_client_close(struct zserv *client); static int zserv_delayed_close(struct thread *thread) { struct zserv *client = THREAD_ARG(thread); client->t_suicide = NULL; zebra_client_close(client); return 0; } static int zserv_flush_data(struct thread *thread) { struct zserv *client = THREAD_ARG(thread); client->t_write = NULL; if (client->t_suicide) { zebra_client_close(client); return -1; } switch (buffer_flush_available(client->wb, client->sock)) { case BUFFER_ERROR: zlog_warn( "%s: buffer_flush_available failed on zserv client fd %d, " "closing", __func__, client->sock); zebra_client_close(client); client = NULL; break; case BUFFER_PENDING: client->t_write = NULL; thread_add_write(zebrad.master, zserv_flush_data, client, client->sock, &client->t_write); break; case BUFFER_EMPTY: break; } if (client) client->last_write_time = monotime(NULL); return 0; } int zebra_server_send_message(struct zserv *client) { if (client->t_suicide) return -1; if (client->is_synchronous) return 0; stream_set_getp(client->obuf, 0); client->last_write_cmd = stream_getw_from(client->obuf, 6); switch (buffer_write(client->wb, client->sock, STREAM_DATA(client->obuf), stream_get_endp(client->obuf))) { case BUFFER_ERROR: zlog_warn( "%s: buffer_write failed to zserv client fd %d, closing", __func__, client->sock); /* Schedule a delayed close since many of the functions that call this one do not check the return code. They do not allow for the possibility that an I/O error may have caused the client to be deleted. */ client->t_suicide = NULL; thread_add_event(zebrad.master, zserv_delayed_close, client, 0, &client->t_suicide); return -1; case BUFFER_EMPTY: THREAD_OFF(client->t_write); break; case BUFFER_PENDING: thread_add_write(zebrad.master, zserv_flush_data, client, client->sock, &client->t_write); break; } client->last_write_time = monotime(NULL); return 0; } void zserv_create_header(struct stream *s, uint16_t cmd, vrf_id_t vrf_id) { /* length placeholder, caller can update */ stream_putw(s, ZEBRA_HEADER_SIZE); stream_putc(s, ZEBRA_HEADER_MARKER); stream_putc(s, ZSERV_VERSION); stream_putw(s, vrf_id); stream_putw(s, cmd); } static void zserv_encode_interface(struct stream *s, struct interface *ifp) { /* Interface information. */ stream_put(s, ifp->name, INTERFACE_NAMSIZ); stream_putl(s, ifp->ifindex); stream_putc(s, ifp->status); stream_putq(s, ifp->flags); stream_putc(s, ifp->ptm_enable); stream_putc(s, ifp->ptm_status); stream_putl(s, ifp->metric); stream_putl(s, ifp->speed); stream_putl(s, ifp->mtu); stream_putl(s, ifp->mtu6); stream_putl(s, ifp->bandwidth); stream_putl(s, ifp->ll_type); stream_putl(s, ifp->hw_addr_len); if (ifp->hw_addr_len) stream_put(s, ifp->hw_addr, ifp->hw_addr_len); /* Then, Traffic Engineering parameters if any */ if (HAS_LINK_PARAMS(ifp) && IS_LINK_PARAMS_SET(ifp->link_params)) { stream_putc(s, 1); zebra_interface_link_params_write(s, ifp); } else stream_putc(s, 0); /* Write packet size. */ stream_putw_at(s, 0, stream_get_endp(s)); } static void zserv_encode_vrf(struct stream *s, struct zebra_vrf *zvrf) { struct vrf_data data; data.l.table_id = zvrf->table_id; /* Pass the tableid */ stream_put(s, &data, sizeof(struct vrf_data)); /* Interface information. */ stream_put(s, zvrf_name(zvrf), VRF_NAMSIZ); /* Write packet size. */ stream_putw_at(s, 0, stream_get_endp(s)); } /* 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; s = client->obuf; stream_reset(s); zserv_create_header(s, ZEBRA_INTERFACE_ADD, ifp->vrf_id); zserv_encode_interface(s, ifp); client->ifadd_cnt++; return zebra_server_send_message(client); } /* Interface deletion from zebra daemon. */ int zsend_interface_delete(struct zserv *client, struct interface *ifp) { struct stream *s; s = client->obuf; stream_reset(s); zserv_create_header(s, ZEBRA_INTERFACE_DELETE, ifp->vrf_id); zserv_encode_interface(s, ifp); client->ifdel_cnt++; return zebra_server_send_message(client); } int zsend_vrf_add(struct zserv *client, struct zebra_vrf *zvrf) { struct stream *s; s = client->obuf; stream_reset(s); zserv_create_header(s, ZEBRA_VRF_ADD, zvrf_id(zvrf)); zserv_encode_vrf(s, zvrf); client->vrfadd_cnt++; return zebra_server_send_message(client); } /* VRF deletion from zebra daemon. */ int zsend_vrf_delete(struct zserv *client, struct zebra_vrf *zvrf) { struct stream *s; s = client->obuf; stream_reset(s); zserv_create_header(s, ZEBRA_VRF_DELETE, zvrf_id(zvrf)); zserv_encode_vrf(s, zvrf); client->vrfdel_cnt++; return zebra_server_send_message(client); } int zsend_interface_link_params(struct zserv *client, struct interface *ifp) { struct stream *s; /* Check this client need interface information. */ if (!client->ifinfo) return 0; if (!ifp->link_params) return 0; s = client->obuf; stream_reset(s); zserv_create_header(s, ZEBRA_INTERFACE_LINK_PARAMS, ifp->vrf_id); /* Add Interface Index */ stream_putl(s, ifp->ifindex); /* Then TE Link Parameters */ if (zebra_interface_link_params_write(s, ifp) == 0) return 0; /* Write packet size. */ stream_putw_at(s, 0, stream_get_endp(s)); return zebra_server_send_message(client); } /* 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 [|