diff --git a/doc/guides/rel_notes/release_23_11.rst b/doc/guides/rel_notes/release_23_11.rst
index 2213aeae7b..8db3bbbd2f 100644
--- a/doc/guides/rel_notes/release_23_11.rst
+++ b/doc/guides/rel_notes/release_23_11.rst
@@ -142,6 +142,19 @@ New Features
   a group's miss actions, which are the actions to be performed on packets
   that didn't match any of the flow rules in the group.
 
+* **Updated kvargs process API.**
+
+  * Introduced rte_kvargs_process_opt() API, which inherits the function
+    of rte_kvargs_process() and could handle both key=value and only-key
+    cases.
+
+  * Constraint rte_kvargs_process() API can only handle key=value cases,
+    it will return -1 when handle only-key case (that is the matched key's
+    value is NULL).
+
+  * Make sure rte_kvargs_process_opt() and rte_kvargs_process() API both
+    return -1 when the kvlist parameter is NULL.
+
 * **Updated Amazon ena (Elastic Network Adapter) net driver.**
 
   * Upgraded ENA HAL to latest version.
diff --git a/lib/kvargs/rte_kvargs.c b/lib/kvargs/rte_kvargs.c
index c77bb82feb..adc47f8898 100644
--- a/lib/kvargs/rte_kvargs.c
+++ b/lib/kvargs/rte_kvargs.c
@@ -167,31 +167,56 @@ rte_kvargs_count(const struct rte_kvargs *kvlist, const char *key_match)
 	return ret;
 }
 
-/*
- * For each matching key, call the given handler function.
- */
-int
-rte_kvargs_process(const struct rte_kvargs *kvlist,
-		const char *key_match,
-		arg_handler_t handler,
-		void *opaque_arg)
+static int
+kvargs_process_common(const struct rte_kvargs *kvlist,
+		      const char *key_match,
+		      arg_handler_t handler,
+		      void *opaque_arg,
+		      bool support_only_key)
 {
 	const struct rte_kvargs_pair *pair;
 	unsigned i;
 
 	if (kvlist == NULL)
-		return 0;
+		return -1;
 
 	for (i = 0; i < kvlist->count; i++) {
 		pair = &kvlist->pairs[i];
 		if (key_match == NULL || strcmp(pair->key, key_match) == 0) {
+			if (!support_only_key && pair->value == NULL)
+				return -1;
 			if ((*handler)(pair->key, pair->value, opaque_arg) < 0)
 				return -1;
 		}
 	}
+
 	return 0;
 }
 
+/*
+ * For each matching key in key/value, call the given handler function.
+ */
+int
+rte_kvargs_process(const struct rte_kvargs *kvlist,
+		   const char *key_match,
+		   arg_handler_t handler,
+		   void *opaque_arg)
+{
+	return kvargs_process_common(kvlist, key_match, handler, opaque_arg, false);
+}
+
+/*
+ * For each matching key in key/value or only-key, call the given handler function.
+ */
+int
+rte_kvargs_process_opt(const struct rte_kvargs *kvlist,
+		       const char *key_match,
+		       arg_handler_t handler,
+		       void *opaque_arg)
+{
+	return kvargs_process_common(kvlist, key_match, handler, opaque_arg, true);
+}
+
 /* free the rte_kvargs structure */
 void
 rte_kvargs_free(struct rte_kvargs *kvlist)
diff --git a/lib/kvargs/rte_kvargs.h b/lib/kvargs/rte_kvargs.h
index 4900b750bc..ad0b609ad7 100644
--- a/lib/kvargs/rte_kvargs.h
+++ b/lib/kvargs/rte_kvargs.h
@@ -172,14 +172,17 @@ const char *rte_kvargs_get_with_value(const struct rte_kvargs *kvlist,
 				      const char *key, const char *value);
 
 /**
- * Call a handler function for each key/value matching the key
+ * Call a handler function for each key=value matching the key
  *
- * For each key/value association that matches the given key, calls the
+ * For each key=value association that matches the given key, calls the
  * handler function with the for a given arg_name passing the value on the
  * dictionary for that key and a given extra argument.
  *
+ * @note Compared to @see rte_kvargs_process_opt, this API will return -1
+ * when handle only-key case (that is the matched key's value is NULL).
+ *
  * @param kvlist
- *   The rte_kvargs structure. No error if NULL.
+ *   The rte_kvargs structure.
  * @param key_match
  *   The key on which the handler should be called, or NULL to process handler
  *   on all associations
@@ -195,6 +198,34 @@ const char *rte_kvargs_get_with_value(const struct rte_kvargs *kvlist,
 int rte_kvargs_process(const struct rte_kvargs *kvlist,
 	const char *key_match, arg_handler_t handler, void *opaque_arg);
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Call a handler function for each key=value or only-key matching the key
+ *
+ * For each key=value or only-key association that matches the given key, calls
+ * the handler function with the for a given arg_name passing the value on the
+ * dictionary for that key and a given extra argument.
+ *
+ * @param kvlist
+ *   The rte_kvargs structure.
+ * @param key_match
+ *   The key on which the handler should be called, or NULL to process handler
+ *   on all associations
+ * @param handler
+ *   The function to call for each matching key
+ * @param opaque_arg
+ *   A pointer passed unchanged to the handler
+ *
+ * @return
+ *   - 0 on success
+ *   - Negative on error
+ */
+__rte_experimental
+int rte_kvargs_process_opt(const struct rte_kvargs *kvlist,
+	const char *key_match, arg_handler_t handler, void *opaque_arg);
+
 /**
  * Count the number of associations matching the given key
  *
diff --git a/lib/kvargs/version.map b/lib/kvargs/version.map
index 387a94e725..15d482e9b3 100644
--- a/lib/kvargs/version.map
+++ b/lib/kvargs/version.map
@@ -16,4 +16,7 @@ EXPERIMENTAL {
 
 	# added in 21.11
 	rte_kvargs_get_with_value;
+
+	# added in 23.11
+	rte_kvargs_process_opt;
 };
