]> git.puffer.fish Git - mirror/frr.git/commitdiff
lib, zebra: add support for sending ARP requests
authorJakub Urbańczyk <xthaid@gmail.com>
Thu, 6 Aug 2020 11:07:01 +0000 (13:07 +0200)
committerJakub Urbańczyk <xthaid@gmail.com>
Wed, 12 Aug 2020 21:19:58 +0000 (23:19 +0200)
We can make the Linux kernel send an ARP/NDP request by adding
a neighbour with the 'NUD_INCOMPLETE' state and the 'NTF_USE' flag.

This commit adds new dataplane operation as well as new zapi message
to allow other daemons send ARP/NDP requests.

Signed-off-by: Jakub Urbańczyk <xthaid@gmail.com>
13 files changed:
doc/developer/zebra.rst
doc/user/sharp.rst
lib/log.c
lib/zclient.c
lib/zclient.h
zebra/kernel_netlink.c
zebra/kernel_socket.c
zebra/rt_netlink.c
zebra/zapi_msg.c
zebra/zebra_dplane.c
zebra/zebra_dplane.h
zebra/zebra_nhg.c
zebra/zebra_rib.c

index edd8b9ae299bf74ba42507d8f472cb43b6858905..d51cbc9a14bae2592b7577dc6b7b9a82aaf1bfe0 100644 (file)
@@ -382,9 +382,11 @@ Zebra Protocol Commands
 +------------------------------------+-------+
 | ZEBRA_OPAQUE_UNREGISTER            | 109   |
 +------------------------------------+-------+
+| ZEBRA_NEIGH_DISCOVER               | 110   |
++------------------------------------+-------+
 
 Dataplane batching
-=========================
+==================
 
 Dataplane batching is an optimization feature that reduces the processing 
 time involved in the user space to kernel space transition for every message we
index 5a27be22b9c84ce5cc56202de81ea487219b4901..57ef141c7e8a9c89a6dd0434c0bdc45351fb5a4b 100644 (file)
@@ -138,3 +138,9 @@ keyword. At present, no sharp commands will be preserved in the config.
 
    Remove a test zapi client session that was created with the
    specified session id.
+
+.. index:: sharp neigh discover
+.. clicmd:: sharp neigh discover [vrf NAME] <A.B.C.D|X:X::X:X> IFNAME
+
+   Send an ARP/NDP request to trigger the addition of a neighbor in the ARP
+   table.
index 202d6d858fca113eca58db68a78bdd79fd0ac9e6..40541850192f1f4964e56c4d42a4f6fd9cca6688 100644 (file)
--- a/lib/log.c
+++ b/lib/log.c
@@ -451,7 +451,8 @@ static const struct zebra_desc_table command_types[] = {
        DESC_ENTRY(ZEBRA_CLIENT_CAPABILITIES),
        DESC_ENTRY(ZEBRA_OPAQUE_MESSAGE),
        DESC_ENTRY(ZEBRA_OPAQUE_REGISTER),
-       DESC_ENTRY(ZEBRA_OPAQUE_UNREGISTER)};
+       DESC_ENTRY(ZEBRA_OPAQUE_UNREGISTER),
+       DESC_ENTRY(ZEBRA_NEIGH_DISCOVER)};
 #undef DESC_ENTRY
 
 static const struct zebra_desc_table unknown = {0, "unknown", '?'};
index 6449fe15b9e3b225f6ed6bc557d09cc4223af0f4..808aa18bbeb8f08ed3938e06db91303487123380 100644 (file)
@@ -3953,3 +3953,23 @@ int32_t zapi_capabilities_decode(struct stream *s, struct zapi_cap *api)
 stream_failure:
        return 0;
 }
