diff --git a/drivers/net/nfp/flower/nfp_flower.c b/drivers/net/nfp/flower/nfp_flower.c
index 195960e00d..fc3ea84828 100644
--- a/drivers/net/nfp/flower/nfp_flower.c
+++ b/drivers/net/nfp/flower/nfp_flower.c
@@ -589,6 +589,22 @@ nfp_flower_sync_feature_cleanup(struct nfp_app_fw_flower *app_fw_flower)
 		nfp_flower_bond_feature_cleanup(app_fw_flower);
 }
 
+static int
+nfp_flower_start_features(struct nfp_app_fw_flower *app_flower)
+{
+	int ret;
+
+	if (nfp_flower_support_bond_offload(app_flower)) {
+		ret = nfp_flower_bond_reset(app_flower->nfp_bond);
+		if (ret != 0) {
+			PMD_INIT_LOG(ERR, "Reset bond feature failed");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
 static int
 nfp_flower_start_ctrl_vnic(struct nfp_net_hw *net_hw)
 {
@@ -826,6 +842,13 @@ nfp_init_app_fw_flower(struct nfp_pf_dev *pf_dev,
 		goto ctrl_vnic_cleanup;
 	}
 
+	/* Start up some features */
+	ret = nfp_flower_start_features(app_fw_flower);
+	if (ret != 0) {
+		PMD_INIT_LOG(ERR, "Failed to start features");
+		goto sync_feature_cleanup;
+	}
+
 	/* Start up flower services */
 	ret = nfp_flower_enable_services(app_fw_flower);
 	if (ret != 0) {
diff --git a/drivers/net/nfp/flower/nfp_flower_bond.c b/drivers/net/nfp/flower/nfp_flower_bond.c
index bbd2818e68..4ac27f117c 100644
--- a/drivers/net/nfp/flower/nfp_flower_bond.c
+++ b/drivers/net/nfp/flower/nfp_flower_bond.c
@@ -6,8 +6,31 @@
 
 #include <rte_malloc.h>
 
+#include "nfp_flower_cmsg.h"
 #include "nfp_flower_representor.h"
 
+static void
+nfp_fl_bond_cmsg_args_init(struct nfp_flower_bond_cmsg_args *cmsg_args,
+		struct nfp_bond_group *group,
+		struct rte_eth_dev **active_members,
+		uint32_t member_cnt,
+		enum nfp_flower_bond_batch batch)
+{
+	cmsg_args->group = group;
+	cmsg_args->active_members = active_members;
+	cmsg_args->member_cnt = member_cnt;
+	cmsg_args->batch = batch;
+}
+
+static uint32_t
+nfp_fl_get_next_pkt_number(struct nfp_flower_bond *nfp_bond)
+{
+	nfp_bond->pkt_num++;
+	nfp_bond->pkt_num &= NFP_FL_BOND_PKT_NUMBER_MASK;
+
+	return nfp_bond->pkt_num;
+}
+
 static void
 nfp_flower_bond_increment_version(struct nfp_flower_bond *nfp_bond)
 {
@@ -57,3 +80,70 @@ nfp_flower_bond_cleanup(struct nfp_app_fw_flower *app_fw_flower)
 	rte_free(nfp_bond);
 	app_fw_flower->nfp_bond = NULL;
 }
+
+int
+nfp_flower_bond_reset(struct nfp_flower_bond *nfp_bond)
+{
+	struct nfp_app_fw_flower *app_flower;
+	enum nfp_flower_bond_batch batch = NFP_FLOWER_BOND_BATCH_FIRST;
+	struct nfp_flower_bond_cmsg_args init_args;
+
+	app_flower = nfp_bond->app_fw_flower;
+	app_flower->nfp_bond->rst_cfg = true;
+
+	nfp_fl_bond_cmsg_args_init(&init_args, NULL, NULL, 0, batch);
+
+	return nfp_flower_cmsg_bond_config_group(app_flower, &init_args, &batch);
+}
+
+enum nfp_flower_bond_batch
+nfp_flower_bond_cmsg_payload(struct nfp_flower_bond *nfp_bond,
+		struct nfp_flower_cmsg_bond_config *msg,
+		struct nfp_flower_bond_cmsg_args *init_args)
+{
+	uint32_t i;
+	uint8_t flags = 0;
+	struct nfp_flower_representor *repr;
+	enum nfp_flower_bond_batch batch = init_args->batch;
+
+	/* Increment batch version for each new batch of config messages. */
+	if (batch == NFP_FLOWER_BOND_BATCH_FIRST) {
+		flags |= NFP_FL_BOND_FIRST;
+		nfp_flower_bond_increment_version(nfp_bond);
+		batch = NFP_FLOWER_BOND_BATCH_MEMBER;
+	}
+
+	/* If it is a reset msg then it is also the end of the batch. */
+	if (nfp_bond->rst_cfg) {
+		flags |= NFP_FL_BOND_RESET;
+		batch = NFP_FLOWER_BOND_BATCH_FINISHED;
+	}
+
+	/*
+	 * To signal the end of a batch, both the switch and last flags are set
+	 * and the reserved SYNC group ID is used.
+	 */
+	if (batch == NFP_FLOWER_BOND_BATCH_FINISHED) {
+		flags |= NFP_FL_BOND_SWITCH | NFP_FL_BOND_LAST;
+		nfp_bond->rst_cfg = false;
+		msg->group_id = rte_cpu_to_be_32(NFP_FL_BOND_SYNC_ID);
+		msg->group_inst = 0;
+	} else {
+		msg->group_id = rte_cpu_to_be_32(init_args->group->group_id);
+		msg->group_inst = rte_cpu_to_be_32(init_args->group->group_inst);
+	}
+
+	msg->reserved[0] = 0;
+	msg->reserved[1] = 0;
+	msg->ttl = NFP_FL_BOND_HOST_TTL;
+	msg->ctrl_flags = flags;
+	msg->batch_ver = rte_cpu_to_be_32(nfp_bond->batch_ver);
+	msg->pkt_number = rte_cpu_to_be_32(nfp_fl_get_next_pkt_number(nfp_bond));
+
+	for (i = 0; i < init_args->member_cnt; i++) {
+		repr = init_args->active_members[i]->data->dev_private;
+		msg->members[i] = rte_cpu_to_be_32(repr->port_id);
+	}
+
+	return batch;
+}
diff --git a/drivers/net/nfp/flower/nfp_flower_bond.h b/drivers/net/nfp/flower/nfp_flower_bond.h
index 9612b2c6cf..bb7ba8a1ad 100644
--- a/drivers/net/nfp/flower/nfp_flower_bond.h
+++ b/drivers/net/nfp/flower/nfp_flower_bond.h
@@ -6,6 +6,7 @@
 #ifndef __NFP_FLOWER_BOND_H__
 #define __NFP_FLOWER_BOND_H__
 
+#include <rte_byteorder.h>
 #include <rte_spinlock.h>
 #include <stdbool.h>
 #include <sys/queue.h>
@@ -13,12 +14,54 @@
 /* The batch version of bond offload packets between firmware and driver */
 #define NFP_FL_BOND_VERSION_MASK       0x007fffff    /* [0, 22] */
 
+#define NFP_FL_BOND_PKT_NUMBER_MASK    0x7fffffff    /* [0, 30] */
+
 #define NFP_FL_ENABLE_BOND             RTE_BIT32(1)
 
 /* ID 0 reserved and IDs 1 to 31 are valid */
 #define NFP_FL_BOND_GROUP_MIN          1
 #define NFP_FL_BOND_GROUP_MAX          32
 
+#define NFP_FL_BOND_HOST_TTL           0xff
+
+/* Use this ID with zero members to ack a batch config */
+#define NFP_FL_BOND_SYNC_ID            0
+
+/* BOND group config flags */
+#define NFP_FL_BOND_LAST               RTE_BIT32(1)
+#define NFP_FL_BOND_FIRST              RTE_BIT32(2)
+#define NFP_FL_BOND_DATA               RTE_BIT32(3)
+#define NFP_FL_BOND_XON                RTE_BIT32(4)
+#define NFP_FL_BOND_SYNC               RTE_BIT32(5)
+#define NFP_FL_BOND_SWITCH             RTE_BIT32(6)
+#define NFP_FL_BOND_RESET              RTE_BIT32(7)
+
+enum nfp_flower_bond_batch {
+	NFP_FLOWER_BOND_BATCH_FIRST,
+	NFP_FLOWER_BOND_BATCH_MEMBER,
+	NFP_FLOWER_BOND_BATCH_FINISHED
+};
+
+/* Control message payload for bond config */
+struct nfp_flower_cmsg_bond_config {
+	/** Configuration flags */
+	uint8_t ctrl_flags;
+	/** Reserved for future use */
+	uint8_t reserved[2];
+	/** Time to live of packet - host always sets to 0xff */
+	uint8_t ttl;
+	/** Config message packet number - increment for each message */
+	rte_be32_t pkt_number;
+	/** Batch version of messages - increment for each batch of messages */
+	rte_be32_t batch_ver;
+	/** Group ID applicable */
+	rte_be32_t group_id;
+	/** Group instance number - increment when group is reused */
+	rte_be32_t group_inst;
+	/** Array of 32-bit words listing all active group members */
+	rte_be32_t members[];
+};
+
 /* List entry for each bond group */
 struct nfp_bond_group {
 	/** List entry */
@@ -59,7 +102,18 @@ struct nfp_flower_bond {
 	struct nfp_app_fw_flower *app_fw_flower;
 };
 
+struct nfp_flower_bond_cmsg_args {
+	struct nfp_bond_group *group;
+	struct rte_eth_dev **active_members;
+	uint32_t member_cnt;
+	enum nfp_flower_bond_batch batch;
+};
+
 int nfp_flower_bond_init(struct nfp_app_fw_flower *app_fw_flower);
 void nfp_flower_bond_cleanup(struct nfp_app_fw_flower *app_fw_flower);
+int nfp_flower_bond_reset(struct nfp_flower_bond *nfp_bond);
+enum nfp_flower_bond_batch nfp_flower_bond_cmsg_payload(struct nfp_flower_bond *nfp_bond,
+		struct nfp_flower_cmsg_bond_config *msg,
+		struct nfp_flower_bond_cmsg_args *init_args);
 
 #endif /* __NFP_FLOWER_BOND_H__ */
diff --git a/drivers/net/nfp/flower/nfp_flower_cmsg.c b/drivers/net/nfp/flower/nfp_flower_cmsg.c
index 8effe9474d..0cf1bf2281 100644
--- a/drivers/net/nfp/flower/nfp_flower_cmsg.c
+++ b/drivers/net/nfp/flower/nfp_flower_cmsg.c
@@ -567,3 +567,38 @@ nfp_flower_cmsg_qos_stats(struct nfp_app_fw_flower *app_fw_flower,
 
 	return 0;
 }
+
+int
+nfp_flower_cmsg_bond_config_group(struct nfp_app_fw_flower *app_flower,
+		struct nfp_flower_bond_cmsg_args *init_args,
+		enum nfp_flower_bond_batch *batch_out)
+{
+	uint16_t cnt;
+	uint32_t size;
+	struct rte_mbuf *mbuf;
+	struct nfp_flower_bond *nfp_bond;
+	struct nfp_flower_cmsg_bond_config *msg;
+
+	mbuf = rte_pktmbuf_alloc(app_flower->ctrl_pktmbuf_pool);
+	if (mbuf == NULL) {
+		PMD_DRV_LOG(DEBUG, "Alloc mbuf for bond config failed");
+		return -ENOMEM;
+	}
+
+	size = sizeof(*msg) + sizeof(rte_be32_t) * init_args->member_cnt;
+	msg = nfp_flower_cmsg_init(app_flower, mbuf,
+			NFP_FLOWER_CMSG_TYPE_LAG_CONFIG, size);
+
+	nfp_bond = app_flower->nfp_bond;
+
+	*batch_out = nfp_flower_bond_cmsg_payload(nfp_bond, msg, init_args);
+
+	cnt = nfp_flower_ctrl_vnic_xmit(app_flower, mbuf);
+	if (cnt == 0) {
+		PMD_DRV_LOG(ERR, "Send cmsg through ctrl vnic failed.");
+		rte_pktmbuf_free(mbuf);
+		return -EIO;
+	}
+
+	return 0;
+}
diff --git a/drivers/net/nfp/flower/nfp_flower_cmsg.h b/drivers/net/nfp/flower/nfp_flower_cmsg.h
index 45543816ae..60ab58a3b1 100644
--- a/drivers/net/nfp/flower/nfp_flower_cmsg.h
+++ b/drivers/net/nfp/flower/nfp_flower_cmsg.h
@@ -988,5 +988,8 @@ int nfp_flower_cmsg_qos_delete(struct nfp_app_fw_flower *app_fw_flower,
 		struct nfp_profile_conf *conf);
 int nfp_flower_cmsg_qos_stats(struct nfp_app_fw_flower *app_fw_flower,
 		struct nfp_cfg_head *head);
+int nfp_flower_cmsg_bond_config_group(struct nfp_app_fw_flower *app_flower,
+		struct nfp_flower_bond_cmsg_args *init_args,
+		enum nfp_flower_bond_batch *batch_out);
 
 #endif /* __NFP_CMSG_H__ */
