bool connecting;
bool rib_complete;
bool rmac_complete;
+ bool use_nhg;
struct sockaddr_storage addr;
/* data plane buffers. */
FNE_DISABLE,
/* Reset counters. */
FNE_RESET_COUNTERS,
+ /* Toggle next hop group feature. */
+ FNE_TOGGLE_NHG,
};
/*
return CMD_SUCCESS;
}
+DEFUN(fpm_use_nhg, fpm_use_nhg_cmd,
+ "fpm use-next-hop-groups",
+ FPM_STR
+ "Use netlink next hop groups feature.\n")
+{
+ /* Already enabled. */
+ if (gfnc->use_nhg)
+ return CMD_SUCCESS;
+
+ thread_add_event(gfnc->fthread->master, fpm_process_event, gfnc,
+ FNE_TOGGLE_NHG, &gfnc->t_event);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(no_fpm_use_nhg, no_fpm_use_nhg_cmd,
+ "no fpm use-next-hop-groups",
+ NO_STR
+ FPM_STR
+ "Use netlink next hop groups feature.\n")
+{
+ /* Already disabled. */
+ if (!gfnc->use_nhg)
+ return CMD_SUCCESS;
+
+ thread_add_event(gfnc->fthread->master, fpm_process_event, gfnc,
+ FNE_TOGGLE_NHG, &gfnc->t_event);
+
+ return CMD_SUCCESS;
+}
+
DEFUN(fpm_reset_counters, fpm_reset_counters_cmd,
"clear fpm counters",
CLEAR_STR
break;
}
+ if (!gfnc->use_nhg) {
+ vty_out(vty, "no fpm use-next-hop-groups\n");
+ written = 1;
+ }
+
return written;
}
fnc->connecting = false;
- /* Ask zebra main thread to start walking the RIB table. */
- thread_add_timer(zrouter.master, fpm_nhg_send, fnc, 0,
- &fnc->t_nhgwalk);
+ /*
+ * Walk the route tables to send old information before starting
+ * to send updated information.
+ *
+ * NOTE 1:
+ * RIB table walk is called after the next group table walk
+ * ends.
+ *
+ * NOTE 2:
+ * Don't attempt to go through next hop group table if we were
+ * explictly told to not use it.
+ */
+ if (fnc->use_nhg)
+ thread_add_timer(zrouter.master, fpm_nhg_send, fnc, 0,
+ &fnc->t_nhgwalk);
+ else
+ thread_add_timer(zrouter.master, fpm_rib_send, fnc, 0,
+ &fnc->t_ribwalk);
+
thread_add_timer(zrouter.master, fpm_rmac_send, fnc, 0,
&fnc->t_rmacwalk);
}
size_t nl_buf_len;
ssize_t rv;
uint64_t obytes, obytes_peak;
+ enum dplane_op_e op = dplane_ctx_get_op(ctx);
+
+ /*
+ * If we were configured to not use next hop groups, then quit as soon
+ * as possible.
+ */
+ if ((!fnc->use_nhg)
+ && (op == DPLANE_OP_NH_DELETE || op == DPLANE_OP_NH_INSTALL
+ || op == DPLANE_OP_NH_UPDATE))
+ return 0;
nl_buf_len = 0;
frr_mutex_lock_autounlock(&fnc->obuf_mutex);
- switch (dplane_ctx_get_op(ctx)) {
+ switch (op) {
case DPLANE_OP_ROUTE_UPDATE:
case DPLANE_OP_ROUTE_DELETE:
rv = netlink_route_multipath(RTM_DELROUTE, ctx, nl_buf,
- sizeof(nl_buf), true);
+ sizeof(nl_buf), true,
+ fnc->use_nhg);
if (rv <= 0) {
zlog_err("%s: netlink_route_multipath failed",
__func__);
nl_buf_len = (size_t)rv;
/* UPDATE operations need a INSTALL, otherwise just quit. */
- if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_DELETE)
+ if (op == DPLANE_OP_ROUTE_DELETE)
break;
/* FALL THROUGH */
case DPLANE_OP_ROUTE_INSTALL:
- rv = netlink_route_multipath(RTM_NEWROUTE, ctx,
- &nl_buf[nl_buf_len],
- sizeof(nl_buf) - nl_buf_len, true);
+ rv = netlink_route_multipath(
+ RTM_NEWROUTE, ctx, &nl_buf[nl_buf_len],
+ sizeof(nl_buf) - nl_buf_len, true, fnc->use_nhg);
if (rv <= 0) {
zlog_err("%s: netlink_route_multipath failed",
__func__);
memset(&fnc->counters, 0, sizeof(fnc->counters));
break;
+ case FNE_TOGGLE_NHG:
+ zlog_info("%s: toggle next hop groups support", __func__);
+ fnc->use_nhg = !fnc->use_nhg;
+ fpm_reconnect(fnc);
+ break;
+
default:
if (IS_ZEBRA_DEBUG_FPM)
zlog_debug("%s: unhandled event %d", __func__, event);
TAILQ_INIT(&fnc->ctxqueue);
pthread_mutex_init(&fnc->ctxqueue_mutex, NULL);
+ /* Set default values. */
+ fnc->use_nhg = true;
+
return 0;
}
install_element(ENABLE_NODE, &fpm_reset_counters_cmd);
install_element(CONFIG_NODE, &fpm_set_address_cmd);
install_element(CONFIG_NODE, &no_fpm_set_address_cmd);
+ install_element(CONFIG_NODE, &fpm_use_nhg_cmd);
+ install_element(CONFIG_NODE, &no_fpm_use_nhg_cmd);
return 0;
}
* Routing table change via netlink interface, using a dataplane context object
*/
ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx,
- uint8_t *data, size_t datalen, bool fpm)
+ uint8_t *data, size_t datalen, bool fpm,
+ bool force_nhg)
{
int bytelen;
struct nexthop *nexthop = NULL;
RTA_PAYLOAD(rta));
}
- if (kernel_nexthops_supported()) {
+ if (kernel_nexthops_supported() || force_nhg) {
/* Kernel supports nexthop objects */
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
!RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) {
netlink_route_multipath(RTM_DELROUTE, ctx,
nl_pkt, sizeof(nl_pkt),
- false);
+ false, false);
netlink_talk_info(netlink_talk_filter,
(struct nlmsghdr *)nl_pkt,
dplane_ctx_get_ns(ctx), 0);
if (!RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) {
netlink_route_multipath(RTM_DELROUTE, ctx,
nl_pkt, sizeof(nl_pkt),
- false);
+ false, false);
netlink_talk_info(netlink_talk_filter,
(struct nlmsghdr *)nl_pkt,
dplane_ctx_get_ns(ctx), 0);
if (!RSYSTEM_ROUTE(dplane_ctx_get_type(ctx))) {
netlink_route_multipath(cmd, ctx, nl_pkt, sizeof(nl_pkt),
- false);
+ false, false);
ret = netlink_talk_info(netlink_talk_filter,
(struct nlmsghdr *)nl_pkt,
dplane_ctx_get_ns(ctx), 0);