Skip to content

Commit

Permalink
sfc: use a dynamic m-port for representor RX and set it promisc
Browse files Browse the repository at this point in the history
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: Edward Cree <ecree.xilinx@gmail.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Edward Cree authored and Jakub Kicinski committed Jul 30, 2022
1 parent 77eb407 commit e37f3b1
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 3 deletions.
15 changes: 15 additions & 0 deletions drivers/net/ethernet/sfc/ef100_nic.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "ef100_tx.h"
#include "ef100_sriov.h"
#include "ef100_netdev.h"
#include "tc.h"
#include "mae.h"
#include "rx_common.h"

Expand Down Expand Up @@ -383,7 +384,18 @@ static int ef100_filter_table_up(struct efx_nic *efx)
rc = efx_mcdi_filter_add_vlan(efx, 0);
if (rc)
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);
#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;

fail_vlan0:
Expand All @@ -396,6 +408,9 @@ static int ef100_filter_table_up(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);
efx_mcdi_filter_del_vlan(efx, 0);
efx_mcdi_filter_del_vlan(efx, EFX_FILTER_VID_UNSPEC);
Expand Down
18 changes: 18 additions & 0 deletions drivers/net/ethernet/sfc/filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,15 @@ enum efx_filter_priority {
* the automatic filter in its place.
* @EFX_FILTER_FLAG_RX: Filter is for RX
* @EFX_FILTER_FLAG_TX: Filter is for TX
* @EFX_FILTER_FLAG_VPORT_ID: Virtual port ID for adapter switching.
*/
enum efx_filter_flags {
EFX_FILTER_FLAG_RX_RSS = 0x01,
EFX_FILTER_FLAG_RX_SCATTER = 0x02,
EFX_FILTER_FLAG_RX_OVER_AUTO = 0x04,
EFX_FILTER_FLAG_RX = 0x08,
EFX_FILTER_FLAG_TX = 0x10,
EFX_FILTER_FLAG_VPORT_ID = 0x20,
};

/** enum efx_encap_type - types of encapsulation
Expand Down Expand Up @@ -127,6 +129,9 @@ enum efx_encap_type {
* MCFW context_id.
* @dmaq_id: Source/target queue index, or %EFX_FILTER_RX_DMAQ_ID_DROP for
* 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
* @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
Expand Down Expand Up @@ -156,6 +161,7 @@ struct efx_filter_spec {
u32 priority:2;
u32 flags:6;
u32 dmaq_id:12;
u32 vport_id;
u32 rss_context;
__be16 outer_vid __aligned(4); /* allow jhash2() of match values */
__be16 inner_vid;
Expand Down Expand Up @@ -292,6 +298,18 @@ static inline int efx_filter_set_mc_def(struct efx_filter_spec *spec)
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,
enum efx_encap_type encap_type)
{
Expand Down
37 changes: 37 additions & 0 deletions drivers/net/ethernet/sfc/mae.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,43 @@
#include "mcdi.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)
{
efx_dword_t mport;
Expand Down
3 changes: 3 additions & 0 deletions drivers/net/ethernet/sfc/mae.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
#include "tc.h"
#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_uplink(struct efx_nic *efx, u32 *out);
void efx_mae_mport_vf(struct efx_nic *efx, u32 vf_id, u32 *out);
Expand Down
6 changes: 5 additions & 1 deletion drivers/net/ethernet/sfc/mcdi_filters.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

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,
spec->dmaq_id == EFX_FILTER_RX_DMAQ_ID_DROP ?
MC_CMD_FILTER_OP_IN_RX_DEST_DROP :
Expand Down Expand Up @@ -488,6 +491,7 @@ static s32 efx_mcdi_filter_insert_locked(struct efx_nic *efx,
saved_spec->flags |= spec->flags;
saved_spec->rss_context = spec->rss_context;
saved_spec->dmaq_id = spec->dmaq_id;
saved_spec->vport_id = spec->vport_id;
}
} else if (!replacing) {
kfree(saved_spec);
Expand Down
73 changes: 71 additions & 2 deletions drivers/net/ethernet/sfc/tc.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "tc.h"
#include "mae.h"
#include "ef100_rep.h"
#include "efx.h"

static void efx_tc_free_action_set(struct efx_nic *efx,
struct efx_tc_action_set *act, bool in_hw)
Expand Down Expand Up @@ -122,7 +123,7 @@ int efx_tc_configure_default_rule_rep(struct efx_rep *efv)
u32 ing_port, eg_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);
}

Expand All @@ -134,21 +135,87 @@ void efx_tc_deconfigure_default_rule(struct efx_nic *efx,
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 rc;

rc = efx_tc_configure_default_rule_pf(efx);
if (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)
{
/* We can get called even if efx_init_struct_tc() failed */
if (!efx->tc)
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.wire);
}
Expand All @@ -162,6 +229,8 @@ int efx_init_struct_tc(struct efx_nic *efx)
if (!efx->tc)
return -ENOMEM;

efx->tc->reps_filter_uc = -1;
efx->tc->reps_filter_mc = -1;
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;
INIT_LIST_HEAD(&efx->tc->dflt.wire.acts.list);
Expand Down
9 changes: 9 additions & 0 deletions drivers/net/ethernet/sfc/tc.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,18 @@ enum efx_tc_rule_prios {
/**
* 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
* %EFX_TC_PRIO_DFLT. Named by *ingress* port
* @dflt.pf: rule for traffic ingressing from PF (egresses to wire)
* @dflt.wire: rule for traffic ingressing from wire (egresses to PF)
*/
struct efx_tc_state {
u32 reps_mport_id, reps_mport_vport_id;
s32 reps_filter_uc, reps_filter_mc;
struct {
struct efx_tc_flow_rule pf;
struct efx_tc_flow_rule wire;
Expand All @@ -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,
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);
void efx_fini_tc(struct efx_nic *efx);

Expand Down

0 comments on commit e37f3b1

Please sign in to comment.