1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 // Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3 
4 #include "act.h"
5 #include "en/tc_priv.h"
6 
7 static bool
tc_act_can_offload_police(struct mlx5e_tc_act_parse_state * parse_state,const struct flow_action_entry * act,int act_index,struct mlx5_flow_attr * attr)8 tc_act_can_offload_police(struct mlx5e_tc_act_parse_state *parse_state,
9 			  const struct flow_action_entry *act,
10 			  int act_index,
11 			  struct mlx5_flow_attr *attr)
12 {
13 	if (act->police.notexceed.act_id != FLOW_ACTION_PIPE &&
14 	    act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
15 		NL_SET_ERR_MSG_MOD(parse_state->extack,
16 				   "Offload not supported when conform action is not pipe or ok");
17 		return false;
18 	}
19 	if (mlx5e_policer_validate(parse_state->flow_action, act,
20 				   parse_state->extack))
21 		return false;
22 
23 	return !!mlx5e_get_flow_meters(parse_state->flow->priv->mdev);
24 }
25 
26 static int
fill_meter_params_from_act(const struct flow_action_entry * act,struct mlx5e_flow_meter_params * params)27 fill_meter_params_from_act(const struct flow_action_entry *act,
28 			   struct mlx5e_flow_meter_params *params)
29 {
30 	params->index = act->hw_index;
31 	if (act->police.rate_bytes_ps) {
32 		params->mode = MLX5_RATE_LIMIT_BPS;
33 		/* change rate to bits per second */
34 		params->rate = act->police.rate_bytes_ps << 3;
35 		params->burst = act->police.burst;
36 	} else if (act->police.rate_pkt_ps) {
37 		params->mode = MLX5_RATE_LIMIT_PPS;
38 		params->rate = act->police.rate_pkt_ps;
39 		params->burst = act->police.burst_pkt;
40 	} else {
41 		return -EOPNOTSUPP;
42 	}
43 
44 	return 0;
45 }
46 
47 static int
tc_act_parse_police(struct mlx5e_tc_act_parse_state * parse_state,const struct flow_action_entry * act,struct mlx5e_priv * priv,struct mlx5_flow_attr * attr)48 tc_act_parse_police(struct mlx5e_tc_act_parse_state *parse_state,
49 		    const struct flow_action_entry *act,
50 		    struct mlx5e_priv *priv,
51 		    struct mlx5_flow_attr *attr)
52 {
53 	int err;
54 
55 	err = fill_meter_params_from_act(act, &attr->meter_attr.params);
56 	if (err)
57 		return err;
58 
59 	attr->action |= MLX5_FLOW_CONTEXT_ACTION_EXECUTE_ASO;
60 	attr->exe_aso_type = MLX5_EXE_ASO_FLOW_METER;
61 
62 	return 0;
63 }
64 
65 static bool
tc_act_is_multi_table_act_police(struct mlx5e_priv * priv,const struct flow_action_entry * act,struct mlx5_flow_attr * attr)66 tc_act_is_multi_table_act_police(struct mlx5e_priv *priv,
67 				 const struct flow_action_entry *act,
68 				 struct mlx5_flow_attr *attr)
69 {
70 	return true;
71 }
72 
73 static int
tc_act_police_offload(struct mlx5e_priv * priv,struct flow_offload_action * fl_act,struct flow_action_entry * act)74 tc_act_police_offload(struct mlx5e_priv *priv,
75 		      struct flow_offload_action *fl_act,
76 		      struct flow_action_entry *act)
77 {
78 	struct mlx5e_flow_meter_params params = {};
79 	struct mlx5e_flow_meter_handle *meter;
80 	int err = 0;
81 
82 	err = mlx5e_policer_validate(&fl_act->action, act, fl_act->extack);
83 	if (err)
84 		return err;
85 
86 	err = fill_meter_params_from_act(act, &params);
87 	if (err)
88 		return err;
89 
90 	meter = mlx5e_tc_meter_get(priv->mdev, &params);
91 	if (IS_ERR(meter) && PTR_ERR(meter) == -ENOENT) {
92 		meter = mlx5e_tc_meter_replace(priv->mdev, &params);
93 	} else if (!IS_ERR(meter)) {
94 		err = mlx5e_tc_meter_update(meter, &params);
95 		mlx5e_tc_meter_put(meter);
96 	}
97 
98 	if (IS_ERR(meter)) {
99 		NL_SET_ERR_MSG_MOD(fl_act->extack, "Failed to get flow meter");
100 		mlx5_core_err(priv->mdev, "Failed to get flow meter %d\n", params.index);
101 		err = PTR_ERR(meter);
102 	}
103 
104 	return err;
105 }
106 
107 static int
tc_act_police_destroy(struct mlx5e_priv * priv,struct flow_offload_action * fl_act)108 tc_act_police_destroy(struct mlx5e_priv *priv,
109 		      struct flow_offload_action *fl_act)
110 {
111 	struct mlx5e_flow_meter_params params = {};
112 	struct mlx5e_flow_meter_handle *meter;
113 
114 	params.index = fl_act->index;
115 	meter = mlx5e_tc_meter_get(priv->mdev, &params);
116 	if (IS_ERR(meter)) {
117 		NL_SET_ERR_MSG_MOD(fl_act->extack, "Failed to get flow meter");
118 		mlx5_core_err(priv->mdev, "Failed to get flow meter %d\n", params.index);
119 		return PTR_ERR(meter);
120 	}
121 	/* first put for the get and second for cleanup */
122 	mlx5e_tc_meter_put(meter);
123 	mlx5e_tc_meter_put(meter);
124 	return 0;
125 }
126 
127 static int
tc_act_police_stats(struct mlx5e_priv * priv,struct flow_offload_action * fl_act)128 tc_act_police_stats(struct mlx5e_priv *priv,
129 		    struct flow_offload_action *fl_act)
130 {
131 	struct mlx5e_flow_meter_params params = {};
132 	struct mlx5e_flow_meter_handle *meter;
133 	u64 bytes, packets, drops, lastuse;
134 
135 	params.index = fl_act->index;
136 	meter = mlx5e_tc_meter_get(priv->mdev, &params);
137 	if (IS_ERR(meter)) {
138 		NL_SET_ERR_MSG_MOD(fl_act->extack, "Failed to get flow meter");
139 		mlx5_core_err(priv->mdev, "Failed to get flow meter %d\n", params.index);
140 		return PTR_ERR(meter);
141 	}
142 
143 	mlx5e_tc_meter_get_stats(meter, &bytes, &packets, &drops, &lastuse);
144 	flow_stats_update(&fl_act->stats, bytes, packets, drops, lastuse,
145 			  FLOW_ACTION_HW_STATS_DELAYED);
146 	mlx5e_tc_meter_put(meter);
147 	return 0;
148 }
149 
150 struct mlx5e_tc_act mlx5e_tc_act_police = {
151 	.can_offload = tc_act_can_offload_police,
152 	.parse_action = tc_act_parse_police,
153 	.is_multi_table_act = tc_act_is_multi_table_act_police,
154 	.offload_action = tc_act_police_offload,
155 	.destroy_action = tc_act_police_destroy,
156 	.stats_action = tc_act_police_stats,
157 };
158