Meter Sharing Between Ports Inside a Single switchdev
testpmd> add port meter profile srtcm_rfc2697 0
21
155189248
19398656
0
0
testpmd> add port meter policy 0
37
g_actions jump group 2
/ end y_actions end r_actions drop / end
testpmd> create port meter 0
102
21
37
yes 0xffff
1
0
testpmd> flow create 0
ingress transfer group 1
pattern eth / end actions meter mtr_id 102
/ end
testpmd> flow create 0
ingress transfer group 1
pattern eth / port_id id is 1
/ end actions meter mtr_id 102
/ end
Meter is created on PF Rep (port 0) which is used to match the traffic on VF Rep1 (port 1) and redirect the matching items to VF Rep2 (port 2).
static
struct rte_flow_item pattern[] = {
[L2] = { /* ETH type is set since we always start from ETH. */
.type = RTE_FLOW_ITEM_TYPE_ETH,
.spec = NULL,
.mask = NULL,
.last = NULL },
[L3] = {
.type = RTE_FLOW_ITEM_TYPE_VOID,
.spec = NULL,
.mask = NULL,
.last = NULL },
[L4] = {
.type = RTE_FLOW_ITEM_TYPE_VOID,
.spec = NULL,
.mask = NULL,
.last = NULL },
[TUNNEL] = {
.type = RTE_FLOW_ITEM_TYPE_VOID,
.spec = NULL,
.mask = NULL,
.last = NULL },
[L2_INNER] = {
.type = RTE_FLOW_ITEM_TYPE_VOID,
.spec = NULL,
.mask = NULL,
.last = NULL },
[L3_INNER] = {
.type = RTE_FLOW_ITEM_TYPE_VOID,
.spec = NULL,
.mask = NULL,
.last = NULL },
[L4_INNER] = {
.type = RTE_FLOW_ITEM_TYPE_VOID,
.spec = NULL,
.mask = NULL,
.last = NULL },
[END] = {
.type = RTE_FLOW_ITEM_TYPE_END,
.spec = NULL,
.mask = NULL,
.last = NULL },
};
static
int
add_meter_profile(uint16_t port_id, uint32_t profile_id,
struct rte_mtr_error *error)
{
struct rte_mtr_meter_profile profile;
memset(&profile, 0
, sizeof(profile));
profile.alg = RTE_MTR_SRTCM_RFC2697; /* the one supported. */
profile.srtcm_rfc2697.cir = 1
*1024
*1024
; /* 1MBps. */
profile.srtcm_rfc2697.cbs = 64
*1024
; /* allow burst in 64KB. */
profile.srtcm_rfc2697.ebs = 0
; /* ignored. */
profile.packet_mode = 0
;
return
rte_mtr_meter_profile_add(port_id, profile_id, &profile, error);
}
static
int
add_meter_policy(uint16_t port_id, uint32_t policy_id,
struct rte_mtr_error *error)
{
struct rte_mtr_meter_policy_params policy = {0
};
const
struct rte_flow_action end = {RTE_FLOW_ACTION_TYPE_DROP, NULL};
policy.actions[RTE_COLOR_GREEN] = NULL;
policy.actions[RTE_COLOR_YELLOW] = NULL;
policy.actions[RTE_COLOR_RED] = &end;
return
rte_mtr_meter_policy_add(port_id, policy_id, &policy, error);
}
static
int
create_meter(uint16_t port_id, uint32_t mtr_id, uint32_t profile_id,
uint32_t policy_id, int
shared, struct rte_mtr_error *error)
{
struct rte_mtr_params params;
memset(params, 0
, sizeof(params));
params.meter_enable = 1
;
params.use_prev_mtr_color = 0
;
params.meter_policy_id = policy_id;
params.meter_profile_id = profile_id;
params.dscp_table = NULL; /* no input color. */
/* Enable all stats. */
params.stats_mask = RTE_MTR_STATS_N_BYTES_GREEN |
RTE_MTR_STATS_N_BYTES_YELLOW |
RTE_MTR_STATS_N_BYTES_RED |
RTE_MTR_STATS_N_BYTES_DROPPED |
RTE_MTR_STATS_N_PKTS_GREEN |
RTE_MTR_STATS_N_PKTS_YELLOW |
RTE_MTR_STATS_N_PKTS_RED |
RTE_MTR_STATS_N_PKTS_DROPPED;
return
rte_mtr_create(port_id, mtr_id, ms, shared, error);
}
/*
* create flow with meter. port 0-2 is PF, VF1, VF2
* meter create on port_id, and match port_id + 1 traffic,
* redirect to port + 2 if matching
*/
int
create_flow_with_meter(uint16_t port_id)
{
int
ret;
struct rte_mtr_error mtr_error;
uint32_t profile_id = 0
;
uint32_t policy_id = 0
;
uint32_t mtr_id = 0
;
int
shared = 1
; /* mtr is shared. */
ret = add_meter_profile(port_id, profile_id, &mtr_error);
if
(ret) {
printf("cannot add meter profile, error: %s\n"
,
mtr_error.message);
return
ret;
}
ret = add_meter_policy(port_id, policy_id, &mtr_error);
if
(ret) {
printf("cannot add meter policy, error: %s\n"
,
mtr_error.message);
return
ret;
}
ret = create_meter(port_id, mtr_id, profile_id, policy_id, shared, &mtr_error);
if
(ret) {
printf("cannot create meter: %u with profile: %u, error: %s\n"
,
mtr_id, profile_id, mtr_error.message);
return
ret;
}
struct rte_flow *flow;
struct rte_flow_error error;
struct rte_flow_attr attr = { /* holds the flow attributes. */
.group = 0
, /* set the rule on the main group. */
.ingress = 1
,/* rx flow. */
.transfer = 1
,
.priority = 1
, }; /* add priority to rule
to give the decap rule higher priority since
it is more specific */
struct rte_flow_item_port_id port_mask = {
.id = 0xffffffff
,
};
struct rte_flow_item_port_id port_spec = {
.id = port_id + 1
,
};
struct rte_flow_item_ipv4 ipv4_outer = {
.hdr = {
.src_addr = rte_cpu_to_be_32(0x0D0A0A0A
),
/* match on 13.10.10.10 src address */
}};
struct rte_flow_item_ipv4 ipv4_mask = {
.hdr = {
.src_addr = RTE_BE32(0xffffffff
)}};
pattern[L2].type = RTE_FLOW_ITEM_TYPE_ETH;
pattern[L3].type = RTE_FLOW_ITEM_TYPE_IPV4;
pattern[L3].spec = &ipv4_outer;
pattern[L3].mask = &ipv4_mask;
pattern[L4].type = RTE_FLOW_ITEM_TYPE_PORT_ID;
pattern[L4].spec = &port_spec;
pattern[L4].mask = &port_mask;
pattern[TUNNEL].type = RTE_FLOW_ITEM_TYPE_END;
struct rte_flow_action_meter meter = {.mtr_id = mtr_id};
struct rte_flow_action_port_id port_conf = {.id = port_id + 2
};
struct rte_flow_action actions[] = {
[0
] = { /* meter action. */
.type = RTE_FLOW_ACTION_TYPE_METER,
.conf = &meter},
[1
] = { /* the queue action to be used. */
.type = RTE_FLOW_ACTION_TYPE_PORT_ID,
.conf = &port_conf },
[2
] = { /* end action mast be the last action. */
.type = RTE_FLOW_ACTION_TYPE_END,},
};
flow = rte_flow_create(port_id, &attr, pattern, actions, &error);
if
(!flow) {
printf("can't create flow with with mtr id: %u, mtr profile: %u on port: %u, error: %s\n"
,
mtr_id, profile_id, port_id, error.message);
return
-1
;
}
return
0
;
}