lib, zebra: add support for sending ARP requests

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>
This commit is contained in:
Jakub Urbańczyk 2020-08-06 13:07:01 +02:00
parent c2e6684110
commit d68e74b41c
13 changed files with 117 additions and 9 deletions

View 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

View 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.

View File

@ -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", '?'};

View 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);
}

View 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

View 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:

View 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;

View 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:

View 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;

View 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);

View 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;

View 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;
}

View 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);