+
+int zclient_send_neigh_discovery_req(struct zclient *zclient,
+                                    const struct interface *ifp,
+                                    const struct prefix *p)
+{
+       struct stream *s;
+
+       s = zclient->obuf;
+       stream_reset(s);
+
+       zclient_create_header(s, ZEBRA_NEIGH_DISCOVER, ifp->vrf_id);
+       stream_putl(s, ifp->ifindex);
+
+       stream_putc(s, p->family);
+       stream_putc(s, p->prefixlen);
+       stream_put(s, &p->u.prefix, prefix_blen(p));
+
+       stream_putw_at(s, 0, stream_get_endp(s));
+       return zclient_send_message(zclient);
+}
index bcdae85823c2571d2d955c11d5f49cdb57292368..dab384d5ec247bb4044e7a420228328f983ffd55 100644 (file)
@@ -214,6 +214,7 @@ typedef enum {
        ZEBRA_OPAQUE_MESSAGE,
        ZEBRA_OPAQUE_REGISTER,
        ZEBRA_OPAQUE_UNREGISTER,
+       ZEBRA_NEIGH_DISCOVER,
 } zebra_message_types_t;
 
 enum zebra_error_types {
@@ -956,6 +957,10 @@ enum zapi_opaque_registry {
  */
 extern int zclient_send_hello(struct zclient *client);
 
+extern int zclient_send_neigh_discovery_req(struct zclient *zclient,
+                                           const struct interface *ifp,
+                                           const struct prefix *p);
+
 #ifdef __cplusplus
 }
 #endif
index b04076b945f08d9cd96e4134e3525aa01236a242..d0c1bc812de4d2c102d46700cd6df0fd9e669b0f 100644 (file)
@@ -1417,6 +1417,7 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth,
        case DPLANE_OP_NEIGH_DELETE:
        case DPLANE_OP_VTEP_ADD:
        case DPLANE_OP_VTEP_DELETE:
+       case DPLANE_OP_NEIGH_DISCOVER:
                return netlink_put_neigh_update_msg(bth, ctx);
 
        case DPLANE_OP_RULE_ADD:
index 9e56e2988dddf292c77fdbc2b2fd5c540e9759db..4c29b999f0a013c8f05a440ab781a3328a4a4d90 100644 (file)
@@ -1526,6 +1526,7 @@ void kernel_update_multi(struct dplane_ctx_q *ctx_list)
                case DPLANE_OP_NEIGH_DELETE:
                case DPLANE_OP_VTEP_ADD:
                case DPLANE_OP_VTEP_DELETE:
+               case DPLANE_OP_NEIGH_DISCOVER:
                        res = kernel_neigh_update_ctx(ctx);
                        break;
 
index 190af3f59d9795991267837bf0e994576aba013f..4a6839d3b180c363606f14c871d7d62b567eac5b 100644 (file)
@@ -147,6 +147,8 @@ static uint8_t neigh_flags_to_netlink(uint8_t dplane_flags)
                flags |= NTF_EXT_LEARNED;
        if (dplane_flags & DPLANE_NTF_ROUTER)
                flags |= NTF_ROUTER;
+       if (dplane_flags & DPLANE_NTF_USE)
+               flags |= NTF_USE;
 
        return flags;
 }
@@ -166,6 +168,8 @@ static uint16_t neigh_state_to_netlink(uint16_t dplane_state)
                state |= NUD_NOARP;
        if (dplane_state & DPLANE_NUD_PROBE)
                state |= NUD_PROBE;
+       if (dplane_state & DPLANE_NUD_INCOMPLETE)
+               state |= NUD_INCOMPLETE;
 
        return state;
 }
