]> git.proxmox.com Git - mirror_frr.git/blobdiff - zebra/zapi_msg.c
Merge pull request #5789 from donaldsharp/bgp_ebgp_reason
[mirror_frr.git] / zebra / zapi_msg.c
index 18b733f884fdaf8be0ec9133d71a5f8c345bad3e..4d0e34561a5a8854abc889fca35eb41cc3071951 100644 (file)
@@ -41,6 +41,7 @@
 #include "lib/vrf.h"
 #include "lib/libfrr.h"
 #include "lib/sockopt.h"
+#include "lib/lib_errors.h"
 
 #include "zebra/zebra_router.h"
 #include "zebra/rib.h"
@@ -64,6 +65,7 @@
 #include "zebra/zapi_msg.h"
 #include "zebra/zebra_errors.h"
 #include "zebra/zebra_mlag.h"
+#include "zebra/connected.h"
 
 /* Encoding helpers -------------------------------------------------------- */
 
@@ -147,6 +149,25 @@ static int zserv_encode_nexthop(struct stream *s, struct nexthop *nexthop)
        return 1;
 }
 
+/*
+ * Zebra error addition adds error type.
+ *
+ *
+ *  0                   1
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |      enum zebra_error_types   |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ */
+static void zserv_encode_error(struct stream *s, enum zebra_error_types error)
+{
+       stream_put(s, &error, sizeof(error));
+
+       /* Write packet size. */
+       stream_putw_at(s, 0, stream_get_endp(s));
+}
+
 /* Send handlers ----------------------------------------------------------- */
 
 /* Interface is added. Send ZEBRA_INTERFACE_ADD to client. */
@@ -1397,8 +1418,9 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
        struct nexthop *nexthop = NULL;
        struct nexthop_group *ng = NULL;
        int i, ret;
-       vrf_id_t vrf_id = 0;
+       vrf_id_t vrf_id;
        struct ipaddr vtep_ip;
+       struct interface *ifp;
 
        s = msg;
        if (zapi_route_decode(s, &api) < 0) {
@@ -1453,6 +1475,8 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
                api_nh = &api.nexthops[i];
                ifindex_t ifindex = 0;
 
+               nexthop = NULL;
+
                if (IS_ZEBRA_DEBUG_RECV)
                        zlog_debug("nh type %d", api_nh->type);
 
@@ -1491,6 +1515,9 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
                                &api_nh->gate.ipv4, NULL, ifindex,
                                api_nh->vrf_id);
 
+                       ifp = if_lookup_by_index(ifindex, api_nh->vrf_id);
+                       if (ifp && connected_is_unnumbered(ifp))
+                               SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK);
                        /* Special handling for IPv4 routes sourced from EVPN:
                         * the nexthop and associated MAC need to be installed.
                         */
@@ -1593,6 +1620,14 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
        if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
                src_p = &api.src_prefix;
 
+       if (api.safi != SAFI_UNICAST && api.safi != SAFI_MULTICAST) {
+               flog_warn(EC_LIB_ZAPI_MISSMATCH,
+                         "%s: Received safi: %d but we can only accept UNICAST or MULTICAST",
+                         __func__, api.safi);
+               nexthop_group_delete(&ng);
+               XFREE(MTYPE_RE, re);
+               return;
+       }
        ret = rib_add_multipath(afi, api.safi, &api.prefix, src_p, re, ng);
 
        /* Stats */
@@ -1740,6 +1775,8 @@ static void zread_hello(ZAPI_HANDLER_ARGS)
                client->instance = instance;
        }
 
+       /* Graceful restart processing for client connect */
+       zebra_gr_client_reconnect(client);
        zsend_capabilities(client, zvrf);
        zebra_vrf_update_all(client);
 stream_failure:
@@ -2136,6 +2173,7 @@ static void zread_pseudowire(ZAPI_HANDLER_ARGS)
 
        /* Get data. */
        STREAM_GET(ifname, s, IF_NAMESIZE);
+       ifname[IF_NAMESIZE - 1] = '\0';
        STREAM_GETL(s, ifindex);
        STREAM_GETL(s, type);
        STREAM_GETL(s, af);
@@ -2243,6 +2281,12 @@ static void zread_vrf_label(ZAPI_HANDLER_ARGS)
        s = msg;
        STREAM_GETL(s, nlabel);
        STREAM_GETC(s, afi);
