Skip to content

Commit

Permalink
Merge pull request #12075 from donaldsharp/highline
Browse files Browse the repository at this point in the history
Add ability for dplane_fpm_nl to receive RTM_NEWROUTE netlink messages that signal route handling in the asic
  • Loading branch information
rzalamena authored Dec 14, 2022
2 parents 22e60ca + a0e1173 commit 79f4ba7
Show file tree
Hide file tree
Showing 10 changed files with 392 additions and 146 deletions.
16 changes: 16 additions & 0 deletions doc/developer/fpm.rst
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,19 @@ Data
^^^^

The netlink or protobuf message payload.


Route Status Notification from ASIC
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The dplane_fpm_nl has the ability to read route netlink messages
from the underlying fpm implementation that can tell zebra
whether or not the route has been Offloaded/Failed or Trapped.
The end developer must send the data up the same socket that has
been created to listen for FPM messages from Zebra. The data sent
must have a Frame Header with Version set to 1, Message Type set to 1
and an appropriate message Length. The message data must contain
a RTM_NEWROUTE netlink message that sends the prefix and nexthops
associated with the route. Finally rtm_flags must contain
RTM_F_OFFLOAD, RTM_F_TRAP and or RTM_F_OFFLOAD_FAILED to signify
what has happened to the route in the ASIC.
137 changes: 127 additions & 10 deletions zebra/dplane_fpm_nl.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
#include "zebra/kernel_netlink.h"
#include "zebra/rt_netlink.h"
#include "zebra/debug.h"
#include "fpm/fpm.h"

#define SOUTHBOUND_DEFAULT_ADDR INADDR_LOOPBACK
#define SOUTHBOUND_DEFAULT_PORT 2620
Expand Down Expand Up @@ -462,18 +463,17 @@ static void fpm_reconnect(struct fpm_nl_ctx *fnc)
static void fpm_read(struct thread *t)
{
struct fpm_nl_ctx *fnc = THREAD_ARG(t);
fpm_msg_hdr_t fpm;
ssize_t rv;
char buf[65535];
struct nlmsghdr *hdr;
struct zebra_dplane_ctx *ctx;
size_t available_bytes;
size_t hdr_available_bytes;

/* Let's ignore the input at the moment. */
rv = stream_read_try(fnc->ibuf, fnc->socket,
STREAM_WRITEABLE(fnc->ibuf));
/* We've got an interruption. */
if (rv == -2) {
/* Schedule next read. */
thread_add_read(fnc->fthread->master, fpm_read, fnc,
fnc->socket, &fnc->t_read);
return;
}
if (rv == 0) {
atomic_fetch_add_explicit(&fnc->counters.connection_closes, 1,
memory_order_relaxed);
Expand All @@ -492,14 +492,131 @@ static void fpm_read(struct thread *t)
FPM_RECONNECT(fnc);
return;
}
stream_reset(fnc->ibuf);

/* Schedule the next read */
thread_add_read(fnc->fthread->master, fpm_read, fnc, fnc->socket,
&fnc->t_read);

/* We've got an interruption. */
if (rv == -2)
return;


/* Account all bytes read. */
atomic_fetch_add_explicit(&fnc->counters.bytes_read, rv,
memory_order_relaxed);

thread_add_read(fnc->fthread->master, fpm_read, fnc, fnc->socket,
&fnc->t_read);
available_bytes = STREAM_READABLE(fnc->ibuf);
while (available_bytes) {
if (available_bytes < (ssize_t)FPM_MSG_HDR_LEN) {
stream_pulldown(fnc->ibuf);
return;
}

fpm.version = stream_getc(fnc->ibuf);
fpm.msg_type = stream_getc(fnc->ibuf);
fpm.msg_len = stream_getw(fnc->ibuf);

if (fpm.version != FPM_PROTO_VERSION &&
fpm.msg_type != FPM_MSG_TYPE_NETLINK) {
stream_reset(fnc->ibuf);
zlog_warn(
"%s: Received version/msg_type %u/%u, expected 1/1",
__func__, fpm.version, fpm.msg_type);

FPM_RECONNECT(fnc);
return;
}

/*
* If the passed in length doesn't even fill in the header
* something is wrong and reset.
*/
if (fpm.msg_len < FPM_MSG_HDR_LEN) {
zlog_warn(
"%s: Received message length: %u that does not even fill the FPM header",
__func__, fpm.msg_len);
FPM_RECONNECT(fnc);
return;
}

/*
* If we have not received the whole payload, reset the stream
* back to the beginning of the header and move it to the
* top.
*/
if (fpm.msg_len > available_bytes) {
stream_rewind_getp(fnc->ibuf, FPM_MSG_HDR_LEN);
stream_pulldown(fnc->ibuf);
return;
}

available_bytes -= FPM_MSG_HDR_LEN;

/*
* Place the data from the stream into a buffer
*/
hdr = (struct nlmsghdr *)buf;
stream_get(buf, fnc->ibuf, fpm.msg_len - FPM_MSG_HDR_LEN);
hdr_available_bytes = fpm.msg_len - FPM_MSG_HDR_LEN;
available_bytes -= hdr_available_bytes;

/* Sanity check: must be at least header size. */
if (hdr->nlmsg_len < sizeof(*hdr)) {
zlog_warn(
"%s: [seq=%u] invalid message length %u (< %zu)",
__func__, hdr->nlmsg_seq, hdr->nlmsg_len,
sizeof(*hdr));
continue;
}
if (hdr->nlmsg_len > fpm.msg_len) {
zlog_warn(
"%s: Received a inner header length of %u that is greater than the fpm total length of %u",
__func__, hdr->nlmsg_len, fpm.msg_len);
FPM_RECONNECT(fnc);
}
/* Not enough bytes available. */
if (hdr->nlmsg_len > hdr_available_bytes) {
zlog_warn(
"%s: [seq=%u] invalid message length %u (> %zu)",
__func__, hdr->nlmsg_seq, hdr->nlmsg_len,
available_bytes);
continue;
}

if (!(hdr->nlmsg_flags & NLM_F_REQUEST)) {
if (IS_ZEBRA_DEBUG_FPM)
zlog_debug(
"%s: [seq=%u] not a request, skipping",
__func__, hdr->nlmsg_seq);

/*
* This request is a bust, go to the next one
*/
continue;
}

switch (hdr->nlmsg_type) {
case RTM_NEWROUTE:
ctx = dplane_ctx_alloc();
dplane_ctx_set_op(ctx, DPLANE_OP_ROUTE_NOTIFY);
if (netlink_route_change_read_unicast_internal(
hdr, 0, false, ctx) != 1) {
dplane_ctx_fini(&ctx);
stream_pulldown(fnc->ibuf);
return;
}
break;
default:
if (IS_ZEBRA_DEBUG_FPM)
zlog_debug(
"%s: Received message type %u which is not currently handled",
__func__, hdr->nlmsg_type);
break;
}
}

stream_reset(fnc->ibuf);
}

