ACTION_COUNT,
        ACTION_RSS,
        ACTION_RSS_FUNC,
+       ACTION_RSS_LEVEL,
        ACTION_RSS_FUNC_DEFAULT,
        ACTION_RSS_FUNC_TOEPLITZ,
        ACTION_RSS_FUNC_SIMPLE_XOR,
 
 static const enum index action_rss[] = {
        ACTION_RSS_FUNC,
+       ACTION_RSS_LEVEL,
        ACTION_RSS_TYPES,
        ACTION_RSS_KEY,
        ACTION_RSS_KEY_LEN,
                .help = "simple XOR hash function",
                .call = parse_vc_action_rss_func,
        },
+       [ACTION_RSS_LEVEL] = {
+               .name = "level",
+               .help = "encapsulation level for \"types\"",
+               .next = NEXT(action_rss, NEXT_ENTRY(UNSIGNED)),
+               .args = ARGS(ARGS_ENTRY_ARB
+                            (offsetof(struct action_rss_data, conf) +
+                             offsetof(struct rte_flow_action_rss, level),
+                             sizeof(((struct rte_flow_action_rss *)0)->
+                                    level))),
+       },
        [ACTION_RSS_TYPES] = {
                .name = "types",
                .help = "specific RSS hash types",
        *action_rss_data = (struct action_rss_data){
                .conf = (struct rte_flow_action_rss){
                        .func = RTE_ETH_HASH_FUNCTION_DEFAULT,
+                       .level = 0,
                        .types = rss_hf,
                        .key_len = sizeof(action_rss_data->key),
                        .queue_num = RTE_MIN(nb_rxq, ACTION_RSS_QUEUE_NUM),
 
                if (dst.rss)
                        *dst.rss = (struct rte_flow_action_rss){
                                .func = src.rss->func,
+                               .level = src.rss->level,
                                .types = src.rss->types,
                                .key_len = src.rss->key_len,
                                .queue_num = src.rss->queue_num,
 
 overlaps ``hash.fdir.lo``. Since `Action: MARK`_ sets the ``hash.fdir.hi``
 field only, both can be requested simultaneously.
 
+Also, regarding packet encapsulation ``level``:
+
+- ``0`` requests the default behavior. Depending on the packet type, it can
+  mean outermost, innermost, anything in between or even no RSS.
+
+  It basically stands for the innermost encapsulation level RSS can be
+  performed on according to PMD and device capabilities.
+
+- ``1`` requests RSS to be performed on the outermost packet encapsulation
+  level.
+
+- ``2`` and subsequent values request RSS to be performed on the specified
+   inner packet encapsulation level, from outermost to innermost (lower to
+   higher values).
+
+Values other than ``0`` are not necessarily supported.
+
+Requesting a specific RSS level on unrecognized traffic results in undefined
+behavior. For predictable results, it is recommended to make the flow rule
+pattern match packet headers up to the requested encapsulation level so that
+only matching traffic goes through.
+
 .. _table_rte_flow_action_rss:
 
 .. table:: RSS
    +===============+=============================================+
    | ``func``      | RSS hash function to apply                  |
    +---------------+---------------------------------------------+
+   | ``level``     | encapsulation level for ``types``           |
+   +---------------+---------------------------------------------+
    | ``types``     | specific RSS hash types (see ``ETH_RSS_*``) |
    +---------------+---------------------------------------------+
    | ``key_len``   | hash key length in bytes                    |
 
   Target release for removal of the legacy API will be defined once most
   PMDs have switched to rte_flow.
 
-* ethdev: A new rss level field planned in 18.05.
-  The new API add rss_level field to ``rte_eth_rss_conf`` to enable a choice
-  of RSS hash calculation on outer or inner header of tunneled packet.
-
 * ethdev: A work is being planned for 18.05 to expose VF port representors
   as a mean to perform control and data path operation on the different VFs.
   As VF representor is an ethdev port, new fields are needed in order to map
 
     ``rss_conf->rss_key_len`` => ``key_len``,
     ``rss_conf->rss_hf`` => ``types``,
     ``num`` => ``queue_num``), and the addition of missing RSS parameters
-    (``func`` for RSS hash function to apply).
+    (``func`` for RSS hash function to apply and ``level`` for the
+    encapsulation level).
 
 
 ABI Changes
 
   - ``func {hash function}``: RSS hash function to apply, allowed tokens are
     the same as `set_hash_global_config`_.
 
+  - ``level {unsigned}``: encapsulation level for ``types``.
+
   - ``types [{RSS hash type} [...]] end``: specific RSS hash types, allowed
     tokens are the same as `set_hash_input_set`_, except that an empty list
     does not disable RSS but instead requests unspecified "best-effort"
 
                return rte_flow_error_set
                        (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act,
                         "non-default RSS hash functions are not supported");
+       if (rss->level)
+               return rte_flow_error_set
+                       (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act,
+                        "a nonzero RSS encapsulation level is not supported");
        if (rss->key_len && rss->key_len != RTE_DIM(rss_conf->key))
                return rte_flow_error_set
                        (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act,
 
                return -EINVAL;
        out->conf = (struct rte_flow_action_rss){
                .func = in->func,
+               .level = in->level,
                .types = in->types,
                .key_len = in->key_len,
                .queue_num = in->queue_num,
                    const struct rte_flow_action_rss *with)
 {
        return (comp->func == with->func &&
+               comp->level == with->level &&
                comp->types == with->types &&
                comp->key_len == with->key_len &&
                comp->queue_num == with->queue_num &&
 
                return -EINVAL;
        out->conf = (struct rte_flow_action_rss){
                .func = in->func,
+               .level = in->level,
                .types = in->types,
                .key_len = in->key_len,
                .queue_num = in->queue_num,
                     const struct rte_flow_action_rss *with)
 {
        return (comp->func == with->func &&
+               comp->level == with->level &&
                comp->types == with->types &&
                comp->key_len == with->key_len &&
                comp->queue_num == with->queue_num &&
 
                return rte_flow_error_set
                        (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act,
                         "non-default RSS hash functions are not supported");
+       if (rss->level)
+               return rte_flow_error_set
+                       (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act,
+                        "a nonzero RSS encapsulation level is not supported");
        if (rss->key_len && rss->key_len > RTE_DIM(rss_config->key))
                return rte_flow_error_set
                        (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act,
 
                return rte_flow_error_set
                        (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act,
                         "non-default RSS hash functions are not supported");
+       if (rss->level)
+               return rte_flow_error_set
+                       (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act,
+                        "a nonzero RSS encapsulation level is not supported");
        if (rss->key_len && rss->key_len != RTE_DIM(rss_conf->key))
                return rte_flow_error_set
                        (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act,
 
                return -EINVAL;
        out->conf = (struct rte_flow_action_rss){
                .func = in->func,
+               .level = in->level,
                .types = in->types,
                .key_len = in->key_len,
                .queue_num = in->queue_num,
                      const struct rte_flow_action_rss *with)
 {
        return (comp->func == with->func &&
+               comp->level == with->level &&
                comp->types == with->types &&
                comp->key_len == with->key_len &&
                comp->queue_num == with->queue_num &&
 
                                        " is Toeplitz";
                                goto exit_action_not_supported;
                        }
+                       if (rss->level) {
+                               msg = "a nonzero RSS encapsulation level is"
+                                       " not supported";
+                               goto exit_action_not_supported;
+                       }
                        rte_errno = 0;
                        fields = mlx4_conv_rss_types(priv, rss->types);
                        if (fields == (uint64_t)-1 && rte_errno) {
        uint16_t queue[queues];
        struct rte_flow_action_rss action_rss = {
                .func = RTE_ETH_HASH_FUNCTION_DEFAULT,
+               .level = 0,
                .types = -1,
                .key_len = MLX4_RSS_HASH_KEY_SIZE,
                .queue_num = queues,
 
                                                   " function is Toeplitz");
                                return -rte_errno;
                        }
+                       if (rss->level) {
+                               rte_flow_error_set(error, EINVAL,
+                                                  RTE_FLOW_ERROR_TYPE_ACTION,
+                                                  actions,
+                                                  "a nonzero RSS encapsulation"
+                                                  " level is not supported");
+                               return -rte_errno;
+                       }
                        if (rss->types & MLX5_RSS_HF_MASK) {
                                rte_flow_error_set(error, EINVAL,
                                                   RTE_FLOW_ERROR_TYPE_ACTION,
                        }
                        parser->rss_conf = (struct rte_flow_action_rss){
                                .func = RTE_ETH_HASH_FUNCTION_DEFAULT,
+                               .level = 0,
                                .types = rss->types,
                                .key_len = rss_key_len,
                                .queue_num = rss->queue_num,
        flow->queues = (uint16_t (*)[])(flow + 1);
        flow->rss_conf = (struct rte_flow_action_rss){
                .func = RTE_ETH_HASH_FUNCTION_DEFAULT,
+               .level = 0,
                .types = parser.rss_conf.types,
                .key_len = parser.rss_conf.key_len,
                .queue_num = parser.rss_conf.queue_num,
        uint16_t queue[priv->reta_idx_n];
        struct rte_flow_action_rss action_rss = {
                .func = RTE_ETH_HASH_FUNCTION_DEFAULT,
+               .level = 0,
                .types = priv->rss_conf.rss_hf,
                .key_len = priv->rss_conf.rss_key_len,
                .queue_num = priv->reta_idx_n,
 
                return -EINVAL;
        }
 
+       if (rss->level)
+               return -EINVAL;
+
        if ((rss->types & ~SFC_RSS_OFFLOADS) != 0)
                return -EINVAL;
 
 
        struct rss_key rss_entry = { .hash_fields = 0,
                                     .key_size = 0 };
 
-       /* Check supported hash functions */
+       /* Check supported RSS features */
        if (rss->func != RTE_ETH_HASH_FUNCTION_DEFAULT)
                return rte_flow_error_set
                        (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
                         "non-default RSS hash functions are not supported");
+       if (rss->level)
+               return rte_flow_error_set
+                       (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+                        "a nonzero RSS encapsulation level is not supported");
 
        /* Get a new map key for a new RSS rule */
        err = bpf_rss_key(KEY_CMD_GET, &flow->key_idx);
 
                if (dst.rss)
                        *dst.rss = (struct rte_flow_action_rss){
                                .func = src.rss->func,
+                               .level = src.rss->level,
                                .types = src.rss->types,
                                .key_len = src.rss->key_len,
                                .queue_num = src.rss->queue_num,
 
  */
 struct rte_flow_action_rss {
        enum rte_eth_hash_function func; /**< RSS hash function to apply. */
+       /**
+        * Packet encapsulation level RSS hash @p types apply to.
+        *
+        * - @p 0 requests the default behavior. Depending on the packet
+        *   type, it can mean outermost, innermost, anything in between or
+        *   even no RSS.
+        *
+        *   It basically stands for the innermost encapsulation level RSS
+        *   can be performed on according to PMD and device capabilities.
+        *
+        * - @p 1 requests RSS to be performed on the outermost packet
+        *   encapsulation level.
+        *
+        * - @p 2 and subsequent values request RSS to be performed on the
+        *   specified inner packet encapsulation level, from outermost to
+        *   innermost (lower to higher values).
+        *
+        * Values other than @p 0 are not necessarily supported.
+        *
+        * Requesting a specific RSS level on unrecognized traffic results
+        * in undefined behavior. For predictable results, it is recommended
+        * to make the flow rule pattern match packet headers up to the
+        * requested encapsulation level so that only matching traffic goes
+        * through.
+        */
+       uint32_t level;
        uint64_t types; /**< Specific RSS hash types (see ETH_RSS_*). */
        uint32_t key_len; /**< Hash key length in bytes. */
        uint32_t queue_num; /**< Number of entries in @p queue. */