Skip to content

Commit 8af56f4

Browse files
jahurleydavem330
authored andcommitted
nfp: flower: offload merge flows
A merge flow is formed from 2 sub flows. The match fields of the merge are the same as the first sub flow that has formed it, with the actions being a combination of the first and second sub flow. Therefore, a merge flow should replace sub flow 1 when offloaded. Offload valid merge flows by using a new 'flow mod' message type to replace an existing offloaded rule. Track the deletion of sub flows that are linked to a merge flow and revert offloaded merge rules if required. Signed-off-by: John Hurley <[email protected]> Signed-off-by: Simon Horman <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent aa6ce2e commit 8af56f4

File tree

4 files changed

+126
-13
lines changed

4 files changed

+126
-13
lines changed

drivers/net/ethernet/netronome/nfp/flower/cmsg.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,7 @@ struct nfp_flower_cmsg_hdr {
402402
/* Types defined for port related control messages */
403403
enum nfp_flower_cmsg_type_port {
404404
NFP_FLOWER_CMSG_TYPE_FLOW_ADD = 0,
405+
NFP_FLOWER_CMSG_TYPE_FLOW_MOD = 1,
405406
NFP_FLOWER_CMSG_TYPE_FLOW_DEL = 2,
406407
NFP_FLOWER_CMSG_TYPE_LAG_CONFIG = 4,
407408
NFP_FLOWER_CMSG_TYPE_PORT_REIFY = 6,

drivers/net/ethernet/netronome/nfp/flower/main.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ struct nfp_fl_payload {
253253
char *mask_data;
254254
char *action_data;
255255
struct list_head linked_flows;
256+
bool in_hw;
256257
};
257258

258259
struct nfp_fl_payload_link {
@@ -329,6 +330,8 @@ int nfp_compile_flow_metadata(struct nfp_app *app,
329330
struct tc_cls_flower_offload *flow,
330331
struct nfp_fl_payload *nfp_flow,
331332
struct net_device *netdev);
333+
void __nfp_modify_flow_metadata(struct nfp_flower_priv *priv,
334+
struct nfp_fl_payload *nfp_flow);
332335
int nfp_modify_flow_metadata(struct nfp_app *app,
333336
struct nfp_fl_payload *nfp_flow);
334337

drivers/net/ethernet/netronome/nfp/flower/metadata.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -276,9 +276,6 @@ nfp_check_mask_remove(struct nfp_app *app, char *mask_data, u32 mask_len,
276276
if (!mask_entry)
277277
return false;
278278

279-
if (meta_flags)
280-
*meta_flags &= ~NFP_FL_META_FLAG_MANAGE_MASK;
281-
282279
*mask_id = mask_entry->mask_id;
283280
mask_entry->ref_cnt--;
284281
if (!mask_entry->ref_cnt) {
@@ -367,6 +364,14 @@ int nfp_compile_flow_metadata(struct nfp_app *app,
367364
return err;
368365
}
369366

367+
void __nfp_modify_flow_metadata(struct nfp_flower_priv *priv,
368+
struct nfp_fl_payload *nfp_flow)
369+
{
370+
nfp_flow->meta.flags &= ~NFP_FL_META_FLAG_MANAGE_MASK;
371+
nfp_flow->meta.flow_version = cpu_to_be64(priv->flower_version);
372+
priv->flower_version++;
373+
}
374+
370375
int nfp_modify_flow_metadata(struct nfp_app *app,
371376
struct nfp_fl_payload *nfp_flow)
372377
{
@@ -375,13 +380,12 @@ int nfp_modify_flow_metadata(struct nfp_app *app,
375380
u8 new_mask_id = 0;
376381
u32 temp_ctx_id;
377382

383+
__nfp_modify_flow_metadata(priv, nfp_flow);
384+
378385
nfp_check_mask_remove(app, nfp_flow->mask_data,
379386
nfp_flow->meta.mask_len, &nfp_flow->meta.flags,
380387
&new_mask_id);
381388

382-
nfp_flow->meta.flow_version = cpu_to_be64(priv->flower_version);
383-
priv->flower_version++;
384-
385389
/* Update flow payload with mask ids. */
386390
nfp_flow->unmasked_data[NFP_FL_MASK_ID_LOCATION] = new_mask_id;
387391

drivers/net/ethernet/netronome/nfp/flower/offload.c

Lines changed: 112 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
348348
break;
349349

350350
case cpu_to_be16(ETH_P_IPV6):
351-
key_layer |= NFP_FLOWER_LAYER_IPV6;
351+
key_layer |= NFP_FLOWER_LAYER_IPV6;
352352
key_size += sizeof(struct nfp_flower_ipv6);
353353
break;
354354

@@ -399,6 +399,7 @@ nfp_flower_allocate_new(struct nfp_fl_key_ls *key_layer)
399399
flow_pay->nfp_tun_ipv4_addr = 0;
400400
flow_pay->meta.flags = 0;
401401
INIT_LIST_HEAD(&flow_pay->linked_flows);
402+
flow_pay->in_hw = false;
402403

403404
return flow_pay;
404405

@@ -769,6 +770,8 @@ int nfp_flower_merge_offloaded_flows(struct nfp_app *app,
769770
struct nfp_fl_payload *sub_flow1,
770771
struct nfp_fl_payload *sub_flow2)
771772
{
773+
struct tc_cls_flower_offload merge_tc_off;
774+
struct nfp_flower_priv *priv = app->priv;
772775
struct nfp_fl_payload *merge_flow;
773776
struct nfp_fl_key_ls merge_key_ls;
774777
int err;
@@ -810,8 +813,34 @@ int nfp_flower_merge_offloaded_flows(struct nfp_app *app,
810813
if (err)
811814
goto err_unlink_sub_flow1;
812815

813-
err = -EOPNOTSUPP;
816+
merge_tc_off.cookie = merge_flow->tc_flower_cookie;
817+
err = nfp_compile_flow_metadata(app, &merge_tc_off, merge_flow,
818+
merge_flow->ingress_dev);
819+
if (err)
820+
goto err_unlink_sub_flow2;
814821

822+
err = rhashtable_insert_fast(&priv->flow_table, &merge_flow->fl_node,
823+
nfp_flower_table_params);
824+
if (err)
825+
goto err_release_metadata;
826+
827+
err = nfp_flower_xmit_flow(app, merge_flow,
828+
NFP_FLOWER_CMSG_TYPE_FLOW_MOD);
829+
if (err)
830+
goto err_remove_rhash;
831+
832+
merge_flow->in_hw = true;
833+
sub_flow1->in_hw = false;
834+
835+
return 0;
836+
837+
err_remove_rhash:
838+
WARN_ON_ONCE(rhashtable_remove_fast(&priv->flow_table,
839+
&merge_flow->fl_node,
840+
nfp_flower_table_params));
841+
err_release_metadata:
842+
nfp_modify_flow_metadata(app, merge_flow);
843+
err_unlink_sub_flow2:
815844
nfp_flower_unlink_flows(merge_flow, sub_flow2);
816845
err_unlink_sub_flow1:
817846
nfp_flower_unlink_flows(merge_flow, sub_flow1);
@@ -889,6 +918,8 @@ nfp_flower_add_offload(struct nfp_app *app, struct net_device *netdev,
889918
if (port)
890919
port->tc_offload_cnt++;
891920

921+
flow_pay->in_hw = true;
922+
892923
/* Deallocate flow payload when flower rule has been destroyed. */
893924
kfree(key_layer);
894925

@@ -910,14 +941,83 @@ nfp_flower_add_offload(struct nfp_app *app, struct net_device *netdev,
910941
return err;
911942
}
912943

944+
static void
945+
nfp_flower_remove_merge_flow(struct nfp_app *app,
946+
struct nfp_fl_payload *del_sub_flow,
947+
struct nfp_fl_payload *merge_flow)
948+
{
949+
struct nfp_flower_priv *priv = app->priv;
950+
struct nfp_fl_payload_link *link, *temp;
951+
struct nfp_fl_payload *origin;
952+
bool mod = false;
953+
int err;
954+
955+
link = list_first_entry(&merge_flow->linked_flows,
956+
struct nfp_fl_payload_link, merge_flow.list);
957+
origin = link->sub_flow.flow;
958+
959+
/* Re-add rule the merge had overwritten if it has not been deleted. */
960+
if (origin != del_sub_flow)
961+
mod = true;
962+
963+
err = nfp_modify_flow_metadata(app, merge_flow);
964+
if (err) {
965+
nfp_flower_cmsg_warn(app, "Metadata fail for merge flow delete.\n");
966+
goto err_free_links;
967+
}
968+
969+
if (!mod) {
970+
err = nfp_flower_xmit_flow(app, merge_flow,
971+
NFP_FLOWER_CMSG_TYPE_FLOW_DEL);
972+
if (err) {
973+
nfp_flower_cmsg_warn(app, "Failed to delete merged flow.\n");
974+
goto err_free_links;
975+
}
976+
} else {
977+
__nfp_modify_flow_metadata(priv, origin);
978+
err = nfp_flower_xmit_flow(app, origin,
979+
NFP_FLOWER_CMSG_TYPE_FLOW_MOD);
980+
if (err)
981+
nfp_flower_cmsg_warn(app, "Failed to revert merge flow.\n");
982+
origin->in_hw = true;
983+
}
984+
985+
err_free_links:
986+
/* Clean any links connected with the merged flow. */
987+
list_for_each_entry_safe(link, temp, &merge_flow->linked_flows,
988+
merge_flow.list)
989+
nfp_flower_unlink_flow(link);
990+
991+
kfree(merge_flow->action_data);
992+
kfree(merge_flow->mask_data);
993+
kfree(merge_flow->unmasked_data);
994+
WARN_ON_ONCE(rhashtable_remove_fast(&priv->flow_table,
995+
&merge_flow->fl_node,
996+
nfp_flower_table_params));
997+
kfree_rcu(merge_flow, rcu);
998+
}
999+
1000+
static void
1001+
nfp_flower_del_linked_merge_flows(struct nfp_app *app,
1002+
struct nfp_fl_payload *sub_flow)
1003+
{
1004+
struct nfp_fl_payload_link *link, *temp;
1005+
1006+
/* Remove any merge flow formed from the deleted sub_flow. */
1007+
list_for_each_entry_safe(link, temp, &sub_flow->linked_flows,
1008+
sub_flow.list)
1009+
nfp_flower_remove_merge_flow(app, sub_flow,
1010+
link->merge_flow.flow);
1011+
}
1012+
9131013
/**
9141014
* nfp_flower_del_offload() - Removes a flow from hardware.
9151015
* @app: Pointer to the APP handle
9161016
* @netdev: netdev structure.
9171017
* @flow: TC flower classifier offload structure
9181018
*
9191019
* Removes a flow from the repeated hash structure and clears the
920-
* action payload.
1020+
* action payload. Any flows merged from this are also deleted.
9211021
*
9221022
* Return: negative value on error, 0 if removed successfully.
9231023
*/
@@ -939,17 +1039,22 @@ nfp_flower_del_offload(struct nfp_app *app, struct net_device *netdev,
9391039

9401040
err = nfp_modify_flow_metadata(app, nfp_flow);
9411041
if (err)
942-
goto err_free_flow;
1042+
goto err_free_merge_flow;
9431043

9441044
if (nfp_flow->nfp_tun_ipv4_addr)
9451045
nfp_tunnel_del_ipv4_off(app, nfp_flow->nfp_tun_ipv4_addr);
9461046

1047+
if (!nfp_flow->in_hw) {
1048+
err = 0;
1049+
goto err_free_merge_flow;
1050+
}
1051+
9471052
err = nfp_flower_xmit_flow(app, nfp_flow,
9481053
NFP_FLOWER_CMSG_TYPE_FLOW_DEL);
949-
if (err)
950-
goto err_free_flow;
1054+
/* Fall through on error. */
9511055

952-
err_free_flow:
1056+
err_free_merge_flow:
1057+
nfp_flower_del_linked_merge_flows(app, nfp_flow);
9531058
if (port)
9541059
port->tc_offload_cnt--;
9551060
kfree(nfp_flow->action_data);

0 commit comments

Comments
 (0)