summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/developer/zebra.rst4
-rw-r--r--doc/user/sharp.rst6
-rw-r--r--lib/log.c3
-rw-r--r--lib/zclient.c20
-rw-r--r--lib/zclient.h5
-rw-r--r--ospfd/ospf_packet.c14
-rw-r--r--ospfd/ospf_zebra.c5
-rw-r--r--ospfd/ospf_zebra.h4
-rw-r--r--sharpd/sharp_vty.c46
-rw-r--r--sharpd/sharp_zebra.c5
-rw-r--r--sharpd/sharp_zebra.h3
-rw-r--r--zebra/kernel_netlink.c1
-rw-r--r--zebra/kernel_socket.c1
-rw-r--r--zebra/rt_netlink.c5
-rw-r--r--zebra/zapi_msg.c39
-rw-r--r--zebra/zebra_dplane.c29
-rw-r--r--zebra/zebra_dplane.h11
-rw-r--r--zebra/zebra_nhg.c1
-rw-r--r--zebra/zebra_rib.c1
19 files changed, 182 insertions, 21 deletions
diff --git a/doc/developer/zebra.rst b/doc/developer/zebra.rst
index edd8b9ae29..d51cbc9a14 100644
--- a/doc/developer/zebra.rst
+++ b/doc/developer/zebra.rst
@@ -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
diff --git a/doc/user/sharp.rst b/doc/user/sharp.rst
index 5a27be22b9..57ef141c7e 100644
--- a/doc/user/sharp.rst
+++ b/doc/user/sharp.rst
@@ -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.
diff --git a/lib/log.c b/lib/log.c
index 202d6d858f..4054185019 100644
--- 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", '?'};
diff --git a/lib/zclient.c b/lib/zclient.c
index 6449fe15b9..808aa18bbe 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -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);
+}
diff --git a/lib/zclient.h b/lib/zclient.h
index bcdae85823..dab384d5ec 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -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
diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c
index b0dd5c6fc2..49cd42d030 100644
--- a/ospfd/ospf_packet.c
+++ b/ospfd/ospf_packet.c
@@ -53,6 +53,7 @@
#include "ospfd/ospf_flood.h"
#include "ospfd/ospf_dump.h"
#include "ospfd/ospf_errors.h"
+#include "ospfd/ospf_zebra.h"
/*
* OSPF Fragmentation / fragmented writes
@@ -4319,21 +4320,10 @@ void ospf_ls_ack_send_delayed(struct ospf_interface *oi)
* punt-to-CPU set on them. This may overload the CPU control path that
* can be avoided if the MAC was known apriori.
*/
-#define OSPF_PING_NBR_STR_MAX (BUFSIZ)
void ospf_proactively_arp(struct ospf_neighbor *nbr)
{
- char ping_nbr[OSPF_PING_NBR_STR_MAX];
- int ret;
-
if (!nbr)
return;
- snprintf(ping_nbr, sizeof(ping_nbr),
- "ping -c 1 -I %s %s > /dev/null 2>&1 &", nbr->oi->ifp->name,
- inet_ntoa(nbr->address.u.prefix4));
-
- ret = system(ping_nbr);
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug("Executed %s %s", ping_nbr,
- ((ret == 0) ? "successfully" : "but failed"));
+ ospf_zebra_send_arp(nbr->oi->ifp, &nbr->address);
}
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
index 84bdb9ec5b..2b8769a4a8 100644
--- a/ospfd/ospf_zebra.c
+++ b/ospfd/ospf_zebra.c
@@ -1741,3 +1741,8 @@ void ospf_zebra_init(struct thread_master *master, unsigned short instance)
prefix_list_add_hook(ospf_prefix_list_update);
prefix_list_delete_hook(ospf_prefix_list_update);
}
+
+void ospf_zebra_send_arp(const struct interface *ifp, const struct prefix *p)
+{
+ zclient_send_neigh_discovery_req(zclient, ifp, p);
+}
diff --git a/ospfd/ospf_zebra.h b/ospfd/ospf_zebra.h
index 80abf62369..6a79f39fa4 100644
--- a/ospfd/ospf_zebra.h
+++ b/ospfd/ospf_zebra.h
@@ -41,6 +41,7 @@ struct ospf_distance {
};
/* Prototypes */
+struct ospf_route;
extern void ospf_zebra_add(struct ospf *ospf, struct prefix_ipv4 *,
struct ospf_route *);
extern void ospf_zebra_delete(struct ospf *ospf, struct prefix_ipv4 *,
@@ -98,4 +99,7 @@ bool ospf_external_default_routemap_apply_walk(
int ospf_external_info_apply_default_routemap(struct ospf *ospf,
struct external_info *ei,
struct external_info *default_ei);
+
+extern void ospf_zebra_send_arp(const struct interface *ifp,
+ const struct prefix *p);
#endif /* _ZEBRA_OSPF_ZEBRA_H */
diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c
index 049b8475e4..d390ea8192 100644
--- a/sharpd/sharp_vty.c
+++ b/sharpd/sharp_vty.c
@@ -649,6 +649,51 @@ DEFPY (send_opaque_reg,
return CMD_SUCCESS;
}
+DEFPY (neigh_discover,
+ neigh_discover_cmd,
+ "sharp neigh discover [vrf NAME$vrf_name] <A.B.C.D$dst4|X:X::X:X$dst6> IFNAME$ifname",
+ SHARP_STR
+ "Discover neighbours\n"
+ "Send an ARP/NDP request\n"
+ VRF_CMD_HELP_STR
+ "v4 Destination address\n"
+ "v6 Destination address\n"
+ "Interface name\n")
+{
+ struct vrf *vrf;
+ struct interface *ifp;
+ struct prefix prefix;
+
+ memset(&prefix, 0, sizeof(prefix));
+
+ if (dst4.s_addr != 0) {
+ prefix.family = AF_INET;
+ prefix.prefixlen = 32;
+ prefix.u.prefix4 = dst4;
+ } else {
+ prefix.family = AF_INET6;
+ prefix.prefixlen = 128;
+ prefix.u.prefix6 = dst6;
+ }
+
+ vrf = vrf_lookup_by_name(vrf_name ? vrf_name : VRF_DEFAULT_NAME);
+ if (!vrf) {
+ vty_out(vty, "The vrf NAME specified: %s does not exist\n",
+ vrf_name ? vrf_name : VRF_DEFAULT_NAME);
+ return CMD_WARNING;
+ }
+
+ ifp = if_lookup_by_name_vrf(ifname, vrf);
+ if (ifp == NULL) {
+ vty_out(vty, "%% Can't find interface %s\n", ifname);
+ return CMD_WARNING;
+ }
+
+ sharp_zebra_send_arp(ifp, &prefix);
+
+ return CMD_SUCCESS;
+}
+
void sharp_vty_init(void)
{
install_element(ENABLE_NODE, &install_routes_data_dump_cmd);
@@ -666,6 +711,7 @@ void sharp_vty_init(void)
install_element(ENABLE_NODE, &send_opaque_cmd);
install_element(ENABLE_NODE, &send_opaque_unicast_cmd);
install_element(ENABLE_NODE, &send_opaque_reg_cmd);
+ install_element(ENABLE_NODE, &neigh_discover_cmd);
install_element(VIEW_NODE, &show_debugging_sharpd_cmd);
diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c
index e0f16d71f5..08f5a07b7e 100644
--- a/sharpd/sharp_zebra.c
+++ b/sharpd/sharp_zebra.c
@@ -663,6 +663,11 @@ void sharp_opaque_reg_send(bool is_reg, uint32_t proto, uint32_t instance,
}
+void sharp_zebra_send_arp(const struct interface *ifp, const struct prefix *p)
+{
+ zclient_send_neigh_discovery_req(zclient, ifp, p);
+}
+
void sharp_zebra_init(void)
{
struct zclient_options opt = {.receive_notify = true};
diff --git a/sharpd/sharp_zebra.h b/sharpd/sharp_zebra.h
index e40585aa6a..0a44fa694f 100644
--- a/sharpd/sharp_zebra.h
+++ b/sharpd/sharp_zebra.h
@@ -58,4 +58,7 @@ void sharp_opaque_send(uint32_t type, uint32_t proto, uint32_t instance,
void sharp_opaque_reg_send(bool is_reg, uint32_t proto, uint32_t instance,
uint32_t session_id, uint32_t type);
+extern void sharp_zebra_send_arp(const struct interface *ifp,
+ const struct prefix *p);
+
#endif
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
index b04076b945..d0c1bc812d 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -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:
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index 9e56e2988d..4c29b999f0 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -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;
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 190af3f59d..4a6839d3b1 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -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:
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index 17114f820c..fbed99dc59 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -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;
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index d34e1433ce..8ab7a7f5bc 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -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);
diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h
index 3b5eda2486..c68a617f38 100644
--- a/zebra/zebra_dplane.h
+++ b/zebra/zebra_dplane.h
@@ -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;
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index 1c5b843539..b8faaa43fd 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -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;
}
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 55dccc4a12..d1d56f2cdb 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -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);