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
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
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
testpmd> flow indirect_action <port> update <quota id> action quota_update limit <tokens> update_op [set|add] / end
Query-only quota tokens number
testpmd> flow indirect_action <port> query <quota id>
Query-and-Modify quota-tokens number
testpmd> flow indirect_action
0
query_update0
mode query_first action quota_update limit <tokens> update_op [set|add] / endCreate flow with quota action
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
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 id0xff
/ 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.
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 = "a_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, "a_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.
/*
* 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);
}