Skip to content

Commit

Permalink
ice: Add guard rule when creating FDB in switchdev
Browse files Browse the repository at this point in the history
Introduce new "guard" rule upon FDB entry creation.

It matches on src_mac, has valid bit unset, allow_pass_l2 set
and has a nop action.

Previously introduced "forward" rule matches on dst_mac, has valid
bit set, need_pass_l2 set and has a forward action.

With these rules, a packet will be offloaded only if FDB exists in both
directions (RX and TX).

Let's assume link partner sends a packet to VF1: src_mac = LP_MAC,
dst_mac = is VF1_MAC. Bridge adds FDB, two rules are created:
1. Guard rule matching on src_mac == LP_MAC
2. Forward rule matching on dst_mac == LP_MAC
Now VF1 responds with src_mac = VF1_MAC, dst_mac = LP_MAC. Before this
change, only one rule with dst_mac == LP_MAC would have existed, and the
packet would have been offloaded, meaning the bridge wouldn't add FDB in
the opposite direction. Now, the forward rule matches (dst_mac == LP_MAC),
but it has need_pass_l2 set an there is no guard rule with
src_mac == VF1_MAC, so the packet goes through slow-path and the bridge
adds FDB. Two rules are created:
1. Guard rule matching on src_mac == VF1_MAC
2. Forward rule matching on dst_mac == VF1_MAC
Further packets in both directions will be offloaded.

The same example is true in opposite direction (i.e. VF1 is the first to
send a packet out).

Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: Marcin Szycik <marcin.szycik@intel.com>
Signed-off-by: Wojciech Drewek <wojciech.drewek@intel.com>
Tested-by: Sujai Buvaneswaran <sujai.buvaneswaran@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
  • Loading branch information