+
+       if (!(IS_VALID_AFI(afi))) {
+               zlog_warn("Invalid AFI for VRF label: %u", afi);
+               return;
+       }
+
        if (nlabel == zvrf->label[afi]) {
                /*
                 * Nothing to do here move along
@@ -2362,14 +2406,19 @@ static inline void zread_rule(ZAPI_HANDLER_ARGS)
 
                if (!(zpr.rule.filter.src_ip.family == AF_INET
                      || zpr.rule.filter.src_ip.family == AF_INET6)) {
-                       zlog_warn("Unsupported PBR source IP family: %s\n",
-                                 family2str(zpr.rule.filter.src_ip.family));
+                       zlog_warn(
+                               "Unsupported PBR source IP family: %s (%" PRIu8
+                               ")\n",
+                               family2str(zpr.rule.filter.src_ip.family),
+                               zpr.rule.filter.src_ip.family);
                        return;
                }
                if (!(zpr.rule.filter.dst_ip.family == AF_INET
                      || zpr.rule.filter.dst_ip.family == AF_INET6)) {
-                       zlog_warn("Unsupported PBR dest IP family: %s\n",
-                                 family2str(zpr.rule.filter.dst_ip.family));
+                       zlog_warn("Unsupported PBR IP family: %s (%" PRIu8
+                                 ")\n",
+                                 family2str(zpr.rule.filter.dst_ip.family),
+                                 zpr.rule.filter.dst_ip.family);
                        return;
                }
 
@@ -2430,6 +2479,7 @@ static inline void zread_ipset_entry(ZAPI_HANDLER_ARGS)
                zpi.sock = client->sock;
                STREAM_GETL(s, zpi.unique);
                STREAM_GET(&ipset.ipset_name, s, ZEBRA_IPSET_NAME_SIZE);
+               ipset.ipset_name[ZEBRA_IPSET_NAME_SIZE - 1] = '\0';
                STREAM_GETC(s, zpi.src.family);
                STREAM_GETC(s, zpi.src.prefixlen);
                STREAM_GET(&zpi.src.u.prefix, s, prefix_blen(&zpi.src));
@@ -2461,6 +2511,13 @@ static inline void zread_ipset_entry(ZAPI_HANDLER_ARGS)
                /* calculate backpointer */
                zpi.backpointer =
                        zebra_pbr_lookup_ipset_pername(ipset.ipset_name);
+
+               if (!zpi.backpointer) {
+                       zlog_warn("ipset name specified: %s does not exist",
+                                 ipset.ipset_name);
+                       goto stream_failure;
+               }
+
                if (hdr->command == ZEBRA_IPSET_ENTRY_ADD)
                        zebra_pbr_add_ipset_entry(&zpi);
                else
@@ -2473,40 +2530,72 @@ stream_failure:
 
 static inline void zread_iptable(ZAPI_HANDLER_ARGS)
 {
-       struct zebra_pbr_iptable zpi;
+       struct zebra_pbr_iptable *zpi =
+               XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_iptable));
        struct stream *s;
 
        s = msg;
 
-       memset(&zpi, 0, sizeof(zpi));
-
-       zpi.interface_name_list = list_new();
-       zpi.sock = client->sock;
-       zpi.vrf_id = zvrf->vrf->vrf_id;
-       STREAM_GETL(s, zpi.unique);
-       STREAM_GETL(s, zpi.type);
-       STREAM_GETL(s, zpi.filter_bm);
-       STREAM_GETL(s, zpi.action);
-       STREAM_GETL(s, zpi.fwmark);
-       STREAM_GET(&zpi.ipset_name, s, ZEBRA_IPSET_NAME_SIZE);
-       STREAM_GETW(s, zpi.pkt_len_min);
-       STREAM_GETW(s, zpi.pkt_len_max);
-       STREAM_GETW(s, zpi.tcp_flags);
-       STREAM_GETW(s, zpi.tcp_mask_flags);
-       STREAM_GETC(s, zpi.dscp_value);
-       STREAM_GETC(s, zpi.fragment);
-       STREAM_GETC(s, zpi.protocol);
-       STREAM_GETL(s, zpi.nb_interface);
-       zebra_pbr_iptable_update_interfacelist(s, &zpi);
+       zpi->interface_name_list = list_new();
+       zpi->sock = client->sock;
+       zpi->vrf_id = zvrf->vrf->vrf_id;
+       STREAM_GETL(s, zpi->unique);
+       STREAM_GETL(s, zpi->type);
+       STREAM_GETL(s, zpi->filter_bm);
+       STREAM_GETL(s, zpi->action);
+       STREAM_GETL(s, zpi->fwmark);
+       STREAM_GET(&zpi->ipset_name, s, ZEBRA_IPSET_NAME_SIZE);
+       STREAM_GETW(s, zpi->pkt_len_min);
+       STREAM_GETW(s, zpi->pkt_len_max);
+       STREAM_GETW(s, zpi->tcp_flags);
+       STREAM_GETW(s, zpi->tcp_mask_flags);
+       STREAM_GETC(s, zpi->dscp_value);
+       STREAM_GETC(s, zpi->fragment);
+       STREAM_GETC(s, zpi->protocol);
+       STREAM_GETL(s, zpi->nb_interface);
+       zebra_pbr_iptable_update_interfacelist(s, zpi);
 
        if (hdr->command == ZEBRA_IPTABLE_ADD)
