/* * Zebra API message creation & consumption. * Portions: * Copyright (C) 1997-1999 Kunihiro Ishiguro * Copyright (C) 2015-2018 Cumulus Networks, Inc. * et al. * * This program 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 of the License, or (at your option) * any later version. * * This program 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 #include "lib/prefix.h" #include "lib/stream.h" #include "lib/memory.h" #include "lib/table.h" #include "lib/network.h" #include "lib/log.h" #include "lib/zclient.h" #include "lib/privs.h" #include "lib/nexthop.h" #include "lib/vrf.h" #include "lib/libfrr.h" #include "lib/lib_errors.h" #include "zebra/zebra_router.h" #include "zebra/rib.h" #include "zebra/zebra_memory.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/zebra_rnh.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/zebra_vxlan.h" #include "zebra/zebra_evpn_mh.h" #include "zebra/rt.h" #include "zebra/zebra_pbr.h" #include "zebra/table_manager.h" #include "zebra/zapi_msg.h" #include "zebra/zebra_errors.h" #include "zebra/zebra_mlag.h" #include "zebra/connected.h" #include "zebra/zebra_opaque.h" #include "zebra/zebra_srte.h" /* Encoding helpers -------------------------------------------------------- */ static void zserv_encode_interface(struct stream *s, struct interface *ifp) { /* Interface information. */ struct zebra_if *zif = ifp->info; 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, zif->link_ifindex); 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; const char *netns_name = zvrf_ns_name(zvrf); data.l.table_id = zvrf->table_id; if (netns_name) strlcpy(data.l.netns_name, basename((char *)netns_name), NS_NAMSIZ); else memset(data.l.netns_name, 0, NS_NAMSIZ); /* Pass the tableid and the netns NAME */ 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)); } static int zserv_encode_nexthop(struct stream *s, struct nexthop *nexthop) { stream_putl(s, nexthop->vrf_id); stream_putc(s, nexthop->type); switch (nexthop->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: stream_put_in_addr(s, &nexthop->gate.ipv4); stream_putl(s, nexthop->ifindex); break; case NEXTHOP_TYPE_IPV6: stream_put(s, &nexthop->gate.ipv6, 16); break; case NEXTHOP_TYPE_IPV6_IFINDEX: stream_put(s, &nexthop->gate.ipv6, 16); stream_putl(s, nexthop->ifindex); break; case NEXTHOP_TYPE_IFINDEX: stream_putl(s, nexthop->ifindex); break; default: /* do nothing */ break; } return 1; } /* * Zebra error addition adds error type. * * * 0 1 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | enum zebra_error_types | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * */ static void zserv_encode_error(struct stream *s, enum zebra_error_types error) { stream_put(s, &error, sizeof(error)); /* Write packet size. */ stream_putw_at(s, 0, stream_get_endp(s)); } /* Send handlers ----------------------------------------------------------- */ /* 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 = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, ZEBRA_INTERFACE_ADD, ifp->vrf_id); zserv_encode_interface(s, ifp); client->ifadd_cnt++; return zserv_send_message(client, s); } /* Interface deletion from zebra daemon. */ int zsend_interface_delete(struct zserv *client, struct interface *ifp) { struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, ZEBRA_INTERFACE_DELETE, ifp->vrf_id); zserv_encode_interface(s, ifp); client->ifdel_cnt++; return zserv_send_message(client, s); } int zsend_vrf_add(struct zserv *client, struct zebra_vrf *zvrf) { struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, ZEBRA_VRF_ADD, zvrf_id(zvrf)); zserv_encode_vrf(s, zvrf); client->vrfadd_cnt++; return zserv_send_message(client, s); } /* VRF deletion from zebra daemon. */ int zsend_vrf_delete(struct zserv *client, struct zebra_vrf *zvrf) { struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, ZEBRA_VRF_DELETE, zvrf_id(zvrf)); zserv_encode_vrf(s, zvrf); client->vrfdel_cnt++; return zserv_send_message(client, s); } int zsend_interface_link_params(struct zserv *client, struct interface *ifp) { struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); if (!ifp->link_params) { stream_free(s); return 0; } zclient_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) { stream_free(s); return 0; } /* Write packet size. */ stream_putw_at(s, 0, stream_get_endp(s)); return zserv_send_message(client, s); } /* 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 [