@@ -3631,6 +3635,7 @@ static ssize_t netlink_neigh_msg_encoder(struct zebra_dplane_ctx *ctx,
        switch (dplane_ctx_get_op(ctx)) {
        case DPLANE_OP_NEIGH_INSTALL:
        case DPLANE_OP_NEIGH_UPDATE:
+       case DPLANE_OP_NEIGH_DISCOVER:
                ret = netlink_neigh_update_ctx(ctx, RTM_NEWNEIGH, buf, buflen);
                break;
        case DPLANE_OP_NEIGH_DELETE:
index 17114f820c0d73e3f323d2a8288b2ce0345b03f5..fbed99dc5934b36068551034bdadf624f1f1f9bc 100644 (file)
@@ -2962,6 +2962,41 @@ stream_failure:
        return;
 }
 
+static inline void zread_neigh_discover(ZAPI_HANDLER_ARGS)
+{
+       struct stream *s;
+       ifindex_t ifindex;
+       struct interface *ifp;
+       struct prefix p;
+       struct ipaddr ip;
+
+       s = msg;
+
+       STREAM_GETL(s, ifindex);
+
+       ifp = if_lookup_by_index_per_ns(zvrf->zns, ifindex);
+       if (!ifp) {
+               zlog_debug("Failed to lookup ifindex: %u", ifindex);
+               return;
+       }
+
+       STREAM_GETC(s, p.family);
+       STREAM_GETC(s, p.prefixlen);
+       STREAM_GET(&p.u.prefix, s, prefix_blen(&p));
+
+       if (p.family == AF_INET)
+               SET_IPADDR_V4(&ip);
+       else
+               SET_IPADDR_V6(&ip);
+
+       memcpy(&ip.ip.addr, &p.u.prefix, prefix_blen(&p));
+
+       dplane_neigh_discover(ifp, &ip);
+
+stream_failure:
+       return;
+}
+
 static void zsend_error_msg(struct zserv *client, enum zebra_error_types error,
                            struct zmsghdr *bad_hdr)
 {
@@ -3065,8 +3100,8 @@ 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
-};
+       [ZEBRA_CLIENT_CAPABILITIES] = zread_client_capabilities,
+       [ZEBRA_NEIGH_DISCOVER] = zread_neigh_discover};
 
 #if defined(HANDLE_ZAPI_FUZZING)
 extern struct zebra_privs_t zserv_privs;
index d34e1433ce53d5a099a7fbe44a6b72b9832a0f4a..8ab7a7f5bc23e6b29360fb51aada6ca36404dbb3 100644 (file)
@@ -185,7 +185,7 @@ struct dplane_mac_info {
 };
 
 /*
- * EVPN neighbor info for the dataplane
+ * Neighbor info for the dataplane
  */
 struct dplane_neigh_info {
        struct ipaddr ip_addr;
@@ -607,6 +607,7 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx)
        case DPLANE_OP_RULE_ADD:
        case DPLANE_OP_RULE_DELETE:
        case DPLANE_OP_RULE_UPDATE:
+       case DPLANE_OP_NEIGH_DISCOVER:
        case DPLANE_OP_NONE:
                break;
        }
@@ -839,6 +840,10 @@ const char *dplane_op2str(enum dplane_op_e op)
        case DPLANE_OP_RULE_UPDATE:
                ret = "RULE_UPDATE";
                break;
+
+       case DPLANE_OP_NEIGH_DISCOVER:
+               ret = "NEIGH_DISCOVER";
+               break;
        }
 
        return ret;
@@ -3223,8 +3228,19 @@ enum zebra_dplane_result dplane_vtep_delete(const struct interface *ifp,
        return result;
 }
 
+enum zebra_dplane_result dplane_neigh_discover(const struct interface *ifp,
+                                              const struct ipaddr *ip)
+{
+       enum zebra_dplane_result result;
+
+       result = neigh_update_internal(DPLANE_OP_NEIGH_DISCOVER, ifp, NULL, ip,
+                                      DPLANE_NTF_USE, DPLANE_NUD_INCOMPLETE, 0);
+
+       return result;
+}
+
 /*
- * Common helper api for evpn neighbor updates
+ * Common helper api for neighbor updates
  */
 static enum zebra_dplane_result
 neigh_update_internal(enum dplane_op_e op,
@@ -3243,9 +3259,8 @@ neigh_update_internal(enum dplane_op_e op,
                char buf1[ETHER_ADDR_STRLEN], buf2[PREFIX_STRLEN];
 
                zlog_debug("init neigh ctx %s: ifp %s, mac %s, ip %s",
-                          dplane_op2str(op),
+                          dplane_op2str(op), ifp->name,
                           prefix_mac2str(mac, buf1, sizeof(buf1)),
-                          ifp->name,
                           ipaddr2str(ip, buf2, sizeof(buf2)));
        }
 
@@ -3446,7 +3461,9 @@ int dplane_show_provs_helper(struct vty *vty, bool detailed)
                out_max = atomic_load_explicit(&prov->dp_out_max,
                                               memory_order_relaxed);
 
-               vty_out(vty, "%s (%u): in: %"PRIu64", q_max: %"PRIu64", out: %"PRIu64", q_max: %"PRIu64"\n",
+               vty_out(vty,
+                       "%s (%u): in: %" PRIu64 ", q_max: %" PRIu64
+                       ", out: %" PRIu64 ", q_max: %" PRIu64 "\n",
                        prov->dp_name, prov->dp_id, in, in_max, out, out_max);
 
                DPLANE_LOCK();
@@ -3780,6 +3797,7 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx)
        case DPLANE_OP_NEIGH_DELETE:
        case DPLANE_OP_VTEP_ADD:
        case DPLANE_OP_VTEP_DELETE:
+       case DPLANE_OP_NEIGH_DISCOVER:
                ipaddr2str(dplane_ctx_neigh_get_ipaddr(ctx), buf,
                           sizeof(buf));
 
@@ -3886,6 +3904,7 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx)
        case DPLANE_OP_NEIGH_DELETE:
        case DPLANE_OP_VTEP_ADD:
        case DPLANE_OP_VTEP_DELETE:
