Commit e37f3b15 authored by Edward Cree's avatar Edward Cree Committed by Jakub Kicinski

sfc: use a dynamic m-port for representor RX and set it promisc

Representors do not want to be subject to the PF's Ethernet address
 filters, since traffic from VFs will typically have a destination
 either elsewhere on the link segment or on an overlay network.
So, create a dynamic m-port with promiscuous and all-multicast
 filters, and set it as the egress port of representor default rules.
 Since the m-port is an alias of the calling PF's own m-port, traffic
 will still be delivered to the PF's RXQs, but it will be subject to
 the VNRX filter rules installed on the dynamic m-port (specified by
 the v-port ID field of the filter spec).
Signed-off-by: default avatarEdward Cree <ecree.xilinx@gmail.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 77eb4074
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "ef100_tx.h" #include "ef100_tx.h"
#include "ef100_sriov.h" #include "ef100_sriov.h"
#include "ef100_netdev.h" #include "ef100_netdev.h"
#include "tc.h"
#include "mae.h" #include "mae.h"
#include "rx_common.h" #include "rx_common.h"
...@@ -383,7 +384,18 @@ static int ef100_filter_table_up(struct efx_nic *efx) ...@@ -383,7 +384,18 @@ static int ef100_filter_table_up(struct efx_nic *efx)
rc = efx_mcdi_filter_add_vlan(efx, 0); rc = efx_mcdi_filter_add_vlan(efx, 0);
if (rc) if (rc)
goto fail_vlan0; goto fail_vlan0;
/* Drop the lock: we've finished altering table existence, and
* filter insertion will need to take the lock for read.
*/
up_write(&efx->filter_sem); up_write(&efx->filter_sem);
#ifdef CONFIG_SFC_SRIOV
rc = efx_tc_insert_rep_filters(efx);
/* Rep filter failure is nonfatal */
if (rc)
netif_warn(efx, drv, efx->net_dev,
"Failed to insert representor filters, rc %d\n",
rc);
#endif
return 0; return 0;
fail_vlan0: fail_vlan0:
...@@ -396,6 +408,9 @@ static int ef100_filter_table_up(struct efx_nic *efx) ...@@ -396,6 +408,9 @@ static int ef100_filter_table_up(struct efx_nic *efx)
static void ef100_filter_table_down(struct efx_nic *efx) static void ef100_filter_table_down(struct efx_nic *efx)
{ {
#ifdef CONFIG_SFC_SRIOV
efx_tc_remove_rep_filters(efx);
#endif
down_write(&efx->filter_sem); down_write(&efx->filter_sem);
efx_mcdi_filter_del_vlan(efx, 0); efx_mcdi_filter_del_vlan(efx, 0);
efx_mcdi_filter_del_vlan(efx, EFX_FILTER_VID_UNSPEC); efx_mcdi_filter_del_vlan(efx, EFX_FILTER_VID_UNSPEC);
......
...@@ -88,6 +88,7 @@ enum efx_filter_priority { ...@@ -88,6 +88,7 @@ enum efx_filter_priority {
* the automatic filter in its place. * the automatic filter in its place.
* @EFX_FILTER_FLAG_RX: Filter is for RX * @EFX_FILTER_FLAG_RX: Filter is for RX
* @EFX_FILTER_FLAG_TX: Filter is for TX * @EFX_FILTER_FLAG_TX: Filter is for TX
* @EFX_FILTER_FLAG_VPORT_ID: Virtual port ID for adapter switching.
*/ */
enum efx_filter_flags { enum efx_filter_flags {
EFX_FILTER_FLAG_RX_RSS = 0x01, EFX_FILTER_FLAG_RX_RSS = 0x01,
...@@ -95,6 +96,7 @@ enum efx_filter_flags { ...@@ -95,6 +96,7 @@ enum efx_filter_flags {
EFX_FILTER_FLAG_RX_OVER_AUTO = 0x04, EFX_FILTER_FLAG_RX_OVER_AUTO = 0x04,
EFX_FILTER_FLAG_RX = 0x08, EFX_FILTER_FLAG_RX = 0x08,
EFX_FILTER_FLAG_TX = 0x10, EFX_FILTER_FLAG_TX = 0x10,
EFX_FILTER_FLAG_VPORT_ID = 0x20,
}; };
/** enum efx_encap_type - types of encapsulation /** enum efx_encap_type - types of encapsulation
...@@ -127,6 +129,9 @@ enum efx_encap_type { ...@@ -127,6 +129,9 @@ enum efx_encap_type {
* MCFW context_id. * MCFW context_id.
* @dmaq_id: Source/target queue index, or %EFX_FILTER_RX_DMAQ_ID_DROP for * @dmaq_id: Source/target queue index, or %EFX_FILTER_RX_DMAQ_ID_DROP for
* an RX drop filter * an RX drop filter
* @vport_id: Virtual port ID associated with RX queue, for adapter switching,
* if %EFX_FILTER_FLAG_VPORT_ID is set. This is an MCFW vport_id, or on
* EF100 an mport selector.
* @outer_vid: Outer VLAN ID to match, if %EFX_FILTER_MATCH_OUTER_VID is set * @outer_vid: Outer VLAN ID to match, if %EFX_FILTER_MATCH_OUTER_VID is set
* @inner_vid: Inner VLAN ID to match, if %EFX_FILTER_MATCH_INNER_VID is set * @inner_vid: Inner VLAN ID to match, if %EFX_FILTER_MATCH_INNER_VID is set
* @loc_mac: Local MAC address to match, if %EFX_FILTER_MATCH_LOC_MAC or * @loc_mac: Local MAC address to match, if %EFX_FILTER_MATCH_LOC_MAC or
...@@ -156,6 +161,7 @@ struct efx_filter_spec { ...@@ -156,6 +161,7 @@ struct efx_filter_spec {
u32 priority:2; u32 priority:2;
u32 flags:6; u32 flags:6;
u32 dmaq_id:12; u32 dmaq_id:12;
u32 vport_id;
u32 rss_context; u32 rss_context;
__be16 outer_vid __aligned(4); /* allow jhash2() of match values */ __be16 outer_vid __aligned(4); /* allow jhash2() of match values */
__be16 inner_vid; __be16 inner_vid;
...@@ -292,6 +298,18 @@ static inline int efx_filter_set_mc_def(struct efx_filter_spec *spec) ...@@ -292,6 +298,18 @@ static inline int efx_filter_set_mc_def(struct efx_filter_spec *spec)
return 0; return 0;
} }
/**
* efx_filter_set_vport_id - override virtual port id relating to filter
* @spec: Specification to initialise
* @vport_id: firmware ID of the virtual port
*/
static inline void efx_filter_set_vport_id(struct efx_filter_spec *spec,
u32 vport_id)
{
spec->flags |= EFX_FILTER_FLAG_VPORT_ID;
spec->vport_id = vport_id;
}
static inline void efx_filter_set_encap_type(struct efx_filter_spec *spec, static inline void efx_filter_set_encap_type(struct efx_filter_spec *spec,
enum efx_encap_type encap_type) enum efx_encap_type encap_type)
{ {
......
...@@ -13,6 +13,43 @@ ...@@ -13,6 +13,43 @@
#include "mcdi.h" #include "mcdi.h"
#include "mcdi_pcol_mae.h" #include "mcdi_pcol_mae.h"
int efx_mae_allocate_mport(struct efx_nic *efx, u32 *id, u32 *label)
{
MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_MPORT_ALLOC_ALIAS_OUT_LEN);
MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_ALLOC_ALIAS_IN_LEN);
size_t outlen;
int rc;
if (WARN_ON_ONCE(!id))
return -EINVAL;
if (WARN_ON_ONCE(!label))
return -EINVAL;
MCDI_SET_DWORD(inbuf, MAE_MPORT_ALLOC_ALIAS_IN_TYPE,
MC_CMD_MAE_MPORT_ALLOC_ALIAS_IN_MPORT_TYPE_ALIAS);
MCDI_SET_DWORD(inbuf, MAE_MPORT_ALLOC_ALIAS_IN_DELIVER_MPORT,
MAE_MPORT_SELECTOR_ASSIGNED);
rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MPORT_ALLOC, inbuf, sizeof(inbuf),
outbuf, sizeof(outbuf), &outlen);
if (rc)
return rc;
if (outlen < sizeof(outbuf))
return -EIO;
*id = MCDI_DWORD(outbuf, MAE_MPORT_ALLOC_ALIAS_OUT_MPORT_ID);
*label = MCDI_DWORD(outbuf, MAE_MPORT_ALLOC_ALIAS_OUT_LABEL);
return 0;
}
int efx_mae_free_mport(struct efx_nic *efx, u32 id)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_FREE_IN_LEN);
BUILD_BUG_ON(MC_CMD_MAE_MPORT_FREE_OUT_LEN);
MCDI_SET_DWORD(inbuf, MAE_MPORT_FREE_IN_MPORT_ID, id);
return efx_mcdi_rpc(efx, MC_CMD_MAE_MPORT_FREE, inbuf, sizeof(inbuf),
NULL, 0, NULL);
}
void efx_mae_mport_wire(struct efx_nic *efx, u32 *out) void efx_mae_mport_wire(struct efx_nic *efx, u32 *out)
{ {
efx_dword_t mport; efx_dword_t mport;
......
...@@ -17,6 +17,9 @@ ...@@ -17,6 +17,9 @@
#include "tc.h" #include "tc.h"
#include "mcdi_pcol.h" /* needed for various MC_CMD_MAE_*_NULL defines */ #include "mcdi_pcol.h" /* needed for various MC_CMD_MAE_*_NULL defines */
int efx_mae_allocate_mport(struct efx_nic *efx, u32 *id, u32 *label);
int efx_mae_free_mport(struct efx_nic *efx, u32 id);
void efx_mae_mport_wire(struct efx_nic *efx, u32 *out); void efx_mae_mport_wire(struct efx_nic *efx, u32 *out);
void efx_mae_mport_uplink(struct efx_nic *efx, u32 *out); void efx_mae_mport_uplink(struct efx_nic *efx, u32 *out);
void efx_mae_mport_vf(struct efx_nic *efx, u32 vf_id, u32 *out); void efx_mae_mport_vf(struct efx_nic *efx, u32 vf_id, u32 *out);
......
...@@ -221,7 +221,10 @@ static void efx_mcdi_filter_push_prep(struct efx_nic *efx, ...@@ -221,7 +221,10 @@ static void efx_mcdi_filter_push_prep(struct efx_nic *efx,
efx_mcdi_filter_push_prep_set_match_fields(efx, spec, inbuf); efx_mcdi_filter_push_prep_set_match_fields(efx, spec, inbuf);
} }
MCDI_SET_DWORD(inbuf, FILTER_OP_IN_PORT_ID, efx->vport_id); if (flags & EFX_FILTER_FLAG_VPORT_ID)
MCDI_SET_DWORD(inbuf, FILTER_OP_IN_PORT_ID, spec->vport_id);
else
MCDI_SET_DWORD(inbuf, FILTER_OP_IN_PORT_ID, efx->vport_id);
MCDI_SET_DWORD(inbuf, FILTER_OP_IN_RX_DEST, MCDI_SET_DWORD(inbuf, FILTER_OP_IN_RX_DEST,
spec->dmaq_id == EFX_FILTER_RX_DMAQ_ID_DROP ? spec->dmaq_id == EFX_FILTER_RX_DMAQ_ID_DROP ?
MC_CMD_FILTER_OP_IN_RX_DEST_DROP : MC_CMD_FILTER_OP_IN_RX_DEST_DROP :
...@@ -488,6 +491,7 @@ static s32 efx_mcdi_filter_insert_locked(struct efx_nic *efx, ...@@ -488,6 +491,7 @@ static s32 efx_mcdi_filter_insert_locked(struct efx_nic *efx,
saved_spec->flags |= spec->flags; saved_spec->flags |= spec->flags;
saved_spec->rss_context = spec->rss_context; saved_spec->rss_context = spec->rss_context;
saved_spec->dmaq_id = spec->dmaq_id; saved_spec->dmaq_id = spec->dmaq_id;
saved_spec->vport_id = spec->vport_id;
} }
} else if (!replacing) { } else if (!replacing) {
kfree(saved_spec); kfree(saved_spec);
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "tc.h" #include "tc.h"
#include "mae.h" #include "mae.h"
#include "ef100_rep.h" #include "ef100_rep.h"
#include "efx.h"
static void efx_tc_free_action_set(struct efx_nic *efx, static void efx_tc_free_action_set(struct efx_nic *efx,
struct efx_tc_action_set *act, bool in_hw) struct efx_tc_action_set *act, bool in_hw)
...@@ -122,7 +123,7 @@ int efx_tc_configure_default_rule_rep(struct efx_rep *efv) ...@@ -122,7 +123,7 @@ int efx_tc_configure_default_rule_rep(struct efx_rep *efv)
u32 ing_port, eg_port; u32 ing_port, eg_port;
efx_mae_mport_mport(efx, efv->mport, &ing_port); efx_mae_mport_mport(efx, efv->mport, &ing_port);
efx_mae_mport_uplink(efx, &eg_port); efx_mae_mport_mport(efx, efx->tc->reps_mport_id, &eg_port);
return efx_tc_configure_default_rule(efx, ing_port, eg_port, rule); return efx_tc_configure_default_rule(efx, ing_port, eg_port, rule);
} }
...@@ -134,6 +135,68 @@ void efx_tc_deconfigure_default_rule(struct efx_nic *efx, ...@@ -134,6 +135,68 @@ void efx_tc_deconfigure_default_rule(struct efx_nic *efx,
rule->fw_id = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL; rule->fw_id = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL;
} }
static int efx_tc_configure_rep_mport(struct efx_nic *efx)
{
u32 rep_mport_label;
int rc;
rc = efx_mae_allocate_mport(efx, &efx->tc->reps_mport_id, &rep_mport_label);
if (rc)
return rc;
pci_dbg(efx->pci_dev, "created rep mport 0x%08x (0x%04x)\n",
efx->tc->reps_mport_id, rep_mport_label);
/* Use mport *selector* as vport ID */
efx_mae_mport_mport(efx, efx->tc->reps_mport_id,
&efx->tc->reps_mport_vport_id);
return 0;
}
static void efx_tc_deconfigure_rep_mport(struct efx_nic *efx)
{
efx_mae_free_mport(efx, efx->tc->reps_mport_id);
efx->tc->reps_mport_id = MAE_MPORT_SELECTOR_NULL;
}
int efx_tc_insert_rep_filters(struct efx_nic *efx)
{
struct efx_filter_spec promisc, allmulti;
int rc;
if (efx->type->is_vf)
return 0;
if (!efx->tc)
return 0;
efx_filter_init_rx(&promisc, EFX_FILTER_PRI_REQUIRED, 0, 0);
efx_filter_set_uc_def(&promisc);
efx_filter_set_vport_id(&promisc, efx->tc->reps_mport_vport_id);
rc = efx_filter_insert_filter(efx, &promisc, false);
if (rc < 0)
return rc;
efx->tc->reps_filter_uc = rc;
efx_filter_init_rx(&allmulti, EFX_FILTER_PRI_REQUIRED, 0, 0);
efx_filter_set_mc_def(&allmulti);
efx_filter_set_vport_id(&allmulti, efx->tc->reps_mport_vport_id);
rc = efx_filter_insert_filter(efx, &allmulti, false);
if (rc < 0)
return rc;
efx->tc->reps_filter_mc = rc;
return 0;
}
void efx_tc_remove_rep_filters(struct efx_nic *efx)
{
if (efx->type->is_vf)
return;
if (!efx->tc)
return;
if (efx->tc->reps_filter_mc >= 0)
efx_filter_remove_id_safe(efx, EFX_FILTER_PRI_REQUIRED, efx->tc->reps_filter_mc);
efx->tc->reps_filter_mc = -1;
if (efx->tc->reps_filter_uc >= 0)
efx_filter_remove_id_safe(efx, EFX_FILTER_PRI_REQUIRED, efx->tc->reps_filter_uc);
efx->tc->reps_filter_uc = -1;
}
int efx_init_tc(struct efx_nic *efx) int efx_init_tc(struct efx_nic *efx)
{ {
int rc; int rc;
...@@ -141,7 +204,10 @@ int efx_init_tc(struct efx_nic *efx) ...@@ -141,7 +204,10 @@ int efx_init_tc(struct efx_nic *efx)
rc = efx_tc_configure_default_rule_pf(efx); rc = efx_tc_configure_default_rule_pf(efx);
if (rc) if (rc)
return rc; return rc;
return efx_tc_configure_default_rule_wire(efx); rc = efx_tc_configure_default_rule_wire(efx);
if (rc)
return rc;
return efx_tc_configure_rep_mport(efx);
} }
void efx_fini_tc(struct efx_nic *efx) void efx_fini_tc(struct efx_nic *efx)
...@@ -149,6 +215,7 @@ void efx_fini_tc(struct efx_nic *efx) ...@@ -149,6 +215,7 @@ void efx_fini_tc(struct efx_nic *efx)
/* We can get called even if efx_init_struct_tc() failed */ /* We can get called even if efx_init_struct_tc() failed */
if (!efx->tc) if (!efx->tc)
return; return;
efx_tc_deconfigure_rep_mport(efx);
efx_tc_deconfigure_default_rule(efx, &efx->tc->dflt.pf); efx_tc_deconfigure_default_rule(efx, &efx->tc->dflt.pf);
efx_tc_deconfigure_default_rule(efx, &efx->tc->dflt.wire); efx_tc_deconfigure_default_rule(efx, &efx->tc->dflt.wire);
} }
...@@ -162,6 +229,8 @@ int efx_init_struct_tc(struct efx_nic *efx) ...@@ -162,6 +229,8 @@ int efx_init_struct_tc(struct efx_nic *efx)
if (!efx->tc) if (!efx->tc)
return -ENOMEM; return -ENOMEM;
efx->tc->reps_filter_uc = -1;
efx->tc->reps_filter_mc = -1;
INIT_LIST_HEAD(&efx->tc->dflt.pf.acts.list); INIT_LIST_HEAD(&efx->tc->dflt.pf.acts.list);
efx->tc->dflt.pf.fw_id = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL; efx->tc->dflt.pf.fw_id = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL;
INIT_LIST_HEAD(&efx->tc->dflt.wire.acts.list); INIT_LIST_HEAD(&efx->tc->dflt.wire.acts.list);
......
...@@ -49,12 +49,18 @@ enum efx_tc_rule_prios { ...@@ -49,12 +49,18 @@ enum efx_tc_rule_prios {
/** /**
* struct efx_tc_state - control plane data for TC offload * struct efx_tc_state - control plane data for TC offload
* *
* @reps_mport_id: MAE port allocated for representor RX
* @reps_filter_uc: VNIC filter for representor unicast RX (promisc)
* @reps_filter_mc: VNIC filter for representor multicast RX (allmulti)
* @reps_mport_vport_id: vport_id for representor RX filters
* @dflt: Match-action rules for default switching; at priority * @dflt: Match-action rules for default switching; at priority
* %EFX_TC_PRIO_DFLT. Named by *ingress* port * %EFX_TC_PRIO_DFLT. Named by *ingress* port
* @dflt.pf: rule for traffic ingressing from PF (egresses to wire) * @dflt.pf: rule for traffic ingressing from PF (egresses to wire)
* @dflt.wire: rule for traffic ingressing from wire (egresses to PF) * @dflt.wire: rule for traffic ingressing from wire (egresses to PF)
*/ */
struct efx_tc_state { struct efx_tc_state {
u32 reps_mport_id, reps_mport_vport_id;
s32 reps_filter_uc, reps_filter_mc;
struct { struct {
struct efx_tc_flow_rule pf; struct efx_tc_flow_rule pf;
struct efx_tc_flow_rule wire; struct efx_tc_flow_rule wire;
...@@ -67,6 +73,9 @@ int efx_tc_configure_default_rule_rep(struct efx_rep *efv); ...@@ -67,6 +73,9 @@ int efx_tc_configure_default_rule_rep(struct efx_rep *efv);
void efx_tc_deconfigure_default_rule(struct efx_nic *efx, void efx_tc_deconfigure_default_rule(struct efx_nic *efx,
struct efx_tc_flow_rule *rule); struct efx_tc_flow_rule *rule);
int efx_tc_insert_rep_filters(struct efx_nic *efx);
void efx_tc_remove_rep_filters(struct efx_nic *efx);
int efx_init_tc(struct efx_nic *efx); int efx_init_tc(struct efx_nic *efx);
void efx_fini_tc(struct efx_nic *efx); void efx_fini_tc(struct efx_nic *efx);
......
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