mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-28 11:18:45 +07:00
nfp: flower: allow offloading of matches on 'internal' ports
Recent FW modifications allow the offloading of non repr ports. These ports exist internally on the NFP. So if a rule outputs to an 'internal' port, then the packet will recirculate back into the system but will now have this internal port as it's incoming port. These ports are indicated by a specific type field combined with an 8 bit port id. Add private app data to assign additional port ids for use in offloads. Provide functions to lookup or create new ids when a rule attempts to match on an internal netdev - the only internal netdevs currently supported are of type openvswitch. Have a netdev notifier to release port ids on netdev unregister. OvS offloads rules that match on internal ports as TC egress filters. Ensure that such rules are accepted by the driver. Signed-off-by: John Hurley <john.hurley@netronome.com> Signed-off-by: Simon Horman <simon.horman@netronome.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
2f2622f59c
commit
4d12ba4278
@ -474,6 +474,13 @@ enum nfp_flower_cmsg_port_vnic_type {
|
|||||||
#define NFP_FLOWER_CMSG_PORT_PCIE_Q GENMASK(5, 0)
|
#define NFP_FLOWER_CMSG_PORT_PCIE_Q GENMASK(5, 0)
|
||||||
#define NFP_FLOWER_CMSG_PORT_PHYS_PORT_NUM GENMASK(7, 0)
|
#define NFP_FLOWER_CMSG_PORT_PHYS_PORT_NUM GENMASK(7, 0)
|
||||||
|
|
||||||
|
static inline u32 nfp_flower_internal_port_get_port_id(u8 internal_port)
|
||||||
|
{
|
||||||
|
return FIELD_PREP(NFP_FLOWER_CMSG_PORT_PHYS_PORT_NUM, internal_port) |
|
||||||
|
FIELD_PREP(NFP_FLOWER_CMSG_PORT_TYPE,
|
||||||
|
NFP_FLOWER_CMSG_PORT_TYPE_OTHER_PORT);
|
||||||
|
}
|
||||||
|
|
||||||
static inline u32 nfp_flower_cmsg_phys_port(u8 phys_port)
|
static inline u32 nfp_flower_cmsg_phys_port(u8 phys_port)
|
||||||
{
|
{
|
||||||
return FIELD_PREP(NFP_FLOWER_CMSG_PORT_PHYS_PORT_NUM, phys_port) |
|
return FIELD_PREP(NFP_FLOWER_CMSG_PORT_PHYS_PORT_NUM, phys_port) |
|
||||||
|
@ -22,6 +22,9 @@
|
|||||||
|
|
||||||
#define NFP_FLOWER_ALLOWED_VER 0x0001000000010000UL
|
#define NFP_FLOWER_ALLOWED_VER 0x0001000000010000UL
|
||||||
|
|
||||||
|
#define NFP_MIN_INT_PORT_ID 1
|
||||||
|
#define NFP_MAX_INT_PORT_ID 256
|
||||||
|
|
||||||
static const char *nfp_flower_extra_cap(struct nfp_app *app, struct nfp_net *nn)
|
static const char *nfp_flower_extra_cap(struct nfp_app *app, struct nfp_net *nn)
|
||||||
{
|
{
|
||||||
return "FLOWER";
|
return "FLOWER";
|
||||||
@ -32,6 +35,100 @@ static enum devlink_eswitch_mode eswitch_mode_get(struct nfp_app *app)
|
|||||||
return DEVLINK_ESWITCH_MODE_SWITCHDEV;
|
return DEVLINK_ESWITCH_MODE_SWITCHDEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nfp_flower_lookup_internal_port_id(struct nfp_flower_priv *priv,
|
||||||
|
struct net_device *netdev)
|
||||||
|
{
|
||||||
|
struct net_device *entry;
|
||||||
|
int i, id = 0;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
idr_for_each_entry(&priv->internal_ports.port_ids, entry, i)
|
||||||
|
if (entry == netdev) {
|
||||||
|
id = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nfp_flower_get_internal_port_id(struct nfp_app *app, struct net_device *netdev)
|
||||||
|
{
|
||||||
|
struct nfp_flower_priv *priv = app->priv;
|
||||||
|
int id;
|
||||||
|
|
||||||
|
id = nfp_flower_lookup_internal_port_id(priv, netdev);
|
||||||
|
if (id > 0)
|
||||||
|
return id;
|
||||||
|
|
||||||
|
idr_preload(GFP_ATOMIC);
|
||||||
|
spin_lock_bh(&priv->internal_ports.lock);
|
||||||
|
id = idr_alloc(&priv->internal_ports.port_ids, netdev,
|
||||||
|
NFP_MIN_INT_PORT_ID, NFP_MAX_INT_PORT_ID, GFP_ATOMIC);
|
||||||
|
spin_unlock_bh(&priv->internal_ports.lock);
|
||||||
|
idr_preload_end();
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 nfp_flower_get_port_id_from_netdev(struct nfp_app *app,
|
||||||
|
struct net_device *netdev)
|
||||||
|
{
|
||||||
|
int ext_port;
|
||||||
|
|
||||||
|
if (nfp_netdev_is_nfp_repr(netdev)) {
|
||||||
|
return nfp_repr_get_port_id(netdev);
|
||||||
|
} else if (nfp_flower_internal_port_can_offload(app, netdev)) {
|
||||||
|
ext_port = nfp_flower_get_internal_port_id(app, netdev);
|
||||||
|
if (ext_port < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return nfp_flower_internal_port_get_port_id(ext_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nfp_flower_free_internal_port_id(struct nfp_app *app, struct net_device *netdev)
|
||||||
|
{
|
||||||
|
struct nfp_flower_priv *priv = app->priv;
|
||||||
|
int id;
|
||||||
|
|
||||||
|
id = nfp_flower_lookup_internal_port_id(priv, netdev);
|
||||||
|
if (!id)
|
||||||
|
return;
|
||||||
|
|
||||||
|
spin_lock_bh(&priv->internal_ports.lock);
|
||||||
|
idr_remove(&priv->internal_ports.port_ids, id);
|
||||||
|
spin_unlock_bh(&priv->internal_ports.lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nfp_flower_internal_port_event_handler(struct nfp_app *app,
|
||||||
|
struct net_device *netdev,
|
||||||
|
unsigned long event)
|
||||||
|
{
|
||||||
|
if (event == NETDEV_UNREGISTER &&
|
||||||
|
nfp_flower_internal_port_can_offload(app, netdev))
|
||||||
|
nfp_flower_free_internal_port_id(app, netdev);
|
||||||
|
|
||||||
|
return NOTIFY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nfp_flower_internal_port_init(struct nfp_flower_priv *priv)
|
||||||
|
{
|
||||||
|
spin_lock_init(&priv->internal_ports.lock);
|
||||||
|
idr_init(&priv->internal_ports.port_ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nfp_flower_internal_port_cleanup(struct nfp_flower_priv *priv)
|
||||||
|
{
|
||||||
|
idr_destroy(&priv->internal_ports.port_ids);
|
||||||
|
}
|
||||||
|
|
||||||
static struct nfp_flower_non_repr_priv *
|
static struct nfp_flower_non_repr_priv *
|
||||||
nfp_flower_non_repr_priv_lookup(struct nfp_app *app, struct net_device *netdev)
|
nfp_flower_non_repr_priv_lookup(struct nfp_app *app, struct net_device *netdev)
|
||||||
{
|
{
|
||||||
@ -645,12 +742,14 @@ static int nfp_flower_init(struct nfp_app *app)
|
|||||||
/* Tell the firmware that the driver supports flow merging. */
|
/* Tell the firmware that the driver supports flow merging. */
|
||||||
err = nfp_rtsym_write_le(app->pf->rtbl,
|
err = nfp_rtsym_write_le(app->pf->rtbl,
|
||||||
"_abi_flower_merge_hint_enable", 1);
|
"_abi_flower_merge_hint_enable", 1);
|
||||||
if (!err)
|
if (!err) {
|
||||||
app_priv->flower_ext_feats |= NFP_FL_FEATS_FLOW_MERGE;
|
app_priv->flower_ext_feats |= NFP_FL_FEATS_FLOW_MERGE;
|
||||||
else if (err == -ENOENT)
|
nfp_flower_internal_port_init(app_priv);
|
||||||
|
} else if (err == -ENOENT) {
|
||||||
nfp_warn(app->cpp, "Flow merge not supported by FW.\n");
|
nfp_warn(app->cpp, "Flow merge not supported by FW.\n");
|
||||||
else
|
} else {
|
||||||
goto err_lag_clean;
|
goto err_lag_clean;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
nfp_warn(app->cpp, "Flow mod/merge not supported by FW.\n");
|
nfp_warn(app->cpp, "Flow mod/merge not supported by FW.\n");
|
||||||
}
|
}
|
||||||
@ -681,6 +780,9 @@ static void nfp_flower_clean(struct nfp_app *app)
|
|||||||
if (app_priv->flower_ext_feats & NFP_FL_FEATS_LAG)
|
if (app_priv->flower_ext_feats & NFP_FL_FEATS_LAG)
|
||||||
nfp_flower_lag_cleanup(&app_priv->nfp_lag);
|
nfp_flower_lag_cleanup(&app_priv->nfp_lag);
|
||||||
|
|
||||||
|
if (app_priv->flower_ext_feats & NFP_FL_FEATS_FLOW_MERGE)
|
||||||
|
nfp_flower_internal_port_cleanup(app_priv);
|
||||||
|
|
||||||
nfp_flower_metadata_cleanup(app);
|
nfp_flower_metadata_cleanup(app);
|
||||||
vfree(app->priv);
|
vfree(app->priv);
|
||||||
app->priv = NULL;
|
app->priv = NULL;
|
||||||
@ -779,6 +881,10 @@ nfp_flower_netdev_event(struct nfp_app *app, struct net_device *netdev,
|
|||||||
if (ret & NOTIFY_STOP_MASK)
|
if (ret & NOTIFY_STOP_MASK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
ret = nfp_flower_internal_port_event_handler(app, netdev, event);
|
||||||
|
if (ret & NOTIFY_STOP_MASK)
|
||||||
|
return ret;
|
||||||
|
|
||||||
return nfp_tunnel_mac_event_handler(app, netdev, event, ptr);
|
return nfp_tunnel_mac_event_handler(app, netdev, event, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,6 +116,16 @@ struct nfp_fl_lag {
|
|||||||
struct sk_buff_head retrans_skbs;
|
struct sk_buff_head retrans_skbs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct nfp_fl_internal_ports - Flower APP priv data for additional ports
|
||||||
|
* @port_ids: Assignment of ids to any additional ports
|
||||||
|
* @lock: Lock for extra ports list
|
||||||
|
*/
|
||||||
|
struct nfp_fl_internal_ports {
|
||||||
|
struct idr port_ids;
|
||||||
|
spinlock_t lock;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct nfp_flower_priv - Flower APP per-vNIC priv data
|
* struct nfp_flower_priv - Flower APP per-vNIC priv data
|
||||||
* @app: Back pointer to app
|
* @app: Back pointer to app
|
||||||
@ -145,6 +155,7 @@ struct nfp_fl_lag {
|
|||||||
* @non_repr_priv: List of offloaded non-repr ports and their priv data
|
* @non_repr_priv: List of offloaded non-repr ports and their priv data
|
||||||
* @active_mem_unit: Current active memory unit for flower rules
|
* @active_mem_unit: Current active memory unit for flower rules
|
||||||
* @total_mem_units: Total number of available memory units for flower rules
|
* @total_mem_units: Total number of available memory units for flower rules
|
||||||
|
* @internal_ports: Internal port ids used in offloaded rules
|
||||||
*/
|
*/
|
||||||
struct nfp_flower_priv {
|
struct nfp_flower_priv {
|
||||||
struct nfp_app *app;
|
struct nfp_app *app;
|
||||||
@ -171,6 +182,7 @@ struct nfp_flower_priv {
|
|||||||
struct list_head non_repr_priv;
|
struct list_head non_repr_priv;
|
||||||
unsigned int active_mem_unit;
|
unsigned int active_mem_unit;
|
||||||
unsigned int total_mem_units;
|
unsigned int total_mem_units;
|
||||||
|
struct nfp_fl_internal_ports internal_ports;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -249,6 +261,22 @@ struct nfp_fl_stats_frame {
|
|||||||
__be64 stats_cookie;
|
__be64 stats_cookie;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
nfp_flower_internal_port_can_offload(struct nfp_app *app,
|
||||||
|
struct net_device *netdev)
|
||||||
|
{
|
||||||
|
struct nfp_flower_priv *app_priv = app->priv;
|
||||||
|
|
||||||
|
if (!(app_priv->flower_ext_feats & NFP_FL_FEATS_FLOW_MERGE))
|
||||||
|
return false;
|
||||||
|
if (!netdev->rtnl_link_ops)
|
||||||
|
return false;
|
||||||
|
if (!strcmp(netdev->rtnl_link_ops->kind, "openvswitch"))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count,
|
int nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count,
|
||||||
unsigned int host_ctx_split);
|
unsigned int host_ctx_split);
|
||||||
void nfp_flower_metadata_cleanup(struct nfp_app *app);
|
void nfp_flower_metadata_cleanup(struct nfp_app *app);
|
||||||
@ -313,4 +341,6 @@ void
|
|||||||
__nfp_flower_non_repr_priv_put(struct nfp_flower_non_repr_priv *non_repr_priv);
|
__nfp_flower_non_repr_priv_put(struct nfp_flower_non_repr_priv *non_repr_priv);
|
||||||
void
|
void
|
||||||
nfp_flower_non_repr_priv_put(struct nfp_app *app, struct net_device *netdev);
|
nfp_flower_non_repr_priv_put(struct nfp_app *app, struct net_device *netdev);
|
||||||
|
u32 nfp_flower_get_port_id_from_netdev(struct nfp_app *app,
|
||||||
|
struct net_device *netdev);
|
||||||
#endif
|
#endif
|
||||||
|
@ -326,13 +326,12 @@ int nfp_flower_compile_flow_match(struct nfp_app *app,
|
|||||||
struct nfp_fl_payload *nfp_flow,
|
struct nfp_fl_payload *nfp_flow,
|
||||||
enum nfp_flower_tun_type tun_type)
|
enum nfp_flower_tun_type tun_type)
|
||||||
{
|
{
|
||||||
u32 cmsg_port = 0;
|
u32 port_id;
|
||||||
int err;
|
int err;
|
||||||
u8 *ext;
|
u8 *ext;
|
||||||
u8 *msk;
|
u8 *msk;
|
||||||
|
|
||||||
if (nfp_netdev_is_nfp_repr(netdev))
|
port_id = nfp_flower_get_port_id_from_netdev(app, netdev);
|
||||||
cmsg_port = nfp_repr_get_port_id(netdev);
|
|
||||||
|
|
||||||
memset(nfp_flow->unmasked_data, 0, key_ls->key_size);
|
memset(nfp_flow->unmasked_data, 0, key_ls->key_size);
|
||||||
memset(nfp_flow->mask_data, 0, key_ls->key_size);
|
memset(nfp_flow->mask_data, 0, key_ls->key_size);
|
||||||
@ -358,13 +357,13 @@ int nfp_flower_compile_flow_match(struct nfp_app *app,
|
|||||||
|
|
||||||
/* Populate Exact Port data. */
|
/* Populate Exact Port data. */
|
||||||
err = nfp_flower_compile_port((struct nfp_flower_in_port *)ext,
|
err = nfp_flower_compile_port((struct nfp_flower_in_port *)ext,
|
||||||
cmsg_port, false, tun_type);
|
port_id, false, tun_type);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
/* Populate Mask Port Data. */
|
/* Populate Mask Port Data. */
|
||||||
err = nfp_flower_compile_port((struct nfp_flower_in_port *)msk,
|
err = nfp_flower_compile_port((struct nfp_flower_in_port *)msk,
|
||||||
cmsg_port, true, tun_type);
|
port_id, true, tun_type);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -682,7 +682,9 @@ nfp_flower_setup_indr_tc_block(struct net_device *netdev, struct nfp_app *app,
|
|||||||
struct nfp_flower_priv *priv = app->priv;
|
struct nfp_flower_priv *priv = app->priv;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
|
if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS &&
|
||||||
|
!(f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS &&
|
||||||
|
nfp_flower_internal_port_can_offload(app, netdev)))
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
switch (f->command) {
|
switch (f->command) {
|
||||||
|
Loading…
Reference in New Issue
Block a user