+       case DPLANE_OP_NEIGH_DISCOVER:
                if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
                        atomic_fetch_add_explicit(&zdplane_info.dg_neigh_errors,
                                                  1, memory_order_relaxed);
index 3b5eda248675ca9ea11ea376508d57422b2852da..c68a617f38dd4f6b57852d98a6a6ad5ee9ae7624 100644 (file)
@@ -149,6 +149,9 @@ enum dplane_op_e {
        DPLANE_OP_RULE_ADD,
        DPLANE_OP_RULE_DELETE,
        DPLANE_OP_RULE_UPDATE,
+
+       /* Link layer address discovery */
+       DPLANE_OP_NEIGH_DISCOVER,
 };
 
 /*
@@ -160,12 +163,14 @@ enum dplane_op_e {
 /* Neighbor cache flags */
 #define DPLANE_NTF_EXT_LEARNED    0x01
 #define DPLANE_NTF_ROUTER         0x02
+#define DPLANE_NTF_USE            0x04
 
 /* Neighbor cache states */
 #define DPLANE_NUD_REACHABLE      0x01
 #define DPLANE_NUD_STALE          0x02
 #define DPLANE_NUD_NOARP          0x04
 #define DPLANE_NUD_PROBE          0x08
+#define DPLANE_NUD_INCOMPLETE     0x10
 
 /* MAC update flags - dplane_mac_info.update_flags */
 #define DPLANE_MAC_REMOTE       (1 << 0)
@@ -572,6 +577,12 @@ enum zebra_dplane_result dplane_vtep_delete(const struct interface *ifp,
                                            const struct in_addr *ip,
                                            vni_t vni);
 
+/*
+ * Enqueue a neighbour discovery request for the dataplane.
+ */
+enum zebra_dplane_result dplane_neigh_discover(const struct interface *ifp,
+                                              const struct ipaddr *ip);
+
 /* Forward ref of zebra_pbr_rule */
 struct zebra_pbr_rule;
 
index 1c5b8435390f0d3d2ccd64ea1b5dea6b7a4dbc58..b8faaa43fd95ac238bae04117d11dd16061b1f41 100644 (file)
@@ -2663,6 +2663,7 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
        case DPLANE_OP_RULE_ADD:
        case DPLANE_OP_RULE_DELETE:
        case DPLANE_OP_RULE_UPDATE:
+       case DPLANE_OP_NEIGH_DISCOVER:
        case DPLANE_OP_NONE:
                break;
        }
index 55dccc4a1253824e806701c3fa051e71b355a9e7..d1d56f2cdb9f7fefc60b26ad25dc6f444e977dc5 100644 (file)
@@ -3764,6 +3764,7 @@ static int rib_process_dplane_results(struct thread *thread)
                        case DPLANE_OP_NEIGH_DELETE:
                        case DPLANE_OP_VTEP_ADD:
                        case DPLANE_OP_VTEP_DELETE:
+                       case DPLANE_OP_NEIGH_DISCOVER:
                        case DPLANE_OP_NONE:
                                /* Don't expect this: just return the struct? */
                                dplane_ctx_fini(&ctx);