diff --git a/ethtool.c b/ethtool.c
index 97280cb676db..6a28307004d5 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -5173,6 +5173,7 @@ static const struct option args[] = {
 	{
 		.opts	= "-C|--coalesce",
 		.func	= do_scoalesce,
+		.nlfunc	= nl_scoalesce,
 		.help	= "Set coalesce options",
 		.xhelp	= "		[adaptive-rx on|off]\n"
 			  "		[adaptive-tx on|off]\n"
diff --git a/netlink/coalesce.c b/netlink/coalesce.c
index f1ad671c3bd4..65f75cf9a8dd 100644
--- a/netlink/coalesce.c
+++ b/netlink/coalesce.c
@@ -1,7 +1,7 @@
 /*
  * coalesce.c - netlink implementation of coalescing commands
  *
- * Implementation of "ethtool -c <dev>"
+ * Implementation of "ethtool -c <dev>" and "ethtool -C <dev> ..."
  */
 
 #include <errno.h>
@@ -11,6 +11,7 @@
 #include "../internal.h"
 #include "../common.h"
 #include "netlink.h"
+#include "parser.h"
 
 /* COALESCE_GET */
 
@@ -89,3 +90,180 @@ int nl_gcoalesce(struct cmd_context *ctx)
 		return ret;
 	return nlsock_send_get_request(nlsk, coalesce_reply_cb);
 }
+
+/* COALESCE_SET */
+
+static const struct param_parser scoalesce_params[] = {
+	{
+		.arg		= "adaptive-rx",
+		.type		= ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX,
+		.handler	= nl_parse_u8bool,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "adaptive-tx",
+		.type		= ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX,
+		.handler	= nl_parse_u8bool,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "sample-interval",
+		.type		= ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL,
+		.handler	= nl_parse_direct_u32,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "stats-block-usecs",
+		.type		= ETHTOOL_A_COALESCE_STATS_BLOCK_USECS,
+		.handler	= nl_parse_direct_u32,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "pkt-rate-low",
+		.type		= ETHTOOL_A_COALESCE_PKT_RATE_LOW,
+		.handler	= nl_parse_direct_u32,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "pkt-rate-high",
+		.type		= ETHTOOL_A_COALESCE_PKT_RATE_HIGH,
+		.handler	= nl_parse_direct_u32,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "rx-usecs",
+		.type		= ETHTOOL_A_COALESCE_RX_USECS,
+		.handler	= nl_parse_direct_u32,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "rx-frames",
+		.type		= ETHTOOL_A_COALESCE_RX_MAX_FRAMES,
+		.handler	= nl_parse_direct_u32,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "rx-usecs-irq",
+		.type		= ETHTOOL_A_COALESCE_RX_USECS_IRQ,
+		.handler	= nl_parse_direct_u32,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "rx-frames-irq",
+		.type		= ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ,
+		.handler	= nl_parse_direct_u32,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "tx-usecs",
+		.type		= ETHTOOL_A_COALESCE_TX_USECS,
+		.handler	= nl_parse_direct_u32,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "tx-frames",
+		.type		= ETHTOOL_A_COALESCE_TX_MAX_FRAMES,
+		.handler	= nl_parse_direct_u32,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "tx-usecs-irq",
+		.type		= ETHTOOL_A_COALESCE_TX_USECS_IRQ,
+		.handler	= nl_parse_direct_u32,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "tx-frames-irq",
+		.type		= ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ,
+		.handler	= nl_parse_direct_u32,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "rx-usecs-low",
+		.type		= ETHTOOL_A_COALESCE_RX_USECS_LOW,
+		.handler	= nl_parse_direct_u32,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "rx-frames-low",
+		.type		= ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW,
+		.handler	= nl_parse_direct_u32,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "tx-usecs-low",
+		.type		= ETHTOOL_A_COALESCE_TX_USECS_LOW,
+		.handler	= nl_parse_direct_u32,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "tx-frames-low",
+		.type		= ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW,
+		.handler	= nl_parse_direct_u32,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "rx-usecs-high",
+		.type		= ETHTOOL_A_COALESCE_RX_USECS_HIGH,
+		.handler	= nl_parse_direct_u32,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "rx-frames-high",
+		.type		= ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH,
+		.handler	= nl_parse_direct_u32,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "tx-usecs-high",
+		.type		= ETHTOOL_A_COALESCE_TX_USECS_HIGH,
+		.handler	= nl_parse_direct_u32,
+		.min_argc	= 1,
+	},
+	{
+		.arg		= "tx-frames-high",
+		.type		= ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH,
+		.handler	= nl_parse_direct_u32,
+		.min_argc	= 1,
+	},
+	{}
+};
+
+int nl_scoalesce(struct cmd_context *ctx)
+{
+	struct nl_context *nlctx = ctx->nlctx;
+	struct nl_msg_buff *msgbuff;
+	struct nl_socket *nlsk;
+	int ret;
+
+	if (netlink_cmd_check(ctx, ETHTOOL_MSG_COALESCE_SET, false))
+		return -EOPNOTSUPP;
+
+	nlctx->cmd = "-C";
+	nlctx->argp = ctx->argp;
+	nlctx->argc = ctx->argc;
+	nlctx->devname = ctx->devname;
+	nlsk = nlctx->ethnl_socket;
+	msgbuff = &nlsk->msgbuff;
+
+	ret = msg_init(nlctx, msgbuff, ETHTOOL_MSG_COALESCE_SET,
+		       NLM_F_REQUEST | NLM_F_ACK);
+	if (ret < 0)
+		return 2;
+	if (ethnla_fill_header(msgbuff, ETHTOOL_A_COALESCE_HEADER,
+			       ctx->devname, 0))
+		return -EMSGSIZE;
+
+	ret = nl_parser(nlctx, scoalesce_params, NULL, PARSER_GROUP_NONE);
+	if (ret < 0)
+		return 1;
+
+	ret = nlsock_sendmsg(nlsk, NULL);
+	if (ret < 0)
+		return 1;
+	ret = nlsock_process_reply(nlsk, nomsg_reply_cb, nlctx);
+	if (ret == 0)
+		return 0;
+	else
+		return nlctx->exit_code ?: 1;
+}
diff --git a/netlink/extapi.h b/netlink/extapi.h
index f25fc6e4389f..d35029576d5c 100644
--- a/netlink/extapi.h
+++ b/netlink/extapi.h
@@ -29,6 +29,7 @@ int nl_sring(struct cmd_context *ctx);
 int nl_gchannels(struct cmd_context *ctx);
 int nl_schannels(struct cmd_context *ctx);
 int nl_gcoalesce(struct cmd_context *ctx);
+int nl_scoalesce(struct cmd_context *ctx);
 int nl_monitor(struct cmd_context *ctx);
 
 void nl_monitor_usage(void);
@@ -62,6 +63,7 @@ static inline void nl_monitor_usage(void)
 #define nl_gchannels		NULL
 #define nl_schannels		NULL
 #define nl_gcoalesce		NULL
+#define nl_scoalesce		NULL
 
 #endif /* ETHTOOL_ENABLE_NETLINK */
 
