What can I help you with?
NVIDIA DPDK Documentation MLNX_DPDK_22.11_2310.5.1 LTS

Flow Quota

Quota flow action (RTE_FLOW_ACTION_TYPE_QUOTA) marks packet quota state as PASS or BLOCK depending on the available tokens number. If the number of the available tokens is zero or above, the quota state is PASS. Otherwise, quota state is BLOCK.

When the quota is in the PASS state, the number of tokens reduced by the hardware matches the packet L3 or L2 length, depending on the quota object mode. Additional quota mode allows reduction to a single token for each packet.

Application matches the quota state with the flow quota item (RTE_FLOW_ITEM_TYPE_QUOTA) and updates the available quota tokens number with SET or ADD operations:

  • SET assigns new available tokens value, and overwrites any tokens number already stored in the quota

  • ADD increases the available quota tokens

Application can query the number of quota tokens with the existing rte_flow_query() or with a new rte_flow_action_handle_query_update() APIs. The new API allows atomic tokens exchange.

The Quota design assumes that quota object tokens are distributed between application and hardware. Application tokens are initiated according to the application or business logic. Application transfers limited tokens amount to the hardware quota object to police network traffic associated with that hardware quota object. The hardware quota tokens are consumed according to the network traffic rate. The application replenishes periodically the hardware quota tokens from application tokens. When all the hardware and application tokens are exhausted, the quota remains in the BLOCK state until more tokens are provided.

Current State

Processed packet length

New State

Quota State

Quota Tokens Number

Quota State

Quota Tokens Number

1

PASS

500

200

PASS

300

2

PASS

500

1000

PASS

-500

3

PASS

0

1000

BLOCK

-1000

4

BLOCK

-100

ANY

BLOCK

-100

  • Quota is implemented with HWS API only

  • Quota is implemented as an indirect flow action only

  • The maximal value for SET and ADD quota operations is INT32_MAX (2G)

  • Application cannot use 2 consecutive ADD updates. Next tokens update after ADD must always be SET

  • Hardware can reduce non-negative tokens number to negative value

  • Quota flow action cannot be used with Meter or CT flow actions in the same rule

  • Quota flow action and item supported in non-root HWS tables – flow group must be > 0

  • The maximal number of hardware quota and HW meter objects <= 16e6

  • HWS Port Configuration

    Copy
    Copied!
                

    testpmd> flow configure <port> queues_number <qnum> queues_size <qsize> \                                      quotas_number <quota number[*]>

[*]quota number: maximal number of hardware quota objects assigned to a port

  • Create indirect quota flow action

    Copy
    Copied!
                

    testpmd> flow indirect_action <port> create ingress action_id <quota id> \                     action quota_create limit <tokens> mode [l2|l3|packet] / end

  • Modify-only quota tokens number

    Copy
    Copied!
                

    testpmd> flow indirect_action <port> update <quota id> action quota_update limit <tokens> update_op [set|add] / end

  • Query-only quota tokens number

    Copy
    Copied!
                

    testpmd> flow indirect_action <port> query <quota id>

  • Query-and-Modify quota-tokens number

    Copy
    Copied!
                

    testpmd> flow indirect_action 0 query_update 0 mode query_first action quota_update limit <tokens> update_op [set|add] / end

  • Create flow with quota action

    Copy
    Copied!
                

    testpmd> flow pattern_template <port> create … template <pattern> testpmd> flow queue <port> create <queue> … pattern <pattern> actions indirect <id> / jump group <grp> / end

  • Create flow with quota item

    Copy
    Copied!
                

    testpmd> flow pattern_template <port> create … template quota / end testpmd> flow queue <port> create <queue> … pattern quota quota_state spec pass quota_state mask pass / end actions mark id 0xaa / rss / end testpmd> flow queue <port> create <queue> … pattern quota quota_state spec drop quota_state mask drop / end actions mark id 0xff / rss / end

Quota Update

The handle_quota_object() shows how application can update tokens number in Quota the hardware object. The selection of Quota object for update and update frequency is determined by the application logic.

Copy
Copied!
            