Marcin Szycik authored and Tony Nguyen committed Jul 24, 2023
1 parent 7c945a1 commit bccd9bc
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 36 deletions.
64 changes: 63 additions & 1 deletion drivers/net/ethernet/intel/ice/ice_eswitch_br.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ ice_eswitch_br_fwd_rule_create(struct ice_hw *hw, int vsi_idx, int port_type,
ether_addr_copy(list[0].h_u.eth_hdr.dst_addr, mac);
eth_broadcast_addr(list[0].m_u.eth_hdr.dst_addr);

rule_info.need_pass_l2 = true;

rule_info.sw_act.fltr_act = ICE_FWD_TO_VSI;

err = ice_add_adv_rule(hw, list, lkups_cnt, &rule_info, rule);
Expand All @@ -125,11 +127,54 @@ ice_eswitch_br_fwd_rule_create(struct ice_hw *hw, int vsi_idx, int port_type,
return ERR_PTR(err);
}

static struct ice_rule_query_data *
ice_eswitch_br_guard_rule_create(struct ice_hw *hw, u16 vsi_idx,
const unsigned char *mac)
{
struct ice_adv_rule_info rule_info = { 0 };
struct ice_rule_query_data *rule;
struct ice_adv_lkup_elem *list;
const u16 lkups_cnt = 1;
int err = -ENOMEM;

rule = kzalloc(sizeof(*rule), GFP_KERNEL);
if (!rule)
goto err_exit;

list = kcalloc(lkups_cnt, sizeof(*list), GFP_ATOMIC);
if (!list)
goto err_list_alloc;

list[0].type = ICE_MAC_OFOS;
ether_addr_copy(list[0].h_u.eth_hdr.src_addr, mac);
eth_broadcast_addr(list[0].m_u.eth_hdr.src_addr);

rule_info.allow_pass_l2 = true;
rule_info.sw_act.vsi_handle = vsi_idx;
rule_info.sw_act.fltr_act = ICE_NOP;
rule_info.priority = 5;

err = ice_add_adv_rule(hw, list, lkups_cnt, &rule_info, rule);
if (err)
goto err_add_rule;

kfree(list);

return rule;

err_add_rule:
kfree(list);
err_list_alloc:
kfree(rule);
err_exit:
return ERR_PTR(err);
}

static struct ice_esw_br_flow *
ice_eswitch_br_flow_create(struct device *dev, struct ice_hw *hw, int vsi_idx,
int port_type, const unsigned char *mac)
{
struct ice_rule_query_data *fwd_rule;
struct ice_rule_query_data *fwd_rule, *guard_rule;
struct ice_esw_br_flow *flow;
int err;

Expand All @@ -146,10 +191,22 @@ ice_eswitch_br_flow_create(struct device *dev, struct ice_hw *hw, int vsi_idx,
goto err_fwd_rule;
}

guard_rule = ice_eswitch_br_guard_rule_create(hw, vsi_idx, mac);
err = PTR_ERR_OR_ZERO(guard_rule);
if (err) {
dev_err(dev, "Failed to create eswitch bridge %sgress guard rule, err: %d\n",
port_type == ICE_ESWITCH_BR_UPLINK_PORT ? "e" : "in",
err);
goto err_guard_rule;
}

flow->fwd_rule = fwd_rule;
flow->guard_rule = guard_rule;

return flow;

err_guard_rule:
ice_eswitch_br_rule_delete(hw, fwd_rule);
err_fwd_rule:
kfree(flow);

Expand Down Expand Up @@ -180,6 +237,11 @@ ice_eswitch_br_flow_delete(struct ice_pf *pf, struct ice_esw_br_flow *flow)
dev_err(dev, "Failed to delete FDB forward rule, err: %d\n",
err);

err = ice_eswitch_br_rule_delete(&pf->hw, flow->guard_rule);
if (err)
dev_err(dev, "Failed to delete FDB guard rule, err: %d\n",
err);

kfree(flow);
}

Expand Down
1 change: 1 addition & 0 deletions drivers/net/ethernet/intel/ice/ice_eswitch_br.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ struct ice_esw_br_fdb_data {

struct ice_esw_br_flow {
struct ice_rule_query_data *fwd_rule;
struct ice_rule_query_data *guard_rule;
};

enum {
Expand Down
97 changes: 62 additions & 35 deletions drivers/net/ethernet/intel/ice/ice_switch.c
Original file line number Diff line number Diff line change
Expand Up @@ -2272,6 +2272,10 @@ ice_get_recp_frm_fw(struct ice_hw *hw, struct ice_sw_recipe *recps, u8 rid,
/* Propagate some data to the recipe database */
recps[idx].is_root = !!is_root;
recps[idx].priority = root_bufs.content.act_ctrl_fwd_priority;
recps[idx].need_pass_l2 = root_bufs.content.act_ctrl &
ICE_AQ_RECIPE_ACT_NEED_PASS_L2;
recps[idx].allow_pass_l2 = root_bufs.content.act_ctrl &
ICE_AQ_RECIPE_ACT_ALLOW_PASS_L2;
bitmap_zero(recps[idx].res_idxs, ICE_MAX_FV_WORDS);
if (root_bufs.content.result_indx & ICE_AQ_RECIPE_RESULT_EN) {
recps[idx].chain_idx = root_bufs.content.result_indx &
Expand Down Expand Up @@ -4613,13 +4617,13 @@ static struct ice_protocol_entry ice_prot_id_tbl[ICE_PROTOCOL_LAST] = {
* ice_find_recp - find a recipe
* @hw: pointer to the hardware structure
* @lkup_exts: extension sequence to match
* @tun_type: type of recipe tunnel
* @rinfo: information regarding the rule e.g. priority and action info
*
* Returns index of matching recipe, or ICE_MAX_NUM_RECIPES if not found.
*/
static u16
ice_find_recp(struct ice_hw *hw, struct ice_prot_lkup_ext *lkup_exts,
enum ice_sw_tunnel_type tun_type)
const struct ice_adv_rule_info *rinfo)
{
bool refresh_required = true;
struct ice_sw_recipe *recp;
Expand Down Expand Up @@ -4680,9 +4684,12 @@ ice_find_recp(struct ice_hw *hw, struct ice_prot_lkup_ext *lkup_exts,
}
/* If for "i"th recipe the found was never set to false
* then it means we found our match
* Also tun type of recipe needs to be checked
* Also tun type and *_pass_l2 of recipe needs to be
* checked
*/
if (found && recp[i].tun_type == tun_type)
if (found && recp[i].tun_type == rinfo->tun_type &&
recp[i].need_pass_l2 == rinfo->need_pass_l2 &&
recp[i].allow_pass_l2 == rinfo->allow_pass_l2)
return i; /* Return the recipe ID */
}
}
Expand Down Expand Up @@ -4952,6 +4959,7 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
unsigned long *profiles)
{
DECLARE_BITMAP(result_idx_bm, ICE_MAX_FV_WORDS);
struct ice_aqc_recipe_content *content;
struct ice_aqc_recipe_data_elem *tmp;
struct ice_aqc_recipe_data_elem *buf;
struct ice_recp_grp_entry *entry;
Expand Down Expand Up @@ -5012,6 +5020,8 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
if (status)
goto err_unroll;

content = &buf[recps].content;

/* Clear the result index of the located recipe, as this will be
* updated, if needed, later in the recipe creation process.
*/
Expand All @@ -5022,26 +5032,24 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
/* if the recipe is a non-root recipe RID should be programmed
* as 0 for the rules to be applied correctly.
*/
buf[recps].content.rid = 0;
memset(&buf[recps].content.lkup_indx, 0,
sizeof(buf[recps].content.lkup_indx));
content->rid = 0;
memset(&content->lkup_indx, 0,
sizeof(content->lkup_indx));

/* All recipes use look-up index 0 to match switch ID. */
buf[recps].content.lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX;
buf[recps].content.mask[0] =
cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK);
content->lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX;
content->mask[0] = cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK);
/* Setup lkup_indx 1..4 to INVALID/ignore and set the mask
* to be 0
*/
for (i = 1; i <= ICE_NUM_WORDS_RECIPE; i++) {
buf[recps].content.lkup_indx[i] = 0x80;
buf[recps].content.mask[i] = 0;
content->lkup_indx[i] = 0x80;
content->mask[i] = 0;
}

for (i = 0; i < entry->r_group.n_val_pairs; i++) {
buf[recps].content.lkup_indx[i + 1] = entry->fv_idx[i];
buf[recps].content.mask[i + 1] =
cpu_to_le16(entry->fv_mask[i]);
content->lkup_indx[i + 1] = entry->fv_idx[i];
content->mask[i + 1] = cpu_to_le16(entry->fv_mask[i]);
}

if (rm->n_grp_count > 1) {
Expand All @@ -5055,7 +5063,7 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
}

entry->chain_idx = chain_idx;
buf[recps].content.result_indx =
content->result_indx =
ICE_AQ_RECIPE_RESULT_EN |
((chain_idx << ICE_AQ_RECIPE_RESULT_DATA_S) &
ICE_AQ_RECIPE_RESULT_DATA_M);
Expand All @@ -5069,7 +5077,13 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
ICE_MAX_NUM_RECIPES);
set_bit(buf[recps].recipe_indx,
(unsigned long *)buf[recps].recipe_bitmap);
buf[recps].content.act_ctrl_fwd_priority = rm->priority;
content->act_ctrl_fwd_priority = rm->priority;

if (rm->need_pass_l2)
content->act_ctrl |= ICE_AQ_RECIPE_ACT_NEED_PASS_L2;

if (rm->allow_pass_l2)
content->act_ctrl |= ICE_AQ_RECIPE_ACT_ALLOW_PASS_L2;
recps++;
}