static void fpm_write(struct thread *t)
Expand Down
30 changes: 22 additions & 8 deletions zebra/rt_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -692,8 +692,9 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id,
}

/* Looking up routing table by netlink interface. */
static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
int startup)
int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
ns_id_t ns_id, int startup,
struct zebra_dplane_ctx *ctx)
{
int len;
struct rtmsg *rtm;
Expand Down Expand Up @@ -768,9 +769,8 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,

selfroute = is_selfroute(rtm->rtm_protocol);

if (!startup && selfroute
&& h->nlmsg_type == RTM_NEWROUTE
&& !zrouter.asic_offloaded) {
if (!startup && selfroute && h->nlmsg_type == RTM_NEWROUTE &&
!zrouter.asic_offloaded && !ctx) {
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("Route type: %d Received that we think we have originated, ignoring",
rtm->rtm_protocol);
Expand Down Expand Up @@ -988,8 +988,8 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
}
}
if (nhe_id || ng)
rib_add_multipath(afi, SAFI_UNICAST, &p, &src_p, re, ng,
startup);
dplane_rib_add_multipath(afi, SAFI_UNICAST, &p, &src_p,
re, ng, startup, ctx);
else {
/*
* I really don't see how this is possible
Expand All @@ -1004,6 +1004,13 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
XFREE(MTYPE_RE, re);
}
} else {
if (ctx) {
zlog_err(
"%s: %pFX RTM_DELROUTE received but received a context as well",
__func__, &p);
return 0;
}

if (nhe_id) {
rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags,
&p, &src_p, NULL, nhe_id, table, metric,
Expand All @@ -1028,7 +1035,14 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
}
}

return 0;
return 1;
}

static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
int startup)
{
return netlink_route_change_read_unicast_internal(h, ns_id, startup,
NULL);
}

static struct mcast_route_data *mroute = NULL;
Expand Down
4 changes: 4 additions & 0 deletions zebra/rt_netlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ netlink_put_lsp_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx);
extern enum netlink_msg_status
netlink_put_pw_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx);

int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
ns_id_t ns_id, int startup,
struct zebra_dplane_ctx *ctx);

#ifdef NETLINK_DEBUG
const char *nlmsg_type2str(uint16_t type);
const char *af_type2str(int type);
Expand Down
Loading

0 comments on commit 79f4ba7

Please sign in to comment.