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; }
int zclient_send_linkmetrics_subscribe (struct zclient *zclient, uint16_t cmd) { struct stream *s; if (zclient->sock < 0) { zlog_err ("%s: not connected to zebra", __func__); return -1; } s = zclient->obuf; stream_reset (s); zclient_create_header (s, cmd); stream_putw_at (s, 0, stream_get_endp (s)); if (zclient_send_message (zclient)) { zlog_err ("%s: zclient_send_message() failed", __func__); return -1; } return 0; }
static int zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p) { struct stream *s; struct rib *rib; unsigned long nump; u_char num; struct nexthop *nexthop; /* Lookup nexthop. */ rib = rib_lookup_ipv4 (p); /* Get output stream. */ s = client->obuf; stream_reset (s); /* Fill in result. */ stream_putw (s, 0); stream_putc (s, ZEBRA_IPV4_IMPORT_LOOKUP); stream_put_in_addr (s, &p->prefix); if (rib) { stream_putl (s, rib->metric); num = 0; nump = s->putp; stream_putc (s, 0); for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) { stream_putc (s, nexthop->type); switch (nexthop->type) { case ZEBRA_NEXTHOP_IPV4: stream_put_in_addr (s, &nexthop->gate.ipv4); break; case ZEBRA_NEXTHOP_IFINDEX: case ZEBRA_NEXTHOP_IFNAME: stream_putl (s, nexthop->ifindex); break; default: /* do nothing */ break; } num++; } stream_putc_at (s, nump, num); } else { stream_putl (s, 0); stream_putc (s, 0); } stream_putw_at (s, 0, stream_get_endp (s)); zebra_server_send_message (client->sock, s->data, stream_get_endp (s)); return 0; }
/* * "xdr_encode"-like interface that allows daemon (client) to send * a message to zebra server for a route that needs to be * added/deleted to the kernel. Info about the route is specified * by the caller in a struct zapi_ipv4. zapi_ipv4_read() then writes * the info down the zclient socket using the stream_* functions. * * The corresponding read ("xdr_decode") function on the server * side is zread_ipv4_add()/zread_ipv4_delete(). * * 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Length (2) | Command | Route Type | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | ZEBRA Flags | Message Flags | Prefix length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Destination IPv4 Prefix for route | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Nexthop count | * +-+-+-+-+-+-+-+-+ * * * A number of IPv4 nexthop(s) or nexthop interface index(es) are then * described, as per the Nexthop count. Each nexthop described as: * * +-+-+-+-+-+-+-+-+ * | Nexthop Type | Set to one of ZEBRA_NEXTHOP_* * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | IPv4 Nexthop address or Interface Index number | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * Alternatively, if the flags field has ZEBRA_FLAG_BLACKHOLE or * ZEBRA_FLAG_REJECT is set then Nexthop count is set to 1, then _no_ * nexthop information is provided, and the message describes a prefix * to blackhole or reject route. * * If ZAPI_MESSAGE_DISTANCE is set, the distance value is written as a 1 * byte value. * * If ZAPI_MESSAGE_METRIC is set, the metric value is written as an 8 * byte value. * * XXX: No attention paid to alignment. */ int zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p, struct zapi_ipv4 *api) { int i; int psize; struct stream *s; /* Reset stream. */ s = zclient->obuf; stream_reset (s); zclient_create_header (s, cmd); /* Put type and nexthop. */ stream_putc (s, api->type); stream_putc (s, api->flags); stream_putc (s, api->message); stream_putw (s, api->safi); /* Put prefix information. */ psize = PSIZE (p->prefixlen); stream_putc (s, p->prefixlen); stream_write (s, (u_char *) & p->prefix, psize); /* Nexthop, ifindex, distance and metric information. */ if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP)) { if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE)) { stream_putc (s, 1); stream_putc (s, ZEBRA_NEXTHOP_BLACKHOLE); /* XXX assert(api->nexthop_num == 0); */ /* XXX assert(api->ifindex_num == 0); */ } else stream_putc (s, api->nexthop_num + api->ifindex_num); for (i = 0; i < api->nexthop_num; i++) { stream_putc (s, ZEBRA_NEXTHOP_IPV4); stream_put_in_addr (s, api->nexthop[i]); } for (i = 0; i < api->ifindex_num; i++) { stream_putc (s, ZEBRA_NEXTHOP_IFINDEX); stream_putl (s, api->ifindex[i]); } } if (CHECK_FLAG (api->message, ZAPI_MESSAGE_DISTANCE)) stream_putc (s, api->distance); if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC)) stream_putl (s, api->metric); /* Put length at the first point of the stream. */ stream_putw_at (s, 0, stream_get_endp (s)); return zclient_send_message(zclient); }
/* * The cmd passed to zsend_interface_update may be ZEBRA_INTERFACE_UP or * ZEBRA_INTERFACE_DOWN. * * The ZEBRA_INTERFACE_UP message is sent from the zebra server to * the clients in one of 2 situations: * - an if_up is detected e.g., as a result of an RTM_IFINFO message * - a vty command modifying the bandwidth of an interface is received. * The ZEBRA_INTERFACE_DOWN message is sent when an if_down is detected. */ int zsend_interface_update (int cmd, struct zserv *client, struct interface_FOO *ifp) { struct stream *s; /* Check this client need interface information. */ if (! client->ifinfo) return 0; s = client->obuf; stream_reset (s); zserv_create_header (s, cmd); /* 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_putl (s, ifp->metric); stream_putl (s, ifp->mtu); stream_putl (s, ifp->mtu6); stream_putl (s, ifp->bandwidth); /* Write packet size. */ stream_putw_at (s, 0, stream_get_endp (s)); return zebra_server_send_message(client); }
/* Router-id is updated. Send ZEBRA_ROUTER_ID_ADD to client. */ int zsend_router_id_update (struct zserv *client, struct prefix *p) { struct stream *s; int blen; /* Check this client need interface information. */ if (!client->ridinfo) return 0; s = client->obuf; stream_reset (s); /* Message type. */ zserv_create_header (s, ZEBRA_ROUTER_ID_UPDATE); /* Prefix information. */ stream_putc (s, p->family); blen = prefix_blen (p); stream_put (s, &p->u.prefix, blen); stream_putc (s, p->prefixlen); /* Write packet size. */ stream_putw_at (s, 0, stream_get_endp (s)); return zebra_server_send_message(client); }
struct bgp_nexthop_cache * zlookup_query_ipv6 (struct in6_addr *addr) { int ret; struct stream *s; /* Check socket. */ if (zlookup->sock < 0) return NULL; s = zlookup->obuf; stream_reset (s); zclient_create_header (s, ZEBRA_IPV6_NEXTHOP_LOOKUP); stream_put (s, addr, 16); stream_putw_at (s, 0, stream_get_endp (s)); ret = writen (zlookup->sock, s->data, stream_get_endp (s)); if (ret < 0) { zlog_err ("can't write to zlookup->sock"); close (zlookup->sock); zlookup->sock = -1; return NULL; } if (ret == 0) { zlog_err ("zlookup->sock connection closed"); close (zlookup->sock); zlookup->sock = -1; return NULL; } return zlookup_read_ipv6 (); }
/* Router-id is updated. Send ZEBRA_ROUTER_ID_ADD to client. */ int zsend_router_id_update (struct zserv *client, struct prefix *p) { struct stream *s; int blen; /* Check this client need interface information. */ if (!client->ridinfo) return -1; s = client->obuf; stream_reset (s); /* Place holder for size. */ stream_putw (s, 0); /* Message type. */ stream_putc (s, ZEBRA_ROUTER_ID_UPDATE); /* Prefix information. */ stream_putc (s, p->family); blen = prefix_blen (p); stream_put (s, &p->u.prefix, blen); stream_putc (s, p->prefixlen); /* Write packet size. */ stream_putw_at (s, 0, stream_get_endp (s)); return writen (client->sock, s->data, stream_get_endp (s)); }
/* * The cmd passed to zsend_interface_update may be ZEBRA_INTERFACE_UP or * ZEBRA_INTERFACE_DOWN. * * The ZEBRA_INTERFACE_UP message is sent from the zebra server to * the clients in one of 2 situations: * - an if_up is detected e.g., as a result of an RTM_IFINFO message * - a vty command modifying the bandwidth of an interface is received. * The ZEBRA_INTERFACE_DOWN message is sent when an if_down is detected. */ int zsend_interface_update (int cmd, 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); /* Zebra command. */ stream_putc (s, cmd); /* 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); /* 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; }
int zapi_ipv6_route (u_char cmd, struct_zclient *zclient, struct prefix_ipv6 *p, struct zapi_ipv6 *api) { int i; int psize; struct stream *s; /* Reset stream. */ s = zclient->obuf; stream_reset (s); /* Length place holder. */ stream_putw (s, 0); /* Put command, type and nexthop. */ stream_putc (s, cmd); stream_putc (s, api->type); stream_putc (s, api->flags); stream_putc (s, api->message); /* Put prefix information. */ psize = PSIZE (p->prefixlen); stream_putc (s, p->prefixlen); stream_write (s, (u_char *)&p->prefix, psize); /* Nexthop, ifindex, distance and metric information. */ if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP)) { stream_putc (s, api->nexthop_num + api->ifindex_num); for (i = 0; i < api->nexthop_num; i++) { stream_putc (s, ZEBRA_NEXTHOP_IPV6); stream_write (s, (u_char *)api->nexthop[i], 16); } for (i = 0; i < api->ifindex_num; i++) { stream_putc (s, ZEBRA_NEXTHOP_IFINDEX); stream_putl (s, api->ifindex[i]); } } if (CHECK_FLAG (api->message, ZAPI_MESSAGE_DISTANCE)) stream_putc (s, api->distance); if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC)) stream_putl (s, api->metric); /* Put length at the first point of the stream. */ stream_putw_at (s, 0, stream_get_endp (s)); return writen (zclient->sock, s->data, stream_get_endp (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 [<secondary>|<label LINE>]" * and "no bandwidth <1-10000000>", "ipv6 address X:X::X:X/M" * - when an RTM_NEWADDR message is received from the kernel, * * The call tree that triggers ZEBRA_INTERFACE_ADDRESS_DELETE: * * zsend_interface_address(DELETE) * ^ * | * zebra_interface_address_delete_update * ^ ^ ^ * | | if_delete_update (not called on * | | Solaris) * ip_address_uninstall connected_delete_ipv4 * [ipv6_addresss_uninstall] [connected_delete_ipv6] * ^ ^ * | | * | RTM_NEWADDR on routing/netlink socket * | * vty commands: * "no ip address A.B.C.D/M [label LINE]" * "no ip address A.B.C.D/M secondary" * ["no ipv6 address X:X::X:X/M"] * */ int zsend_interface_address (int cmd, struct zserv *client, struct interface *ifp, struct connected *ifc) { int blen; struct stream *s; struct prefix *p; /* 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); stream_putc (s, cmd); stream_putl (s, ifp->ifindex); /* Interface address flag. */ stream_putc (s, ifc->flags); /* Prefix information. */ p = ifc->address; stream_putc (s, p->family); blen = prefix_blen (p); stream_put (s, &p->u.prefix, blen); /* * XXX gnu version does not send prefixlen for ZEBRA_INTERFACE_ADDRESS_DELETE * but zebra_interface_address_delete_read() in the gnu version * expects to find it */ stream_putc (s, p->prefixlen); /* Destination. */ p = ifc->destination; if (p) stream_put (s, &p->u.prefix, blen); else stream_put (s, NULL, blen); /* 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; }
s32 bgp_fec_announce_6pe(struct zclient *zc, struct prefix *p, struct bgp_info *info, struct bgp *bgp) { u32 flags = 0; struct stream * s = zc->obuf ; struct peer * peer = info->peer ; u32 gateway ,label ; struct rtm_fec_info_key key; struct in6_addr *nexthop = NULL; if( !info || !info->attr || !info->attr->extra ) return -1 ; if (info->attr->extra->mp_nexthop_len == 16) { nexthop = &info->attr->extra->mp_nexthop_global; } /* If both global and link-local address present. */ else if (info->attr->extra->mp_nexthop_len == 32) { /* Workaround for Cisco's nexthop bug. */ if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->extra->mp_nexthop_global) && peer->su_remote->sa.sa_family == AF_INET6) nexthop = &peer->su_remote->sin6.sin6_addr; else nexthop = &info->attr->extra->mp_nexthop_local; } if(NULL == nexthop || !IN6_IS_ADDR_V4MAPPED(nexthop)) { return -1; } memcpy (&gateway , ((s8 *)nexthop) + 12, 4); label = decode_label ( bgp_info_extra_get(info)->tag) ; SET_FLAG(flags, ZAPI_FEC_GATEWAY); stream_reset(s); zclient_create_header(s,ZEBRA_MPLS_FEC6_INFO_ADD); stream_put_prefix(s,p); stream_putl(s, flags); stream_putl(s, ZEBRA_FEC_TYPE_6PE); if( peer ) stream_putl(s,peer->nexthop.v4.s_addr); else stream_putl(s,0); // lsr_id = 0 stream_putl(s,label); stream_putl(s,gateway); stream_putw_at (s, 0, stream_get_endp (s)); key.peer_addr = gateway; return rtm_fec_send(ZEBRA_MPLS_FEC6_INFO_ADD, zc, p, s, &key) ; }
/* * send a ZEBRA_REDISTRIBUTE_ADD or ZEBRA_REDISTRIBUTE_DELETE * for the route type (ZEBRA_ROUTE_KERNEL etc.). The zebra server will * then set/unset redist[type] in the client handle (a struct zserv) for the * sending client */ int zebra_redistribute_send (int command, struct zclient *zclient, int type) { struct stream *s; s = zclient->obuf; stream_reset(s); zclient_create_header (s, command); stream_putc (s, type); stream_putw_at (s, 0, stream_get_endp (s)); return zclient_send_message(zclient); }
static int zclient_lookup_nexthop_once(struct zclient *zlookup, struct pim_zlookup_nexthop nexthop_tab[], const int tab_size, struct in_addr addr) { struct stream *s; int ret; if (PIM_DEBUG_ZEBRA) { char addr_str[100]; pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); zlog_debug("%s: addr=%s", __PRETTY_FUNCTION__, addr_str); } /* Check socket. */ if (zlookup->sock < 0) { zlog_err("%s %s: zclient lookup socket is not connected", __FILE__, __PRETTY_FUNCTION__); zclient_lookup_failed(zlookup); return -1; } s = zlookup->obuf; stream_reset(s); zclient_create_header(s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB); stream_put_in_addr(s, &addr); stream_putw_at(s, 0, stream_get_endp(s)); ret = writen(zlookup->sock, s->data, stream_get_endp(s)); if (ret < 0) { zlog_err("%s %s: writen() failure writing to zclient lookup socket", __FILE__, __PRETTY_FUNCTION__); zclient_lookup_failed(zlookup); return -2; } if (ret == 0) { zlog_err("%s %s: connection closed on zclient lookup socket", __FILE__, __PRETTY_FUNCTION__); zclient_lookup_failed(zlookup); return -3; } return zclient_read_nexthop(zlookup, nexthop_tab, tab_size, addr); }
static int zebra_hello_send (struct zclient *zclient) { struct stream *s; if (zclient->redist_default) { s = zclient->obuf; stream_reset (s); zclient_create_header (s, ZEBRA_HELLO); stream_putc (s, zclient->redist_default); stream_putw_at (s, 0, stream_get_endp (s)); return zclient_send_message(zclient); } return 0; }
static int zebra_hello_send (struct zclient *zclient) { struct stream *s; if (zclient->redist_default) { s = zclient->obuf; stream_reset (s); /* The VRF ID in the HELLO message is always 0. */ zclient_create_header (s, ZEBRA_HELLO, VRF_DEFAULT); stream_putc (s, zclient->redist_default); stream_putw_at (s, 0, stream_get_endp (s)); return zclient_send_message(zclient); } return 0; }
/* * 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; }
s32 bgp_fec_announce_6vpe(bgp_litevrf_config_t *litevrf, struct prefix *p, struct bgp_info *info) { u32 flags = 0; struct stream * s = zclient->obuf ; struct peer * peer = info->peer ; u32 gateway ,label ; struct rtm_fec_info_key key; struct in6_addr *nexthop = NULL; if( !info || !info->attr || !info->attr->extra ) return -1 ; nexthop = &info->attr->extra->mp_nexthop_global; if(NULL == nexthop || !IN6_IS_ADDR_V4MAPPED(nexthop)) { return -1; } memcpy (&gateway , ((s8 *)nexthop) + 12, 4); label = decode_label ( bgp_info_extra_get(info)->tag) ; SET_FLAG(flags, ZAPI_FEC_GATEWAY|ZAPI_FEC_LITEVRF); stream_reset(s); zclient_create_header(s,ZEBRA_MPLS_FEC6_INFO_ADD); stream_put_prefix(s,p); stream_putl(s, flags); stream_putl(s,litevrf->id); stream_putl(s, ZEBRA_FEC_TYPE_6VPE); if( peer ) stream_putl(s,peer->nexthop.v4.s_addr); else stream_putl(s,0); // lsr_id = 0 stream_putl(s,label); stream_putl(s,gateway); stream_putw_at (s, 0, stream_get_endp (s)); key.peer_addr = gateway; return rtm_fec_send(ZEBRA_MPLS_FEC6_INFO_ADD, zclient, p, s, &key) ; }
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_putl (s, ifp->metric); stream_putl (s, ifp->mtu); stream_putl (s, ifp->mtu6); stream_putl (s, ifp->bandwidth); #ifdef HAVE_STRUCT_SOCKADDR_DL stream_put (s, &ifp->sdl, sizeof (ifp->sdl_storage)); #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_STRUCT_SOCKADDR_DL */ /* Write packet size. */ stream_putw_at (s, 0, stream_get_endp (s)); }
void zebra_ipmr_route_stats(ZAPI_HANDLER_ARGS) { struct mcast_route_data mroute; struct stream *s; int suc = -1; memset(&mroute, 0, sizeof(mroute)); STREAM_GET(&mroute.sg.src, msg, 4); STREAM_GET(&mroute.sg.grp, msg, 4); STREAM_GETL(msg, mroute.ifindex); if (IS_ZEBRA_DEBUG_KERNEL) { char sbuf[40]; char gbuf[40]; strlcpy(sbuf, inet_ntoa(mroute.sg.src), sizeof(sbuf)); strlcpy(gbuf, inet_ntoa(mroute.sg.grp), sizeof(gbuf)); zlog_debug("Asking for (%s,%s) mroute information", sbuf, gbuf); } suc = kernel_get_ipmr_sg_stats(zvrf, &mroute); stream_failure: s = stream_new(ZEBRA_MAX_PACKET_SIZ); stream_reset(s); zclient_create_header(s, ZEBRA_IPMR_ROUTE_STATS, zvrf_id(zvrf)); stream_put_in_addr(s, &mroute.sg.src); stream_put_in_addr(s, &mroute.sg.grp); stream_put(s, &mroute.lastused, sizeof(mroute.lastused)); stream_putl(s, suc); stream_putw_at(s, 0, stream_get_endp(s)); zserv_send_message(client, s); }
static int bgp_import_check (struct prefix *p, u_int32_t *igpmetric, struct in_addr *igpnexthop) { struct stream *s; int ret; u_int16_t length, command; u_char version, marker; int nbytes; struct in_addr addr; struct in_addr nexthop; u_int32_t metric = 0; u_char nexthop_num; u_char nexthop_type; /* If lookup connection is not available return valid. */ if (zlookup->sock < 0) { if (igpmetric) *igpmetric = 0; return 1; } /* Send query to the lookup connection */ s = zlookup->obuf; stream_reset (s); zclient_create_header (s, ZEBRA_IPV4_IMPORT_LOOKUP); stream_putc (s, p->prefixlen); stream_put_in_addr (s, &p->u.prefix4); stream_putw_at (s, 0, stream_get_endp (s)); /* Write the packet. */ ret = writen (zlookup->sock, s->data, stream_get_endp (s)); if (ret < 0) { zlog_err ("can't write to zlookup->sock"); close (zlookup->sock); zlookup->sock = -1; return 1; } if (ret == 0) { zlog_err ("zlookup->sock connection closed"); close (zlookup->sock); zlookup->sock = -1; return 1; } /* Get result. */ stream_reset (s); /* Fetch length. */ nbytes = stream_read (s, zlookup->sock, 2); length = stream_getw (s); /* Fetch whole data. */ nbytes = stream_read (s, zlookup->sock, length - 2); marker = stream_getc (s); version = stream_getc (s); if (version != ZSERV_VERSION || marker != ZEBRA_HEADER_MARKER) { zlog_err("%s: socket %d version mismatch, marker %d, version %d", __func__, zlookup->sock, marker, version); return 0; } command = stream_getw (s); addr.s_addr = stream_get_ipv4 (s); metric = stream_getl (s); nexthop_num = stream_getc (s); /* Set IGP metric value. */ if (igpmetric) *igpmetric = metric; /* If there is nexthop then this is active route. */ if (nexthop_num) { nexthop.s_addr = 0; nexthop_type = stream_getc (s); if (nexthop_type == ZEBRA_NEXTHOP_IPV4) { nexthop.s_addr = stream_get_ipv4 (s); if (igpnexthop) *igpnexthop = nexthop; } else *igpnexthop = nexthop; return 1; } else return 0; }
/* Runs under child process. */ static unsigned int bgp_dump_routes_func (int afi, int first_run, unsigned int seq) { struct stream *obuf; struct bgp_info *info; struct bgp_node *rn; struct bgp *bgp; struct bgp_table *table; bgp = bgp_get_default (); if (!bgp) return seq; if (bgp_dump_routes.fp == NULL) return seq; /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers, so this should only be done on the first call to bgp_dump_routes_func. ( this function will be called once for ipv4 and once for ipv6 ) */ if(first_run) bgp_dump_routes_index_table(bgp); obuf = bgp_dump_obuf; stream_reset(obuf); /* Walk down each BGP route. */ table = bgp->rib[afi][SAFI_UNICAST]; for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) { if(!rn->info) continue; stream_reset(obuf); /* MRT header */ if (afi == AFI_IP) bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV4_UNICAST, BGP_DUMP_ROUTES); else if (afi == AFI_IP6) bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV6_UNICAST, BGP_DUMP_ROUTES); /* Sequence number */ stream_putl(obuf, seq); /* Prefix length */ stream_putc (obuf, rn->p.prefixlen); /* Prefix */ if (afi == AFI_IP) { /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */ stream_write(obuf, (u_char *)&rn->p.u.prefix4, (rn->p.prefixlen+7)/8); } else if (afi == AFI_IP6) { /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */ stream_write (obuf, (u_char *)&rn->p.u.prefix6, (rn->p.prefixlen+7)/8); } /* Save where we are now, so we can overwride the entry count later */ int sizep = stream_get_endp(obuf); /* Entry count */ uint16_t entry_count = 0; /* Entry count, note that this is overwritten later */ stream_putw(obuf, 0); for (info = rn->info; info; info = info->next) { entry_count++; /* Peer index */ stream_putw(obuf, info->peer->table_dump_index); /* Originated */ #ifdef HAVE_CLOCK_MONOTONIC stream_putl (obuf, time(NULL) - (bgp_clock() - info->uptime)); #else stream_putl (obuf, info->uptime); #endif /* HAVE_CLOCK_MONOTONIC */ /* Dump attribute. */ /* Skip prefix & AFI/SAFI for MP_NLRI */ bgp_dump_routes_attr (obuf, info->attr, &rn->p); } /* Overwrite the entry count, now that we know the right number */ stream_putw_at (obuf, sizep, entry_count); seq++; bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2); fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp); } fflush (bgp_dump_routes.fp); return seq; }
static int zsend_ipv6_nexthop_lookup (struct zserv *client, struct in6_addr *addr) { struct stream *s; struct rib *rib; unsigned long nump; u_char num; struct nexthop *nexthop; /* Lookup nexthop. */ rib = rib_match_ipv6 (addr); /* Get output stream. */ s = client->obuf; stream_reset (s); /* Fill in result. */ zserv_create_header (s, ZEBRA_IPV6_NEXTHOP_LOOKUP); stream_put (s, &addr, 16); if (rib) { stream_putl (s, rib->metric); num = 0; nump = stream_get_endp(s); stream_putc (s, 0); for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) { stream_putc (s, nexthop->type); switch (nexthop->type) { case ZEBRA_NEXTHOP_IPV6: stream_put (s, &nexthop->gate.ipv6, 16); break; case ZEBRA_NEXTHOP_IPV6_IFINDEX: case ZEBRA_NEXTHOP_IPV6_IFNAME: stream_put (s, &nexthop->gate.ipv6, 16); stream_putl (s, nexthop->ifindex); break; case ZEBRA_NEXTHOP_IFINDEX: case ZEBRA_NEXTHOP_IFNAME: stream_putl (s, nexthop->ifindex); break; default: /* do nothing */ break; } num++; } stream_putc_at (s, nump, num); } else { stream_putl (s, 0); stream_putc (s, 0); } stream_putw_at (s, 0, stream_get_endp (s)); return zebra_server_send_message(client); }
void ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or) { u_char message; u_char distance; u_char flags; int psize; struct stream *s; struct ospf_path *path; struct listnode *node; if (zclient->redist[ZEBRA_ROUTE_OSPF]) { message = 0; flags = 0; /* OSPF pass nexthop and metric */ SET_FLAG (message, ZAPI_MESSAGE_NEXTHOP); SET_FLAG (message, ZAPI_MESSAGE_METRIC); /* Distance value. */ distance = ospf_distance_apply (p, or); if (distance) SET_FLAG (message, ZAPI_MESSAGE_DISTANCE); /* Make packet. */ s = zclient->obuf; stream_reset (s); /* Put command, type, flags, message. */ zclient_create_header (s, ZEBRA_IPV4_ROUTE_ADD); stream_putc (s, ZEBRA_ROUTE_OSPF); stream_putc (s, flags); stream_putc (s, message); stream_putw (s, SAFI_UNICAST); /* Put prefix information. */ psize = PSIZE (p->prefixlen); stream_putc (s, p->prefixlen); stream_write (s, (u_char *) & p->prefix, psize); /* Nexthop count. */ stream_putc (s, or->paths->count); /* Nexthop, ifindex, distance and metric information. */ for (ALL_LIST_ELEMENTS_RO (or->paths, node, path)) { if (path->nexthop.s_addr != INADDR_ANY && path->ifindex != 0) { stream_putc (s, ZEBRA_NEXTHOP_IPV4_IFINDEX); stream_put_in_addr (s, &path->nexthop); stream_putl (s, path->ifindex); } else if (path->nexthop.s_addr != INADDR_ANY) { stream_putc (s, ZEBRA_NEXTHOP_IPV4); stream_put_in_addr (s, &path->nexthop); } else { stream_putc (s, ZEBRA_NEXTHOP_IFINDEX); if (path->ifindex) stream_putl (s, path->ifindex); else stream_putl (s, 0); } if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) { char buf[2][INET_ADDRSTRLEN]; zlog_debug("Zebra: Route add %s/%d nexthop %s", inet_ntop(AF_INET, &p->prefix, buf[0], sizeof(buf[0])), p->prefixlen, inet_ntop(AF_INET, &path->nexthop, buf[1], sizeof(buf[1]))); } } if (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE)) stream_putc (s, distance); if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC)) { if (or->path_type == OSPF_PATH_TYPE1_EXTERNAL) stream_putl (s, or->cost + or->u.ext.type2_cost); else if (or->path_type == OSPF_PATH_TYPE2_EXTERNAL) stream_putl (s, or->u.ext.type2_cost); else stream_putl (s, or->cost); } stream_putw_at (s, 0, stream_get_endp (s)); zclient_send_message(zclient); }
void isis_zebra_route_add_ipv4 (struct prefix *prefix, struct isis_route_info *route_info) { u_char message, flags; int psize; struct stream *stream; struct isis_nexthop *nexthop; struct listnode *node; if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC)) return; if (zclient->redist[ZEBRA_ROUTE_ISIS]) { message = 0; flags = 0; SET_FLAG (message, ZAPI_MESSAGE_NEXTHOP); SET_FLAG (message, ZAPI_MESSAGE_METRIC); #if 0 SET_FLAG (message, ZAPI_MESSAGE_DISTANCE); #endif stream = zclient->obuf; stream_reset (stream); /* Length place holder. */ stream_putw (stream, 0); /* command */ stream_putc (stream, ZEBRA_IPV4_ROUTE_ADD); /* type */ stream_putc (stream, ZEBRA_ROUTE_ISIS); /* flags */ stream_putc (stream, flags); /* message */ stream_putc (stream, message); /* prefix information */ psize = PSIZE (prefix->prefixlen); stream_putc (stream, prefix->prefixlen); stream_write (stream, (u_char *) & prefix->u.prefix4, psize); stream_putc (stream, listcount (route_info->nexthops)); /* Nexthop, ifindex, distance and metric information */ for (node = listhead (route_info->nexthops); node; nextnode (node)) { nexthop = getdata (node); /* FIXME: can it be ? */ if (nexthop->ip.s_addr != INADDR_ANY) { stream_putc (stream, ZEBRA_NEXTHOP_IPV4); stream_put_in_addr (stream, &nexthop->ip); } else { stream_putc (stream, ZEBRA_NEXTHOP_IFINDEX); stream_putl (stream, nexthop->ifindex); } } #if 0 if (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE)) stream_putc (stream, route_info->depth); #endif if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC)) stream_putl (stream, route_info->cost); stream_putw_at (stream, 0, stream_get_endp (stream)); writen (zclient->sock, stream->data, stream_get_endp (stream)); } }
static int zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr) { struct stream *s; struct rib *rib; unsigned long nump; u_char num; struct nexthop *nexthop; /* Lookup nexthop. */ rib = rib_match_ipv4 (addr); /* Get output stream. */ s = client->obuf; stream_reset (s); /* Fill in result. */ zserv_create_header (s, ZEBRA_IPV4_NEXTHOP_LOOKUP); stream_put_in_addr (s, &addr); if (rib) { if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) zlog_debug("%s: Matching rib entry found.", __func__); stream_putl (s, rib->metric); num = 0; nump = stream_get_endp(s); stream_putc (s, 0); for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) { stream_putc (s, nexthop->type); switch (nexthop->type) { case ZEBRA_NEXTHOP_IPV4: stream_put_in_addr (s, &nexthop->gate.ipv4); break; case ZEBRA_NEXTHOP_IPV4_IFINDEX: stream_put_in_addr (s, &nexthop->gate.ipv4); stream_putl (s, nexthop->ifindex); break; case ZEBRA_NEXTHOP_IFINDEX: case ZEBRA_NEXTHOP_IFNAME: stream_putl (s, nexthop->ifindex); break; default: /* do nothing */ break; } num++; } stream_putc_at (s, nump, num); } else { if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) zlog_debug("%s: No matching rib entry found.", __func__); stream_putl (s, 0); stream_putc (s, 0); } stream_putw_at (s, 0, stream_get_endp (s)); return zebra_server_send_message(client); }
static int send_client (struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id) { struct stream *s; struct rib *rib; unsigned long nump; u_char num; struct nexthop *nexthop; struct route_node *rn; rn = rnh->node; rib = rnh->state; /* Get output stream. */ s = client->obuf; stream_reset (s); zserv_create_header (s, ZEBRA_NEXTHOP_UPDATE, vrf_id); stream_putw(s, rn->p.family); stream_put_prefix (s, &rn->p); if (rib) { stream_putl (s, rib->metric); num = 0; nump = stream_get_endp(s); stream_putc (s, 0); for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) && ! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE) && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) { stream_putc (s, nexthop->type); switch (nexthop->type) { case ZEBRA_NEXTHOP_IPV4: stream_put_in_addr (s, &nexthop->gate.ipv4); break; case ZEBRA_NEXTHOP_IFINDEX: case ZEBRA_NEXTHOP_IFNAME: stream_putl (s, nexthop->ifindex); break; case ZEBRA_NEXTHOP_IPV4_IFINDEX: case ZEBRA_NEXTHOP_IPV4_IFNAME: stream_put_in_addr (s, &nexthop->gate.ipv4); stream_putl (s, nexthop->ifindex); break; #ifdef HAVE_IPV6 case ZEBRA_NEXTHOP_IPV6: stream_put (s, &nexthop->gate.ipv6, 16); break; case ZEBRA_NEXTHOP_IPV6_IFINDEX: case ZEBRA_NEXTHOP_IPV6_IFNAME: stream_put (s, &nexthop->gate.ipv6, 16); stream_putl (s, nexthop->ifindex); break; #endif /* HAVE_IPV6 */ default: /* do nothing */ break; } num++; } stream_putc_at (s, nump, num); } else { stream_putl (s, 0); stream_putc (s, 0); } stream_putw_at (s, 0, stream_get_endp (s)); client->nh_last_upd_time = quagga_time(NULL); client->last_write_cmd = ZEBRA_NEXTHOP_UPDATE; return zebra_server_send_message(client); }
static void isis_zebra_route_add_ipv4 (struct prefix *prefix, struct isis_route_info *route_info) { u_char message, flags; int psize; struct stream *stream; struct isis_nexthop *nexthop; struct listnode *node; if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) return; if (vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_ISIS], VRF_DEFAULT)) { message = 0; flags = 0; SET_FLAG (message, ZAPI_MESSAGE_NEXTHOP); SET_FLAG (message, ZAPI_MESSAGE_METRIC); #if 0 SET_FLAG (message, ZAPI_MESSAGE_DISTANCE); #endif stream = zclient->obuf; stream_reset (stream); zclient_create_header (stream, ZEBRA_IPV4_ROUTE_ADD, VRF_DEFAULT); /* type */ stream_putc (stream, ZEBRA_ROUTE_ISIS); /* flags */ stream_putc (stream, flags); /* message */ stream_putc (stream, message); /* SAFI */ stream_putw (stream, SAFI_UNICAST); /* prefix information */ psize = PSIZE (prefix->prefixlen); stream_putc (stream, prefix->prefixlen); stream_write (stream, (u_char *) & prefix->u.prefix4, psize); stream_putc (stream, listcount (route_info->nexthops)); /* Nexthop, ifindex, distance and metric information */ for (ALL_LIST_ELEMENTS_RO (route_info->nexthops, node, nexthop)) { /* FIXME: can it be ? */ if (nexthop->ip.s_addr != INADDR_ANY) { stream_putc (stream, ZEBRA_NEXTHOP_IPV4); stream_put_in_addr (stream, &nexthop->ip); } else { stream_putc (stream, ZEBRA_NEXTHOP_IFINDEX); stream_putl (stream, nexthop->ifindex); } } #if 0 if (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE)) stream_putc (stream, route_info->depth); #endif if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC)) stream_putl (stream, route_info->cost); stream_putw_at (stream, 0, stream_get_endp (stream)); zclient_send_message(zclient); SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); }
static struct bgp_info * bgp_dump_route_node_record (int afi, struct bgp_node *rn, struct bgp_info *info, unsigned int seq) { struct stream *obuf; size_t sizep; size_t endp; obuf = bgp_dump_obuf; stream_reset (obuf); /* MRT header */ if (afi == AFI_IP) bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV4_UNICAST, BGP_DUMP_ROUTES); else if (afi == AFI_IP6) bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV6_UNICAST, BGP_DUMP_ROUTES); /* Sequence number */ stream_putl (obuf, seq); /* Prefix length */ stream_putc (obuf, rn->p.prefixlen); /* Prefix */ if (afi == AFI_IP) { /* We'll dump only the useful bits (those not 0), but have to * align on 8 bits */ stream_write (obuf, (u_char *) &rn->p.u.prefix4, (rn->p.prefixlen + 7) / 8); } else if (afi == AFI_IP6) { /* We'll dump only the useful bits (those not 0), but have to * align on 8 bits */ stream_write (obuf, (u_char *) &rn->p.u.prefix6, (rn->p.prefixlen + 7) / 8); } /* Save where we are now, so we can overwride the entry count later */ sizep = stream_get_endp (obuf); /* Entry count */ uint16_t entry_count = 0; /* Entry count, note that this is overwritten later */ stream_putw (obuf, 0); endp = stream_get_endp (obuf); for (; info; info = info->next) { size_t cur_endp; /* Peer index */ stream_putw (obuf, info->peer->table_dump_index); /* Originated */ #ifdef HAVE_CLOCK_MONOTONIC stream_putl (obuf, time (NULL) - (bgp_clock () - info->uptime)); #else stream_putl (obuf, info->uptime); #endif /* HAVE_CLOCK_MONOTONIC */ /* Dump attribute. */ /* Skip prefix & AFI/SAFI for MP_NLRI */ bgp_dump_routes_attr (obuf, info->attr, &rn->p); cur_endp = stream_get_endp (obuf); if (cur_endp > BGP_MAX_PACKET_SIZE + BGP_DUMP_MSG_HEADER + BGP_DUMP_HEADER_SIZE) { stream_set_endp (obuf, endp); break; } entry_count++; endp = cur_endp; } /* Overwrite the entry count, now that we know the right number */ stream_putw_at (obuf, sizep, entry_count); bgp_dump_set_size (obuf, MSG_TABLE_DUMP_V2); fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp); return info; }
/* * The zebra server sends the clients a ZEBRA_IPV4_ROUTE_ADD or a * ZEBRA_IPV6_ROUTE_ADD via zsend_route_multipath in the following * situations: * - when the client starts up, and requests default information * by sending a ZEBRA_REDISTRIBUTE_DEFAULT_ADD to the zebra server, in the * - case of rip, ripngd, ospfd and ospf6d, when the client sends a * ZEBRA_REDISTRIBUTE_ADD as a result of the "redistribute" vty cmd, * - when the zebra server redistributes routes after it updates its rib * * The zebra server sends clients a ZEBRA_IPV4_ROUTE_DELETE or a * ZEBRA_IPV6_ROUTE_DELETE via zsend_route_multipath when: * - a "ip route" or "ipv6 route" vty command is issued, a prefix is * - deleted from zebra's rib, and this info * has to be redistributed to the clients * * XXX The ZEBRA_IPV*_ROUTE_ADD message is also sent by the client to the * zebra server when the client wants to tell the zebra server to add a * route to the kernel (zapi_ipv4_add etc. ). Since it's essentially the * same message being sent back and forth, this function and * zapi_ipv{4,6}_{add, delete} should be re-written to avoid code * duplication. */ int zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p, struct rib *rib) { int psize; struct stream *s; struct nexthop *nexthop; unsigned long nhnummark = 0; int nhnum = 0; u_char zapi_flags = ZAPI_MESSAGE_NEXTHOP | ZAPI_MESSAGE_IFINDEX; s = client->obuf; stream_reset (s); /* Place holder for size. */ stream_putw (s, 0); /* Put command, type and nexthop. */ stream_putc (s, cmd); stream_putc (s, rib->type); stream_putc (s, rib->flags); /* * XXX no need to set ZAPI_MESSAGE_NEXTHOP if we are going to * send empty nexthop? */ if (cmd == ZEBRA_IPV4_ROUTE_ADD || ZEBRA_IPV6_ROUTE_ADD) zapi_flags |= ZAPI_MESSAGE_METRIC; stream_putc (s, zapi_flags); /* Prefix. */ psize = PSIZE (p->prefixlen); stream_putc (s, p->prefixlen); stream_write (s, (u_char *) & p->u.prefix, psize); /* * XXX The message format sent by zebra below does not match the format * of the corresponding message expected by the zebra server * itself (e.g., see zread_ipv4_add). The nexthop_num is not set correctly, * (is there a bug on the client side if more than one segment is sent?) * nexthop ZEBRA_NEXTHOP_IPV4 is never set, ZEBRA_NEXTHOP_IFINDEX * is hard-coded. */ /* Nexthop */ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) { if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) { nhnummark = stream_get_putp (s); stream_putc (s, 1); /* placeholder */ nhnum++; switch(nexthop->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: stream_put_in_addr (s, &nexthop->gate.ipv4); break; #ifdef HAVE_IPV6 case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: case NEXTHOP_TYPE_IPV6_IFNAME: stream_write (s, (u_char *) &nexthop->gate.ipv6, 16); break; #endif default: if (cmd == ZEBRA_IPV4_ROUTE_ADD || cmd == ZEBRA_IPV4_ROUTE_DELETE) { struct in_addr empty; memset (&empty, 0, sizeof (struct in_addr)); stream_write (s, (u_char *) &empty, IPV4_MAX_BYTELEN); } else { struct in6_addr empty; memset (&empty, 0, sizeof (struct in6_addr)); stream_write (s, (u_char *) &empty, IPV6_MAX_BYTELEN); } } /* Interface index. */ stream_putc (s, 1); stream_putl (s, nexthop->ifindex); break; } } /* Metric */ stream_putl (s, rib->metric); /* Write next-hop number */ if (nhnummark) stream_putc_at (s, nhnummark, nhnum); /* 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; }