Expand Down Expand Up @@ -5107,9 +5121,11 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
if (status)
goto err_unroll;

content = &buf[recps].content;

buf[recps].recipe_indx = (u8)rid;
buf[recps].content.rid = (u8)rid;
buf[recps].content.rid |= ICE_AQ_RECIPE_ID_IS_ROOT;
content->rid = (u8)rid;
content->rid |= ICE_AQ_RECIPE_ID_IS_ROOT;
/* the new entry created should also be part of rg_list to
* make sure we have complete recipe
*/
Expand All @@ -5121,16 +5137,13 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
goto err_unroll;
}
last_chain_entry->rid = rid;
memset(&buf[recps].content.lkup_indx, 0,
sizeof(buf[recps].content.lkup_indx));
memset(&content->lkup_indx, 0, sizeof(content->lkup_indx));
/* All recipes use look-up index 0 to match switch ID. */
buf[recps].content.lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX;
buf[recps].content.mask[0] =
cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK);
content->lkup_indx[0] = ICE_AQ_SW_ID_LKUP_IDX;
content->mask[0] = cpu_to_le16(ICE_AQ_SW_ID_LKUP_MASK);
for (i = 1; i <= ICE_NUM_WORDS_RECIPE; i++) {
buf[recps].content.lkup_indx[i] =
ICE_AQ_RECIPE_LKUP_IGNORE;
buf[recps].content.mask[i] = 0;
content->lkup_indx[i] = ICE_AQ_RECIPE_LKUP_IGNORE;
content->mask[i] = 0;
}

i = 1;
Expand All @@ -5142,8 +5155,8 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
last_chain_entry->chain_idx = ICE_INVAL_CHAIN_IND;
list_for_each_entry(entry, &rm->rg_list, l_entry) {
last_chain_entry->fv_idx[i] = entry->chain_idx;
buf[recps].content.lkup_indx[i] = entry->chain_idx;
buf[recps].content.mask[i++] = cpu_to_le16(0xFFFF);
content->lkup_indx[i] = entry->chain_idx;
content->mask[i++] = cpu_to_le16(0xFFFF);
set_bit(entry->rid, rm->r_bitmap);
}
list_add(&last_chain_entry->l_entry, &rm->rg_list);
Expand All @@ -5155,7 +5168,7 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
status = -EINVAL;
goto err_unroll;
}
buf[recps].content.act_ctrl_fwd_priority = rm->priority;
content->act_ctrl_fwd_priority = rm->priority;

