Commit 59080da0 authored by Baowen Zheng's avatar Baowen Zheng Committed by Jakub Kicinski

nfp: add support to offload tc action to hardware

Add process to offload tc action to hardware.

Currently we only support to offload police action.

Add meter capability to check if firmware supports
meter offload.
Signed-off-by: default avatarBaowen Zheng <baowen.zheng@corigine.com>
Signed-off-by: default avatarLouis Peens <louis.peens@corigine.com>
Signed-off-by: default avatarSimon Horman <simon.horman@corigine.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent bbab5f93
......@@ -12,7 +12,9 @@
#include <linux/rhashtable.h>
#include <linux/time64.h>
#include <linux/types.h>
#include <net/flow_offload.h>
#include <net/pkt_cls.h>
#include <net/pkt_sched.h>
#include <net/tcp.h>
#include <linux/workqueue.h>
#include <linux/idr.h>
......@@ -48,6 +50,7 @@ struct nfp_app;
#define NFP_FL_FEATS_IPV6_TUN BIT(7)
#define NFP_FL_FEATS_VLAN_QINQ BIT(8)
#define NFP_FL_FEATS_QOS_PPS BIT(9)
#define NFP_FL_FEATS_QOS_METER BIT(10)
#define NFP_FL_FEATS_HOST_ACK BIT(31)
#define NFP_FL_ENABLE_FLOW_MERGE BIT(0)
......@@ -569,6 +572,9 @@ nfp_flower_xmit_flow(struct nfp_app *app, struct nfp_fl_payload *nfp_flow,
void
nfp_flower_update_merge_stats(struct nfp_app *app,
struct nfp_fl_payload *sub_flow);
int nfp_setup_tc_act_offload(struct nfp_app *app,
struct flow_offload_action *fl_act);
int nfp_flower_offload_one_police(struct nfp_app *app, bool ingress,
bool pps, u32 id, u32 rate, u32 burst);
#endif
......@@ -1861,6 +1861,20 @@ nfp_flower_setup_indr_tc_block(struct net_device *netdev, struct Qdisc *sch, str
return 0;
}
static int
nfp_setup_tc_no_dev(struct nfp_app *app, enum tc_setup_type type, void *data)
{
if (!data)
return -EOPNOTSUPP;
switch (type) {
case TC_SETUP_ACT:
return nfp_setup_tc_act_offload(app, data);
default:
return -EOPNOTSUPP;
}
}
int
nfp_flower_indr_setup_tc_cb(struct net_device *netdev, struct Qdisc *sch, void *cb_priv,
enum tc_setup_type type, void *type_data,
......@@ -1868,7 +1882,7 @@ nfp_flower_indr_setup_tc_cb(struct net_device *netdev, struct Qdisc *sch, void *
void (*cleanup)(struct flow_block_cb *block_cb))
{
if (!netdev)
return -EOPNOTSUPP;
return nfp_setup_tc_no_dev(cb_priv, type, data);
if (!nfp_fl_is_netdev_to_offload(netdev))
return -EOPNOTSUPP;
......
......@@ -475,3 +475,103 @@ int nfp_flower_setup_qos_offload(struct nfp_app *app, struct net_device *netdev,
return -EOPNOTSUPP;
}
}
/* offload tc action, currently only for tc police */
static int
nfp_act_install_actions(struct nfp_app *app, struct flow_offload_action *fl_act,
struct netlink_ext_ack *extack)
{
struct flow_action_entry *paction = &fl_act->action.entries[0];
u32 action_num = fl_act->action.num_entries;
struct nfp_flower_priv *fl_priv = app->priv;
struct flow_action_entry *action = NULL;
u32 burst, i, meter_id;
bool pps_support, pps;
bool add = false;
u64 rate;
pps_support = !!(fl_priv->flower_ext_feats & NFP_FL_FEATS_QOS_PPS);
for (i = 0 ; i < action_num; i++) {
/*set qos associate data for this interface */
action = paction + i;
if (action->id != FLOW_ACTION_POLICE) {
NL_SET_ERR_MSG_MOD(extack,
"unsupported offload: qos rate limit offload requires police action");
continue;
}
if (action->police.rate_bytes_ps > 0) {
rate = action->police.rate_bytes_ps;
burst = action->police.burst;
} else if (action->police.rate_pkt_ps > 0 && pps_support) {
rate = action->police.rate_pkt_ps;
burst = action->police.burst_pkt;
} else {
NL_SET_ERR_MSG_MOD(extack,
"unsupported offload: unsupported qos rate limit");
continue;
}
if (rate != 0) {
pps = false;
if (action->police.rate_pkt_ps > 0)
pps = true;
meter_id = action->hw_index;
nfp_flower_offload_one_police(app, false, pps, meter_id,
rate, burst);
add = true;
}
}
return add ? 0 : -EOPNOTSUPP;
}
static int
nfp_act_remove_actions(struct nfp_app *app, struct flow_offload_action *fl_act,
struct netlink_ext_ack *extack)
{
struct nfp_police_config *config;
struct sk_buff *skb;
u32 meter_id;
/*delete qos associate data for this interface */
if (fl_act->id != FLOW_ACTION_POLICE) {
NL_SET_ERR_MSG_MOD(extack,
"unsupported offload: qos rate limit offload requires police action");
return -EOPNOTSUPP;
}
meter_id = fl_act->index;
skb = nfp_flower_cmsg_alloc(app, sizeof(struct nfp_police_config),
NFP_FLOWER_CMSG_TYPE_QOS_DEL, GFP_KERNEL);
if (!skb)
return -ENOMEM;
config = nfp_flower_cmsg_get_data(skb);
memset(config, 0, sizeof(struct nfp_police_config));
config->head.flags_opts = cpu_to_be32(NFP_FL_QOS_METER);
config->head.meter_id = cpu_to_be32(meter_id);
nfp_ctrl_tx(app->ctrl, skb);
return 0;
}
int nfp_setup_tc_act_offload(struct nfp_app *app,
struct flow_offload_action *fl_act)
{
struct netlink_ext_ack *extack = fl_act->extack;
struct nfp_flower_priv *fl_priv = app->priv;
if (!(fl_priv->flower_ext_feats & NFP_FL_FEATS_QOS_METER))
return -EOPNOTSUPP;
switch (fl_act->command) {
case FLOW_ACT_REPLACE:
return nfp_act_install_actions(app, fl_act, extack);
case FLOW_ACT_DESTROY:
return nfp_act_remove_actions(app, fl_act, extack);
default:
return -EOPNOTSUPP;
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment