[net-next,V2] octeontx2-af: Tc flower offload support for inner VLAN
Commit Message
This patch extends current TC flower offload support to allow filters
involving inner VLAN matching, to be offloaded to HW.
Example command:
tc filter add dev eth2 protocol 802.1AD parent ffff: flower vlan_id 10
vlan_ethtype 802.1Q cvlan_id 20 skip_sw action drop
Signed-off-by: Suman Ghosh <sumang@marvell.com>
---
v2 changes:
- Addressed review comment from Leon for a minor code readjustment
.../net/ethernet/marvell/octeontx2/af/mbox.h | 1 +
.../net/ethernet/marvell/octeontx2/af/npc.h | 3 +
.../marvell/octeontx2/af/rvu_debugfs.c | 5 +
.../marvell/octeontx2/af/rvu_npc_fs.c | 13 +++
.../ethernet/marvell/octeontx2/nic/otx2_tc.c | 107 +++++++++++-------
5 files changed, 91 insertions(+), 38 deletions(-)
Comments
On Thu, Jul 27, 2023 at 10:42:52AM +0530, Suman Ghosh wrote:
...
> diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
> index 1e6fc23eca4f..89836cd299e4 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
> +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
> @@ -439,6 +439,64 @@ static int otx2_tc_parse_actions(struct otx2_nic *nic,
> return 0;
> }
>
> +static int otx2_tc_process_vlan(struct otx2_nic *nic, struct flow_msg *flow_spec,
> + struct flow_msg *flow_mask, struct flow_rule *rule,
> + struct npc_install_flow_req *req, bool is_inner)
> +{
Hi Suman,
Most of the code in this function seems to be moved from elsewhere.
It might make it slightly easier to review if there was a patch
that moved that code, then another patch that modified to
support the inner VLAN feature.
> + struct flow_match_vlan match;
> + u16 vlan_tci, vlan_tci_mask;
> +
> + if (is_inner)
> + flow_rule_match_cvlan(rule, &match);
> + else
> + flow_rule_match_vlan(rule, &match);
> +
> + if ((ntohs(match.key->vlan_tpid) != ETH_P_8021Q) &&
> + (ntohs(match.key->vlan_tpid) != ETH_P_8021AD)) {
I think eth_type_vlan() can be used here.
> + netdev_err(nic->netdev, "vlan tpid 0x%x not supported\n",
> + ntohs(match.key->vlan_tpid));
> + return -EOPNOTSUPP;
> + }
> +
> + if (!match.mask->vlan_id) {
> + struct flow_action_entry *act;
> + int i;
> +
> + flow_action_for_each(i, act, &rule->action) {
> + if (act->id == FLOW_ACTION_DROP) {
> + netdev_err(nic->netdev,
> + "vlan tpid 0x%x with vlan_id %d is not supported for DROP rule.\n",
> + ntohs(match.key->vlan_tpid), match.key->vlan_id);
> + return -EOPNOTSUPP;
> + }
> + }
> + }
> +
> + if (match.mask->vlan_id ||
> + match.mask->vlan_dei ||
> + match.mask->vlan_priority) {
> + vlan_tci = match.key->vlan_id |
> + match.key->vlan_dei << 12 |
> + match.key->vlan_priority << 13;
> +
> + vlan_tci_mask = match.mask->vlan_id |
> + match.mask->vlan_dei << 12 |
> + match.mask->vlan_priority << 13;
> +
> + if (is_inner) {
> + flow_spec->vlan_itci = htons(vlan_tci);
> + flow_mask->vlan_itci = htons(vlan_tci_mask);
> + req->features |= BIT_ULL(NPC_INNER_VID);
> + } else {
> + flow_spec->vlan_tci = htons(vlan_tci);
> + flow_mask->vlan_tci = htons(vlan_tci_mask);
> + req->features |= BIT_ULL(NPC_OUTER_VID);
> + }
> + }
> +
> + return 0;
> +}
> +
> static int otx2_tc_prepare_flow(struct otx2_nic *nic, struct otx2_tc_flow *node,
> struct flow_cls_offload *f,
> struct npc_install_flow_req *req)
> @@ -458,6 +516,7 @@ static int otx2_tc_prepare_flow(struct otx2_nic *nic, struct otx2_tc_flow *node,
> BIT(FLOW_DISSECTOR_KEY_BASIC) |
> BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
> BIT(FLOW_DISSECTOR_KEY_VLAN) |
> + BIT(FLOW_DISSECTOR_KEY_CVLAN) |
> BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
> BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
> BIT(FLOW_DISSECTOR_KEY_PORTS) |
> @@ -564,47 +623,19 @@ static int otx2_tc_prepare_flow(struct otx2_nic *nic, struct otx2_tc_flow *node,
> }
>
> if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
> - struct flow_match_vlan match;
> - u16 vlan_tci, vlan_tci_mask;
> -
> - flow_rule_match_vlan(rule, &match);
> -
> - if (ntohs(match.key->vlan_tpid) != ETH_P_8021Q) {
> - netdev_err(nic->netdev, "vlan tpid 0x%x not supported\n",
> - ntohs(match.key->vlan_tpid));
> - return -EOPNOTSUPP;
> - }
> + int ret;
>
> - if (!match.mask->vlan_id) {
> - struct flow_action_entry *act;
> - int i;
> -
> - flow_action_for_each(i, act, &rule->action) {
> - if (act->id == FLOW_ACTION_DROP) {
> - netdev_err(nic->netdev,
> - "vlan tpid 0x%x with vlan_id %d is not supported for DROP rule.\n",
> - ntohs(match.key->vlan_tpid),
> - match.key->vlan_id);
> - return -EOPNOTSUPP;
> - }
> - }
> - }
> -
> - if (match.mask->vlan_id ||
> - match.mask->vlan_dei ||
> - match.mask->vlan_priority) {
> - vlan_tci = match.key->vlan_id |
> - match.key->vlan_dei << 12 |
> - match.key->vlan_priority << 13;
> + ret = otx2_tc_process_vlan(nic, flow_spec, flow_mask, rule, req, false);
> + if (ret)
> + return ret;
> + }
>
> - vlan_tci_mask = match.mask->vlan_id |
> - match.mask->vlan_dei << 12 |
> - match.mask->vlan_priority << 13;
> + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CVLAN)) {
> + int ret;
>
> - flow_spec->vlan_tci = htons(vlan_tci);
> - flow_mask->vlan_tci = htons(vlan_tci_mask);
> - req->features |= BIT_ULL(NPC_OUTER_VID);
> - }
> + ret = otx2_tc_process_vlan(nic, flow_spec, flow_mask, rule, req, true);
> + if (ret)
> + return ret;
> }
>
> if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS)) {
> --
> 2.25.1
>
>
>> }
>>
>> +static int otx2_tc_process_vlan(struct otx2_nic *nic, struct flow_msg
>*flow_spec,
>> + struct flow_msg *flow_mask, struct flow_rule *rule,
>> + struct npc_install_flow_req *req, bool is_inner) {
>
>Hi Suman,
>
>Most of the code in this function seems to be moved from elsewhere.
>It might make it slightly easier to review if there was a patch that
>moved that code, then another patch that modified to support the inner
>VLAN feature.
[Suman] Okay Simon. I will push a patch set of 2 patches involving the suggested changes.
>
>> + struct flow_match_vlan match;
>> + u16 vlan_tci, vlan_tci_mask;
>> +
>> + if (is_inner)
>> + flow_rule_match_cvlan(rule, &match);
>> + else
>> + flow_rule_match_vlan(rule, &match);
>> +
>> + if ((ntohs(match.key->vlan_tpid) != ETH_P_8021Q) &&
>> + (ntohs(match.key->vlan_tpid) != ETH_P_8021AD)) {
>
>I think eth_type_vlan() can be used here.
[Suman] Ack.
>
>> + netdev_err(nic->netdev, "vlan tpid 0x%x not supported\n",
>> + ntohs(match.key->vlan_tpid));
>> + return -EOPNOTSUPP;
>> + }
>> +
>> + if (!match.mask->vlan_id) {
>> + struct flow_action_entry *act;
>> + int i;
>> +
>> + flow_action_for_each(i, act, &rule->action) {
>> + if (act->id == FLOW_ACTION_DROP) {
>> + netdev_err(nic->netdev,
>> + "vlan tpid 0x%x with vlan_id %d is not
>supported for DROP rule.\n",
>> + ntohs(match.key->vlan_tpid), match.key-
>>vlan_id);
>> + return -EOPNOTSUPP;
>> + }
>> + }
>> + }
>> +
>> + if (match.mask->vlan_id ||
>> + match.mask->vlan_dei ||
>> + match.mask->vlan_priority) {
>> + vlan_tci = match.key->vlan_id |
>> + match.key->vlan_dei << 12 |
>> + match.key->vlan_priority << 13;
>> +
>> + vlan_tci_mask = match.mask->vlan_id |
>> + match.mask->vlan_dei << 12 |
>> + match.mask->vlan_priority << 13;
>> +
>> + if (is_inner) {
>> + flow_spec->vlan_itci = htons(vlan_tci);
>> + flow_mask->vlan_itci = htons(vlan_tci_mask);
>> + req->features |= BIT_ULL(NPC_INNER_VID);
>> + } else {
>> + flow_spec->vlan_tci = htons(vlan_tci);
>> + flow_mask->vlan_tci = htons(vlan_tci_mask);
>> + req->features |= BIT_ULL(NPC_OUTER_VID);
>> + }
>> + }
>> +
>> + return 0;
>> +}
>> +
>> static int otx2_tc_prepare_flow(struct otx2_nic *nic, struct
>otx2_tc_flow *node,
>> struct flow_cls_offload *f,
>> struct npc_install_flow_req *req) @@ -458,6 +516,7
>@@ static int
>> otx2_tc_prepare_flow(struct otx2_nic *nic, struct otx2_tc_flow *node,
>> BIT(FLOW_DISSECTOR_KEY_BASIC) |
>> BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
>> BIT(FLOW_DISSECTOR_KEY_VLAN) |
>> + BIT(FLOW_DISSECTOR_KEY_CVLAN) |
>> BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
>> BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
>> BIT(FLOW_DISSECTOR_KEY_PORTS) | @@ -564,47 +623,19 @@ static
>> int otx2_tc_prepare_flow(struct otx2_nic *nic, struct otx2_tc_flow
>*node,
>> }
>>
>> if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
>> - struct flow_match_vlan match;
>> - u16 vlan_tci, vlan_tci_mask;
>> -
>> - flow_rule_match_vlan(rule, &match);
>> -
>> - if (ntohs(match.key->vlan_tpid) != ETH_P_8021Q) {
>> - netdev_err(nic->netdev, "vlan tpid 0x%x not supported\n",
>> - ntohs(match.key->vlan_tpid));
>> - return -EOPNOTSUPP;
>> - }
>> + int ret;
>>
>> - if (!match.mask->vlan_id) {
>> - struct flow_action_entry *act;
>> - int i;
>> -
>> - flow_action_for_each(i, act, &rule->action) {
>> - if (act->id == FLOW_ACTION_DROP) {
>> - netdev_err(nic->netdev,
>> - "vlan tpid 0x%x with vlan_id %d is not
>supported for DROP rule.\n",
>> - ntohs(match.key->vlan_tpid),
>> - match.key->vlan_id);
>> - return -EOPNOTSUPP;
>> - }
>> - }
>> - }
>> -
>> - if (match.mask->vlan_id ||
>> - match.mask->vlan_dei ||
>> - match.mask->vlan_priority) {
>> - vlan_tci = match.key->vlan_id |
>> - match.key->vlan_dei << 12 |
>> - match.key->vlan_priority << 13;
>> + ret = otx2_tc_process_vlan(nic, flow_spec, flow_mask, rule,
>req, false);
>> + if (ret)
>> + return ret;
>> + }
>>
>> - vlan_tci_mask = match.mask->vlan_id |
>> - match.mask->vlan_dei << 12 |
>> - match.mask->vlan_priority << 13;
>> + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CVLAN)) {
>> + int ret;
>>
>> - flow_spec->vlan_tci = htons(vlan_tci);
>> - flow_mask->vlan_tci = htons(vlan_tci_mask);
>> - req->features |= BIT_ULL(NPC_OUTER_VID);
>> - }
>> + ret = otx2_tc_process_vlan(nic, flow_spec, flow_mask, rule,
>req, true);
>> + if (ret)
>> + return ret;
>> }
>>
>> if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS)) {
>> --
>> 2.25.1
>>
>>
@@ -1461,6 +1461,7 @@ struct flow_msg {
u8 ip_flag;
u8 next_header;
};
+ __be16 vlan_itci;
};
struct npc_install_flow_req {
@@ -184,6 +184,7 @@ enum key_fields {
NPC_VLAN_ETYPE_CTAG, /* 0x8100 */
NPC_VLAN_ETYPE_STAG, /* 0x88A8 */
NPC_OUTER_VID,
+ NPC_INNER_VID,
NPC_TOS,
NPC_IPFRAG_IPV4,
NPC_SIP_IPV4,
@@ -229,6 +230,8 @@ enum key_fields {
NPC_VLAN_TAG1,
/* outer vlan tci for double tagged frame */
NPC_VLAN_TAG2,
+ /* inner vlan tci for double tagged frame */
+ NPC_VLAN_TAG3,
/* other header fields programmed to extract but not of our interest */
NPC_UNKNOWN,
NPC_KEY_FIELDS_MAX,
@@ -2787,6 +2787,11 @@ static void rvu_dbg_npc_mcam_show_flows(struct seq_file *s,
seq_printf(s, "mask 0x%x\n",
ntohs(rule->mask.vlan_tci));
break;
+ case NPC_INNER_VID:
+ seq_printf(s, "0x%x ", ntohs(rule->packet.vlan_itci));
+ seq_printf(s, "mask 0x%x\n",
+ ntohs(rule->mask.vlan_itci));
+ break;
case NPC_TOS:
seq_printf(s, "%d ", rule->packet.tos);
seq_printf(s, "mask 0x%x\n", rule->mask.tos);
@@ -20,6 +20,7 @@ static const char * const npc_flow_names[] = {
[NPC_VLAN_ETYPE_CTAG] = "vlan ether type ctag",
[NPC_VLAN_ETYPE_STAG] = "vlan ether type stag",
[NPC_OUTER_VID] = "outer vlan id",
+ [NPC_INNER_VID] = "inner vlan id",
[NPC_TOS] = "tos",
[NPC_IPFRAG_IPV4] = "fragmented IPv4 header ",
[NPC_SIP_IPV4] = "ipv4 source ip",
@@ -327,6 +328,8 @@ static void npc_handle_multi_layer_fields(struct rvu *rvu, int blkaddr, u8 intf)
*/
struct npc_key_field *vlan_tag1;
struct npc_key_field *vlan_tag2;
+ /* Inner VLAN TCI for double tagged frames */
+ struct npc_key_field *vlan_tag3;
u64 *features;
u8 start_lid;
int i;
@@ -349,6 +352,7 @@ static void npc_handle_multi_layer_fields(struct rvu *rvu, int blkaddr, u8 intf)
etype_tag2 = &key_fields[NPC_ETYPE_TAG2];
vlan_tag1 = &key_fields[NPC_VLAN_TAG1];
vlan_tag2 = &key_fields[NPC_VLAN_TAG2];
+ vlan_tag3 = &key_fields[NPC_VLAN_TAG3];
/* if key profile programmed does not extract Ethertype at all */
if (!etype_ether->nr_kws && !etype_tag1->nr_kws && !etype_tag2->nr_kws) {
@@ -430,6 +434,12 @@ static void npc_handle_multi_layer_fields(struct rvu *rvu, int blkaddr, u8 intf)
goto done;
}
*features |= BIT_ULL(NPC_OUTER_VID);
+
+ /* If key profile extracts inner vlan tci */
+ if (vlan_tag3->nr_kws) {
+ key_fields[NPC_INNER_VID] = *vlan_tag3;
+ *features |= BIT_ULL(NPC_INNER_VID);
+ }
done:
return;
}
@@ -512,6 +522,7 @@ do { \
NPC_SCAN_HDR(NPC_ETYPE_TAG2, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, 8, 2);
NPC_SCAN_HDR(NPC_VLAN_TAG1, NPC_LID_LB, NPC_LT_LB_CTAG, 2, 2);
NPC_SCAN_HDR(NPC_VLAN_TAG2, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, 2, 2);
+ NPC_SCAN_HDR(NPC_VLAN_TAG3, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, 6, 2);
NPC_SCAN_HDR(NPC_DMAC, NPC_LID_LA, la_ltype, la_start, 6);
/* SMAC follows the DMAC(which is 6 bytes) */
NPC_SCAN_HDR(NPC_SMAC, NPC_LID_LA, la_ltype, la_start + 6, 6);
@@ -932,6 +943,8 @@ do { \
NPC_WRITE_FLOW(NPC_OUTER_VID, vlan_tci, ntohs(pkt->vlan_tci), 0,
ntohs(mask->vlan_tci), 0);
+ NPC_WRITE_FLOW(NPC_INNER_VID, vlan_itci, ntohs(pkt->vlan_itci), 0,
+ ntohs(mask->vlan_itci), 0);
NPC_WRITE_FLOW(NPC_IPFRAG_IPV6, next_header, pkt->next_header, 0,
mask->next_header, 0);
@@ -439,6 +439,64 @@ static int otx2_tc_parse_actions(struct otx2_nic *nic,
return 0;
}
+static int otx2_tc_process_vlan(struct otx2_nic *nic, struct flow_msg *flow_spec,
+ struct flow_msg *flow_mask, struct flow_rule *rule,
+ struct npc_install_flow_req *req, bool is_inner)
+{
+ struct flow_match_vlan match;
+ u16 vlan_tci, vlan_tci_mask;
+
+ if (is_inner)
+ flow_rule_match_cvlan(rule, &match);
+ else
+ flow_rule_match_vlan(rule, &match);
+
+ if ((ntohs(match.key->vlan_tpid) != ETH_P_8021Q) &&
+ (ntohs(match.key->vlan_tpid) != ETH_P_8021AD)) {
+ netdev_err(nic->netdev, "vlan tpid 0x%x not supported\n",
+ ntohs(match.key->vlan_tpid));
+ return -EOPNOTSUPP;
+ }
+
+ if (!match.mask->vlan_id) {
+ struct flow_action_entry *act;
+ int i;
+
+ flow_action_for_each(i, act, &rule->action) {
+ if (act->id == FLOW_ACTION_DROP) {
+ netdev_err(nic->netdev,
+ "vlan tpid 0x%x with vlan_id %d is not supported for DROP rule.\n",
+ ntohs(match.key->vlan_tpid), match.key->vlan_id);
+ return -EOPNOTSUPP;
+ }
+ }
+ }
+
+ if (match.mask->vlan_id ||
+ match.mask->vlan_dei ||
+ match.mask->vlan_priority) {
+ vlan_tci = match.key->vlan_id |
+ match.key->vlan_dei << 12 |
+ match.key->vlan_priority << 13;
+
+ vlan_tci_mask = match.mask->vlan_id |
+ match.mask->vlan_dei << 12 |
+ match.mask->vlan_priority << 13;
+
+ if (is_inner) {
+ flow_spec->vlan_itci = htons(vlan_tci);
+ flow_mask->vlan_itci = htons(vlan_tci_mask);
+ req->features |= BIT_ULL(NPC_INNER_VID);
+ } else {
+ flow_spec->vlan_tci = htons(vlan_tci);
+ flow_mask->vlan_tci = htons(vlan_tci_mask);
+ req->features |= BIT_ULL(NPC_OUTER_VID);
+ }
+ }
+
+ return 0;
+}
+
static int otx2_tc_prepare_flow(struct otx2_nic *nic, struct otx2_tc_flow *node,
struct flow_cls_offload *f,
struct npc_install_flow_req *req)
@@ -458,6 +516,7 @@ static int otx2_tc_prepare_flow(struct otx2_nic *nic, struct otx2_tc_flow *node,
BIT(FLOW_DISSECTOR_KEY_BASIC) |
BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
BIT(FLOW_DISSECTOR_KEY_VLAN) |
+ BIT(FLOW_DISSECTOR_KEY_CVLAN) |
BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
BIT(FLOW_DISSECTOR_KEY_PORTS) |
@@ -564,47 +623,19 @@ static int otx2_tc_prepare_flow(struct otx2_nic *nic, struct otx2_tc_flow *node,
}
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
- struct flow_match_vlan match;
- u16 vlan_tci, vlan_tci_mask;
-
- flow_rule_match_vlan(rule, &match);
-
- if (ntohs(match.key->vlan_tpid) != ETH_P_8021Q) {
- netdev_err(nic->netdev, "vlan tpid 0x%x not supported\n",
- ntohs(match.key->vlan_tpid));
- return -EOPNOTSUPP;
- }
+ int ret;
- if (!match.mask->vlan_id) {
- struct flow_action_entry *act;
- int i;
-
- flow_action_for_each(i, act, &rule->action) {
- if (act->id == FLOW_ACTION_DROP) {
- netdev_err(nic->netdev,
- "vlan tpid 0x%x with vlan_id %d is not supported for DROP rule.\n",
- ntohs(match.key->vlan_tpid),
- match.key->vlan_id);
- return -EOPNOTSUPP;
- }
- }
- }
-
- if (match.mask->vlan_id ||
- match.mask->vlan_dei ||
- match.mask->vlan_priority) {
- vlan_tci = match.key->vlan_id |
- match.key->vlan_dei << 12 |
- match.key->vlan_priority << 13;
+ ret = otx2_tc_process_vlan(nic, flow_spec, flow_mask, rule, req, false);
+ if (ret)
+ return ret;
+ }
- vlan_tci_mask = match.mask->vlan_id |
- match.mask->vlan_dei << 12 |
- match.mask->vlan_priority << 13;
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CVLAN)) {
+ int ret;
- flow_spec->vlan_tci = htons(vlan_tci);
- flow_mask->vlan_tci = htons(vlan_tci_mask);
- req->features |= BIT_ULL(NPC_OUTER_VID);
- }
+ ret = otx2_tc_process_vlan(nic, flow_spec, flow_mask, rule, req, true);
+ if (ret)
+ return ret;
}
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS)) {