recps++;
rm->root_rid = (u8)rid;
Expand Down Expand Up @@ -5220,6 +5233,8 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
recp->priority = buf[buf_idx].content.act_ctrl_fwd_priority;
recp->n_grp_count = rm->n_grp_count;
recp->tun_type = rm->tun_type;
recp->need_pass_l2 = rm->need_pass_l2;
recp->allow_pass_l2 = rm->allow_pass_l2;
recp->recp_created = true;
}
rm->root_buf = buf;
Expand Down Expand Up @@ -5388,6 +5403,9 @@ ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
/* set the recipe priority if specified */
rm->priority = (u8)rinfo->priority;

rm->need_pass_l2 = rinfo->need_pass_l2;
rm->allow_pass_l2 = rinfo->allow_pass_l2;

/* Find offsets from the field vector. Pick the first one for all the
* recipes.
*/
Expand All @@ -5403,7 +5421,7 @@ ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
}

/* Look for a recipe which matches our requested fv / mask list */
*rid = ice_find_recp(hw, lkup_exts, rinfo->tun_type);
*rid = ice_find_recp(hw, lkup_exts, rinfo);
if (*rid < ICE_MAX_NUM_RECIPES)
/* Success if found a recipe that match the existing criteria */
goto err_unroll;
Expand Down Expand Up @@ -5839,7 +5857,9 @@ static bool ice_rules_equal(const struct ice_adv_rule_info *first,
return first->sw_act.flag == second->sw_act.flag &&
first->tun_type == second->tun_type &&
first->vlan_type == second->vlan_type &&
first->src_vsi == second->src_vsi;
first->src_vsi == second->src_vsi &&
first->need_pass_l2 == second->need_pass_l2 &&
first->allow_pass_l2 == second->allow_pass_l2;
}

/**
Expand Down Expand Up @@ -6078,7 +6098,8 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
if (!(rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI ||
rinfo->sw_act.fltr_act == ICE_FWD_TO_Q ||
rinfo->sw_act.fltr_act == ICE_FWD_TO_QGRP ||
rinfo->sw_act.fltr_act == ICE_DROP_PACKET)) {
rinfo->sw_act.fltr_act == ICE_DROP_PACKET ||
rinfo->sw_act.fltr_act == ICE_NOP)) {
status = -EIO;
goto free_pkt_profile;
}
Expand All @@ -6089,7 +6110,8 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
goto free_pkt_profile;
}

if (rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI)
if (rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI ||
rinfo->sw_act.fltr_act == ICE_NOP)
rinfo->sw_act.fwd_id.hw_vsi_id =
ice_get_hw_vsi_num(hw, vsi_handle);

Expand Down Expand Up @@ -6159,6 +6181,11 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP |
ICE_SINGLE_ACT_VALID_BIT;
break;
case ICE_NOP:
act |= FIELD_PREP(ICE_SINGLE_ACT_VSI_ID_M,
rinfo->sw_act.fwd_id.hw_vsi_id);
act &= ~ICE_SINGLE_ACT_VALID_BIT;
break;
default:
status = -EIO;
goto err_ice_add_adv_rule;
Expand Down Expand Up @@ -6439,7 +6466,7 @@ ice_rem_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
return -EIO;
}

rid = ice_find_recp(hw, &lkup_exts, rinfo->tun_type);
rid = ice_find_recp(hw, &lkup_exts, rinfo);
/* If did not find a recipe that match the existing criteria */
if (rid == ICE_MAX_NUM_RECIPES)
return -EINVAL;
Expand Down
5 changes: 5 additions & 0 deletions drivers/net/ethernet/intel/ice/ice_switch.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ struct ice_adv_rule_info {
u16 vlan_type;
u16 fltr_rule_id;
u32 priority;
u16 need_pass_l2:1;
u16 allow_pass_l2:1;
u16 src_vsi;
struct ice_sw_act_ctrl sw_act;
struct ice_adv_rule_flags_info flags_info;
Expand Down Expand Up @@ -254,6 +256,9 @@ struct ice_sw_recipe {
*/
u8 priority;

u8 need_pass_l2:1;
u8 allow_pass_l2:1;

struct list_head rg_list;

/* AQ buffer associated with this recipe */
Expand Down
1 change: 1 addition & 0 deletions drivers/net/ethernet/intel/ice/ice_type.h
Original file line number Diff line number Diff line change
Expand Up @@ -1033,6 +1033,7 @@ enum ice_sw_fwd_act_type {
ICE_FWD_TO_Q,
ICE_FWD_TO_QGRP,
ICE_DROP_PACKET,
ICE_NOP,
ICE_INVAL_ACT
};

Expand Down

0 comments on commit bccd9bc

Please sign in to comment.