forked from mirrors/linux
		
	ice: Implement ice_bridge_getlink and ice_bridge_setlink
ice_bridge_getlink returns the current bridge mode using ndo_dflt_bridge_getlink and the mode parameter available in first_switch->bridge_mode. ice_bridge_setlink is invoked when the bridge mode needs to changed. The value to be changed to is available as a netlink message which is parsed in this function. If the mode has to be changed, switch_flags is set appropriately (set ALLOW_LB for VEB mode and clear it for VEPA mode) and ice_aq_update_vsi is called. Also change the unicast switch filter rules. Signed-off-by: Md Fahad Iqbal Polash <md.fahad.iqbal.polash@intel.com> Signed-off-by: Anirudh Venkataramanan <anirudh.venkataramanan@intel.com> Tested-by: Tony Brelinski <tonyx.brelinski@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
This commit is contained in:
		
							parent
							
								
									b3969fd727
								
							
						
					
					
						commit
						b1edc14a3f
					
				
					 3 changed files with 181 additions and 1 deletions
				
			
		| 
						 | 
					@ -3599,7 +3599,11 @@ static int ice_probe(struct pci_dev *pdev,
 | 
				
			||||||
		goto err_msix_misc_unroll;
 | 
							goto err_msix_misc_unroll;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pf->first_sw->bridge_mode = BRIDGE_MODE_VEB;
 | 
						if (hw->evb_veb)
 | 
				
			||||||
 | 
							pf->first_sw->bridge_mode = BRIDGE_MODE_VEB;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							pf->first_sw->bridge_mode = BRIDGE_MODE_VEPA;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pf->first_sw->pf = pf;
 | 
						pf->first_sw->pf = pf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* record the sw_id available for later use */
 | 
						/* record the sw_id available for later use */
 | 
				
			||||||
| 
						 | 
					@ -5695,6 +5699,138 @@ int ice_get_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * ice_bridge_getlink - Get the hardware bridge mode
 | 
				
			||||||
 | 
					 * @skb: skb buff
 | 
				
			||||||
 | 
					 * @pid: process id
 | 
				
			||||||
 | 
					 * @seq: RTNL message seq
 | 
				
			||||||
 | 
					 * @dev: the netdev being configured
 | 
				
			||||||
 | 
					 * @filter_mask: filter mask passed in
 | 
				
			||||||
 | 
					 * @nlflags: netlink flags passed in
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Return the bridge mode (VEB/VEPA)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					ice_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
 | 
				
			||||||
 | 
							   struct net_device *dev, u32 filter_mask, int nlflags)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ice_netdev_priv *np = netdev_priv(dev);
 | 
				
			||||||
 | 
						struct ice_vsi *vsi = np->vsi;
 | 
				
			||||||
 | 
						struct ice_pf *pf = vsi->back;
 | 
				
			||||||
 | 
						u16 bmode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bmode = pf->first_sw->bridge_mode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ndo_dflt_bridge_getlink(skb, pid, seq, dev, bmode, 0, 0, nlflags,
 | 
				
			||||||
 | 
									       filter_mask, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * ice_vsi_update_bridge_mode - Update VSI for switching bridge mode (VEB/VEPA)
 | 
				
			||||||
 | 
					 * @vsi: Pointer to VSI structure
 | 
				
			||||||
 | 
					 * @bmode: Hardware bridge mode (VEB/VEPA)
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns 0 on success, negative on failure
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int ice_vsi_update_bridge_mode(struct ice_vsi *vsi, u16 bmode)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct device *dev = &vsi->back->pdev->dev;
 | 
				
			||||||
 | 
						struct ice_aqc_vsi_props *vsi_props;
 | 
				
			||||||
 | 
						struct ice_hw *hw = &vsi->back->hw;
 | 
				
			||||||
 | 
						struct ice_vsi_ctx ctxt = { 0 };
 | 
				
			||||||
 | 
						enum ice_status status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vsi_props = &vsi->info;
 | 
				
			||||||
 | 
						ctxt.info = vsi->info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (bmode == BRIDGE_MODE_VEB)
 | 
				
			||||||
 | 
							/* change from VEPA to VEB mode */
 | 
				
			||||||
 | 
							ctxt.info.sw_flags |= ICE_AQ_VSI_SW_FLAG_ALLOW_LB;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							/* change from VEB to VEPA mode */
 | 
				
			||||||
 | 
							ctxt.info.sw_flags &= ~ICE_AQ_VSI_SW_FLAG_ALLOW_LB;
 | 
				
			||||||
 | 
						ctxt.vsi_num = vsi->vsi_num;
 | 
				
			||||||
 | 
						ctxt.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SW_VALID);
 | 
				
			||||||
 | 
						status = ice_aq_update_vsi(hw, &ctxt, NULL);
 | 
				
			||||||
 | 
						if (status) {
 | 
				
			||||||
 | 
							dev_err(dev, "update VSI for bridge mode failed, bmode = %d err %d aq_err %d\n",
 | 
				
			||||||
 | 
								bmode, status, hw->adminq.sq_last_status);
 | 
				
			||||||
 | 
							return -EIO;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						/* Update sw flags for book keeping */
 | 
				
			||||||
 | 
						vsi_props->sw_flags = ctxt.info.sw_flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * ice_bridge_setlink - Set the hardware bridge mode
 | 
				
			||||||
 | 
					 * @dev: the netdev being configured
 | 
				
			||||||
 | 
					 * @nlh: RTNL message
 | 
				
			||||||
 | 
					 * @flags: bridge setlink flags
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Sets the bridge mode (VEB/VEPA) of the switch to which the netdev (VSI) is
 | 
				
			||||||
 | 
					 * hooked up to. Iterates through the PF VSI list and sets the loopback mode (if
 | 
				
			||||||
 | 
					 * not already set for all VSIs connected to this switch. And also update the
 | 
				
			||||||
 | 
					 * unicast switch filter rules for the corresponding switch of the netdev.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					ice_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh,
 | 
				
			||||||
 | 
							   u16 __always_unused flags)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ice_netdev_priv *np = netdev_priv(dev);
 | 
				
			||||||
 | 
						struct ice_pf *pf = np->vsi->back;
 | 
				
			||||||
 | 
						struct nlattr *attr, *br_spec;
 | 
				
			||||||
 | 
						struct ice_hw *hw = &pf->hw;
 | 
				
			||||||
 | 
						enum ice_status status;
 | 
				
			||||||
 | 
						struct ice_sw *pf_sw;
 | 
				
			||||||
 | 
						int rem, v, err = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pf_sw = pf->first_sw;
 | 
				
			||||||
 | 
						/* find the attribute in the netlink message */
 | 
				
			||||||
 | 
						br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						nla_for_each_nested(attr, br_spec, rem) {
 | 
				
			||||||
 | 
							__u16 mode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (nla_type(attr) != IFLA_BRIDGE_MODE)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							mode = nla_get_u16(attr);
 | 
				
			||||||
 | 
							if (mode != BRIDGE_MODE_VEPA && mode != BRIDGE_MODE_VEB)
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							/* Continue  if bridge mode is not being flipped */
 | 
				
			||||||
 | 
							if (mode == pf_sw->bridge_mode)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							/* Iterates through the PF VSI list and update the loopback
 | 
				
			||||||
 | 
							 * mode of the VSI
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							ice_for_each_vsi(pf, v) {
 | 
				
			||||||
 | 
								if (!pf->vsi[v])
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								err = ice_vsi_update_bridge_mode(pf->vsi[v], mode);
 | 
				
			||||||
 | 
								if (err)
 | 
				
			||||||
 | 
									return err;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							hw->evb_veb = (mode == BRIDGE_MODE_VEB);
 | 
				
			||||||
 | 
							/* Update the unicast switch filter rules for the corresponding
 | 
				
			||||||
 | 
							 * switch of the netdev
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							status = ice_update_sw_rule_bridge_mode(hw);
 | 
				
			||||||
 | 
							if (status) {
 | 
				
			||||||
 | 
								netdev_err(dev, "update SW_RULE for bridge mode failed,  = %d err %d aq_err %d\n",
 | 
				
			||||||
 | 
									   mode, status, hw->adminq.sq_last_status);
 | 
				
			||||||
 | 
								/* revert hw->evb_veb */
 | 
				
			||||||
 | 
								hw->evb_veb = (pf_sw->bridge_mode == BRIDGE_MODE_VEB);
 | 
				
			||||||
 | 
								return -EIO;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							pf_sw->bridge_mode = mode;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * ice_tx_timeout - Respond to a Tx Hang
 | 
					 * ice_tx_timeout - Respond to a Tx Hang
 | 
				
			||||||
 * @netdev: network interface device structure
 | 
					 * @netdev: network interface device structure
 | 
				
			||||||
| 
						 | 
					@ -5907,6 +6043,8 @@ static const struct net_device_ops ice_netdev_ops = {
 | 
				
			||||||
	.ndo_vlan_rx_add_vid = ice_vlan_rx_add_vid,
 | 
						.ndo_vlan_rx_add_vid = ice_vlan_rx_add_vid,
 | 
				
			||||||
	.ndo_vlan_rx_kill_vid = ice_vlan_rx_kill_vid,
 | 
						.ndo_vlan_rx_kill_vid = ice_vlan_rx_kill_vid,
 | 
				
			||||||
	.ndo_set_features = ice_set_features,
 | 
						.ndo_set_features = ice_set_features,
 | 
				
			||||||
 | 
						.ndo_bridge_getlink = ice_bridge_getlink,
 | 
				
			||||||
 | 
						.ndo_bridge_setlink = ice_bridge_setlink,
 | 
				
			||||||
	.ndo_fdb_add = ice_fdb_add,
 | 
						.ndo_fdb_add = ice_fdb_add,
 | 
				
			||||||
	.ndo_fdb_del = ice_fdb_del,
 | 
						.ndo_fdb_del = ice_fdb_del,
 | 
				
			||||||
	.ndo_tx_timeout = ice_tx_timeout,
 | 
						.ndo_tx_timeout = ice_tx_timeout,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1130,6 +1130,47 @@ ice_update_pkt_fwd_rule(struct ice_hw *hw, struct ice_fltr_info *f_info)
 | 
				
			||||||
	return status;
 | 
						return status;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * ice_update_sw_rule_bridge_mode
 | 
				
			||||||
 | 
					 * @hw: pointer to the hw struct
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Updates unicast switch filter rules based on VEB/VEPA mode
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					enum ice_status ice_update_sw_rule_bridge_mode(struct ice_hw *hw)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ice_switch_info *sw = hw->switch_info;
 | 
				
			||||||
 | 
						struct ice_fltr_mgmt_list_entry *fm_entry;
 | 
				
			||||||
 | 
						enum ice_status status = 0;
 | 
				
			||||||
 | 
						struct list_head *rule_head;
 | 
				
			||||||
 | 
						struct mutex *rule_lock; /* Lock to protect filter rule list */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rule_lock = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rule_lock;
 | 
				
			||||||
 | 
						rule_head = &sw->recp_list[ICE_SW_LKUP_MAC].filt_rules;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(rule_lock);
 | 
				
			||||||
 | 
						list_for_each_entry(fm_entry, rule_head, list_entry) {
 | 
				
			||||||
 | 
							struct ice_fltr_info *fi = &fm_entry->fltr_info;
 | 
				
			||||||
 | 
							u8 *addr = fi->l_data.mac.mac_addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Update unicast Tx rules to reflect the selected
 | 
				
			||||||
 | 
							 * VEB/VEPA mode
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							if ((fi->flag & ICE_FLTR_TX) && is_unicast_ether_addr(addr) &&
 | 
				
			||||||
 | 
							    (fi->fltr_act == ICE_FWD_TO_VSI ||
 | 
				
			||||||
 | 
							     fi->fltr_act == ICE_FWD_TO_VSI_LIST ||
 | 
				
			||||||
 | 
							     fi->fltr_act == ICE_FWD_TO_Q ||
 | 
				
			||||||
 | 
							     fi->fltr_act == ICE_FWD_TO_QGRP)) {
 | 
				
			||||||
 | 
								status = ice_update_pkt_fwd_rule(hw, fi);
 | 
				
			||||||
 | 
								if (status)
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_unlock(rule_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return status;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * ice_add_update_vsi_list
 | 
					 * ice_add_update_vsi_list
 | 
				
			||||||
 * @hw: pointer to the hardware structure
 | 
					 * @hw: pointer to the hardware structure
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -169,6 +169,7 @@ ice_free_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,
 | 
				
			||||||
enum ice_status ice_get_initial_sw_cfg(struct ice_hw *hw);
 | 
					enum ice_status ice_get_initial_sw_cfg(struct ice_hw *hw);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Switch/bridge related commands */
 | 
					/* Switch/bridge related commands */
 | 
				
			||||||
 | 
					enum ice_status ice_update_sw_rule_bridge_mode(struct ice_hw *hw);
 | 
				
			||||||
enum ice_status ice_add_mac(struct ice_hw *hw, struct list_head *m_lst);
 | 
					enum ice_status ice_add_mac(struct ice_hw *hw, struct list_head *m_lst);
 | 
				
			||||||
enum ice_status ice_remove_mac(struct ice_hw *hw, struct list_head *m_lst);
 | 
					enum ice_status ice_remove_mac(struct ice_hw *hw, struct list_head *m_lst);
 | 
				
			||||||
void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_id);
 | 
					void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_id);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue