diff options
Diffstat (limited to 'zebra')
| -rw-r--r-- | zebra/connected.c | 4 | ||||
| -rw-r--r-- | zebra/kernel_netlink.c | 144 | ||||
| -rw-r--r-- | zebra/kernel_netlink.h | 4 | ||||
| -rw-r--r-- | zebra/kernel_socket.c | 4 | ||||
| -rw-r--r-- | zebra/main.c | 51 | ||||
| -rw-r--r-- | zebra/redistribute.c | 18 | ||||
| -rw-r--r-- | zebra/rib.h | 2 | ||||
| -rw-r--r-- | zebra/rt_netlink.c | 6 | ||||
| -rw-r--r-- | zebra/rule_netlink.c | 14 | ||||
| -rw-r--r-- | zebra/zapi_msg.c | 85 | ||||
| -rw-r--r-- | zebra/zebra_dplane.c | 31 | ||||
| -rw-r--r-- | zebra/zebra_dplane.h | 1 | ||||
| -rw-r--r-- | zebra/zebra_evpn.c | 4 | ||||
| -rw-r--r-- | zebra/zebra_evpn_mac.c | 4 | ||||
| -rw-r--r-- | zebra/zebra_evpn_mh.c | 17 | ||||
| -rw-r--r-- | zebra/zebra_evpn_mh.h | 4 | ||||
| -rw-r--r-- | zebra/zebra_evpn_neigh.c | 7 | ||||
| -rw-r--r-- | zebra/zebra_pbr.c | 79 | ||||
| -rw-r--r-- | zebra/zebra_pbr.h | 7 | ||||
| -rw-r--r-- | zebra/zebra_rib.c | 200 | ||||
| -rw-r--r-- | zebra/zserv.c | 11 | ||||
| -rw-r--r-- | zebra/zserv.h | 4 |
22 files changed, 323 insertions, 378 deletions
diff --git a/zebra/connected.c b/zebra/connected.c index 3b9ebe14a4..8c4ba163bd 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -393,10 +393,10 @@ void connected_down(struct interface *ifp, struct connected *ifc) * head. */ rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0, - 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false); + 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false, true); rib_delete(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, - 0, 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false); + 0, 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false, true); /* Schedule LSP forwarding entries for processing, if appropriate. */ if (zvrf->vrf->vrf_id == VRF_DEFAULT) { diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index d0c1bc812d..ad0d4bf56b 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -20,12 +20,6 @@ #include <zebra.h> -#if defined(HANDLE_NETLINK_FUZZING) -#include <stdio.h> -#include <string.h> -#include "libfrr.h" -#endif /* HANDLE_NETLINK_FUZZING */ - #ifdef HAVE_NETLINK #include "linklist.h" @@ -96,14 +90,7 @@ */ #define NL_DEFAULT_BATCH_SEND_THRESHOLD (15 * NL_PKT_BUF_SIZE) -/* - * For every request sent to the kernel that has failed we get an error message, - * which contains a standard netlink message header and the payload consisting - * of an error code and the original netlink mesage. So the receiving buffer - * must be at least as big as the transmitting buffer increased by some space - * for headers. - */ -#define NL_BATCH_RX_BUFSIZE (NL_DEFAULT_BATCH_BUFSIZE + NL_PKT_BUF_SIZE) +#define NL_BATCH_RX_BUFSIZE NL_RCV_PKT_BUF_SIZE static const struct message nlmsg_str[] = {{RTM_NEWROUTE, "RTM_NEWROUTE"}, {RTM_DELROUTE, "RTM_DELROUTE"}, @@ -404,86 +391,6 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, return 0; } -#if defined(HANDLE_NETLINK_FUZZING) -/* Using globals here to avoid adding function parameters */ - -/* Keep distinct filenames for netlink fuzzy collection */ -static unsigned int netlink_file_counter = 1; - -/* File name to read fuzzed netlink from */ -static char netlink_fuzz_file[MAXPATHLEN] = ""; - -/* Flag for whether to read from file or not */ -bool netlink_read; - -/** - * netlink_read_init() - Starts the message parser - * @fname: Filename to read. - */ -void netlink_read_init(const char *fname) -{ - struct zebra_dplane_info dp_info; - - snprintf(netlink_fuzz_file, MAXPATHLEN, "%s", fname); - /* Creating this fake socket for testing purposes */ - struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); - - /* Capture key info from zns struct */ - zebra_dplane_info_from_zns(&dp_info, zns, false); - - netlink_parse_info(netlink_information_fetch, &zns->netlink, - &dp_info, 1, 0); -} - -/** - * netlink_write_incoming() - Writes all data received from netlink to a file - * @buf: Data from netlink. - * @size: Size of data. - * @counter: Counter for keeping filenames distinct. - */ -static void netlink_write_incoming(const char *buf, const unsigned int size, - unsigned int counter) -{ - char fname[MAXPATHLEN]; - FILE *f; - - snprintf(fname, MAXPATHLEN, "%s/%s_%u", frr_vtydir, "netlink", counter); - frr_with_privs(&zserv_privs) { - f = fopen(fname, "w"); - } - if (f) { - fwrite(buf, 1, size, f); - fclose(f); - } -} - -/** - * netlink_read_file() - Reads netlink data from file - * @buf: Netlink buffer being overwritten. - * @fname: File name to read from. - * - * Return: Size of file. - */ -static long netlink_read_file(char *buf, const char *fname) -{ - FILE *f; - long file_bytes = -1; - - frr_with_privs(&zserv_privs) { - f = fopen(fname, "r"); - } - if (f) { - fseek(f, 0, SEEK_END); - file_bytes = ftell(f); - rewind(f); - fread(buf, NL_RCV_PKT_BUF_SIZE, 1, f); - fclose(f); - } - return file_bytes; -} - -#endif /* HANDLE_NETLINK_FUZZING */ - static int kernel_read(struct thread *thread) { struct zebra_ns *zns = (struct zebra_ns *)THREAD_ARG(thread); @@ -834,18 +741,7 @@ static int netlink_recv_msg(const struct nlsock *nl, struct msghdr msg, msg.msg_iovlen = 1; do { -#if defined(HANDLE_NETLINK_FUZZING) - /* Check if reading and filename is set */ - if (netlink_read && '\0' != netlink_fuzz_file[0]) { - zlog_debug("Reading netlink fuzz file"); - status = netlink_read_file(buf, netlink_fuzz_file); - ((struct sockaddr_nl *)msg.msg_name)->nl_pid = 0; - } else { - status = recvmsg(nl->sock, &msg, 0); - } -#else status = recvmsg(nl->sock, &msg, 0); -#endif /* HANDLE_NETLINK_FUZZING */ } while (status == -1 && errno == EINTR); if (status == -1) { @@ -877,13 +773,6 @@ static int netlink_recv_msg(const struct nlsock *nl, struct msghdr msg, zlog_hexdump(buf, status); } -#if defined(HANDLE_NETLINK_FUZZING) - if (!netlink_read) { - zlog_debug("Writing incoming netlink message"); - netlink_write_incoming(buf, status, netlink_file_counter++); - } -#endif /* HANDLE_NETLINK_FUZZING */ - return status; } @@ -1173,14 +1062,17 @@ static int nl_batch_read_resp(struct nl_batch *bth) msg.msg_name = (void *)&snl; msg.msg_namelen = sizeof(snl); - status = netlink_recv_msg(nl, msg, nl_batch_rx_buf, - sizeof(nl_batch_rx_buf)); - if (status == -1 || status == 0) - return status; + /* + * The responses are not batched, so we need to read and process one + * message at a time. + */ + while (true) { + status = netlink_recv_msg(nl, msg, nl_batch_rx_buf, + sizeof(nl_batch_rx_buf)); + if (status == -1 || status == 0) + return status; - for (h = (struct nlmsghdr *)nl_batch_rx_buf; - (status >= 0 && NLMSG_OK(h, (unsigned int)status)); - h = NLMSG_NEXT(h, status)) { + h = (struct nlmsghdr *)nl_batch_rx_buf; ignore_msg = false; seq = h->nlmsg_seq; /* @@ -1561,6 +1453,15 @@ void kernel_init(struct zebra_ns *zns) if (ret < 0) zlog_notice("Registration for extended dp ACK failed : %d %s", errno, safe_strerror(errno)); + + /* + * Trim off the payload of the original netlink message in the + * acknowledgment. This option is available since Linux 4.2, so if + * setsockopt fails, ignore the error. + */ + one = 1; + ret = setsockopt(zns->netlink_dplane.sock, SOL_NETLINK, NETLINK_CAP_ACK, + &one, sizeof(one)); #endif /* Register kernel socket. */ @@ -1577,8 +1478,11 @@ void kernel_init(struct zebra_ns *zns) zns->netlink_dplane.name, safe_strerror(errno), errno); /* Set receive buffer size if it's set from command line */ - if (nl_rcvbufsize) + if (nl_rcvbufsize) { netlink_recvbuf(&zns->netlink, nl_rcvbufsize); + netlink_recvbuf(&zns->netlink_cmd, nl_rcvbufsize); + netlink_recvbuf(&zns->netlink_dplane, nl_rcvbufsize); + } netlink_install_filter(zns->netlink.sock, zns->netlink_cmd.snl.nl_pid, diff --git a/zebra/kernel_netlink.h b/zebra/kernel_netlink.h index c02e16480b..696f9be4f6 100644 --- a/zebra/kernel_netlink.h +++ b/zebra/kernel_netlink.h @@ -86,10 +86,6 @@ extern const char *nl_rtproto_to_str(uint8_t rtproto); extern const char *nl_family_to_str(uint8_t family); extern const char *nl_rttype_to_str(uint8_t rttype); -#if defined(HANDLE_NETLINK_FUZZING) -extern bool netlink_read; -extern void netlink_read_init(const char *fname); -#endif /* HANDLE_NETLINK_FUZZING */ extern int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), const struct nlsock *nl, const struct zebra_dplane_info *dp_info, diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 4c29b999f0..02963651a0 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -1136,7 +1136,7 @@ void rtm_read(struct rt_msghdr *rtm) if (rtm->rtm_type == RTM_CHANGE) rib_delete(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL, NULL, 0, RT_TABLE_MAIN, 0, - 0, true); + 0, true, false); if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) rib_add(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, @@ -1145,7 +1145,7 @@ void rtm_read(struct rt_msghdr *rtm) else rib_delete(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL, &nh, 0, RT_TABLE_MAIN, 0, - 0, true); + 0, true, false); } /* Interface function for the kernel routing table updates. Support diff --git a/zebra/main.c b/zebra/main.c index 2b97e915fb..2afef46bb2 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -59,10 +59,6 @@ #include "zebra/zebra_opaque.h" #include "zebra/zebra_srte.h" -#if defined(HANDLE_NETLINK_FUZZING) -#include "zebra/kernel_netlink.h" -#endif /* HANDLE_NETLINK_FUZZING */ - #define ZEBRA_PTM_SUPPORT /* process id. */ @@ -284,12 +280,6 @@ int main(int argc, char **argv) char *vrf_default_name_configured = NULL; struct sockaddr_storage dummy; socklen_t dummylen; -#if defined(HANDLE_ZAPI_FUZZING) - char *zapi_fuzzing = NULL; -#endif /* HANDLE_ZAPI_FUZZING */ -#if defined(HANDLE_NETLINK_FUZZING) - char *netlink_fuzzing = NULL; -#endif /* HANDLE_NETLINK_FUZZING */ graceful_restart = 0; vrf_configure_backend(VRF_BACKEND_VRF_LITE); @@ -301,12 +291,6 @@ int main(int argc, char **argv) #ifdef HAVE_NETLINK "s:n" #endif -#if defined(HANDLE_ZAPI_FUZZING) - "c:" -#endif /* HANDLE_ZAPI_FUZZING */ -#if defined(HANDLE_NETLINK_FUZZING) - "w:" -#endif /* HANDLE_NETLINK_FUZZING */ , longopts, " -b, --batch Runs in batch mode\n" @@ -321,12 +305,6 @@ int main(int argc, char **argv) " -s, --nl-bufsize Set netlink receive buffer size\n" " --v6-rr-semantics Use v6 RR semantics\n" #endif /* HAVE_NETLINK */ -#if defined(HANDLE_ZAPI_FUZZING) - " -c <file> Bypass normal startup and use this file for testing of zapi\n" -#endif /* HANDLE_ZAPI_FUZZING */ -#if defined(HANDLE_NETLINK_FUZZING) - " -w <file> Bypass normal startup and use this file for testing of netlink input\n" -#endif /* HANDLE_NETLINK_FUZZING */ ); while (1) { @@ -388,21 +366,6 @@ int main(int argc, char **argv) v6_rr_semantics = true; break; #endif /* HAVE_NETLINK */ -#if defined(HANDLE_ZAPI_FUZZING) - case 'c': - zapi_fuzzing = optarg; - break; -#endif /* HANDLE_ZAPI_FUZZING */ -#if defined(HANDLE_NETLINK_FUZZING) - case 'w': - netlink_fuzzing = optarg; - /* This ensures we are aren't writing any of the - * startup netlink messages that happen when we - * just want to read. - */ - netlink_read = true; - break; -#endif /* HANDLE_NETLINK_FUZZING */ default: frr_help_exit(1); break; @@ -489,20 +452,6 @@ int main(int argc, char **argv) /* Error init */ zebra_error_init(); -#if defined(HANDLE_ZAPI_FUZZING) - if (zapi_fuzzing) { - zserv_read_file(zapi_fuzzing); - exit(0); - } -#endif /* HANDLE_ZAPI_FUZZING */ -#if defined(HANDLE_NETLINK_FUZZING) - if (netlink_fuzzing) { - netlink_read_init(netlink_fuzzing); - exit(0); - } -#endif /* HANDLE_NETLINK_FUZZING */ - - frr_run(zrouter.master); /* Not reached... */ diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 4d6346151a..c0f89e6afe 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -200,8 +200,8 @@ void redistribute_update(const struct prefix *p, const struct prefix *src_p, if (IS_ZEBRA_DEBUG_RIB) { zlog_debug( - "%u:%s: Redist update re %p (%s), old %p (%s)", - re->vrf_id, prefix2str(p, buf, sizeof(buf)), + "(%u:%u):%s: Redist update re %p (%s), old %p (%s)", + re->vrf_id, re->table, prefix2str(p, buf, sizeof(buf)), re, zebra_route_string(re->type), prev_re, prev_re ? zebra_route_string(prev_re->type) : "None"); } @@ -224,12 +224,12 @@ void redistribute_update(const struct prefix *p, const struct prefix *src_p, if (zebra_redistribute_check(re, client, p, afi)) { if (IS_ZEBRA_DEBUG_RIB) { zlog_debug( - "%s: client %s %s(%u), type=%d, distance=%d, metric=%d", - __func__, - zebra_route_string(client->proto), - prefix2str(p, buf, sizeof(buf)), - re->vrf_id, re->type, - re->distance, re->metric); + "%s: client %s %s(%u:%u), type=%d, distance=%d, metric=%d", + __func__, + zebra_route_string(client->proto), + prefix2str(p, buf, sizeof(buf)), + re->vrf_id, re->table, re->type, + re->distance, re->metric); } zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD, client, p, src_p, re); @@ -727,7 +727,7 @@ int zebra_del_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn, rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_TABLE, re->table, re->flags, &p, NULL, re->nhe->nhg.nexthop, re->nhe_id, zvrf->table_id, re->metric, re->distance, - false); + false, false); return 0; } diff --git a/zebra/rib.h b/zebra/rib.h index b9f4e56905..be680a112f 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -379,7 +379,7 @@ extern void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, unsigned short instance, int flags, struct prefix *p, struct prefix_ipv6 *src_p, const struct nexthop *nh, uint32_t nhe_id, uint32_t table_id, uint32_t metric, - uint8_t distance, bool fromkernel); + uint8_t distance, bool fromkernel, bool connected_down); extern struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id, union g_addr *addr, diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 4a6839d3b1..50b1a62d86 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -837,7 +837,7 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, if (nhe_id) { rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, &p, &src_p, NULL, nhe_id, table, metric, - distance, true); + distance, true, false); } else { if (!tb[RTA_MULTIPATH]) { struct nexthop nh; @@ -847,13 +847,13 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, gate, afi, vrf_id); rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, &p, &src_p, &nh, 0, table, - metric, distance, true); + metric, distance, true, false); } else { /* XXX: need to compare the entire list of * nexthops here for NLM_F_APPEND stupidity */ rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, &p, &src_p, NULL, 0, table, - metric, distance, true); + metric, distance, true, false); } } } diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c index 3a3baab4ca..d6a34327a6 100644 --- a/zebra/rule_netlink.c +++ b/zebra/rule_netlink.c @@ -74,7 +74,7 @@ netlink_rule_msg_encode(int cmd, const struct zebra_dplane_ctx *ctx, char buf[]; } *req = buf; - const char *ifname = dplane_ctx_get_ifname(ctx); + const char *ifname = dplane_ctx_rule_get_ifname(ctx); char buf1[PREFIX_STRLEN]; char buf2[PREFIX_STRLEN]; @@ -141,9 +141,9 @@ netlink_rule_msg_encode(int cmd, const struct zebra_dplane_ctx *ctx, if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( - "Tx %s family %s IF %s(%u) Pref %u Fwmark %u Src %s Dst %s Table %u", + "Tx %s family %s IF %s Pref %u Fwmark %u Src %s Dst %s Table %u", nl_msg_type_to_str(cmd), nl_family_to_str(family), - ifname, dplane_ctx_get_ifindex(ctx), priority, fwmark, + ifname, priority, fwmark, prefix2str(src_ip, buf1, sizeof(buf1)), prefix2str(dst_ip, buf2, sizeof(buf2)), table); @@ -324,13 +324,13 @@ int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) ret = dplane_pbr_rule_delete(&rule); zlog_debug( - "%s: %s leftover rule: family %s IF %s(%u) Pref %u Src %s Dst %s Table %u", + "%s: %s leftover rule: family %s IF %s Pref %u Src %s Dst %s Table %u", __func__, ((ret == ZEBRA_DPLANE_REQUEST_FAILURE) ? "Failed to remove" : "Removed"), nl_family_to_str(frh->family), rule.ifname, - rule.rule.ifindex, rule.rule.priority, + rule.rule.priority, prefix2str(&rule.rule.filter.src_ip, buf1, sizeof(buf1)), prefix2str(&rule.rule.filter.dst_ip, buf2, @@ -350,10 +350,10 @@ int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( - "Rx %s family %s IF %s(%u) Pref %u Src %s Dst %s Table %u", + "Rx %s family %s IF %s Pref %u Src %s Dst %s Table %u", nl_msg_type_to_str(h->nlmsg_type), nl_family_to_str(frh->family), rule.ifname, - rule.rule.ifindex, rule.rule.priority, + rule.rule.priority, prefix2str(&rule.rule.filter.src_ip, buf1, sizeof(buf1)), prefix2str(&rule.rule.filter.dst_ip, buf2, diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index fbed99dc59..e436e5a288 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -815,7 +815,7 @@ void zsend_rule_notify_owner(const struct zebra_dplane_ctx *ctx, stream_putl(s, dplane_ctx_rule_get_seq(ctx)); stream_putl(s, dplane_ctx_rule_get_priority(ctx)); stream_putl(s, dplane_ctx_rule_get_unique(ctx)); - stream_putl(s, dplane_ctx_get_ifindex(ctx)); + stream_put(s, dplane_ctx_rule_get_ifname(ctx), INTERFACE_NAMSIZ); stream_putw_at(s, 0, stream_get_endp(s)); @@ -1349,6 +1349,20 @@ static void zread_interface_add(ZAPI_HANDLER_ARGS) struct vrf *vrf; struct interface *ifp; + vrf_id_t vrf_id = zvrf_id(zvrf); + if (vrf_id != VRF_DEFAULT && vrf_id != VRF_UNKNOWN) { + FOR_ALL_INTERFACES (zvrf->vrf, ifp) { + /* Skip pseudo interface. */ + if (!CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) + continue; + + zsend_interface_add(client, ifp); + zsend_interface_link_params(client, ifp); + zsend_interface_addresses(client, ifp); + } + return; + } + RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { FOR_ALL_INTERFACES (vrf, ifp) { /* Skip pseudo interface. */ @@ -1588,16 +1602,17 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) return; } + vrf_id = zvrf_id(zvrf); + if (IS_ZEBRA_DEBUG_RECV) { char buf_prefix[PREFIX_STRLEN]; prefix2str(&api.prefix, buf_prefix, sizeof(buf_prefix)); - zlog_debug("%s: p=%s, msg flags=0x%x, flags=0x%x", - __func__, buf_prefix, (int)api.message, api.flags); + zlog_debug("%s: p=(%u:%u)%s, msg flags=0x%x, flags=0x%x", + __func__, vrf_id, api.tableid, buf_prefix, (int)api.message, api.flags); } /* Allocate new route. */ - vrf_id = zvrf_id(zvrf); re = XCALLOC(MTYPE_RE, sizeof(struct route_entry)); re->type = api.type; re->instance = api.instance; @@ -1878,9 +1893,18 @@ static void zread_route_del(ZAPI_HANDLER_ARGS) else table_id = zvrf->table_id; + if (IS_ZEBRA_DEBUG_RECV) { + char buf_prefix[PREFIX_STRLEN]; + + prefix2str(&api.prefix, buf_prefix, sizeof(buf_prefix)); + zlog_debug("%s: p=(%u:%u)%s, msg flags=0x%x, flags=0x%x", + __func__, zvrf_id(zvrf), table_id, buf_prefix, + (int)api.message, api.flags); + } + rib_delete(afi, api.safi, zvrf_id(zvrf), api.type, api.instance, api.flags, &api.prefix, src_p, NULL, 0, table_id, api.metric, - api.distance, false); + api.distance, false, false); /* Stats */ switch (api.prefix.family) { @@ -2727,6 +2751,7 @@ static inline void zread_rule(ZAPI_HANDLER_ARGS) struct zebra_pbr_rule zpr; struct stream *s; uint32_t total, i; + char ifname[INTERFACE_NAMSIZ + 1] = {}; s = msg; STREAM_GETL(s, total); @@ -2752,21 +2777,10 @@ static inline void zread_rule(ZAPI_HANDLER_ARGS) STREAM_GETC(s, zpr.rule.filter.dsfield); STREAM_GETL(s, zpr.rule.filter.fwmark); STREAM_GETL(s, zpr.rule.action.table); - STREAM_GETL(s, zpr.rule.ifindex); + STREAM_GET(ifname, s, INTERFACE_NAMSIZ); - if (zpr.rule.ifindex) { - struct interface *ifp; - - ifp = if_lookup_by_index_per_ns(zvrf->zns, - zpr.rule.ifindex); - if (!ifp) { - zlog_debug("Failed to lookup ifindex: %u", - zpr.rule.ifindex); - return; - } - - strlcpy(zpr.ifname, ifp->name, sizeof(zpr.ifname)); - } + strlcpy(zpr.ifname, ifname, sizeof(zpr.ifname)); + strlcpy(zpr.rule.ifname, ifname, sizeof(zpr.rule.ifname)); if (!is_default_prefix(&zpr.rule.filter.src_ip)) zpr.rule.filter.filter_bm |= PBR_FILTER_SRC_IP; @@ -2831,6 +2845,7 @@ static inline void zread_ipset(ZAPI_HANDLER_ARGS) zpi.vrf_id = zvrf->vrf->vrf_id; STREAM_GETL(s, zpi.unique); STREAM_GETL(s, zpi.type); + STREAM_GETC(s, zpi.family); STREAM_GET(&zpi.ipset_name, s, ZEBRA_IPSET_NAME_SIZE); if (hdr->command == ZEBRA_IPSET_CREATE) @@ -2941,6 +2956,7 @@ static inline void zread_iptable(ZAPI_HANDLER_ARGS) STREAM_GETL(s, zpi->action); STREAM_GETL(s, zpi->fwmark); STREAM_GET(&zpi->ipset_name, s, ZEBRA_IPSET_NAME_SIZE); + STREAM_GETC(s, zpi->family); STREAM_GETW(s, zpi->pkt_len_min); STREAM_GETW(s, zpi->pkt_len_max); STREAM_GETW(s, zpi->tcp_flags); @@ -2948,6 +2964,7 @@ static inline void zread_iptable(ZAPI_HANDLER_ARGS) STREAM_GETC(s, zpi->dscp_value); STREAM_GETC(s, zpi->fragment); STREAM_GETC(s, zpi->protocol); + STREAM_GETW(s, zpi->flow_label); STREAM_GETL(s, zpi->nb_interface); zebra_pbr_iptable_update_interfacelist(s, zpi); @@ -3103,29 +3120,6 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_CLIENT_CAPABILITIES] = zread_client_capabilities, [ZEBRA_NEIGH_DISCOVER] = zread_neigh_discover}; -#if defined(HANDLE_ZAPI_FUZZING) -extern struct zebra_privs_t zserv_privs; - -static void zserv_write_incoming(struct stream *orig, uint16_t command) -{ - char fname[MAXPATHLEN]; - struct stream *copy; - int fd = -1; - - copy = stream_dup(orig); - stream_set_getp(copy, 0); - - snprintf(fname, MAXPATHLEN, "%s/%u", frr_vtydir, command); - - frr_with_privs(&zserv_privs) { - fd = open(fname, O_CREAT | O_WRONLY | O_EXCL, 0644); - } - stream_flush(copy, fd); - close(fd); - stream_free(copy); -} -#endif - /* * Process a batch of zapi messages. */ @@ -3152,13 +3146,10 @@ void zserv_handle_commands(struct zserv *client, struct stream_fifo *fifo) zapi_parse_header(msg, &hdr); - if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) + if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV + && IS_ZEBRA_DEBUG_DETAIL) zserv_log_message(NULL, msg, &hdr); -#if defined(HANDLE_ZAPI_FUZZING) - zserv_write_incoming(msg, hdr.command); -#endif - hdr.length -= ZEBRA_HEADER_SIZE; /* Before checking for a handler function, check for diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 6e8d35aa77..abd0adb64e 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -210,6 +210,7 @@ struct dplane_ctx_rule { uint8_t dsfield; struct prefix src_ip; struct prefix dst_ip; + char ifname[INTERFACE_NAMSIZ + 1]; }; struct dplane_rule_info { @@ -1632,6 +1633,13 @@ int dplane_ctx_rule_get_sock(const struct zebra_dplane_ctx *ctx) return ctx->u.rule.sock; } +const char *dplane_ctx_rule_get_ifname(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.rule.new.ifname; +} + int dplane_ctx_rule_get_unique(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); @@ -1911,10 +1919,11 @@ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, * If its a delete we only use the prefix anyway, so this only * matters for INSTALL/UPDATE. */ - if (((op == DPLANE_OP_ROUTE_INSTALL) - || (op == DPLANE_OP_ROUTE_UPDATE)) - && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED) - && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED)) { + if (zebra_nhg_kernel_nexthops_enabled() + && (((op == DPLANE_OP_ROUTE_INSTALL) + || (op == DPLANE_OP_ROUTE_UPDATE)) + && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED) + && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED))) { ret = ENOENT; goto done; } @@ -2190,6 +2199,7 @@ static void dplane_ctx_rule_init_single(struct dplane_ctx_rule *dplane_rule, dplane_rule->dsfield = rule->rule.filter.dsfield; prefix_copy(&(dplane_rule->dst_ip), &rule->rule.filter.dst_ip); prefix_copy(&(dplane_rule->src_ip), &rule->rule.filter.src_ip); + strlcpy(dplane_rule->ifname, rule->ifname, INTERFACE_NAMSIZ); } /** @@ -2211,10 +2221,9 @@ static int dplane_ctx_rule_init(struct zebra_dplane_ctx *ctx, char buf2[PREFIX_STRLEN]; zlog_debug( - "init dplane ctx %s: IF %s(%u) Prio %u Fwmark %u Src %s Dst %s Table %u", + "init dplane ctx %s: IF %s Prio %u Fwmark %u Src %s Dst %s Table %u", dplane_op2str(op), new_rule->ifname, - new_rule->rule.ifindex, new_rule->rule.priority, - new_rule->rule.filter.fwmark, + new_rule->rule.priority, new_rule->rule.filter.fwmark, prefix2str(&new_rule->rule.filter.src_ip, buf1, sizeof(buf1)), prefix2str(&new_rule->rule.filter.dst_ip, buf2, @@ -2231,7 +2240,6 @@ static int dplane_ctx_rule_init(struct zebra_dplane_ctx *ctx, ctx->zd_vrf_id = new_rule->vrf_id; memcpy(ctx->zd_ifname, new_rule->ifname, sizeof(new_rule->ifname)); - ctx->zd_ifindex = new_rule->rule.ifindex; ctx->u.rule.sock = new_rule->sock; ctx->u.rule.unique = new_rule->rule.unique; @@ -2352,11 +2360,8 @@ dplane_route_update_internal(struct route_node *rn, if (ret == AOK) result = ZEBRA_DPLANE_REQUEST_QUEUED; else { - if (ret == ENOENT) - result = ZEBRA_DPLANE_REQUEST_SUCCESS; - else - atomic_fetch_add_explicit(&zdplane_info.dg_route_errors, - 1, memory_order_relaxed); + atomic_fetch_add_explicit(&zdplane_info.dg_route_errors, 1, + memory_order_relaxed); if (ctx) dplane_ctx_free(&ctx); } diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 5dd789a851..1d852b1bac 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -423,6 +423,7 @@ uint32_t dplane_ctx_neigh_get_update_flags(const struct zebra_dplane_ctx *ctx); int dplane_ctx_rule_get_sock(const struct zebra_dplane_ctx *ctx); int dplane_ctx_rule_get_unique(const struct zebra_dplane_ctx *ctx); int dplane_ctx_rule_get_seq(const struct zebra_dplane_ctx *ctx); +const char *dplane_ctx_rule_get_ifname(const struct zebra_dplane_ctx *ctx); uint32_t dplane_ctx_rule_get_priority(const struct zebra_dplane_ctx *ctx); uint32_t dplane_ctx_rule_get_old_priority(const struct zebra_dplane_ctx *ctx); uint32_t dplane_ctx_rule_get_table(const struct zebra_dplane_ctx *ctx); diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c index 80124f92b3..56699c4e83 100644 --- a/zebra/zebra_evpn.c +++ b/zebra/zebra_evpn.c @@ -1011,7 +1011,7 @@ zebra_evpn_t *zebra_evpn_add(vni_t vni) zevpn = hash_get(zvrf->evpn_table, &tmp_zevpn, zebra_evpn_alloc); assert(zevpn); - zebra_evpn_evpn_es_init(zevpn); + zebra_evpn_es_evi_init(zevpn); /* Create hash table for MAC */ zevpn->mac_table = zebra_mac_db_create("Zebra EVPN MAC Table"); @@ -1041,7 +1041,7 @@ int zebra_evpn_del(zebra_evpn_t *zevpn) hash_free(zevpn->mac_table); zevpn->mac_table = NULL; - zebra_evpn_evpn_es_cleanup(zevpn); + zebra_evpn_es_evi_cleanup(zevpn); /* Free the EVPN hash entry and allocated memory. */ tmp_zevpn = hash_release(zvrf->evpn_table, zevpn); diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c index 6fc141efbb..75031ddba6 100644 --- a/zebra/zebra_evpn_mac.c +++ b/zebra/zebra_evpn_mac.c @@ -2067,6 +2067,7 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn, if (is_dup_detect) { inform_client = false; upd_neigh = false; + es_change = false; } } } @@ -2099,7 +2100,8 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn, mac->es ? mac->es->esi_str : "", mac->loc_seq, mac->flags, local_inactive ? " local-inactive" : ""); - inform_client = true; + if (!is_dup_detect) + inform_client = true; } if (es_change) { diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c index 029480eb4a..2567171c5e 100644 --- a/zebra/zebra_evpn_mh.c +++ b/zebra/zebra_evpn_mh.c @@ -363,7 +363,7 @@ void zebra_evpn_es_evi_show_vni(struct vty *vty, bool uj, vni_t vni, int detail) } /* Initialize the ES tables maintained per-L2_VNI */ -void zebra_evpn_evpn_es_init(zebra_evpn_t *zevpn) +void zebra_evpn_es_evi_init(zebra_evpn_t *zevpn) { /* Initialize the ES-EVI RB tree */ RB_INIT(zebra_es_evi_rb_head, &zevpn->es_evi_rb_tree); @@ -376,7 +376,7 @@ void zebra_evpn_evpn_es_init(zebra_evpn_t *zevpn) } /* Cleanup the ES info maintained per- EVPN */ -void zebra_evpn_evpn_es_cleanup(zebra_evpn_t *zevpn) +void zebra_evpn_es_evi_cleanup(zebra_evpn_t *zevpn) { struct zebra_evpn_es_evi *es_evi; struct zebra_evpn_es_evi *es_evi_next; @@ -1356,7 +1356,8 @@ static void zebra_evpn_es_local_info_clear(struct zebra_evpn_es *es) if (!(es->flags & ZEBRA_EVPNES_LOCAL)) return; - es->flags &= ~ZEBRA_EVPNES_LOCAL; + es->flags &= ~(ZEBRA_EVPNES_LOCAL | ZEBRA_EVPNES_READY_FOR_BGP); + /* if there any local macs referring to the ES as dest we * need to clear the static reference on them */ @@ -1613,9 +1614,13 @@ bool zebra_evpn_es_mac_ref(zebra_mac_t *mac, esi_t *esi) es = zebra_evpn_es_find(esi); if (!es) { - es = zebra_evpn_es_new(esi); - if (IS_ZEBRA_DEBUG_EVPN_MH_ES) - zlog_debug("auto es %s add on mac ref", es->esi_str); + /* If non-zero esi implicitly create a new ES */ + if (memcmp(esi, zero_esi, sizeof(esi_t))) { + es = zebra_evpn_es_new(esi); + if (IS_ZEBRA_DEBUG_EVPN_MH_ES) + zlog_debug("auto es %s add on mac ref", + es->esi_str); + } } return zebra_evpn_es_mac_ref_entry(mac, es); diff --git a/zebra/zebra_evpn_mh.h b/zebra/zebra_evpn_mh.h index ed62677e3b..72b7f9b675 100644 --- a/zebra/zebra_evpn_mh.h +++ b/zebra/zebra_evpn_mh.h @@ -198,8 +198,8 @@ extern void zebra_evpn_mh_terminate(void); extern bool zebra_evpn_is_if_es_capable(struct zebra_if *zif); extern void zebra_evpn_if_init(struct zebra_if *zif); extern void zebra_evpn_if_cleanup(struct zebra_if *zif); -extern void zebra_evpn_evpn_es_init(zebra_evpn_t *zevpn); -extern void zebra_evpn_evpn_es_cleanup(zebra_evpn_t *zevpn); +extern void zebra_evpn_es_evi_init(zebra_evpn_t *zevpn); +extern void zebra_evpn_es_evi_cleanup(zebra_evpn_t *zevpn); extern void zebra_evpn_vxl_evpn_set(struct zebra_if *zif, zebra_evpn_t *zevpn, bool set); extern void zebra_evpn_es_set_base_evpn(zebra_evpn_t *zevpn); diff --git a/zebra/zebra_evpn_neigh.c b/zebra/zebra_evpn_neigh.c index 492052b1b2..661d1c7f81 100644 --- a/zebra/zebra_evpn_neigh.c +++ b/zebra/zebra_evpn_neigh.c @@ -2184,9 +2184,10 @@ void process_neigh_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf, seq, n->flags); zebra_evpn_neigh_clear_sync_info(n); if (IS_ZEBRA_NEIGH_ACTIVE(n)) - zebra_evpn_mac_send_del_to_client( - zevpn->vni, &mac->macaddr, - mac->flags, false /*force*/); + zebra_evpn_neigh_send_del_to_client( + zevpn->vni, &n->ip, &n->emac, + n->flags, n->state, + false /*force*/); } if (memcmp(&n->emac, &mac->macaddr, sizeof(struct ethaddr)) diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c index 1bc8d893bc..c244d2a955 100644 --- a/zebra/zebra_pbr.c +++ b/zebra/zebra_pbr.c @@ -83,6 +83,27 @@ const struct message icmp_typecode_str[] = { {0} }; +const struct message icmpv6_typecode_str[] = { + { 128 << 8, "echo-request"}, + { 129 << 8, "echo-reply"}, + { 1 << 8, "no-route"}, + { (1 << 8) + 1, "communication-prohibited"}, + { (1 << 8) + 3, "address-unreachable"}, + { (1 << 8) + 4, "port-unreachable"}, + { (2 << 8), "packet-too-big"}, + { 3 << 0, "ttl-zero-during-transit"}, + { (3 << 8) + 1, "ttl-zero-during-reassembly"}, + { 4 << 0, "bad-header"}, + { (4 << 0) + 1, "unknown-header-type"}, + { (4 << 0) + 2, "unknown-option"}, + { 133 << 8, "router-solicitation"}, + { 134 << 8, "router-advertisement"}, + { 135 << 8, "neighbor-solicitation"}, + { 136 << 8, "neighbor-advertisement"}, + { 137 << 8, "redirect"}, + {0} +}; + /* definitions */ static const struct message tcp_value_str[] = { {TCP_HEADER_FIN, "FIN"}, @@ -146,10 +167,11 @@ uint32_t zebra_pbr_rules_hash_key(const void *arg) prefix_hash_key(&rule->rule.filter.src_ip)); if (rule->rule.filter.fwmark) - key = jhash_3words(rule->rule.filter.fwmark, rule->vrf_id, - rule->rule.ifindex, key); + key = jhash_2words(rule->rule.filter.fwmark, rule->vrf_id, key); else - key = jhash_2words(rule->vrf_id, rule->rule.ifindex, key); + key = jhash_1word(rule->vrf_id, key); + + key = jhash(rule->ifname, strlen(rule->ifname), key); return jhash_3words(rule->rule.filter.src_port, rule->rule.filter.dst_port, @@ -191,7 +213,7 @@ bool zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2) if (!prefix_same(&r1->rule.filter.dst_ip, &r2->rule.filter.dst_ip)) return false; - if (r1->rule.ifindex != r2->rule.ifindex) + if (strcmp(r1->rule.ifname, r2->rule.ifname) != 0) return false; if (r1->vrf_id != r2->vrf_id) @@ -203,7 +225,7 @@ bool zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2) struct pbr_rule_unique_lookup { struct zebra_pbr_rule *rule; uint32_t unique; - ifindex_t ifindex; + char ifname[INTERFACE_NAMSIZ + 1]; vrf_id_t vrf_id; }; @@ -213,7 +235,7 @@ static int pbr_rule_lookup_unique_walker(struct hash_bucket *b, void *data) struct zebra_pbr_rule *rule = b->data; if (pul->unique == rule->rule.unique - && pul->ifindex == rule->rule.ifindex + && strncmp(pul->ifname, rule->rule.ifname, INTERFACE_NAMSIZ) == 0 && pul->vrf_id == rule->vrf_id) { pul->rule = rule; return HASHWALK_ABORT; @@ -228,7 +250,7 @@ pbr_rule_lookup_unique(struct zebra_pbr_rule *zrule) struct pbr_rule_unique_lookup pul; pul.unique = zrule->rule.unique; - pul.ifindex = zrule->rule.ifindex; + strlcpy(pul.ifname, zrule->rule.ifname, INTERFACE_NAMSIZ); pul.rule = NULL; pul.vrf_id = zrule->vrf_id; hash_walk(zrouter.rules_hash, &pbr_rule_lookup_unique_walker, &pul); @@ -251,6 +273,8 @@ uint32_t zebra_pbr_ipset_hash_key(const void *arg) uint32_t *pnt = (uint32_t *)&ipset->ipset_name; uint32_t key = jhash_1word(ipset->vrf_id, 0x63ab42de); + key = jhash_1word(ipset->family, key); + return jhash2(pnt, ZEBRA_IPSET_NAME_HASH_SIZE, key); } @@ -267,6 +291,8 @@ bool zebra_pbr_ipset_hash_equal(const void *arg1, const void *arg2) return false; if (r1->vrf_id != r2->vrf_id) return false; + if (r1->family != r2->family) + return false; if (strncmp(r1->ipset_name, r2->ipset_name, ZEBRA_IPSET_NAME_SIZE)) @@ -376,6 +402,8 @@ uint32_t zebra_pbr_iptable_hash_key(const void *arg) key = jhash2(pnt, ZEBRA_IPSET_NAME_HASH_SIZE, 0x63ab42de); key = jhash_1word(iptable->fwmark, key); + key = jhash_1word(iptable->family, key); + key = jhash_1word(iptable->flow_label, key); key = jhash_1word(iptable->pkt_len_min, key); key = jhash_1word(iptable->pkt_len_max, key); key = jhash_1word(iptable->tcp_flags, key); @@ -411,6 +439,10 @@ bool zebra_pbr_iptable_hash_equal(const void *arg1, const void *arg2) if (strncmp(r1->ipset_name, r2->ipset_name, ZEBRA_IPSET_NAME_SIZE)) return false; + if (r1->family != r2->family) + return false; + if (r1->flow_label != r2->flow_label) + return false; if (r1->pkt_len_min != r2->pkt_len_min) return false; if (r1->pkt_len_max != r2->pkt_len_max) @@ -876,7 +908,8 @@ static const char *zebra_pbr_prefix2str(union prefixconstptr pu, const struct prefix *p = pu.p; char buf[PREFIX2STR_BUFFER]; - if (p->family == AF_INET && p->prefixlen == IPV4_MAX_PREFIXLEN) { + if ((p->family == AF_INET && p->prefixlen == IPV4_MAX_PREFIXLEN) || + (p->family == AF_INET6 && p->prefixlen == IPV6_MAX_PREFIXLEN)) { snprintf(str, size, "%s", inet_ntop(p->family, &p->u.prefix, buf, PREFIX2STR_BUFFER)); return str; @@ -889,6 +922,9 @@ static void zebra_pbr_display_icmp(struct vty *vty, { char decoded_str[20]; uint16_t port; + struct zebra_pbr_ipset *zpi; + + zpi = zpie->backpointer; /* range icmp type */ if (zpie->src_port_max || zpie->dst_port_max) { @@ -901,8 +937,10 @@ static void zebra_pbr_display_icmp(struct vty *vty, memset(decoded_str, 0, sizeof(decoded_str)); snprintf(decoded_str, sizeof(decoded_str), "%u/%u", zpie->src_port_min, zpie->dst_port_min); - vty_out(vty, ":icmp:%s", - lookup_msg(icmp_typecode_str, + vty_out(vty, ":%s:%s", + zpi->family == AF_INET6 ? "ipv6-icmp" : "icmp", + lookup_msg(zpi->family == AF_INET6 ? + icmpv6_typecode_str : icmp_typecode_str, port, decoded_str)); } } @@ -1012,8 +1050,9 @@ static int zebra_pbr_show_ipset_walkcb(struct hash_bucket *bucket, void *arg) struct vty *vty = uniqueipset->vty; struct zebra_ns *zns = uniqueipset->zns; - vty_out(vty, "IPset %s type %s\n", zpi->ipset_name, - zebra_pbr_ipset_type2str(zpi->type)); + vty_out(vty, "IPset %s type %s family %s\n", zpi->ipset_name, + zebra_pbr_ipset_type2str(zpi->type), + family2str(zpi->family)); unique.vty = vty; unique.zpi = zpi; unique.zns = zns; @@ -1058,9 +1097,9 @@ void zebra_pbr_show_ipset_list(struct vty *vty, char *ipsetname) vty_out(vty, "No IPset %s found\n", ipsetname); return; } - vty_out(vty, "IPset %s type %s\n", ipsetname, - zebra_pbr_ipset_type2str(zpi->type)); - + vty_out(vty, "IPset %s type %s family %s\n", ipsetname, + zebra_pbr_ipset_type2str(zpi->type), + family2str(zpi->family)); unique.vty = vty; unique.zpi = zpi; unique.zns = zns; @@ -1101,7 +1140,9 @@ static void zebra_pbr_show_iptable_unit(struct zebra_pbr_iptable *iptable, int ret; uint64_t pkts = 0, bytes = 0; - vty_out(vty, "IPtable %s action %s (%u)\n", iptable->ipset_name, + vty_out(vty, "IPtable %s family %s action %s (%u)\n", + iptable->ipset_name, + family2str(iptable->family), iptable->action == ZEBRA_IPTABLES_DROP ? "drop" : "redirect", iptable->unique); if (iptable->type == IPSET_NET_PORT || @@ -1140,6 +1181,12 @@ static void zebra_pbr_show_iptable_unit(struct zebra_pbr_iptable *iptable, iptable->filter_bm & MATCH_DSCP_INVERSE_SET ? "not" : "", iptable->dscp_value); } + if (iptable->filter_bm & (MATCH_FLOW_LABEL_SET | + MATCH_FLOW_LABEL_INVERSE_SET)) { + vty_out(vty, "\t flowlabel %s %d\n", + iptable->filter_bm & MATCH_FLOW_LABEL_INVERSE_SET ? + "not" : "", iptable->flow_label); + } if (iptable->fragment) { char val_str[10]; diff --git a/zebra/zebra_pbr.h b/zebra/zebra_pbr.h index 888d2fcfa0..e7504a3547 100644 --- a/zebra/zebra_pbr.h +++ b/zebra/zebra_pbr.h @@ -79,6 +79,9 @@ struct zebra_pbr_ipset { * but value is an enum ipset_type */ uint32_t type; + + uint8_t family; + char ipset_name[ZEBRA_IPSET_NAME_SIZE]; }; @@ -150,6 +153,9 @@ struct zebra_pbr_iptable { uint8_t protocol; uint32_t nb_interface; + uint16_t flow_label; + + uint8_t family; struct list *interface_name_list; @@ -157,6 +163,7 @@ struct zebra_pbr_iptable { }; extern const struct message icmp_typecode_str[]; +extern const struct message icmpv6_typecode_str[]; const char *zebra_pbr_ipset_type2str(uint32_t type); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index d1d56f2cdb..ff30de18a3 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -120,6 +120,7 @@ _rnode_zlog(const char *_func, vrf_id_t vrf_id, struct route_node *rn, char buf[SRCDEST2STR_BUFFER + sizeof(" (MRIB)")]; char msgbuf[512]; va_list ap; + uint32_t table = 0; va_start(ap, msgfmt); vsnprintf(msgbuf, sizeof(msgbuf), msgfmt, ap); @@ -127,15 +128,24 @@ _rnode_zlog(const char *_func, vrf_id_t vrf_id, struct route_node *rn, if (rn) { struct rib_table_info *info = srcdest_rnode_table_info(rn); + rib_dest_t *dest = NULL; + struct route_entry *re = NULL; + srcdest_rnode2str(rn, buf, sizeof(buf)); if (info->safi == SAFI_MULTICAST) strlcat(buf, " (MRIB)", sizeof(buf)); + + dest = rib_dest_from_rnode(rn); + if (dest) + re = re_list_first(&dest->routes); + if (re) + table = re->table; } else { snprintf(buf, sizeof(buf), "{(route_node *) NULL}"); } - zlog(priority, "%s: %d:%s: %s", _func, vrf_id, buf, msgbuf); + zlog(priority, "%s: (%u:%u):%s: %s", _func, vrf_id, table, buf, msgbuf); } #define rnode_debug(node, vrf_id, ...) \ @@ -489,8 +499,8 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re, srcdest_rnode2str(rn, str, sizeof(str)); flog_err(EC_ZEBRA_DP_INSTALL_FAIL, - "%u:%s: Failed to enqueue dataplane install", - re->vrf_id, str); + "%u:%u:%s: Failed to enqueue dataplane install", + re->vrf_id, re->table, str); break; } case ZEBRA_DPLANE_REQUEST_SUCCESS: @@ -758,9 +768,9 @@ static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn, if (IS_ZEBRA_DEBUG_RIB) { char buf[SRCDEST2STR_BUFFER]; srcdest_rnode2str(rn, buf, sizeof(buf)); - zlog_debug("%s(%u):%s: Adding route rn %p, re %p (%s)", - zvrf_name(zvrf), zvrf_id(zvrf), buf, rn, new, - zebra_route_string(new->type)); + zlog_debug("%s(%u:%u):%s: Adding route rn %p, re %p (%s)", + zvrf_name(zvrf), zvrf_id(zvrf), new->table, buf, rn, + new, zebra_route_string(new->type)); } /* If labeled-unicast route, install transit LSP. */ @@ -781,9 +791,9 @@ static void rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn, if (IS_ZEBRA_DEBUG_RIB) { char buf[SRCDEST2STR_BUFFER]; srcdest_rnode2str(rn, buf, sizeof(buf)); - zlog_debug("%s(%u):%s: Deleting route rn %p, re %p (%s)", - zvrf_name(zvrf), zvrf_id(zvrf), buf, rn, old, - zebra_route_string(old->type)); + zlog_debug("%s(%u:%u):%s: Deleting route rn %p, re %p (%s)", + zvrf_name(zvrf), zvrf_id(zvrf), old->table, buf, rn, + old, zebra_route_string(old->type)); } /* If labeled-unicast route, uninstall transit LSP. */ @@ -834,17 +844,17 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, srcdest_rnode2str(rn, buf, sizeof(buf)); if (new != old) zlog_debug( - "%s(%u):%s: Updating route rn %p, re %p (%s) old %p (%s)", + "%s(%u:%u):%s: Updating route rn %p, re %p (%s) old %p (%s)", zvrf_name(zvrf), zvrf_id(zvrf), - buf, rn, new, + new->table, buf, rn, new, zebra_route_string(new->type), old, zebra_route_string(old->type)); else zlog_debug( - "%s(%u):%s: Updating route rn %p, re %p (%s)", + "%s(%u:%u):%s: Updating route rn %p, re %p (%s)", zvrf_name(zvrf), zvrf_id(zvrf), - buf, rn, new, + new->table, buf, rn, new, zebra_route_string(new->type)); } @@ -874,17 +884,17 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, srcdest_rnode2str(rn, buf, sizeof(buf)); if (new != old) zlog_debug( - "%s(%u):%s: Deleting route rn %p, re %p (%s) old %p (%s) - nexthop inactive", + "%s(%u:%u):%s: Deleting route rn %p, re %p (%s) old %p (%s) - nexthop inactive", zvrf_name(zvrf), zvrf_id(zvrf), - buf, rn, new, + new->table, buf, rn, new, zebra_route_string(new->type), old, zebra_route_string(old->type)); else zlog_debug( - "%s(%u):%s: Deleting route rn %p, re %p (%s) - nexthop inactive", + "%s(%u:%u):%s: Deleting route rn %p, re %p (%s) - nexthop inactive", zvrf_name(zvrf), zvrf_id(zvrf), - buf, rn, new, + new->table, buf, rn, new, zebra_route_string(new->type)); } @@ -1018,24 +1028,29 @@ static void rib_process(struct route_node *rn) if (IS_ZEBRA_DEBUG_RIB) srcdest_rnode2str(rn, buf, sizeof(buf)); - if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug("%s(%u):%s: Processing rn %p", VRF_LOGNAME(vrf), - vrf_id, buf, rn); - /* * we can have rn's that have a NULL info pointer * (dest). As such let's not let the deref happen * additionally we know RNODE_FOREACH_RE_SAFE * will not iterate so we are ok. */ - if (dest) + if (dest) { + if (IS_ZEBRA_DEBUG_RIB_DETAILED) { + struct route_entry *re = re_list_first(&dest->routes); + + zlog_debug("%s(%u:%u):%s: Processing rn %p", + VRF_LOGNAME(vrf), vrf_id, re->table, buf, + rn); + } + old_fib = dest->selected_fib; + } RNODE_FOREACH_RE_SAFE (rn, re, next) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug( - "%s(%u):%s: Examine re %p (%s) status %x flags %x dist %d metric %d", - VRF_LOGNAME(vrf), vrf_id, buf, re, + "%s(%u:%u):%s: Examine re %p (%s) status %x flags %x dist %d metric %d", + VRF_LOGNAME(vrf), vrf_id, re->table, buf, re, zebra_route_string(re->type), re->status, re->flags, re->distance, re->metric); @@ -1131,10 +1146,20 @@ static void rib_process(struct route_node *rn) */ if (IS_ZEBRA_DEBUG_RIB_DETAILED) { + struct route_entry *entry; + + entry = old_selected + ? old_selected + : new_selected + ? new_selected + : old_fib ? old_fib + : new_fib ? new_fib : NULL; + zlog_debug( - "%s(%u):%s: After processing: old_selected %p new_selected %p old_fib %p new_fib %p", - VRF_LOGNAME(vrf), vrf_id, buf, (void *)old_selected, - (void *)new_selected, (void *)old_fib, (void *)new_fib); + "%s(%u:%u):%s: After processing: old_selected %p new_selected %p old_fib %p new_fib %p", + VRF_LOGNAME(vrf), vrf_id, entry ? entry->table : 0, buf, + (void *)old_selected, (void *)new_selected, + (void *)old_fib, (void *)new_fib); } /* Buffer ROUTE_ENTRY_CHANGED here, because it will get cleared if @@ -1456,8 +1481,8 @@ static bool rib_update_re_from_ctx(struct route_entry *re, is_selected = (re == dest->selected_fib); if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug("update_from_ctx: %s(%u):%s: %sSELECTED, re %p", - VRF_LOGNAME(vrf), re->vrf_id, dest_str, + zlog_debug("update_from_ctx: %s(%u:%u):%s: %sSELECTED, re %p", + VRF_LOGNAME(vrf), re->vrf_id, re->table, dest_str, (is_selected ? "" : "NOT "), re); /* Update zebra's nexthop FIB flag for each nexthop that was installed. @@ -1483,8 +1508,9 @@ static bool rib_update_re_from_ctx(struct route_entry *re, if (matched) { if (IS_ZEBRA_DEBUG_RIB) zlog_debug( - "%s(%u):%s update_from_ctx(): existing fib nhg, no change", - VRF_LOGNAME(vrf), re->vrf_id, dest_str); + "%s(%u:%u):%s update_from_ctx(): existing fib nhg, no change", + VRF_LOGNAME(vrf), re->vrf_id, re->table, + dest_str); goto check_backups; } else if (CHECK_FLAG(re->status, ROUTE_ENTRY_USE_FIB_NHG)) { @@ -1493,8 +1519,9 @@ static bool rib_update_re_from_ctx(struct route_entry *re, */ if (IS_ZEBRA_DEBUG_RIB) zlog_debug( - "%s(%u):%s update_from_ctx(): replacing fib nhg", - VRF_LOGNAME(vrf), re->vrf_id, dest_str); + "%s(%u:%u):%s update_from_ctx(): replacing fib nhg", + VRF_LOGNAME(vrf), re->vrf_id, re->table, + dest_str); nexthops_free(re->fib_ng.nexthop); re->fib_ng.nexthop = NULL; @@ -1504,8 +1531,9 @@ static bool rib_update_re_from_ctx(struct route_entry *re, changed_p = true; } else { if (IS_ZEBRA_DEBUG_RIB) - zlog_debug("%s(%u):%s update_from_ctx(): no fib nhg", - VRF_LOGNAME(vrf), re->vrf_id, dest_str); + zlog_debug("%s(%u:%u):%s update_from_ctx(): no fib nhg", + VRF_LOGNAME(vrf), re->vrf_id, re->table, + dest_str); } /* @@ -1532,9 +1560,9 @@ static bool rib_update_re_from_ctx(struct route_entry *re, if (matched) { if (IS_ZEBRA_DEBUG_RIB) zlog_debug( - "%s(%u):%s update_from_ctx(): rib nhg matched, changed '%s'", - VRF_LOGNAME(vrf), re->vrf_id, dest_str, - (changed_p ? "true" : "false")); + "%s(%u:%u):%s update_from_ctx(): rib nhg matched, changed '%s'", + VRF_LOGNAME(vrf), re->vrf_id, re->table, + dest_str, (changed_p ? "true" : "false")); goto check_backups; } @@ -1545,8 +1573,8 @@ no_nexthops: */ if (IS_ZEBRA_DEBUG_RIB) zlog_debug( - "%s(%u):%s update_from_ctx(): changed %s, adding new fib nhg%s", - VRF_LOGNAME(vrf), re->vrf_id, dest_str, + "%s(%u:%u):%s update_from_ctx(): changed %s, adding new fib nhg%s", + VRF_LOGNAME(vrf), re->vrf_id, re->table, dest_str, (changed_p ? "true" : "false"), ctxnhg->nexthop != NULL ? "" : " (empty)"); @@ -1722,9 +1750,10 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) zlog_debug( - "%s(%u):%s Processing dplane result ctx %p, op %s result %s", - VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), dest_str, - ctx, dplane_op2str(op), dplane_res2str(status)); + "%s(%u:%u):%s Processing dplane result ctx %p, op %s result %s", + VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), + dplane_ctx_get_table(ctx), dest_str, ctx, + dplane_op2str(op), dplane_res2str(status)); /* * Update is a bit of a special case, where we may have both old and new @@ -1774,10 +1803,10 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) if (old_re->dplane_sequence != dplane_ctx_get_old_seq(ctx)) { if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) zlog_debug( - "%s(%u):%s Stale dplane result for old_re %p", + "%s(%u:%u):%s Stale dplane result for old_re %p", VRF_LOGNAME(vrf), - dplane_ctx_get_vrf(ctx), dest_str, - old_re); + dplane_ctx_get_vrf(ctx), old_re->table, + dest_str, old_re); } else UNSET_FLAG(old_re->status, ROUTE_ENTRY_QUEUED); } @@ -1815,9 +1844,11 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) if (!fib_changed) { if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) zlog_debug( - "%s(%u):%s no fib change for re", + "%s(%u:%u):%s no fib change for re", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), + dplane_ctx_get_table( + ctx), dest_str); } @@ -1854,8 +1885,9 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) zsend_route_notify_owner(re, dest_pfx, ZAPI_ROUTE_FAIL_INSTALL); - zlog_warn("%s(%u):%s: Route install failed", + zlog_warn("%s(%u:%u):%s: Route install failed", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), + dplane_ctx_get_table(ctx), prefix2str(dest_pfx, dest_str, sizeof(dest_str))); } @@ -1883,8 +1915,9 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) zsend_route_notify_owner_ctx(ctx, ZAPI_ROUTE_REMOVE_FAIL); - zlog_warn("%s(%u):%s: Route Deletion failure", + zlog_warn("%s(%u:%u):%s: Route Deletion failure", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), + dplane_ctx_get_table(ctx), prefix2str(dest_pfx, dest_str, sizeof(dest_str))); } @@ -1981,9 +2014,9 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) if (rn == NULL) { if (debug_p) { zlog_debug( - "Failed to process dplane notification: no routes for %s(%u):%s", + "Failed to process dplane notification: no routes for %s(%u:%u):%s", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dest_str); + dplane_ctx_get_table(ctx), dest_str); } goto done; } @@ -1992,9 +2025,9 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) srcdest_rnode_prefixes(rn, &dest_pfx, &src_pfx); if (debug_p) - zlog_debug("%s(%u):%s Processing dplane notif ctx %p", - VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), dest_str, - ctx); + zlog_debug("%s(%u:%u):%s Processing dplane notif ctx %p", + VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), + dplane_ctx_get_table(ctx), dest_str, ctx); /* * Take a pass through the routes, look for matches with the context @@ -2009,9 +2042,9 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) if (re == NULL) { if (debug_p) zlog_debug( - "%s(%u):%s Unable to process dplane notification: no entry for type %s", + "%s(%u:%u):%s Unable to process dplane notification: no entry for type %s", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dest_str, + dplane_ctx_get_table(ctx), dest_str, zebra_route_string(dplane_ctx_get_type(ctx))); goto done; @@ -2043,18 +2076,20 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); if (debug_p) zlog_debug( - "%s(%u):%s dplane notif, uninstalled type %s route", + "%s(%u:%u):%s dplane notif, uninstalled type %s route", VRF_LOGNAME(vrf), - dplane_ctx_get_vrf(ctx), dest_str, + dplane_ctx_get_vrf(ctx), + dplane_ctx_get_table(ctx), dest_str, zebra_route_string( dplane_ctx_get_type(ctx))); } else { /* At least report on the event. */ if (debug_p) zlog_debug( - "%s(%u):%s dplane notif, but type %s not selected_fib", + "%s(%u:%u):%s dplane notif, but type %s not selected_fib", VRF_LOGNAME(vrf), - dplane_ctx_get_vrf(ctx), dest_str, + dplane_ctx_get_vrf(ctx), + dplane_ctx_get_table(ctx), dest_str, zebra_route_string( dplane_ctx_get_type(ctx))); } @@ -2078,9 +2113,9 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) if (!fib_changed) { if (debug_p) zlog_debug( - "%s(%u):%s dplane notification: rib_update returns FALSE", + "%s(%u:%u):%s dplane notification: rib_update returns FALSE", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dest_str); + dplane_ctx_get_table(ctx), dest_str); } /* @@ -2095,9 +2130,9 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) if (start_count > 0 && end_count > 0) { if (debug_p) zlog_debug( - "%s(%u):%s applied nexthop changes from dplane notification", + "%s(%u:%u):%s applied nexthop changes from dplane notification", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dest_str); + dplane_ctx_get_table(ctx), dest_str); /* Changed nexthops - update kernel/others */ dplane_route_notif_update(rn, re, @@ -2106,9 +2141,9 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) } else if (start_count == 0 && end_count > 0) { if (debug_p) zlog_debug( - "%s(%u):%s installed transition from dplane notification", + "%s(%u:%u):%s installed transition from dplane notification", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dest_str); + dplane_ctx_get_table(ctx), dest_str); /* We expect this to be the selected route, so we want * to tell others about this transition. @@ -2124,9 +2159,9 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) } else if (start_count > 0 && end_count == 0) { if (debug_p) zlog_debug( - "%s(%u):%s un-installed transition from dplane notification", + "%s(%u:%u):%s un-installed transition from dplane notification", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dest_str); + dplane_ctx_get_table(ctx), dest_str); /* Transition from _something_ installed to _nothing_ * installed. @@ -2182,17 +2217,20 @@ static void process_subq_route(struct listnode *lnode, uint8_t qindex) rnode = listgetdata(lnode); dest = rib_dest_from_rnode(rnode); - if (dest) - zvrf = rib_dest_vrf(dest); + assert(dest); + + zvrf = rib_dest_vrf(dest); rib_process(rnode); if (IS_ZEBRA_DEBUG_RIB_DETAILED) { + struct route_entry *re = re_list_first(&dest->routes); char buf[SRCDEST2STR_BUFFER]; srcdest_rnode2str(rnode, buf, sizeof(buf)); - zlog_debug("%s(%u):%s: rn %p dequeued from sub-queue %u", - zvrf_name(zvrf), zvrf_id(zvrf), buf, rnode, qindex); + zlog_debug("%s(%u:%u):%s: rn %p dequeued from sub-queue %u", + zvrf_name(zvrf), zvrf_id(zvrf), re ? re->table : 0, buf, + rnode, qindex); } if (rnode->info) @@ -3003,7 +3041,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, unsigned short instance, int flags, struct prefix *p, struct prefix_ipv6 *src_p, const struct nexthop *nh, uint32_t nhe_id, uint32_t table_id, uint32_t metric, - uint8_t distance, bool fromkernel) + uint8_t distance, bool fromkernel, bool connected_down) { struct route_table *table; struct route_node *rn; @@ -3125,7 +3163,8 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, rn, fib, zebra_route_string(fib->type)); } - if (allow_delete) { + if (allow_delete + || CHECK_FLAG(dest->flags, RIB_ROUTE_ANY_QUEUED)) { UNSET_FLAG(fib->status, ROUTE_ENTRY_INSTALLED); /* Unset flags. */ for (rtnh = fib->nhe->nhg.nexthop; rtnh; @@ -3210,6 +3249,19 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, rib_delnode(rn, same); } + /* + * This is to force an immediate re-eval of this particular + * node via nexthop tracking. Why? Because there are scenarios + * where the interface is flapping and the normal queuing methodology + * will cause down/up events to very very rarely be combined into + * a non-event from nexthop tracking perspective. Leading + * to some fun timing situations with upper level routing protocol + * trying to and failing to install routes during this blip. Especially + * when zebra is under load. + */ + if (connected_down) + zebra_rib_evaluate_rn_nexthops(rn, + zebra_router_get_next_sequence()); route_unlock_node(rn); return; } diff --git a/zebra/zserv.c b/zebra/zserv.c index cded6ea12b..4c8656af0d 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -1294,17 +1294,6 @@ DEFUN (show_zebra_client_summary, return CMD_SUCCESS; } -#if defined(HANDLE_ZAPI_FUZZING) -void zserv_read_file(char *input) -{ - int fd; - - fd = open(input, O_RDONLY | O_NONBLOCK); - - zserv_client_create(fd); -} -#endif - void zserv_init(void) { /* Client list init. */ diff --git a/zebra/zserv.h b/zebra/zserv.h index 54e840cd56..c60799b8ba 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -375,10 +375,6 @@ extern void zserv_close_client(struct zserv *client); void zserv_log_message(const char *errmsg, struct stream *msg, struct zmsghdr *hdr); -#if defined(HANDLE_ZAPI_FUZZING) -extern void zserv_read_file(char *input); -#endif - /* TODO */ __attribute__((__noreturn__)) int zebra_finalize(struct thread *event); |