-               zebra_pbr_add_iptable(&zpi);
+               zebra_pbr_add_iptable(zpi);
        else
-               zebra_pbr_del_iptable(&zpi);
+               zebra_pbr_del_iptable(zpi);
+
 stream_failure:
+       zebra_pbr_iptable_free(zpi);
+       zpi = NULL;
        return;
 }
 
+static void zsend_error_msg(struct zserv *client, enum zebra_error_types error,
+                           struct zmsghdr *bad_hdr)
+{
+
+       struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+
+       zclient_create_header(s, ZEBRA_ERROR, bad_hdr->vrf_id);
+
+       zserv_encode_error(s, error);
+
+       client->error_cnt++;
+       zserv_send_message(client, s);
+}
+
+static void zserv_error_no_vrf(ZAPI_HANDLER_ARGS)
+{
+       if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV)
+               zlog_debug("ZAPI message specifies unknown VRF: %d",
+                          hdr->vrf_id);
+
+       zsend_error_msg(client, ZEBRA_NO_VRF, hdr);
+}
+
+static void zserv_error_invalid_msg_type(ZAPI_HANDLER_ARGS)
+{
+       zlog_info("Zebra received unknown command %d", hdr->command);
+
+       zsend_error_msg(client, ZEBRA_INVALID_MSG_TYPE, hdr);
+}
+
 void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
        [ZEBRA_ROUTER_ID_ADD] = zread_router_id_add,
        [ZEBRA_ROUTER_ID_DELETE] = zread_router_id_delete,
@@ -2581,6 +2670,7 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
        [ZEBRA_MLAG_CLIENT_REGISTER] = zebra_mlag_client_register,
        [ZEBRA_MLAG_CLIENT_UNREGISTER] = zebra_mlag_client_unregister,
        [ZEBRA_MLAG_FORWARD_MSG] = zebra_mlag_forward_client_msg,
+       [ZEBRA_CLIENT_CAPABILITIES] = zread_client_capabilities
 };
 
 #if defined(HANDLE_ZAPI_FUZZING)
@@ -2611,6 +2701,14 @@ void zserv_handle_commands(struct zserv *client, struct stream *msg)
        struct zmsghdr hdr;
        struct zebra_vrf *zvrf;
 
+       if (STREAM_READABLE(msg) > ZEBRA_MAX_PACKET_SIZ) {
+               if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV)
+                       zlog_debug(
+                               "ZAPI message is %zu bytes long but the maximum packet size is %u; dropping",
+                               STREAM_READABLE(msg), ZEBRA_MAX_PACKET_SIZ);
+               return;
+       }
+
        zapi_parse_header(msg, &hdr);
 
        if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV)
@@ -2624,16 +2722,12 @@ void zserv_handle_commands(struct zserv *client, struct stream *msg)
 
        /* lookup vrf */
        zvrf = zebra_vrf_lookup_by_id(hdr.vrf_id);
-       if (!zvrf) {
-               if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV)
-                       zlog_debug("ZAPI message specifies unknown VRF: %d",
-                                  hdr.vrf_id);
-               return;
-       }
+       if (!zvrf)
+               return zserv_error_no_vrf(client, &hdr, msg, zvrf);
 
        if (hdr.command >= array_size(zserv_handlers)
            || zserv_handlers[hdr.command] == NULL)
-               zlog_info("Zebra received unknown command %d", hdr.command);
-       else
-               zserv_handlers[hdr.command](client, &hdr, msg, zvrf);
+               return zserv_error_invalid_msg_type(client, &hdr, msg, zvrf);
+
+       zserv_handlers[hdr.command](client, &hdr, msg, zvrf);
 }