struct application_quota { unsigned long limit; /* Maximal quota for object */ int chunk; /* Maximal HW incremental update */ struct rte_flow_action_handle *quota_handle; /* Indirect quota handle */ };   int handle_quota_objec t(unsigned short port_id, struct application_quota *quota) { int ret; struct rte_flow_error error; struct rte_flow_query_quota quota_query; struct rte_flow_update_quota quota_update_conf; struct rte_flow_action quota_update_action = { .type = RTE_FLOW_ACTION_TYPE_QUOTA, .conf = &quota_update_conf };   if (quota->limit == 0) return 0; else if (quota->limit >= quota->chunk) { quota_update_conf.op = RTE_FLOW_UPDATE_QUOTA_SET; quota_update_conf.quota = quota->chunk; } else { quota_update_conf.op = RTE_FLOW_UPDATE_QUOTA_ADD; quota_update_conf.quota = quota->limit; } ret = rte_flow_action_handle_query_update(port_id, quota->quota_handle, &quota_query, RTE_FLOW_QU_QUERY_FIRST, &error); if (ret) return rte_errno;   quota->limit = max(0, (long)quota->limit - quota_update_conf.quota + (long)quota_query.quota);   return 0; }


Quota RTE API Usage

The following function show how to use RTE API to create Quota flows.

Copy
Copied!
            

/* * Create HWS pattern template with quota flow item to match on quota state */ struct rte_flow_pattern_template * quota_item_template(unsigned short port_id, const struct rte_flow_pattern_template_attr *template_attr, struct rte_flow_error *error) {  const struct rte_flow_item tmpl_pattern[] = { [0] = { .type = RTE_FLOW_ITEM_TYPE_QUOTA }, [1] = { .type = RTE_FLOW_ITEM_TYPE_END } };    return rte_flow_pattern_template_create(port_id, template_attr, tmpl_pattern, error); }   /* * Create HWS actions template with quota flow action to set quota state */ struct rte_flow_actions_template * quota_action_template(unsigned short port_id, const struct rte_flow_action_handle *quota_idirect_action, struct rte_flow_error *error) { const struct rte_flow_actions_template_att tmpl_actions_attr = { .ingress = 1 }; const struct rte_flow_action tmpl_actions[] = { [0] = { .type = RTE_FLOW_ACTION_TYPE_INDIRECT, .conf = quota_idirect_action ? (const void *)*quota_idirect_action : NULL }, [1] = { .type = RTE_FLOW_ACTION_TYPE_JUMP, .conf = NULL }, [2] = { .type = RTE_FLOW_ACTION_TYPE_END } }; const struct rte_flow_action tmpl_actions_mask[] = { [0] = { .type = RTE_FLOW_ACTION_TYPE_QUOTA, .conf = NULL }, [1] = { .type = RTE_FLOW_ACTION_TYPE_JUMP, .conf = (const struct rte_flow_action_jump *)& { .group = 0 } }, [2] = { .type = RTE_FLOW_ACTION_TYPE_END } };   return rte_flow_actions_template_create(port_id, &tmpl_actions_attr, tmpl_actions, tmpl_actions_mask, error); }   /* * Create HWS flow with quota item */ struct rte_flow * quota_item_flow(unsigned short port_id, unsigned int queue_id, enum rte_flow_quota_state quota_state, const struct rte_flow_op_attr *op_attr, struct rte_flow_template_table *template_table, unsigned char pattern_template_index, const struct rte_flow_action actions[], unsigned char actions_template_index, void *user_data, struct rte_flow_error *error) { const struct rte_flow_item pattern[] = { [0] = { .type = RTE_FLOW_ITEM_TYPE_QUOTA, .spec = (const struct rte_flow_item_quota *)& { .state = quota_state }, .mask = (const struct rte_flow_item_quota *)& { .state = quota_state }, }, [1] = { .type = RTE_FLOW_ITEM_TYPE_END } };   return rte_flow_async_create(port_id, queue_id, op_attr, template_table, pattern, pattern_template_index, actions, actions_template_index, user_data, error); }   /* * Create HWS flow with quota action */ struct rte_flow * quota_action_flow(unsigned short port_id, unsigned int queue_id, const struct rte_flow_op_attr *op_attr, struct rte_flow_template_table *template_table, const struct rte_flow_item pattern[], unsigned char pattern_template_index, const struct rte_flow_action_handle *quota_action_handle, unsigned int jump_group, unsigned char actions_template_index, void *user_data, struct rte_flow_error *error) { const struct rte_flow_action actions[] = { [0] = { .type = RTE_FLOW_ACTION_TYPE_INDIRECT, .conf = (const void *)*quota_action_handle }, [1] = { .type = RTE_FLOW_ACTION_TYPE_JUMP, .conf = (const struct rte_flow_action_jump *)& { .group = jump_group } }, [2] = { .type = RTE_FLOW_ACTION_TYPE_END } };   return rte_flow_async_create(port_id, queue_id, op_attr, template_table, pattern, pattern_template_index, actions, actions_template_index, user_data, error); }


© Copyright 2024, NVIDIA. Last updated on Jan 9, 2025.