diff options
Diffstat (limited to 'sys/dev/ixl')
| -rw-r--r-- | sys/dev/ixl/if_ixl.c | 27 | ||||
| -rw-r--r-- | sys/dev/ixl/ixl.h | 1 | ||||
| -rw-r--r-- | sys/dev/ixl/ixl_pf_main.c | 110 | 
3 files changed, 120 insertions, 18 deletions
| diff --git a/sys/dev/ixl/if_ixl.c b/sys/dev/ixl/if_ixl.c index 261f76055901..bfaf6cd69e58 100644 --- a/sys/dev/ixl/if_ixl.c +++ b/sys/dev/ixl/if_ixl.c @@ -1480,17 +1480,33 @@ ixl_if_multi_set(if_ctx_t ctx)  	struct ixl_pf *pf = iflib_get_softc(ctx);  	struct ixl_vsi *vsi = &pf->vsi;  	struct i40e_hw *hw = vsi->hw; +	enum i40e_status_code status;  	int mcnt; +	if_t ifp = iflib_get_ifp(ctx);  	IOCTL_DEBUGOUT("ixl_if_multi_set: begin");  	/* Delete filters for removed multicast addresses */  	ixl_del_multi(vsi, false); -	mcnt = min(if_llmaddr_count(iflib_get_ifp(ctx)), MAX_MULTICAST_ADDR); +	mcnt = min(if_llmaddr_count(ifp), MAX_MULTICAST_ADDR);  	if (__predict_false(mcnt == MAX_MULTICAST_ADDR)) { -		i40e_aq_set_vsi_multicast_promiscuous(hw, +		/* Check if promisc mode is already enabled, if yes return */ +		if (vsi->flags & IXL_FLAGS_MC_PROMISC) +			return; + +		status = i40e_aq_set_vsi_multicast_promiscuous(hw,  		    vsi->seid, TRUE, NULL); +		if (status != I40E_SUCCESS) +			if_printf(ifp, "Failed to enable multicast promiscuous " +			    "mode, status: %s\n", i40e_stat_str(hw, status)); +		else { +			if_printf(ifp, "Enabled multicast promiscuous mode\n"); + +			/* Set the flag to track promiscuous mode */ +			vsi->flags |= IXL_FLAGS_MC_PROMISC; +		} +		/* Delete all existing MC filters */  		ixl_del_multi(vsi, true);  		return;  	} @@ -1693,6 +1709,13 @@ ixl_if_promisc_set(if_ctx_t ctx, int flags)  		return (err);  	err = i40e_aq_set_vsi_multicast_promiscuous(hw,  	    vsi->seid, multi, NULL); + +	/* Update the multicast promiscuous flag based on the new state */ +	if (multi) +		vsi->flags |= IXL_FLAGS_MC_PROMISC; +	else +		vsi->flags &= ~IXL_FLAGS_MC_PROMISC; +  	return (err);  } diff --git a/sys/dev/ixl/ixl.h b/sys/dev/ixl/ixl.h index 95379448b570..ab0f38307d90 100644 --- a/sys/dev/ixl/ixl.h +++ b/sys/dev/ixl/ixl.h @@ -202,6 +202,7 @@  #define IXL_FLAGS_KEEP_TSO6	(1 << 1)  #define IXL_FLAGS_USES_MSIX	(1 << 2)  #define IXL_FLAGS_IS_VF		(1 << 3) +#define IXL_FLAGS_MC_PROMISC	(1 << 4)  #define IXL_VSI_IS_PF(v)	((v->flags & IXL_FLAGS_IS_VF) == 0)  #define IXL_VSI_IS_VF(v)	((v->flags & IXL_FLAGS_IS_VF) != 0) diff --git a/sys/dev/ixl/ixl_pf_main.c b/sys/dev/ixl/ixl_pf_main.c index 1752efc02fff..b62619ced5cb 100644 --- a/sys/dev/ixl/ixl_pf_main.c +++ b/sys/dev/ixl/ixl_pf_main.c @@ -593,24 +593,29 @@ ixl_add_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)   *	Routines for multicast and vlan filter management.   *   *********************************************************************/ + +/** + * ixl_add_multi - Add multicast filters to the hardware + * @vsi: The VSI structure + * + * In case number of multicast filters in the IFP exceeds 127 entries, + * multicast promiscuous mode will be enabled and the filters will be removed + * from the hardware + */  void  ixl_add_multi(struct ixl_vsi *vsi)  {  	if_t			ifp = vsi->ifp; -	struct i40e_hw		*hw = vsi->hw;  	int			mcnt = 0;  	struct ixl_add_maddr_arg cb_arg;  	IOCTL_DEBUGOUT("ixl_add_multi: begin"); -	mcnt = if_llmaddr_count(ifp); -	if (__predict_false(mcnt >= MAX_MULTICAST_ADDR)) { -		i40e_aq_set_vsi_multicast_promiscuous(hw, -		    vsi->seid, TRUE, NULL); -		/* delete all existing MC filters */ -		ixl_del_multi(vsi, true); -		return; -	} +	/* +	 * There is no need to check if the number of multicast addresses +	 * exceeds the MAX_MULTICAST_ADDR threshold and set promiscuous mode +	 * here, as all callers already handle this case. +	 */  	cb_arg.vsi = vsi;  	LIST_INIT(&cb_arg.to_add); @@ -633,30 +638,103 @@ ixl_match_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)  		return (0);  } +/** + * ixl_dis_multi_promisc - Disable multicast promiscuous mode + * @vsi: The VSI structure + * @vsi_mcnt: Number of multicast filters in the VSI + * + * Disable multicast promiscuous mode based on number of entries in the IFP + * and the VSI, then re-add multicast filters. + * + */ +static void +ixl_dis_multi_promisc(struct ixl_vsi *vsi, int vsi_mcnt) +{ +	struct ifnet		*ifp = vsi->ifp; +	struct i40e_hw		*hw = vsi->hw; +	int			ifp_mcnt = 0; +	enum i40e_status_code	status; + +	/* +	 * Check if multicast promiscuous mode was actually enabled. +	 * If promiscuous mode was not enabled, don't attempt to disable it. +	 * Also, don't disable if IFF_PROMISC or IFF_ALLMULTI is set. +	 */ +	if (!(vsi->flags & IXL_FLAGS_MC_PROMISC) || +	    (if_getflags(ifp) & (IFF_PROMISC | IFF_ALLMULTI))) +		return; + +	ifp_mcnt = if_llmaddr_count(ifp); +	/* +	 * Equal lists or empty ifp list mean the list has not been changed +	 * and in such case avoid disabling multicast promiscuous mode as it +	 * was not previously enabled. Case where multicast promiscuous mode has +	 * been enabled is when vsi_mcnt == 0 && ifp_mcnt > 0. +	 */ +	if (ifp_mcnt == vsi_mcnt || ifp_mcnt == 0 || +	    ifp_mcnt >= MAX_MULTICAST_ADDR) +		return; + +	status = i40e_aq_set_vsi_multicast_promiscuous(hw, vsi->seid, +	    FALSE, NULL); +	if (status != I40E_SUCCESS) { +		if_printf(ifp, "Failed to disable multicast promiscuous " +		    "mode, status: %s\n", i40e_stat_str(hw, status)); + +		return; +	} + +	/* Clear the flag since promiscuous mode is now disabled */ +	vsi->flags &= ~IXL_FLAGS_MC_PROMISC; +	if_printf(ifp, "Disabled multicast promiscuous mode\n"); + +	ixl_add_multi(vsi); +} + +/** + * ixl_del_multi - Delete multicast filters from the hardware + * @vsi: The VSI structure + * @all: Bool to determine if all the multicast filters should be removed + * + * In case number of multicast filters in the IFP drops to 127 entries, + * multicast promiscuous mode will be disabled and the filters will be reapplied + * to the hardware. + */  void  ixl_del_multi(struct ixl_vsi *vsi, bool all)  { -	struct ixl_ftl_head	to_del; +	int			to_del_cnt = 0, vsi_mcnt = 0;  	if_t			ifp = vsi->ifp;  	struct ixl_mac_filter	*f, *fn; -	int			mcnt = 0; +	struct ixl_ftl_head	to_del;  	IOCTL_DEBUGOUT("ixl_del_multi: begin");  	LIST_INIT(&to_del);  	/* Search for removed multicast addresses */  	LIST_FOREACH_SAFE(f, &vsi->ftl, ftle, fn) { -		if ((f->flags & IXL_FILTER_MC) == 0 || -		    (!all && (if_foreach_llmaddr(ifp, ixl_match_maddr, f) == 0))) +		if ((f->flags & IXL_FILTER_MC) == 0) +			continue; + +		/* Count all the multicast filters in the VSI for comparison */ +		vsi_mcnt++; + +		if (!all && if_foreach_llmaddr(ifp, ixl_match_maddr, f) != 0)  			continue;  		LIST_REMOVE(f, ftle);  		LIST_INSERT_HEAD(&to_del, f, ftle); -		mcnt++; +		to_del_cnt++;  	} -	if (mcnt > 0) -		ixl_del_hw_filters(vsi, &to_del, mcnt); +	if (to_del_cnt > 0) { +		ixl_del_hw_filters(vsi, &to_del, to_del_cnt); +		return; +	} + +	ixl_dis_multi_promisc(vsi, vsi_mcnt); + +	IOCTL_DEBUGOUT("ixl_del_multi: end");  }  void | 
