Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
0002 /* Copyright (C) 2019 Netronome Systems, Inc. */
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 /* Police cmsg for configuring a trTCM traffic conditioner (8W/32B)
0035  * See RFC 2698 for more details.
0036  * ----------------------------------------------------------------
0037  *    3                   2                   1
0038  *  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
0039  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0040  * |             Reserved          |p|         Reserved            |
0041  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0042  * |                          Port Ingress                         |
0043  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0044  * |                        Token Bucket Peak                      |
0045  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0046  * |                     Token Bucket Committed                    |
0047  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0048  * |                         Peak Burst Size                       |
0049  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0050  * |                      Committed Burst Size                     |
0051  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0052  * |                      Peak Information Rate                    |
0053  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0054  * |                    Committed Information Rate                 |
0055  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0056  * Word[0](FLag options):
0057  * [15] p(pps) 1 for pps, 0 for bps
0058  *
0059  * Meter control message
0060  *  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
0061  * +-------------------------------+-+---+-----+-+---------+-+---+-+
0062  * |            Reserved           |p| Y |TYPE |E|TSHFV    |P| PC|R|
0063  * +-------------------------------+-+---+-----+-+---------+-+---+-+
0064  * |                            meter ID                           |
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         /* Set QoS data for this interface */
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         /* 0:bps 1:pps
0315          * Clear QoS data for this interface.
0316          * There is no need to check if a specific QOS_TYPE was
0317          * configured as the firmware handles clearing a QoS entry
0318          * safely, even if it wasn't explicitly added.
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 /* Offload tc action, currently only for tc police */
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         /* Set qos associate data for this interface */
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     /* Delete qos associate data for this interface */
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 }