summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/intel/ice/ice_eswitch_br.c
diff options
context:
space:
mode:
authorMarcin Szycik <marcin.szycik@intel.com>2023-07-12 13:03:33 +0200
committerTony Nguyen <anthony.l.nguyen@intel.com>2023-07-24 08:53:20 -0700
commitbccd9bce29e0d0ac3d0705cc2e58fffe16179d12 (patch)
tree65d93d0f63b12d650331bb1da85487f419d22202 /drivers/net/ethernet/intel/ice/ice_eswitch_br.c
parent7c945a1a8e5fb84195f74813b5d24c924b694932 (diff)
ice: Add guard rule when creating FDB in switchdev
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>
Diffstat (limited to 'drivers/net/ethernet/intel/ice/ice_eswitch_br.c')
-rw-r--r--drivers/net/ethernet/intel/ice/ice_eswitch_br.c64
1 files changed, 63 insertions, 1 deletions
diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch_br.c b/drivers/net/ethernet/intel/ice/ice_eswitch_br.c
index 49b3ca5e956e..297d0eb45dde 100644
--- a/drivers/net/ethernet/intel/ice/ice_eswitch_br.c
+++ b/drivers/net/ethernet/intel/ice/ice_eswitch_br.c
@@ -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);
@@ -125,11 +127,54 @@ err_list_alloc:
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;
@@ -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);
@@ -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);
}