Jianbo Liu says: ==================== flow_offload: add tc police parameters As a preparation for more advanced police offload in mlx5 (e.g., jumping to another chain when bandwidth is not exceeded), extend the flow offload API with more tc-police parameters. Adjust existing drivers to reject unsupported configurations. Changes since v2: * Rename index to extval in exceed and notexceed acts. * Add policer validate functions for all drivers. Changes since v1: * Add one more strict validation for the control of drop/ok. ====================
Unified · Split
| @@ -300,6 +300,46 @@ static int sja1105_flower_parse_key(struct sja1105_private *priv, · 299 unmodified lines | ||
| 300 | 300 | return -EOPNOTSUPP; |
| 301 | 301 | } |
| 302 | 302 | |
| 303 | +static int sja1105_policer_validate(const struct flow_action *action, | |
| 304 | + const struct flow_action_entry *act, | |
| 305 | + struct netlink_ext_ack *extack) | |
| 306 | +{ | |
| 307 | + if (act->police.exceed.act_id != FLOW_ACTION_DROP) { | |
| 308 | + NL_SET_ERR_MSG_MOD(extack, | |
| 309 | + "Offload not supported when exceed action is not drop"); | |
| 310 | + return -EOPNOTSUPP; | |
| 311 | + } | |
| 312 | + | |
| 313 | + if (act->police.notexceed.act_id != FLOW_ACTION_PIPE && | |
| 314 | + act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) { | |
| 315 | + NL_SET_ERR_MSG_MOD(extack, | |
| 316 | + "Offload not supported when conform action is not pipe or ok"); | |
| 317 | + return -EOPNOTSUPP; | |
| 318 | + } | |
| 319 | + | |
| 320 | + if (act->police.notexceed.act_id == FLOW_ACTION_ACCEPT && | |
| 321 | + !flow_action_is_last_entry(action, act)) { | |
| 322 | + NL_SET_ERR_MSG_MOD(extack, | |
| 323 | + "Offload not supported when conform action is ok, but action is not last"); | |
| 324 | + return -EOPNOTSUPP; | |
| 325 | + } | |
| 326 | + | |
| 327 | + if (act->police.peakrate_bytes_ps || | |
| 328 | + act->police.avrate || act->police.overhead) { | |
| 329 | + NL_SET_ERR_MSG_MOD(extack, | |
| 330 | + "Offload not supported when peakrate/avrate/overhead is configured"); | |
| 331 | + return -EOPNOTSUPP; | |
| 332 | + } | |
| 333 | + | |
| 334 | + if (act->police.rate_pkt_ps) { | |
| 335 | + NL_SET_ERR_MSG_MOD(extack, | |
| 336 | + "QoS offload not support packets per second"); | |
| 337 | + return -EOPNOTSUPP; | |
| 338 | + } | |
| 339 | + | |
| 340 | + return 0; | |
| 341 | +} | |
| 342 | + | |
| 303 | 343 | int sja1105_cls_flower_add(struct dsa_switch *ds, int port, |
| 304 | 344 | struct flow_cls_offload *cls, bool ingress) |
| 305 | 345 | { |
| @@ -321,12 +361,9 @@ int sja1105_cls_flower_add(struct dsa_switch *ds, int port, · 15 unmodified lines | ||
| 321 | 361 | flow_action_for_each(i, act, &rule->action) { |
| 322 | 362 | switch (act->id) { |
| 323 | 363 | case FLOW_ACTION_POLICE: |
| 324 | − if (act->police.rate_pkt_ps) { | |
| 325 | − NL_SET_ERR_MSG_MOD(extack, | |
| 326 | − "QoS offload not support packets per second"); | |
| 327 | − rc = -EOPNOTSUPP; | |
| 364 | + rc = sja1105_policer_validate(&rule->action, act, extack); | |
| 365 | + if (rc) | |
| 328 | 366 | goto out; |
| 329 | − } | |
| 330 | 367 | |
| 331 | 368 | rc = sja1105_flower_policer(priv, port, extack, cookie, |
| 332 | 369 | &key, |
| @@ -8,6 +8,46 @@ · 7 unmodified lines | ||
| 8 | 8 | #include "cxgb4_filter.h" |
| 9 | 9 | #include "cxgb4_tc_flower.h" |
| 10 | 10 | |
| 11 | +static int cxgb4_policer_validate(const struct flow_action *action, | |
| 12 | + const struct flow_action_entry *act, | |
| 13 | + struct netlink_ext_ack *extack) | |
| 14 | +{ | |
| 15 | + if (act->police.exceed.act_id != FLOW_ACTION_DROP) { | |
| 16 | + NL_SET_ERR_MSG_MOD(extack, | |
| 17 | + "Offload not supported when exceed action is not drop"); | |
| 18 | + return -EOPNOTSUPP; | |
| 19 | + } | |
| 20 | + | |
| 21 | + if (act->police.notexceed.act_id != FLOW_ACTION_PIPE && | |
| 22 | + act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) { | |
| 23 | + NL_SET_ERR_MSG_MOD(extack, | |
| 24 | + "Offload not supported when conform action is not pipe or ok"); | |
| 25 | + return -EOPNOTSUPP; | |
| 26 | + } | |
| 27 | + | |
| 28 | + if (act->police.notexceed.act_id == FLOW_ACTION_ACCEPT && | |
| 29 | + !flow_action_is_last_entry(action, act)) { | |
| 30 | + NL_SET_ERR_MSG_MOD(extack, | |
| 31 | + "Offload not supported when conform action is ok, but action is not last"); | |
| 32 | + return -EOPNOTSUPP; | |
| 33 | + } | |
| 34 | + | |
| 35 | + if (act->police.peakrate_bytes_ps || | |
| 36 | + act->police.avrate || act->police.overhead) { | |
| 37 | + NL_SET_ERR_MSG_MOD(extack, | |
| 38 | + "Offload not supported when peakrate/avrate/overhead is configured"); | |
| 39 | + return -EOPNOTSUPP; | |
| 40 | + } | |
| 41 | + | |
| 42 | + if (act->police.rate_pkt_ps) { | |
| 43 | + NL_SET_ERR_MSG_MOD(extack, | |
| 44 | + "QoS offload not support packets per second"); | |
| 45 | + return -EOPNOTSUPP; | |
| 46 | + } | |
| 47 | + | |
| 48 | + return 0; | |
| 49 | +} | |
| 50 | + | |
| 11 | 51 | static int cxgb4_matchall_egress_validate(struct net_device *dev, |
| 12 | 52 | struct tc_cls_matchall_offload *cls) |
| 13 | 53 | { |
| @@ -48,11 +88,10 @@ static int cxgb4_matchall_egress_validate(struct net_device *dev, · 34 unmodified lines | ||
| 48 | 88 | flow_action_for_each(i, entry, actions) { |
| 49 | 89 | switch (entry->id) { |
| 50 | 90 | case FLOW_ACTION_POLICE: |
| 51 | − if (entry->police.rate_pkt_ps) { | |
| 52 | − NL_SET_ERR_MSG_MOD(extack, | |
| 53 | − "QoS offload not support packets per second"); | |
| 54 | − return -EOPNOTSUPP; | |
| 55 | − } | |
| 91 | + ret = cxgb4_policer_validate(actions, entry, extack); | |
| 92 | + if (ret) | |
| 93 | + return ret; | |
| 94 | + | |
| 56 | 95 | /* Convert bytes per second to bits per second */ |
| 57 | 96 | if (entry->police.rate_bytes_ps * 8 > max_link_rate) { |
| 58 | 97 | NL_SET_ERR_MSG_MOD(extack, |
| @@ -150,11 +189,11 @@ static int cxgb4_matchall_alloc_tc(struct net_device *dev, · 91 unmodified lines | ||
| 150 | 189 | flow_action_for_each(i, entry, &cls->rule->action) |
| 151 | 190 | if (entry->id == FLOW_ACTION_POLICE) |
| 152 | 191 | break; |
| 153 | − if (entry->police.rate_pkt_ps) { | |
| 154 | − NL_SET_ERR_MSG_MOD(extack, | |
| 155 | − "QoS offload not support packets per second"); | |
| 156 | − return -EOPNOTSUPP; | |
| 157 | − } | |
| 192 | + | |
| 193 | + ret = cxgb4_policer_validate(&cls->rule->action, entry, extack); | |
| 194 | + if (ret) | |
| 195 | + return ret; | |
| 196 | + | |
| 158 | 197 | /* Convert from bytes per second to Kbps */ |
| 159 | 198 | p.u.params.maxrate = div_u64(entry->police.rate_bytes_ps * 8, 1000); |
| 160 | 199 | p.u.params.channel = pi->tx_chan; |
| @@ -1021,6 +1021,46 @@ static struct actions_fwd *enetc_check_flow_actions(u64 acts, · 1020 unmodified lines | ||
| 1021 | 1021 | return NULL; |
| 1022 | 1022 | } |
| 1023 | 1023 | |
| 1024 | +static int enetc_psfp_policer_validate(const struct flow_action *action, | |
| 1025 | + const struct flow_action_entry *act, | |
| 1026 | + struct netlink_ext_ack *extack) | |
| 1027 | +{ | |
| 1028 | + if (act->police.exceed.act_id != FLOW_ACTION_DROP) { | |
| 1029 | + NL_SET_ERR_MSG_MOD(extack, | |
| 1030 | + "Offload not supported when exceed action is not drop"); | |
| 1031 | + return -EOPNOTSUPP; | |
| 1032 | + } | |
| 1033 | + | |
| 1034 | + if (act->police.notexceed.act_id != FLOW_ACTION_PIPE && | |
| 1035 | + act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) { | |
| 1036 | + NL_SET_ERR_MSG_MOD(extack, | |
| 1037 | + "Offload not supported when conform action is not pipe or ok"); | |
| 1038 | + return -EOPNOTSUPP; | |
| 1039 | + } | |
| 1040 | + | |
| 1041 | + if (act->police.notexceed.act_id == FLOW_ACTION_ACCEPT && | |
| 1042 | + !flow_action_is_last_entry(action, act)) { | |
| 1043 | + NL_SET_ERR_MSG_MOD(extack, | |
| 1044 | + "Offload not supported when conform action is ok, but action is not last"); | |
| 1045 | + return -EOPNOTSUPP; | |
| 1046 | + } | |
| 1047 | + | |
| 1048 | + if (act->police.peakrate_bytes_ps || | |
| 1049 | + act->police.avrate || act->police.overhead) { | |
| 1050 | + NL_SET_ERR_MSG_MOD(extack, | |
| 1051 | + "Offload not supported when peakrate/avrate/overhead is configured"); | |
| 1052 | + return -EOPNOTSUPP; | |
| 1053 | + } | |
| 1054 | + | |
| 1055 | + if (act->police.rate_pkt_ps) { | |
| 1056 | + NL_SET_ERR_MSG_MOD(extack, | |
| 1057 | + "QoS offload not support packets per second"); | |
| 1058 | + return -EOPNOTSUPP; | |
| 1059 | + } | |
| 1060 | + | |
| 1061 | + return 0; | |
| 1062 | +} | |
| 1063 | + | |
| 1024 | 1064 | static int enetc_psfp_parse_clsflower(struct enetc_ndev_priv *priv, |
| 1025 | 1065 | struct flow_cls_offload *f) |
| 1026 | 1066 | { |
| @@ -1177,11 +1217,10 @@ static int enetc_psfp_parse_clsflower(struct enetc_ndev_priv *priv, · 150 unmodified lines | ||
| 1177 | 1217 | |
| 1178 | 1218 | /* Flow meter and max frame size */ |
| 1179 | 1219 | if (entryp) { |
| 1180 | − if (entryp->police.rate_pkt_ps) { | |
| 1181 | − NL_SET_ERR_MSG_MOD(extack, "QoS offload not support packets per second"); | |
| 1182 | − err = -EOPNOTSUPP; | |
| 1220 | + err = enetc_psfp_policer_validate(&rule->action, entryp, extack); | |
| 1221 | + if (err) | |
| 1183 | 1222 | goto free_sfi; |
| 1184 | − } | |
| 1223 | + | |
| 1185 | 1224 | if (entryp->police.burst) { |
| 1186 | 1225 | fmi = kzalloc(sizeof(*fmi), GFP_KERNEL); |
| 1187 | 1226 | if (!fmi) { |
| @@ -190,6 +190,40 @@ static int otx2_tc_validate_flow(struct otx2_nic *nic, · 189 unmodified lines | ||
| 190 | 190 | return 0; |
| 191 | 191 | } |
| 192 | 192 | |
| 193 | +static int otx2_policer_validate(const struct flow_action *action, | |
| 194 | + const struct flow_action_entry *act, | |
| 195 | + struct netlink_ext_ack *extack) | |
| 196 | +{ | |
| 197 | + if (act->police.exceed.act_id != FLOW_ACTION_DROP) { | |
| 198 | + NL_SET_ERR_MSG_MOD(extack, | |
| 199 | + "Offload not supported when exceed action is not drop"); | |
| 200 | + return -EOPNOTSUPP; | |
| 201 | + } | |
| 202 | + | |
| 203 | + if (act->police.notexceed.act_id != FLOW_ACTION_PIPE && | |
| 204 | + act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) { | |
| 205 | + NL_SET_ERR_MSG_MOD(extack, | |
| 206 | + "Offload not supported when conform action is not pipe or ok"); | |
| 207 | + return -EOPNOTSUPP; | |
| 208 | + } | |
| 209 | + | |
| 210 | + if (act->police.notexceed.act_id == FLOW_ACTION_ACCEPT && | |
| 211 | + !flow_action_is_last_entry(action, act)) { | |
| 212 | + NL_SET_ERR_MSG_MOD(extack, | |
| 213 | + "Offload not supported when conform action is ok, but action is not last"); | |
| 214 | + return -EOPNOTSUPP; | |
| 215 | + } | |
| 216 | + | |
| 217 | + if (act->police.peakrate_bytes_ps || | |
| 218 | + act->police.avrate || act->police.overhead) { | |
| 219 | + NL_SET_ERR_MSG_MOD(extack, | |
| 220 | + "Offload not supported when peakrate/avrate/overhead is configured"); | |
| 221 | + return -EOPNOTSUPP; | |
| 222 | + } | |
| 223 | + | |
| 224 | + return 0; | |
| 225 | +} | |
| 226 | + | |
| 193 | 227 | static int otx2_tc_egress_matchall_install(struct otx2_nic *nic, |
| 194 | 228 | struct tc_cls_matchall_offload *cls) |
| 195 | 229 | { |
| @@ -212,6 +246,10 @@ static int otx2_tc_egress_matchall_install(struct otx2_nic *nic, · 16 unmodified lines | ||
| 212 | 246 | entry = &cls->rule->action.entries[0]; |
| 213 | 247 | switch (entry->id) { |
| 214 | 248 | case FLOW_ACTION_POLICE: |
| 249 | + err = otx2_policer_validate(&cls->rule->action, entry, extack); | |
| 250 | + if (err) | |
| 251 | + return err; | |
| 252 | + | |
| 215 | 253 | if (entry->police.rate_pkt_ps) { |
| 216 | 254 | NL_SET_ERR_MSG_MOD(extack, "QoS offload not support packets per second"); |
| 217 | 255 | return -EOPNOTSUPP; |
| @@ -315,6 +353,7 @@ static int otx2_tc_parse_actions(struct otx2_nic *nic, · 97 unmodified lines | ||
| 315 | 353 | u8 nr_police = 0; |
| 316 | 354 | bool pps = false; |
| 317 | 355 | u64 rate; |
| 356 | + int err; | |
| 318 | 357 | int i; |
| 319 | 358 | |
| 320 | 359 | if (!flow_action_has_entries(flow_action)) { |
| @@ -355,6 +394,10 @@ static int otx2_tc_parse_actions(struct otx2_nic *nic, · 34 unmodified lines | ||
| 355 | 394 | return -EOPNOTSUPP; |
| 356 | 395 | } |
| 357 | 396 | |
| 397 | + err = otx2_policer_validate(flow_action, act, extack); | |
| 398 | + if (err) | |
| 399 | + return err; | |
| 400 | + | |
| 358 | 401 | if (act->police.rate_bytes_ps > 0) { |
| 359 | 402 | rate = act->police.rate_bytes_ps * 8; |
| 360 | 403 | burst = act->police.burst; |
| @@ -4482,6 +4482,46 @@ static int apply_police_params(struct mlx5e_priv *priv, u64 rate, · 4481 unmodified lines | ||
| 4482 | 4482 | return err; |
| 4483 | 4483 | } |
| 4484 | 4484 | |
| 4485 | +static int mlx5e_policer_validate(const struct flow_action *action, | |
| 4486 | + const struct flow_action_entry *act, | |
| 4487 | + struct netlink_ext_ack *extack) | |
| 4488 | +{ | |
| 4489 | + if (act->police.exceed.act_id != FLOW_ACTION_DROP) { | |
| 4490 | + NL_SET_ERR_MSG_MOD(extack, | |
| 4491 | + "Offload not supported when exceed action is not drop"); | |
| 4492 | + return -EOPNOTSUPP; | |
| 4493 | + } | |
| 4494 | + | |
| 4495 | + if (act->police.notexceed.act_id != FLOW_ACTION_PIPE && | |
| 4496 | + act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) { | |
| 4497 | + NL_SET_ERR_MSG_MOD(extack, | |
| 4498 | + "Offload not supported when conform action is not pipe or ok"); | |
| 4499 | + return -EOPNOTSUPP; | |
| 4500 | + } | |
| 4501 | + | |
| 4502 | + if (act->police.notexceed.act_id == FLOW_ACTION_ACCEPT && | |
| 4503 | + !flow_action_is_last_entry(action, act)) { | |
| 4504 | + NL_SET_ERR_MSG_MOD(extack, | |
| 4505 | + "Offload not supported when conform action is ok, but action is not last"); | |
| 4506 | + return -EOPNOTSUPP; | |
| 4507 | + } | |
| 4508 | + | |
| 4509 | + if (act->police.peakrate_bytes_ps || | |
| 4510 | + act->police.avrate || act->police.overhead) { | |
| 4511 | + NL_SET_ERR_MSG_MOD(extack, | |
| 4512 | + "Offload not supported when peakrate/avrate/overhead is configured"); | |
| 4513 | + return -EOPNOTSUPP; | |
| 4514 | + } | |
| 4515 | + | |
| 4516 | + if (act->police.rate_pkt_ps) { | |
| 4517 | + NL_SET_ERR_MSG_MOD(extack, | |
| 4518 | + "QoS offload not support packets per second"); | |
| 4519 | + return -EOPNOTSUPP; | |
| 4520 | + } | |
| 4521 | + | |
| 4522 | + return 0; | |
| 4523 | +} | |
| 4524 | + | |
| 4485 | 4525 | static int scan_tc_matchall_fdb_actions(struct mlx5e_priv *priv, |
| 4486 | 4526 | struct flow_action *flow_action, |
| 4487 | 4527 | struct netlink_ext_ack *extack) |
| @@ -4509,10 +4549,10 @@ static int scan_tc_matchall_fdb_actions(struct mlx5e_priv *priv, · 21 unmodified lines | ||
| 4509 | 4549 | flow_action_for_each(i, act, flow_action) { |
| 4510 | 4550 | switch (act->id) { |
| 4511 | 4551 | case FLOW_ACTION_POLICE: |
| 4512 | − if (act->police.rate_pkt_ps) { | |
| 4513 | − NL_SET_ERR_MSG_MOD(extack, "QoS offload not support packets per second"); | |
| 4514 | − return -EOPNOTSUPP; | |
| 4515 | − } | |
| 4552 | + err = mlx5e_policer_validate(flow_action, act, extack); | |
| 4553 | + if (err) | |
| 4554 | + return err; | |
| 4555 | + | |
| 4516 | 4556 | err = apply_police_params(priv, act->police.rate_bytes_ps, extack); |
| 4517 | 4557 | if (err) |
| 4518 | 4558 | return err; |
| @@ -15,6 +15,46 @@ · 14 unmodified lines | ||
| 15 | 15 | #include "spectrum.h" |
| 16 | 16 | #include "core_acl_flex_keys.h" |
| 17 | 17 | |
| 18 | +static int mlxsw_sp_policer_validate(const struct flow_action *action, | |
| 19 | + const struct flow_action_entry *act, | |
| 20 | + struct netlink_ext_ack *extack) | |
| 21 | +{ | |
| 22 | + if (act->police.exceed.act_id != FLOW_ACTION_DROP) { | |
| 23 | + NL_SET_ERR_MSG_MOD(extack, | |
| 24 | + "Offload not supported when exceed action is not drop"); | |
| 25 | + return -EOPNOTSUPP; | |
| 26 | + } | |
| 27 | + | |
| 28 | + if (act->police.notexceed.act_id != FLOW_ACTION_PIPE && | |
| 29 | + act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) { | |
| 30 | + NL_SET_ERR_MSG_MOD(extack, | |
| 31 | + "Offload not supported when conform action is not pipe or ok"); | |
| 32 | + return -EOPNOTSUPP; | |
| 33 | + } | |
| 34 | + | |
| 35 | + if (act->police.notexceed.act_id == FLOW_ACTION_ACCEPT && | |
| 36 | + !flow_action_is_last_entry(action, act)) { | |
| 37 | + NL_SET_ERR_MSG_MOD(extack, | |
| 38 | + "Offload not supported when conform action is ok, but action is not last"); | |
| 39 | + return -EOPNOTSUPP; | |
| 40 | + } | |
| 41 | + | |
| 42 | + if (act->police.peakrate_bytes_ps || | |
| 43 | + act->police.avrate || act->police.overhead) { | |
| 44 | + NL_SET_ERR_MSG_MOD(extack, | |
| 45 | + "Offload not supported when peakrate/avrate/overhead is configured"); | |
| 46 | + return -EOPNOTSUPP; | |
| 47 | + } | |
| 48 | + | |
| 49 | + if (act->police.rate_pkt_ps) { | |
| 50 | + NL_SET_ERR_MSG_MOD(extack, | |
| 51 | + "QoS offload not support packets per second"); | |
| 52 | + return -EOPNOTSUPP; | |
| 53 | + } | |
| 54 | + | |
| 55 | + return 0; | |
| 56 | +} | |
| 57 | + | |
| 18 | 58 | static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp, |
| 19 | 59 | struct mlxsw_sp_flow_block *block, |
| 20 | 60 | struct mlxsw_sp_acl_rule_info *rulei, |
| @@ -191,10 +231,9 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp, · 170 unmodified lines | ||
| 191 | 231 | return -EOPNOTSUPP; |
| 192 | 232 | } |
| 193 | 233 | |
| 194 | − if (act->police.rate_pkt_ps) { | |
| 195 | − NL_SET_ERR_MSG_MOD(extack, "QoS offload not support packets per second"); | |
| 196 | − return -EOPNOTSUPP; | |
| 197 | − } | |
| 234 | + err = mlxsw_sp_policer_validate(flow_action, act, extack); | |
| 235 | + if (err) | |
| 236 | + return err; | |
| 198 | 237 | |
| 199 | 238 | /* The kernel might adjust the requested burst size so |
| 200 | 239 | * that it is not exactly a power of two. Re-adjust it |
| @@ -6,6 +6,7 @@ · 5 unmodified lines | ||
| 6 | 6 | #include <net/pkt_cls.h> |
| 7 | 7 | #include <net/tc_act/tc_gact.h> |
| 8 | 8 | #include <soc/mscc/ocelot_vcap.h> |
| 9 | +#include "ocelot_police.h" | |
| 9 | 10 | #include "ocelot_vcap.h" |
| 10 | 11 | |
| 11 | 12 | /* Arbitrarily chosen constants for encoding the VCAP block and lookup number |
| @@ -217,6 +218,7 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port, · 205 unmodified lines | ||
| 217 | 218 | bool ingress, struct flow_cls_offload *f, |
| 218 | 219 | struct ocelot_vcap_filter *filter) |
| 219 | 220 | { |
| 221 | + const struct flow_action *action = &f->rule->action; | |
| 220 | 222 | struct netlink_ext_ack *extack = f->common.extack; |
| 221 | 223 | bool allow_missing_goto_target = false; |
| 222 | 224 | const struct flow_action_entry *a; |
| @@ -244,7 +246,7 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port, · 21 unmodified lines | ||
| 244 | 246 | filter->goto_target = -1; |
| 245 | 247 | filter->type = OCELOT_VCAP_FILTER_DUMMY; |
| 246 | 248 | |
| 247 | − flow_action_for_each(i, a, &f->rule->action) { | |
| 249 | + flow_action_for_each(i, a, action) { | |
| 248 | 250 | switch (a->id) { |
| 249 | 251 | case FLOW_ACTION_DROP: |
| 250 | 252 | if (filter->block_id != VCAP_IS2) { |
| @@ -297,11 +299,11 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port, · 46 unmodified lines | ||
| 297 | 299 | "Last action must be GOTO"); |
| 298 | 300 | return -EOPNOTSUPP; |
| 299 | 301 | } |
| 300 | − if (a->police.rate_pkt_ps) { | |
| 301 | − NL_SET_ERR_MSG_MOD(extack, | |
| 302 | − "QoS offload not support packets per second"); | |
| 303 | − return -EOPNOTSUPP; | |
| 304 | − } | |
| 302 | + | |
| 303 | + err = ocelot_policer_validate(action, a, extack); | |
| 304 | + if (err) | |
| 305 | + return err; | |
| 306 | + | |
| 305 | 307 | filter->action.police_ena = true; |
| 306 | 308 | |
| 307 | 309 | pol_ix = a->hw_index + ocelot->vcap_pol.base; |
| @@ -14,6 +14,7 @@ · 13 unmodified lines | ||
| 14 | 14 | #include <linux/phy/phy.h> |
| 15 | 15 | #include <net/pkt_cls.h> |
| 16 | 16 | #include "ocelot.h" |
| 17 | +#include "ocelot_police.h" | |
| 17 | 18 | #include "ocelot_vcap.h" |
| 18 | 19 | #include "ocelot_fdma.h" |
| 19 | 20 | |
| @@ -258,11 +259,10 @@ static int ocelot_setup_tc_cls_matchall(struct ocelot_port_private *priv, · 238 unmodified lines | ||
| 258 | 259 | return -EEXIST; |
| 259 | 260 | } |
| 260 | 261 | |
| 261 | − if (action->police.rate_pkt_ps) { | |
| 262 | − NL_SET_ERR_MSG_MOD(extack, | |
| 263 | − "QoS offload not support packets per second"); | |
| 264 | − return -EOPNOTSUPP; | |
| 265 | − } | |
| 262 | + err = ocelot_policer_validate(&f->rule->action, action, | |
| 263 | + extack); | |
| 264 | + if (err) | |
| 265 | + return err; | |
| 266 | 266 | |
| 267 | 267 | pol.rate = (u32)div_u64(action->police.rate_bytes_ps, 1000) * 8; |
| 268 | 268 | pol.burst = action->police.burst; |
| @@ -154,6 +154,47 @@ int qos_policer_conf_set(struct ocelot *ocelot, int port, u32 pol_ix, · 153 unmodified lines | ||
| 154 | 154 | return 0; |
| 155 | 155 | } |
| 156 | 156 | |
| 157 | +int ocelot_policer_validate(const struct flow_action *action, | |
| 158 | + const struct flow_action_entry *a, | |
| 159 | + struct netlink_ext_ack *extack) | |
| 160 | +{ | |
| 161 | + if (a->police.exceed.act_id != FLOW_ACTION_DROP) { | |
| 162 | + NL_SET_ERR_MSG_MOD(extack, | |
| 163 | + "Offload not supported when exceed action is not drop"); | |
| 164 | + return -EOPNOTSUPP; | |
| 165 | + } | |
| 166 | + | |
| 167 | + if (a->police.notexceed.act_id != FLOW_ACTION_PIPE && | |
| 168 | + a->police.notexceed.act_id != FLOW_ACTION_ACCEPT) { | |
| 169 | + NL_SET_ERR_MSG_MOD(extack, | |
| 170 | + "Offload not supported when conform action is not pipe or ok"); | |
| 171 | + return -EOPNOTSUPP; | |
| 172 | + } | |
| 173 | + | |
| 174 | + if (a->police.notexceed.act_id == FLOW_ACTION_ACCEPT && | |
| 175 | + !flow_action_is_last_entry(action, a)) { | |
| 176 | + NL_SET_ERR_MSG_MOD(extack, | |
| 177 | + "Offload not supported when conform action is ok, but police action is not last"); | |
| 178 | + return -EOPNOTSUPP; | |
| 179 | + } | |
| 180 | + | |
| 181 | + if (a->police.peakrate_bytes_ps || | |
| 182 | + a->police.avrate || a->police.overhead) { | |
| 183 | + NL_SET_ERR_MSG_MOD(extack, | |
| 184 | + "Offload not supported when peakrate/avrate/overhead is configured"); | |
| 185 | + return -EOPNOTSUPP; | |
| 186 | + } | |
| 187 | + | |
| 188 | + if (a->police.rate_pkt_ps) { | |
| 189 | + NL_SET_ERR_MSG_MOD(extack, | |
| 190 | + "Offload does not support packets per second"); | |
| 191 | + return -EOPNOTSUPP; | |
| 192 | + } | |
| 193 | + | |
| 194 | + return 0; | |
| 195 | +} | |
| 196 | +EXPORT_SYMBOL(ocelot_policer_validate); | |
| 197 | + | |
| 157 | 198 | int ocelot_port_policer_add(struct ocelot *ocelot, int port, |
| 158 | 199 | struct ocelot_policer *pol) |
| 159 | 200 | { |
| @@ -8,6 +8,7 @@ · 7 unmodified lines | ||
| 8 | 8 | #define _MSCC_OCELOT_POLICE_H_ |
| 9 | 9 | |
| 10 | 10 | #include "ocelot.h" |
| 11 | +#include <net/flow_offload.h> | |
| 11 | 12 | |
| 12 | 13 | enum mscc_qos_rate_mode { |
| 13 | 14 | MSCC_QOS_RATE_MODE_DISABLED, /* Policer/shaper disabled */ |
| @@ -33,4 +34,8 @@ struct qos_policer_conf { · 19 unmodified lines | ||
| 33 | 34 | int qos_policer_conf_set(struct ocelot *ocelot, int port, u32 pol_ix, |
| 34 | 35 | struct qos_policer_conf *conf); |
| 35 | 36 | |
| 37 | +int ocelot_policer_validate(const struct flow_action *action, | |
| 38 | + const struct flow_action_entry *a, | |
| 39 | + struct netlink_ext_ack *extack); | |
| 40 | + | |
| 36 | 41 | #endif /* _MSCC_OCELOT_POLICE_H_ */ |
| @@ -117,6 +117,40 @@ int nfp_flower_offload_one_police(struct nfp_app *app, bool ingress, · 116 unmodified lines | ||
| 117 | 117 | return 0; |
| 118 | 118 | } |
| 119 | 119 | |
| 120 | +static int nfp_policer_validate(const struct flow_action *action, | |
| 121 | + const struct flow_action_entry *act, | |
| 122 | + struct netlink_ext_ack *extack) | |
| 123 | +{ | |
| 124 | + if (act->police.exceed.act_id != FLOW_ACTION_DROP) { | |
| 125 | + NL_SET_ERR_MSG_MOD(extack, | |
| 126 | + "Offload not supported when exceed action is not drop"); | |
| 127 | + return -EOPNOTSUPP; | |
| 128 | + } | |
| 129 | + | |
| 130 | + if (act->police.notexceed.act_id != FLOW_ACTION_PIPE && | |
| 131 | + act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) { | |
| 132 | + NL_SET_ERR_MSG_MOD(extack, | |
| 133 | + "Offload not supported when conform action is not pipe or ok"); | |
| 134 | + return -EOPNOTSUPP; | |
| 135 | + } | |
| 136 | + | |
| 137 | + if (act->police.notexceed.act_id == FLOW_ACTION_ACCEPT && | |
| 138 | + !flow_action_is_last_entry(action, act)) { | |
| 139 | + NL_SET_ERR_MSG_MOD(extack, | |
| 140 | + "Offload not supported when conform action is ok, but action is not last"); | |
| 141 | + return -EOPNOTSUPP; | |
| 142 | + } | |
| 143 | + | |
| 144 | + if (act->police.peakrate_bytes_ps || | |
| 145 | + act->police.avrate || act->police.overhead) { | |
| 146 | + NL_SET_ERR_MSG_MOD(extack, | |
| 147 | + "Offload not supported when peakrate/avrate/overhead is configured"); | |
| 148 | + return -EOPNOTSUPP; | |
| 149 | + } | |
| 150 | + | |
| 151 | + return 0; | |
| 152 | +} | |
| 153 | + | |
| 120 | 154 | static int |
| 121 | 155 | nfp_flower_install_rate_limiter(struct nfp_app *app, struct net_device *netdev, |
| 122 | 156 | struct tc_cls_matchall_offload *flow, |
| @@ -135,6 +169,7 @@ nfp_flower_install_rate_limiter(struct nfp_app *app, struct net_device *netdev, · 12 unmodified lines | ||
| 135 | 169 | u32 burst; |
| 136 | 170 | bool pps; |
| 137 | 171 | u64 rate; |
| 172 | + int err; | |
| 138 | 173 | |
| 139 | 174 | if (!nfp_netdev_is_nfp_repr(netdev)) { |
| 140 | 175 | NL_SET_ERR_MSG_MOD(extack, "unsupported offload: qos rate limit offload not supported on higher level port"); |
| @@ -181,6 +216,11 @@ nfp_flower_install_rate_limiter(struct nfp_app *app, struct net_device *netdev, · 40 unmodified lines | ||
| 181 | 216 | "unsupported offload: qos rate limit offload requires police action"); |
| 182 | 217 | return -EOPNOTSUPP; |
| 183 | 218 | } |
| 219 | + | |
| 220 | + err = nfp_policer_validate(&flow->rule->action, action, extack); | |
| 221 | + if (err) | |
| 222 | + return err; | |
| 223 | + | |
| 184 | 224 | if (action->police.rate_bytes_ps > 0) { |
| 185 | 225 | if (bps_num++) { |
| 186 | 226 | NL_SET_ERR_MSG_MOD(extack, |
| @@ -148,6 +148,8 @@ enum flow_action_id { · 147 unmodified lines | ||
| 148 | 148 | FLOW_ACTION_MPLS_MANGLE, |
| 149 | 149 | FLOW_ACTION_GATE, |
| 150 | 150 | FLOW_ACTION_PPPOE_PUSH, |
| 151 | + FLOW_ACTION_JUMP, | |
| 152 | + FLOW_ACTION_PIPE, | |
| 151 | 153 | NUM_FLOW_ACTIONS, |
| 152 | 154 | }; |
| 153 | 155 | |
| @@ -235,9 +237,16 @@ struct flow_action_entry { · 81 unmodified lines | ||
| 235 | 237 | struct { /* FLOW_ACTION_POLICE */ |
| 236 | 238 | u32 burst; |
| 237 | 239 | u64 rate_bytes_ps; |
| 240 | + u64 peakrate_bytes_ps; | |
| 241 | + u32 avrate; | |
| 242 | + u16 overhead; | |
| 238 | 243 | u64 burst_pkt; |
| 239 | 244 | u64 rate_pkt_ps; |
| 240 | 245 | u32 mtu; |
| 246 | + struct { | |
| 247 | + enum flow_action_id act_id; | |
| 248 | + u32 extval; | |
| 249 | + } exceed, notexceed; | |
| 241 | 250 | } police; |
| 242 | 251 | struct { /* FLOW_ACTION_CT */ |
| 243 | 252 | int action; |
| @@ -302,6 +311,12 @@ static inline bool flow_offload_has_one_action(const struct flow_action *action) · 58 unmodified lines | ||
| 302 | 311 | return action->num_entries == 1; |
| 303 | 312 | } |
| 304 | 313 | |
| 314 | +static inline bool flow_action_is_last_entry(const struct flow_action *action, | |
| 315 | + const struct flow_action_entry *entry) | |
| 316 | +{ | |
| 317 | + return entry == &action->entries[action->num_entries - 1]; | |
| 318 | +} | |
| 319 | + | |
| 305 | 320 | #define flow_action_for_each(__i, __act, __actions) \ |
| 306 | 321 | for (__i = 0, __act = &(__actions)->entries[0]; \ |
| 307 | 322 | __i < (__actions)->num_entries; \ |
| @@ -159,4 +159,34 @@ static inline u32 tcf_police_tcfp_mtu(const struct tc_action *act) · 158 unmodified lines | ||
| 159 | 159 | return params->tcfp_mtu; |
| 160 | 160 | } |
| 161 | 161 | |
| 162 | +static inline u64 tcf_police_peakrate_bytes_ps(const struct tc_action *act) | |
| 163 | +{ | |
| 164 | + struct tcf_police *police = to_police(act); | |
| 165 | + struct tcf_police_params *params; | |
| 166 | + | |
| 167 | + params = rcu_dereference_protected(police->params, | |
| 168 | + lockdep_is_held(&police->tcf_lock)); | |
| 169 | + return params->peak.rate_bytes_ps; | |
| 170 | +} | |
| 171 | + | |
| 172 | +static inline u32 tcf_police_tcfp_ewma_rate(const struct tc_action *act) | |
| 173 | +{ | |
| 174 | + struct tcf_police *police = to_police(act); | |
| 175 | + struct tcf_police_params *params; | |
| 176 | + | |
| 177 | + params = rcu_dereference_protected(police->params, | |
| 178 | + lockdep_is_held(&police->tcf_lock)); | |
| 179 | + return params->tcfp_ewma_rate; | |
| 180 | +} | |
| 181 | + | |
| 182 | +static inline u16 tcf_police_rate_overhead(const struct tc_action *act) | |
| 183 | +{ | |
| 184 | + struct tcf_police *police = to_police(act); | |
| 185 | + struct tcf_police_params *params; | |
| 186 | + | |
| 187 | + params = rcu_dereference_protected(police->params, | |
| 188 | + lockdep_is_held(&police->tcf_lock)); | |
| 189 | + return params->rate.overhead; | |
| 190 | +} | |
| 191 | + | |
| 162 | 192 | #endif /* __NET_TC_POLICE_H */ |
| @@ -419,20 +419,66 @@ static int tcf_police_search(struct net *net, struct tc_action **a, u32 index) · 418 unmodified lines | ||
| 419 | 419 | return tcf_idr_search(tn, a, index); |
| 420 | 420 | } |
| 421 | 421 | |
| 422 | +static int tcf_police_act_to_flow_act(int tc_act, u32 *extval) | |
| 423 | +{ | |
| 424 | + int act_id = -EOPNOTSUPP; | |
| 425 | + | |
| 426 | + if (!TC_ACT_EXT_OPCODE(tc_act)) { | |
| 427 | + if (tc_act == TC_ACT_OK) | |
| 428 | + act_id = FLOW_ACTION_ACCEPT; | |
| 429 | + else if (tc_act == TC_ACT_SHOT) | |
| 430 | + act_id = FLOW_ACTION_DROP; | |
| 431 | + else if (tc_act == TC_ACT_PIPE) | |
| 432 | + act_id = FLOW_ACTION_PIPE; | |
| 433 | + } else if (TC_ACT_EXT_CMP(tc_act, TC_ACT_GOTO_CHAIN)) { | |
| 434 | + act_id = FLOW_ACTION_GOTO; | |
| 435 | + *extval = tc_act & TC_ACT_EXT_VAL_MASK; | |
| 436 | + } else if (TC_ACT_EXT_CMP(tc_act, TC_ACT_JUMP)) { | |
| 437 | + act_id = FLOW_ACTION_JUMP; | |
| 438 | + *extval = tc_act & TC_ACT_EXT_VAL_MASK; | |
| 439 | + } | |
| 440 | + | |
| 441 | + return act_id; | |
| 442 | +} | |
| 443 | + | |
| 422 | 444 | static int tcf_police_offload_act_setup(struct tc_action *act, void *entry_data, |
| 423 | 445 | u32 *index_inc, bool bind) |
| 424 | 446 | { |
| 425 | 447 | if (bind) { |
| 426 | 448 | struct flow_action_entry *entry = entry_data; |
| 449 | + struct tcf_police *police = to_police(act); | |
| 450 | + struct tcf_police_params *p; | |
| 451 | + int act_id; | |
| 452 | + | |
| 453 | + p = rcu_dereference_protected(police->params, | |
| 454 | + lockdep_is_held(&police->tcf_lock)); | |
| 427 | 455 | |
| 428 | 456 | entry->id = FLOW_ACTION_POLICE; |
| 429 | 457 | entry->police.burst = tcf_police_burst(act); |
| 430 | 458 | entry->police.rate_bytes_ps = |
| 431 | 459 | tcf_police_rate_bytes_ps(act); |
| 460 | + entry->police.peakrate_bytes_ps = tcf_police_peakrate_bytes_ps(act); | |
| 461 | + entry->police.avrate = tcf_police_tcfp_ewma_rate(act); | |
| 462 | + entry->police.overhead = tcf_police_rate_overhead(act); | |
| 432 | 463 | entry->police.burst_pkt = tcf_police_burst_pkt(act); |
| 433 | 464 | entry->police.rate_pkt_ps = |
| 434 | 465 | tcf_police_rate_pkt_ps(act); |
| 435 | 466 | entry->police.mtu = tcf_police_tcfp_mtu(act); |
| 467 | + | |
| 468 | + act_id = tcf_police_act_to_flow_act(police->tcf_action, | |
| 469 | + &entry->police.exceed.extval); | |
| 470 | + if (act_id < 0) | |
| 471 | + return act_id; | |
| 472 | + | |
| 473 | + entry->police.exceed.act_id = act_id; | |
| 474 | + | |
| 475 | + act_id = tcf_police_act_to_flow_act(p->tcfp_result, | |
| 476 | + &entry->police.notexceed.extval); | |
| 477 | + if (act_id < 0) | |
| 478 | + return act_id; | |
| 479 | + | |
| 480 | + entry->police.notexceed.act_id = act_id; | |
| 481 | + | |
| 436 | 482 | *index_inc = 1; |
| 437 | 483 | } else { |
| 438 | 484 | struct flow_offload_action *fl_action = entry_data; |