Commit 49cbef13 authored by Pieter Jansen van Vuuren's avatar Pieter Jansen van Vuuren Committed by David S. Miller

nfp: flower: add qos offload install and remove functionality.

Add install and remove offload functionality for qos offloads. We
first check that a police filter can be implemented by the VF rate
limiting feature in hw, then we install the filter via the qos
infrastructure. Finally we implement the mechanism for removing
these types of filters.
Signed-off-by: default avatarPieter Jansen van Vuuren <pieter.jansenvanvuuren@netronome.com>
Reviewed-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b66d035e
......@@ -416,6 +416,8 @@ enum nfp_flower_cmsg_type_port {
NFP_FLOWER_CMSG_TYPE_TUN_IPS = 14,
NFP_FLOWER_CMSG_TYPE_FLOW_STATS = 15,
NFP_FLOWER_CMSG_TYPE_PORT_ECHO = 16,
NFP_FLOWER_CMSG_TYPE_QOS_MOD = 18,
NFP_FLOWER_CMSG_TYPE_QOS_DEL = 19,
NFP_FLOWER_CMSG_TYPE_MAX = 32,
};
......
......@@ -188,6 +188,14 @@ struct nfp_flower_priv {
struct nfp_fl_internal_ports internal_ports;
};
/**
* struct nfp_fl_qos - Flower APP priv data for quality of service
* @netdev_port_id: NFP port number of repr with qos info
*/
struct nfp_fl_qos {
u32 netdev_port_id;
};
/**
* struct nfp_flower_repr_priv - Flower APP per-repr priv data
* @nfp_repr: Back pointer to nfp_repr
......@@ -195,6 +203,7 @@ struct nfp_flower_priv {
* @mac_offloaded: Flag indicating a MAC address is offloaded for repr
* @offloaded_mac_addr: MAC address that has been offloaded for repr
* @mac_list: List entry of reprs that share the same offloaded MAC
* @qos_table: Stored info on filters implementing qos
*/
struct nfp_flower_repr_priv {
struct nfp_repr *nfp_repr;
......@@ -202,6 +211,7 @@ struct nfp_flower_repr_priv {
bool mac_offloaded;
u8 offloaded_mac_addr[ETH_ALEN];
struct list_head mac_list;
struct nfp_fl_qos qos_table;
};
/**
......
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
/* Copyright (C) 2019 Netronome Systems, Inc. */
#include <linux/math64.h>
#include <net/pkt_cls.h>
#include <net/pkt_sched.h>
#include "cmsg.h"
#include "main.h"
#include "../nfp_port.h"
struct nfp_police_cfg_head {
__be32 flags_opts;
__be32 port;
};
/* Police cmsg for configuring a trTCM traffic conditioner (8W/32B)
* See RFC 2698 for more details.
* ----------------------------------------------------------------
* 3 2 1
* 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
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Flag options |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Port Ingress |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Token Bucket Peak |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Token Bucket Committed |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Peak Burst Size |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Committed Burst Size |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Peak Information Rate |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Committed Information Rate |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
struct nfp_police_config {
struct nfp_police_cfg_head head;
__be32 bkt_tkn_p;
__be32 bkt_tkn_c;
__be32 pbs;
__be32 cbs;
__be32 pir;
__be32 cir;
};
static int
nfp_flower_install_rate_limiter(struct nfp_app *app, struct net_device *netdev,
struct tc_cls_matchall_offload *flow,
struct netlink_ext_ack *extack)
{
struct flow_action_entry *action = &flow->rule->action.entries[0];
struct nfp_flower_repr_priv *repr_priv;
struct nfp_police_config *config;
struct nfp_repr *repr;
struct sk_buff *skb;
u32 netdev_port_id;
u64 burst, rate;
if (!nfp_netdev_is_nfp_repr(netdev)) {
NL_SET_ERR_MSG_MOD(extack, "unsupported offload: qos rate limit offload not supported on higher level port");
return -EOPNOTSUPP;
}
repr = netdev_priv(netdev);
if (tcf_block_shared(flow->common.block)) {
NL_SET_ERR_MSG_MOD(extack, "unsupported offload: qos rate limit offload not supported on shared blocks");
return -EOPNOTSUPP;
}
if (repr->port->type != NFP_PORT_VF_PORT) {
NL_SET_ERR_MSG_MOD(extack, "unsupported offload: qos rate limit offload not supported on non-VF ports");
return -EOPNOTSUPP;
}
if (!flow_offload_has_one_action(&flow->rule->action)) {
NL_SET_ERR_MSG_MOD(extack, "unsupported offload: qos rate limit offload requires a single action");
return -EOPNOTSUPP;
}
if (flow->common.prio != (1 << 16)) {
NL_SET_ERR_MSG_MOD(extack, "unsupported offload: qos rate limit offload requires highest priority");
return -EOPNOTSUPP;
}
if (action->id != FLOW_ACTION_POLICE) {
NL_SET_ERR_MSG_MOD(extack, "unsupported offload: qos rate limit offload requires police action");
return -EOPNOTSUPP;
}
rate = action->police.rate_bytes_ps;
burst = div_u64(rate * PSCHED_NS2TICKS(action->police.burst),
PSCHED_TICKS_PER_SEC);
netdev_port_id = nfp_repr_get_port_id(netdev);
skb = nfp_flower_cmsg_alloc(repr->app, sizeof(struct nfp_police_config),
NFP_FLOWER_CMSG_TYPE_QOS_MOD, GFP_KERNEL);
if (!skb)
return -ENOMEM;
config = nfp_flower_cmsg_get_data(skb);
memset(config, 0, sizeof(struct nfp_police_config));
config->head.port = cpu_to_be32(netdev_port_id);
config->bkt_tkn_p = cpu_to_be32(burst);
config->bkt_tkn_c = cpu_to_be32(burst);
config->pbs = cpu_to_be32(burst);
config->cbs = cpu_to_be32(burst);
config->pir = cpu_to_be32(rate);
config->cir = cpu_to_be32(rate);
nfp_ctrl_tx(repr->app->ctrl, skb);
repr_priv = repr->app_priv;
repr_priv->qos_table.netdev_port_id = netdev_port_id;
return 0;
}
static int
nfp_flower_remove_rate_limiter(struct nfp_app *app, struct net_device *netdev,
struct tc_cls_matchall_offload *flow,
struct netlink_ext_ack *extack)
{
struct nfp_flower_repr_priv *repr_priv;
struct nfp_police_config *config;
struct nfp_repr *repr;
struct sk_buff *skb;
u32 netdev_port_id;
if (!nfp_netdev_is_nfp_repr(netdev)) {
NL_SET_ERR_MSG_MOD(extack, "unsupported offload: qos rate limit offload not supported on higher level port");
return -EOPNOTSUPP;
}
repr = netdev_priv(netdev);
netdev_port_id = nfp_repr_get_port_id(netdev);
repr_priv = repr->app_priv;
if (!repr_priv->qos_table.netdev_port_id) {
NL_SET_ERR_MSG_MOD(extack, "unsupported offload: cannot remove qos entry that does not exist");
return -EOPNOTSUPP;
}
skb = nfp_flower_cmsg_alloc(repr->app, sizeof(struct nfp_police_config),
NFP_FLOWER_CMSG_TYPE_QOS_DEL, GFP_KERNEL);
if (!skb)
return -ENOMEM;
/* Clear all qos associate data for this interface */
memset(&repr_priv->qos_table, 0, sizeof(struct nfp_fl_qos));
config = nfp_flower_cmsg_get_data(skb);
memset(config, 0, sizeof(struct nfp_police_config));
config->head.port = cpu_to_be32(netdev_port_id);
nfp_ctrl_tx(repr->app->ctrl, skb);
return 0;
}
int nfp_flower_setup_qos_offload(struct nfp_app *app, struct net_device *netdev,
struct tc_cls_matchall_offload *flow)
......@@ -17,5 +169,14 @@ int nfp_flower_setup_qos_offload(struct nfp_app *app, struct net_device *netdev,
return -EOPNOTSUPP;
}
switch (flow->command) {
case TC_CLSMATCHALL_REPLACE:
return nfp_flower_install_rate_limiter(app, netdev, flow,
extack);
case TC_CLSMATCHALL_DESTROY:
return nfp_flower_remove_rate_limiter(app, netdev, flow,
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