0001
0002
0003
0004 #include <linux/hash.h>
0005 #include <linux/hashtable.h>
0006 #include <linux/jhash.h>
0007 #include <linux/math64.h>
0008 #include <linux/vmalloc.h>
0009 #include <net/pkt_cls.h>
0010 #include <net/pkt_sched.h>
0011
0012 #include "cmsg.h"
0013 #include "main.h"
0014 #include "../nfp_port.h"
0015
0016 #define NFP_FL_QOS_UPDATE msecs_to_jiffies(1000)
0017 #define NFP_FL_QOS_PPS BIT(15)
0018 #define NFP_FL_QOS_METER BIT(10)
0019
0020 struct nfp_police_cfg_head {
0021 __be32 flags_opts;
0022 union {
0023 __be32 meter_id;
0024 __be32 port;
0025 };
0026 };
0027
0028 enum NFP_FL_QOS_TYPES {
0029 NFP_FL_QOS_TYPE_BPS,
0030 NFP_FL_QOS_TYPE_PPS,
0031 NFP_FL_QOS_TYPE_MAX,
0032 };
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068 struct nfp_police_config {
0069 struct nfp_police_cfg_head head;
0070 __be32 bkt_tkn_p;
0071 __be32 bkt_tkn_c;
0072 __be32 pbs;
0073 __be32 cbs;
0074 __be32 pir;
0075 __be32 cir;
0076 };
0077
0078 struct nfp_police_stats_reply {
0079 struct nfp_police_cfg_head head;
0080 __be64 pass_bytes;
0081 __be64 pass_pkts;
0082 __be64 drop_bytes;
0083 __be64 drop_pkts;
0084 };
0085
0086 int nfp_flower_offload_one_police(struct nfp_app *app, bool ingress,
0087 bool pps, u32 id, u32 rate, u32 burst)
0088 {
0089 struct nfp_police_config *config;
0090 struct sk_buff *skb;
0091
0092 skb = nfp_flower_cmsg_alloc(app, sizeof(struct nfp_police_config),
0093 NFP_FLOWER_CMSG_TYPE_QOS_MOD, GFP_KERNEL);
0094 if (!skb)
0095 return -ENOMEM;
0096
0097 config = nfp_flower_cmsg_get_data(skb);
0098 memset(config, 0, sizeof(struct nfp_police_config));
0099 if (pps)
0100 config->head.flags_opts |= cpu_to_be32(NFP_FL_QOS_PPS);
0101 if (!ingress)
0102 config->head.flags_opts |= cpu_to_be32(NFP_FL_QOS_METER);
0103
0104 if (ingress)
0105 config->head.port = cpu_to_be32(id);
0106 else
0107 config->head.meter_id = cpu_to_be32(id);
0108
0109 config->bkt_tkn_p = cpu_to_be32(burst);
0110 config->bkt_tkn_c = cpu_to_be32(burst);
0111 config->pbs = cpu_to_be32(burst);
0112 config->cbs = cpu_to_be32(burst);
0113 config->pir = cpu_to_be32(rate);
0114 config->cir = cpu_to_be32(rate);
0115 nfp_ctrl_tx(app->ctrl, skb);
0116
0117 return 0;
0118 }
0119
0120 static int nfp_policer_validate(const struct flow_action *action,
0121 const struct flow_action_entry *act,
0122 struct netlink_ext_ack *extack)
0123 {
0124 if (act->police.exceed.act_id != FLOW_ACTION_DROP) {
0125 NL_SET_ERR_MSG_MOD(extack,
0126 "Offload not supported when exceed action is not drop");
0127 return -EOPNOTSUPP;
0128 }
0129
0130 if (act->police.notexceed.act_id != FLOW_ACTION_CONTINUE &&
0131 act->police.notexceed.act_id != FLOW_ACTION_PIPE &&
0132 act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
0133 NL_SET_ERR_MSG_MOD(extack,
0134 "Offload not supported when conform action is not continue, pipe or ok");
0135 return -EOPNOTSUPP;
0136 }
0137
0138 if (act->police.notexceed.act_id == FLOW_ACTION_ACCEPT &&
0139 !flow_action_is_last_entry(action, act)) {
0140 NL_SET_ERR_MSG_MOD(extack,
0141 "Offload not supported when conform action is ok, but action is not last");
0142 return -EOPNOTSUPP;
0143 }
0144
0145 if (act->police.peakrate_bytes_ps ||
0146 act->police.avrate || act->police.overhead) {
0147 NL_SET_ERR_MSG_MOD(extack,
0148 "Offload not supported when peakrate/avrate/overhead is configured");
0149 return -EOPNOTSUPP;
0150 }
0151
0152 return 0;
0153 }
0154
0155 static int
0156 nfp_flower_install_rate_limiter(struct nfp_app *app, struct net_device *netdev,
0157 struct tc_cls_matchall_offload *flow,
0158 struct netlink_ext_ack *extack)
0159 {
0160 struct flow_action_entry *paction = &flow->rule->action.entries[0];
0161 u32 action_num = flow->rule->action.num_entries;
0162 struct nfp_flower_priv *fl_priv = app->priv;
0163 struct flow_action_entry *action = NULL;
0164 struct nfp_flower_repr_priv *repr_priv;
0165 u32 netdev_port_id, i;
0166 struct nfp_repr *repr;
0167 bool pps_support;
0168 u32 bps_num = 0;
0169 u32 pps_num = 0;
0170 u32 burst;
0171 bool pps;
0172 u64 rate;
0173 int err;
0174
0175 if (!nfp_netdev_is_nfp_repr(netdev)) {
0176 NL_SET_ERR_MSG_MOD(extack, "unsupported offload: qos rate limit offload not supported on higher level port");
0177 return -EOPNOTSUPP;
0178 }
0179 repr = netdev_priv(netdev);
0180 repr_priv = repr->app_priv;
0181 netdev_port_id = nfp_repr_get_port_id(netdev);
0182 pps_support = !!(fl_priv->flower_ext_feats & NFP_FL_FEATS_QOS_PPS);
0183
0184 if (repr_priv->block_shared) {
0185 NL_SET_ERR_MSG_MOD(extack, "unsupported offload: qos rate limit offload not supported on shared blocks");
0186 return -EOPNOTSUPP;
0187 }
0188
0189 if (repr->port->type != NFP_PORT_VF_PORT) {
0190 NL_SET_ERR_MSG_MOD(extack, "unsupported offload: qos rate limit offload not supported on non-VF ports");
0191 return -EOPNOTSUPP;
0192 }
0193
0194 if (pps_support) {
0195 if (action_num > 2 || action_num == 0) {
0196 NL_SET_ERR_MSG_MOD(extack,
0197 "unsupported offload: qos rate limit offload only support action number 1 or 2");
0198 return -EOPNOTSUPP;
0199 }
0200 } else {
0201 if (!flow_offload_has_one_action(&flow->rule->action)) {
0202 NL_SET_ERR_MSG_MOD(extack,
0203 "unsupported offload: qos rate limit offload requires a single action");
0204 return -EOPNOTSUPP;
0205 }
0206 }
0207
0208 if (flow->common.prio != 1) {
0209 NL_SET_ERR_MSG_MOD(extack, "unsupported offload: qos rate limit offload requires highest priority");
0210 return -EOPNOTSUPP;
0211 }
0212
0213 for (i = 0 ; i < action_num; i++) {
0214 action = paction + i;
0215 if (action->id != FLOW_ACTION_POLICE) {
0216 NL_SET_ERR_MSG_MOD(extack,
0217 "unsupported offload: qos rate limit offload requires police action");
0218 return -EOPNOTSUPP;
0219 }
0220
0221 err = nfp_policer_validate(&flow->rule->action, action, extack);
0222 if (err)
0223 return err;
0224
0225 if (action->police.rate_bytes_ps > 0) {
0226 if (bps_num++) {
0227 NL_SET_ERR_MSG_MOD(extack,
0228 "unsupported offload: qos rate limit offload only support one BPS action");
0229 return -EOPNOTSUPP;
0230 }
0231 }
0232 if (action->police.rate_pkt_ps > 0) {
0233 if (!pps_support) {
0234 NL_SET_ERR_MSG_MOD(extack,
0235 "unsupported offload: FW does not support PPS action");
0236 return -EOPNOTSUPP;
0237 }
0238 if (pps_num++) {
0239 NL_SET_ERR_MSG_MOD(extack,
0240 "unsupported offload: qos rate limit offload only support one PPS action");
0241 return -EOPNOTSUPP;
0242 }
0243 }
0244 }
0245
0246 for (i = 0 ; i < action_num; i++) {
0247
0248 action = paction + i;
0249 if (action->police.rate_bytes_ps > 0) {
0250 rate = action->police.rate_bytes_ps;
0251 burst = action->police.burst;
0252 } else if (action->police.rate_pkt_ps > 0) {
0253 rate = action->police.rate_pkt_ps;
0254 burst = action->police.burst_pkt;
0255 } else {
0256 NL_SET_ERR_MSG_MOD(extack,
0257 "unsupported offload: qos rate limit is not BPS or PPS");
0258 continue;
0259 }
0260
0261 if (rate != 0) {
0262 pps = false;
0263 if (action->police.rate_pkt_ps > 0)
0264 pps = true;
0265 nfp_flower_offload_one_police(repr->app, true,
0266 pps, netdev_port_id,
0267 rate, burst);
0268 }
0269 }
0270 repr_priv->qos_table.netdev_port_id = netdev_port_id;
0271 fl_priv->qos_rate_limiters++;
0272 if (fl_priv->qos_rate_limiters == 1)
0273 schedule_delayed_work(&fl_priv->qos_stats_work,
0274 NFP_FL_QOS_UPDATE);
0275
0276 return 0;
0277 }
0278
0279 static int
0280 nfp_flower_remove_rate_limiter(struct nfp_app *app, struct net_device *netdev,
0281 struct tc_cls_matchall_offload *flow,
0282 struct netlink_ext_ack *extack)
0283 {
0284 struct nfp_flower_priv *fl_priv = app->priv;
0285 struct nfp_flower_repr_priv *repr_priv;
0286 struct nfp_police_config *config;
0287 u32 netdev_port_id, i;
0288 struct nfp_repr *repr;
0289 struct sk_buff *skb;
0290 bool pps_support;
0291
0292 if (!nfp_netdev_is_nfp_repr(netdev)) {
0293 NL_SET_ERR_MSG_MOD(extack, "unsupported offload: qos rate limit offload not supported on higher level port");
0294 return -EOPNOTSUPP;
0295 }
0296 repr = netdev_priv(netdev);
0297
0298 netdev_port_id = nfp_repr_get_port_id(netdev);
0299 repr_priv = repr->app_priv;
0300 pps_support = !!(fl_priv->flower_ext_feats & NFP_FL_FEATS_QOS_PPS);
0301
0302 if (!repr_priv->qos_table.netdev_port_id) {
0303 NL_SET_ERR_MSG_MOD(extack, "unsupported offload: cannot remove qos entry that does not exist");
0304 return -EOPNOTSUPP;
0305 }
0306
0307 memset(&repr_priv->qos_table, 0, sizeof(struct nfp_fl_qos));
0308 fl_priv->qos_rate_limiters--;
0309 if (!fl_priv->qos_rate_limiters)
0310 cancel_delayed_work_sync(&fl_priv->qos_stats_work);
0311 for (i = 0 ; i < NFP_FL_QOS_TYPE_MAX; i++) {
0312 if (i == NFP_FL_QOS_TYPE_PPS && !pps_support)
0313 break;
0314
0315
0316
0317
0318
0319
0320 skb = nfp_flower_cmsg_alloc(repr->app, sizeof(struct nfp_police_config),
0321 NFP_FLOWER_CMSG_TYPE_QOS_DEL, GFP_KERNEL);
0322 if (!skb)
0323 return -ENOMEM;
0324
0325 config = nfp_flower_cmsg_get_data(skb);
0326 memset(config, 0, sizeof(struct nfp_police_config));
0327 if (i == NFP_FL_QOS_TYPE_PPS)
0328 config->head.flags_opts = cpu_to_be32(NFP_FL_QOS_PPS);
0329 config->head.port = cpu_to_be32(netdev_port_id);
0330 nfp_ctrl_tx(repr->app->ctrl, skb);
0331 }
0332
0333 return 0;
0334 }
0335
0336 void nfp_flower_stats_rlim_reply(struct nfp_app *app, struct sk_buff *skb)
0337 {
0338 struct nfp_flower_priv *fl_priv = app->priv;
0339 struct nfp_flower_repr_priv *repr_priv;
0340 struct nfp_police_stats_reply *msg;
0341 struct nfp_stat_pair *curr_stats;
0342 struct nfp_stat_pair *prev_stats;
0343 struct net_device *netdev;
0344 struct nfp_repr *repr;
0345 u32 netdev_port_id;
0346
0347 msg = nfp_flower_cmsg_get_data(skb);
0348 if (be32_to_cpu(msg->head.flags_opts) & NFP_FL_QOS_METER)
0349 return nfp_act_stats_reply(app, msg);
0350
0351 netdev_port_id = be32_to_cpu(msg->head.port);
0352 rcu_read_lock();
0353 netdev = nfp_app_dev_get(app, netdev_port_id, NULL);
0354 if (!netdev)
0355 goto exit_unlock_rcu;
0356
0357 repr = netdev_priv(netdev);
0358 repr_priv = repr->app_priv;
0359 curr_stats = &repr_priv->qos_table.curr_stats;
0360 prev_stats = &repr_priv->qos_table.prev_stats;
0361
0362 spin_lock_bh(&fl_priv->qos_stats_lock);
0363 curr_stats->pkts = be64_to_cpu(msg->pass_pkts) +
0364 be64_to_cpu(msg->drop_pkts);
0365 curr_stats->bytes = be64_to_cpu(msg->pass_bytes) +
0366 be64_to_cpu(msg->drop_bytes);
0367
0368 if (!repr_priv->qos_table.last_update) {
0369 prev_stats->pkts = curr_stats->pkts;
0370 prev_stats->bytes = curr_stats->bytes;
0371 }
0372
0373 repr_priv->qos_table.last_update = jiffies;
0374 spin_unlock_bh(&fl_priv->qos_stats_lock);
0375
0376 exit_unlock_rcu:
0377 rcu_read_unlock();
0378 }
0379
0380 static void
0381 nfp_flower_stats_rlim_request(struct nfp_flower_priv *fl_priv,
0382 u32 id, bool ingress)
0383 {
0384 struct nfp_police_cfg_head *head;
0385 struct sk_buff *skb;
0386
0387 skb = nfp_flower_cmsg_alloc(fl_priv->app,
0388 sizeof(struct nfp_police_cfg_head),
0389 NFP_FLOWER_CMSG_TYPE_QOS_STATS,
0390 GFP_ATOMIC);
0391 if (!skb)
0392 return;
0393 head = nfp_flower_cmsg_get_data(skb);
0394
0395 memset(head, 0, sizeof(struct nfp_police_cfg_head));
0396 if (ingress) {
0397 head->port = cpu_to_be32(id);
0398 } else {
0399 head->flags_opts = cpu_to_be32(NFP_FL_QOS_METER);
0400 head->meter_id = cpu_to_be32(id);
0401 }
0402
0403 nfp_ctrl_tx(fl_priv->app->ctrl, skb);
0404 }
0405
0406 static void
0407 nfp_flower_stats_rlim_request_all(struct nfp_flower_priv *fl_priv)
0408 {
0409 struct nfp_reprs *repr_set;
0410 int i;
0411
0412 rcu_read_lock();
0413 repr_set = rcu_dereference(fl_priv->app->reprs[NFP_REPR_TYPE_VF]);
0414 if (!repr_set)
0415 goto exit_unlock_rcu;
0416
0417 for (i = 0; i < repr_set->num_reprs; i++) {
0418 struct net_device *netdev;
0419
0420 netdev = rcu_dereference(repr_set->reprs[i]);
0421 if (netdev) {
0422 struct nfp_repr *priv = netdev_priv(netdev);
0423 struct nfp_flower_repr_priv *repr_priv;
0424 u32 netdev_port_id;
0425
0426 repr_priv = priv->app_priv;
0427 netdev_port_id = repr_priv->qos_table.netdev_port_id;
0428 if (!netdev_port_id)
0429 continue;
0430
0431 nfp_flower_stats_rlim_request(fl_priv,
0432 netdev_port_id, true);
0433 }
0434 }
0435
0436 exit_unlock_rcu:
0437 rcu_read_unlock();
0438 }
0439
0440 static void update_stats_cache(struct work_struct *work)
0441 {
0442 struct delayed_work *delayed_work;
0443 struct nfp_flower_priv *fl_priv;
0444
0445 delayed_work = to_delayed_work(work);
0446 fl_priv = container_of(delayed_work, struct nfp_flower_priv,
0447 qos_stats_work);
0448
0449 nfp_flower_stats_rlim_request_all(fl_priv);
0450 nfp_flower_stats_meter_request_all(fl_priv);
0451
0452 schedule_delayed_work(&fl_priv->qos_stats_work, NFP_FL_QOS_UPDATE);
0453 }
0454
0455 static int
0456 nfp_flower_stats_rate_limiter(struct nfp_app *app, struct net_device *netdev,
0457 struct tc_cls_matchall_offload *flow,
0458 struct netlink_ext_ack *extack)
0459 {
0460 struct nfp_flower_priv *fl_priv = app->priv;
0461 struct nfp_flower_repr_priv *repr_priv;
0462 struct nfp_stat_pair *curr_stats;
0463 struct nfp_stat_pair *prev_stats;
0464 u64 diff_bytes, diff_pkts;
0465 struct nfp_repr *repr;
0466
0467 if (!nfp_netdev_is_nfp_repr(netdev)) {
0468 NL_SET_ERR_MSG_MOD(extack, "unsupported offload: qos rate limit offload not supported on higher level port");
0469 return -EOPNOTSUPP;
0470 }
0471 repr = netdev_priv(netdev);
0472
0473 repr_priv = repr->app_priv;
0474 if (!repr_priv->qos_table.netdev_port_id) {
0475 NL_SET_ERR_MSG_MOD(extack, "unsupported offload: cannot find qos entry for stats update");
0476 return -EOPNOTSUPP;
0477 }
0478
0479 spin_lock_bh(&fl_priv->qos_stats_lock);
0480 curr_stats = &repr_priv->qos_table.curr_stats;
0481 prev_stats = &repr_priv->qos_table.prev_stats;
0482 diff_pkts = curr_stats->pkts - prev_stats->pkts;
0483 diff_bytes = curr_stats->bytes - prev_stats->bytes;
0484 prev_stats->pkts = curr_stats->pkts;
0485 prev_stats->bytes = curr_stats->bytes;
0486 spin_unlock_bh(&fl_priv->qos_stats_lock);
0487
0488 flow_stats_update(&flow->stats, diff_bytes, diff_pkts, 0,
0489 repr_priv->qos_table.last_update,
0490 FLOW_ACTION_HW_STATS_DELAYED);
0491 return 0;
0492 }
0493
0494 void nfp_flower_qos_init(struct nfp_app *app)
0495 {
0496 struct nfp_flower_priv *fl_priv = app->priv;
0497
0498 spin_lock_init(&fl_priv->qos_stats_lock);
0499 mutex_init(&fl_priv->meter_stats_lock);
0500 nfp_init_meter_table(app);
0501
0502 INIT_DELAYED_WORK(&fl_priv->qos_stats_work, &update_stats_cache);
0503 }
0504
0505 void nfp_flower_qos_cleanup(struct nfp_app *app)
0506 {
0507 struct nfp_flower_priv *fl_priv = app->priv;
0508
0509 cancel_delayed_work_sync(&fl_priv->qos_stats_work);
0510 }
0511
0512 int nfp_flower_setup_qos_offload(struct nfp_app *app, struct net_device *netdev,
0513 struct tc_cls_matchall_offload *flow)
0514 {
0515 struct netlink_ext_ack *extack = flow->common.extack;
0516 struct nfp_flower_priv *fl_priv = app->priv;
0517
0518 if (!(fl_priv->flower_ext_feats & NFP_FL_FEATS_VF_RLIM)) {
0519 NL_SET_ERR_MSG_MOD(extack, "unsupported offload: loaded firmware does not support qos rate limit offload");
0520 return -EOPNOTSUPP;
0521 }
0522
0523 switch (flow->command) {
0524 case TC_CLSMATCHALL_REPLACE:
0525 return nfp_flower_install_rate_limiter(app, netdev, flow,
0526 extack);
0527 case TC_CLSMATCHALL_DESTROY:
0528 return nfp_flower_remove_rate_limiter(app, netdev, flow,
0529 extack);
0530 case TC_CLSMATCHALL_STATS:
0531 return nfp_flower_stats_rate_limiter(app, netdev, flow,
0532 extack);
0533 default:
0534 return -EOPNOTSUPP;
0535 }
0536 }
0537
0538
0539
0540 static const struct rhashtable_params stats_meter_table_params = {
0541 .key_offset = offsetof(struct nfp_meter_entry, meter_id),
0542 .head_offset = offsetof(struct nfp_meter_entry, ht_node),
0543 .key_len = sizeof(u32),
0544 };
0545
0546 struct nfp_meter_entry *
0547 nfp_flower_search_meter_entry(struct nfp_app *app, u32 meter_id)
0548 {
0549 struct nfp_flower_priv *priv = app->priv;
0550
0551 return rhashtable_lookup_fast(&priv->meter_table, &meter_id,
0552 stats_meter_table_params);
0553 }
0554
0555 static struct nfp_meter_entry *
0556 nfp_flower_add_meter_entry(struct nfp_app *app, u32 meter_id)
0557 {
0558 struct nfp_meter_entry *meter_entry = NULL;
0559 struct nfp_flower_priv *priv = app->priv;
0560
0561 meter_entry = rhashtable_lookup_fast(&priv->meter_table,
0562 &meter_id,
0563 stats_meter_table_params);
0564 if (meter_entry)
0565 return meter_entry;
0566
0567 meter_entry = kzalloc(sizeof(*meter_entry), GFP_KERNEL);
0568 if (!meter_entry)
0569 return NULL;
0570
0571 meter_entry->meter_id = meter_id;
0572 meter_entry->used = jiffies;
0573 if (rhashtable_insert_fast(&priv->meter_table, &meter_entry->ht_node,
0574 stats_meter_table_params)) {
0575 kfree(meter_entry);
0576 return NULL;
0577 }
0578
0579 priv->qos_rate_limiters++;
0580 if (priv->qos_rate_limiters == 1)
0581 schedule_delayed_work(&priv->qos_stats_work,
0582 NFP_FL_QOS_UPDATE);
0583
0584 return meter_entry;
0585 }
0586
0587 static void nfp_flower_del_meter_entry(struct nfp_app *app, u32 meter_id)
0588 {
0589 struct nfp_meter_entry *meter_entry = NULL;
0590 struct nfp_flower_priv *priv = app->priv;
0591
0592 meter_entry = rhashtable_lookup_fast(&priv->meter_table, &meter_id,
0593 stats_meter_table_params);
0594 if (!meter_entry)
0595 return;
0596
0597 rhashtable_remove_fast(&priv->meter_table,
0598 &meter_entry->ht_node,
0599 stats_meter_table_params);
0600 kfree(meter_entry);
0601 priv->qos_rate_limiters--;
0602 if (!priv->qos_rate_limiters)
0603 cancel_delayed_work_sync(&priv->qos_stats_work);
0604 }
0605
0606 int nfp_flower_setup_meter_entry(struct nfp_app *app,
0607 const struct flow_action_entry *action,
0608 enum nfp_meter_op op,
0609 u32 meter_id)
0610 {
0611 struct nfp_flower_priv *fl_priv = app->priv;
0612 struct nfp_meter_entry *meter_entry = NULL;
0613 int err = 0;
0614
0615 mutex_lock(&fl_priv->meter_stats_lock);
0616
0617 switch (op) {
0618 case NFP_METER_DEL:
0619 nfp_flower_del_meter_entry(app, meter_id);
0620 goto exit_unlock;
0621 case NFP_METER_ADD:
0622 meter_entry = nfp_flower_add_meter_entry(app, meter_id);
0623 break;
0624 default:
0625 err = -EOPNOTSUPP;
0626 goto exit_unlock;
0627 }
0628
0629 if (!meter_entry) {
0630 err = -ENOMEM;
0631 goto exit_unlock;
0632 }
0633
0634 if (action->police.rate_bytes_ps > 0) {
0635 meter_entry->bps = true;
0636 meter_entry->rate = action->police.rate_bytes_ps;
0637 meter_entry->burst = action->police.burst;
0638 } else {
0639 meter_entry->bps = false;
0640 meter_entry->rate = action->police.rate_pkt_ps;
0641 meter_entry->burst = action->police.burst_pkt;
0642 }
0643
0644 exit_unlock:
0645 mutex_unlock(&fl_priv->meter_stats_lock);
0646 return err;
0647 }
0648
0649 int nfp_init_meter_table(struct nfp_app *app)
0650 {
0651 struct nfp_flower_priv *priv = app->priv;
0652
0653 return rhashtable_init(&priv->meter_table, &stats_meter_table_params);
0654 }
0655
0656 void
0657 nfp_flower_stats_meter_request_all(struct nfp_flower_priv *fl_priv)
0658 {
0659 struct nfp_meter_entry *meter_entry = NULL;
0660 struct rhashtable_iter iter;
0661
0662 mutex_lock(&fl_priv->meter_stats_lock);
0663 rhashtable_walk_enter(&fl_priv->meter_table, &iter);
0664 rhashtable_walk_start(&iter);
0665
0666 while ((meter_entry = rhashtable_walk_next(&iter)) != NULL) {
0667 if (IS_ERR(meter_entry))
0668 continue;
0669 nfp_flower_stats_rlim_request(fl_priv,
0670 meter_entry->meter_id, false);
0671 }
0672
0673 rhashtable_walk_stop(&iter);
0674 rhashtable_walk_exit(&iter);
0675 mutex_unlock(&fl_priv->meter_stats_lock);
0676 }
0677
0678 static int
0679 nfp_act_install_actions(struct nfp_app *app, struct flow_offload_action *fl_act,
0680 struct netlink_ext_ack *extack)
0681 {
0682 struct flow_action_entry *paction = &fl_act->action.entries[0];
0683 u32 action_num = fl_act->action.num_entries;
0684 struct nfp_flower_priv *fl_priv = app->priv;
0685 struct flow_action_entry *action = NULL;
0686 u32 burst, i, meter_id;
0687 bool pps_support, pps;
0688 bool add = false;
0689 u64 rate;
0690
0691 pps_support = !!(fl_priv->flower_ext_feats & NFP_FL_FEATS_QOS_PPS);
0692
0693 for (i = 0 ; i < action_num; i++) {
0694
0695 action = paction + i;
0696 if (action->id != FLOW_ACTION_POLICE) {
0697 NL_SET_ERR_MSG_MOD(extack,
0698 "unsupported offload: qos rate limit offload requires police action");
0699 continue;
0700 }
0701 if (action->police.rate_bytes_ps > 0) {
0702 rate = action->police.rate_bytes_ps;
0703 burst = action->police.burst;
0704 } else if (action->police.rate_pkt_ps > 0 && pps_support) {
0705 rate = action->police.rate_pkt_ps;
0706 burst = action->police.burst_pkt;
0707 } else {
0708 NL_SET_ERR_MSG_MOD(extack,
0709 "unsupported offload: unsupported qos rate limit");
0710 continue;
0711 }
0712
0713 if (rate != 0) {
0714 meter_id = action->hw_index;
0715 if (nfp_flower_setup_meter_entry(app, action, NFP_METER_ADD, meter_id))
0716 continue;
0717
0718 pps = false;
0719 if (action->police.rate_pkt_ps > 0)
0720 pps = true;
0721 nfp_flower_offload_one_police(app, false, pps, meter_id,
0722 rate, burst);
0723 add = true;
0724 }
0725 }
0726
0727 return add ? 0 : -EOPNOTSUPP;
0728 }
0729
0730 static int
0731 nfp_act_remove_actions(struct nfp_app *app, struct flow_offload_action *fl_act,
0732 struct netlink_ext_ack *extack)
0733 {
0734 struct nfp_meter_entry *meter_entry = NULL;
0735 struct nfp_police_config *config;
0736 struct sk_buff *skb;
0737 u32 meter_id;
0738 bool pps;
0739
0740
0741 if (fl_act->id != FLOW_ACTION_POLICE) {
0742 NL_SET_ERR_MSG_MOD(extack,
0743 "unsupported offload: qos rate limit offload requires police action");
0744 return -EOPNOTSUPP;
0745 }
0746
0747 meter_id = fl_act->index;
0748 meter_entry = nfp_flower_search_meter_entry(app, meter_id);
0749 if (!meter_entry) {
0750 NL_SET_ERR_MSG_MOD(extack,
0751 "no meter entry when delete the action index.");
0752 return -ENOENT;
0753 }
0754 pps = !meter_entry->bps;
0755
0756 skb = nfp_flower_cmsg_alloc(app, sizeof(struct nfp_police_config),
0757 NFP_FLOWER_CMSG_TYPE_QOS_DEL, GFP_KERNEL);
0758 if (!skb)
0759 return -ENOMEM;
0760
0761 config = nfp_flower_cmsg_get_data(skb);
0762 memset(config, 0, sizeof(struct nfp_police_config));
0763 config->head.flags_opts = cpu_to_be32(NFP_FL_QOS_METER);
0764 config->head.meter_id = cpu_to_be32(meter_id);
0765 if (pps)
0766 config->head.flags_opts |= cpu_to_be32(NFP_FL_QOS_PPS);
0767
0768 nfp_ctrl_tx(app->ctrl, skb);
0769 nfp_flower_setup_meter_entry(app, NULL, NFP_METER_DEL, meter_id);
0770
0771 return 0;
0772 }
0773
0774 void
0775 nfp_act_stats_reply(struct nfp_app *app, void *pmsg)
0776 {
0777 struct nfp_flower_priv *fl_priv = app->priv;
0778 struct nfp_meter_entry *meter_entry = NULL;
0779 struct nfp_police_stats_reply *msg = pmsg;
0780 u32 meter_id;
0781
0782 meter_id = be32_to_cpu(msg->head.meter_id);
0783 mutex_lock(&fl_priv->meter_stats_lock);
0784
0785 meter_entry = nfp_flower_search_meter_entry(app, meter_id);
0786 if (!meter_entry)
0787 goto exit_unlock;
0788
0789 meter_entry->stats.curr.pkts = be64_to_cpu(msg->pass_pkts) +
0790 be64_to_cpu(msg->drop_pkts);
0791 meter_entry->stats.curr.bytes = be64_to_cpu(msg->pass_bytes) +
0792 be64_to_cpu(msg->drop_bytes);
0793 meter_entry->stats.curr.drops = be64_to_cpu(msg->drop_pkts);
0794 if (!meter_entry->stats.update) {
0795 meter_entry->stats.prev.pkts = meter_entry->stats.curr.pkts;
0796 meter_entry->stats.prev.bytes = meter_entry->stats.curr.bytes;
0797 meter_entry->stats.prev.drops = meter_entry->stats.curr.drops;
0798 }
0799
0800 meter_entry->stats.update = jiffies;
0801
0802 exit_unlock:
0803 mutex_unlock(&fl_priv->meter_stats_lock);
0804 }
0805
0806 static int
0807 nfp_act_stats_actions(struct nfp_app *app, struct flow_offload_action *fl_act,
0808 struct netlink_ext_ack *extack)
0809 {
0810 struct nfp_flower_priv *fl_priv = app->priv;
0811 struct nfp_meter_entry *meter_entry = NULL;
0812 u64 diff_bytes, diff_pkts, diff_drops;
0813 int err = 0;
0814
0815 if (fl_act->id != FLOW_ACTION_POLICE) {
0816 NL_SET_ERR_MSG_MOD(extack,
0817 "unsupported offload: qos rate limit offload requires police action");
0818 return -EOPNOTSUPP;
0819 }
0820
0821 mutex_lock(&fl_priv->meter_stats_lock);
0822 meter_entry = nfp_flower_search_meter_entry(app, fl_act->index);
0823 if (!meter_entry) {
0824 err = -ENOENT;
0825 goto exit_unlock;
0826 }
0827 diff_pkts = meter_entry->stats.curr.pkts > meter_entry->stats.prev.pkts ?
0828 meter_entry->stats.curr.pkts - meter_entry->stats.prev.pkts : 0;
0829 diff_bytes = meter_entry->stats.curr.bytes > meter_entry->stats.prev.bytes ?
0830 meter_entry->stats.curr.bytes - meter_entry->stats.prev.bytes : 0;
0831 diff_drops = meter_entry->stats.curr.drops > meter_entry->stats.prev.drops ?
0832 meter_entry->stats.curr.drops - meter_entry->stats.prev.drops : 0;
0833
0834 flow_stats_update(&fl_act->stats, diff_bytes, diff_pkts, diff_drops,
0835 meter_entry->stats.update,
0836 FLOW_ACTION_HW_STATS_DELAYED);
0837
0838 meter_entry->stats.prev.pkts = meter_entry->stats.curr.pkts;
0839 meter_entry->stats.prev.bytes = meter_entry->stats.curr.bytes;
0840 meter_entry->stats.prev.drops = meter_entry->stats.curr.drops;
0841
0842 exit_unlock:
0843 mutex_unlock(&fl_priv->meter_stats_lock);
0844 return err;
0845 }
0846
0847 int nfp_setup_tc_act_offload(struct nfp_app *app,
0848 struct flow_offload_action *fl_act)
0849 {
0850 struct netlink_ext_ack *extack = fl_act->extack;
0851 struct nfp_flower_priv *fl_priv = app->priv;
0852
0853 if (!(fl_priv->flower_ext_feats & NFP_FL_FEATS_QOS_METER))
0854 return -EOPNOTSUPP;
0855
0856 switch (fl_act->command) {
0857 case FLOW_ACT_REPLACE:
0858 return nfp_act_install_actions(app, fl_act, extack);
0859 case FLOW_ACT_DESTROY:
0860 return nfp_act_remove_actions(app, fl_act, extack);
0861 case FLOW_ACT_STATS:
0862 return nfp_act_stats_actions(app, fl_act, extack);
0863 default:
0864 return -EOPNOTSUPP;
0865 }
0866 }