From patchwork Fri Dec 30 06:20:59 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Samudrala, Sridhar" X-Patchwork-Id: 709576 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3tqN4d72VJz9s3T for ; Fri, 30 Dec 2016 08:28:17 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 500DA8567D; Thu, 29 Dec 2016 21:28:16 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from fraxinus.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ZgejajxVX_Fh; Thu, 29 Dec 2016 21:28:14 +0000 (UTC) Received: from ash.osuosl.org (ash.osuosl.org [140.211.166.34]) by fraxinus.osuosl.org (Postfix) with ESMTP id 6352885C5A; Thu, 29 Dec 2016 21:28:14 +0000 (UTC) X-Original-To: intel-wired-lan@lists.osuosl.org Delivered-To: intel-wired-lan@lists.osuosl.org Received: from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by ash.osuosl.org (Postfix) with ESMTP id 61AFD1BFCB6 for ; Thu, 29 Dec 2016 21:28:11 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id 5C8AF2DDD4 for ; Thu, 29 Dec 2016 21:28:11 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from silver.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id MbTizRZFJktk for ; Thu, 29 Dec 2016 21:28:09 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by silver.osuosl.org (Postfix) with ESMTPS id 650B92DF9C for ; Thu, 29 Dec 2016 21:28:09 +0000 (UTC) Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga103.fm.intel.com with ESMTP; 29 Dec 2016 13:28:08 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos; i="5.33,428,1477983600"; d="scan'208"; a="1077443907" Received: from sri-mi-02.jf.intel.com ([10.166.188.51]) by orsmga001.jf.intel.com with ESMTP; 29 Dec 2016 13:28:08 -0800 From: Sridhar Samudrala To: alexander.h.duyck@intel.com, john.r.fastabend@intel.com, anjali.singhai@intel.com, jakub.kicinski@netronome.com, intel-wired-lan@lists.osuosl.org, netdev@vger.kernel.org Date: Thu, 29 Dec 2016 22:20:59 -0800 Message-Id: <1483078863-22026-3-git-send-email-sridhar.samudrala@intel.com> X-Mailer: git-send-email 2.5.5 In-Reply-To: <1483078863-22026-1-git-send-email-sridhar.samudrala@intel.com> References: <1483078863-22026-1-git-send-email-sridhar.samudrala@intel.com> Subject: [Intel-wired-lan] [net-next PATCH 2/6] i40e: Introduce VF Port Representator(VFPR) netdevs. X-BeenThere: intel-wired-lan@lists.osuosl.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: Intel Wired Ethernet Linux Kernel Driver Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: intel-wired-lan-bounces@lists.osuosl.org Sender: "Intel-wired-lan" VF Port Representator netdevs are created for each VF if the switch mode is set to 'switchdev'. These netdevs can be used to control and configure VFs from PFs namespace. They enable exposing VF statistics, configure and monitor link state, mtu, filters, fdb/vlan entries etc. of VFs. Broadcast filters are not enabled in switchdev mode. Sample script to create VF port representors # rmmod i40e; modprobe i40e # devlink dev eswitch set pci/0000:05:00.0 mode switchdev # echo 2 > /sys/class/net/enp5s0f0/device/sriov_numvfs # ip l show 297: enp5s0f0: mtu 1500 qdisc noop portid 6805ca2e7268 state DOWN mode DEFAULT group default qlen 1000 link/ether 68:05:ca:2e:72:68 brd ff:ff:ff:ff:ff:ff vf 0 MAC 00:00:00:00:00:00, spoof checking on, link-state auto, trust off vf 1 MAC 00:00:00:00:00:00, spoof checking on, link-state auto, trust off 299: enp5s0f0-vf0: mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff 300: enp5s0f0-vf1: mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff Signed-off-by: Sridhar Samudrala --- drivers/net/ethernet/intel/i40e/i40e_main.c | 14 +- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 151 ++++++++++++++++++++- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h | 14 ++ 3 files changed, 172 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index c01a620..03d07dd 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -10938,15 +10938,27 @@ static int i40e_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode) static int i40e_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode) { struct i40e_pf *pf = devlink_priv(devlink); - int err = 0; + struct i40e_vf *vf; + int i, err = 0; if (mode == pf->eswitch_mode) goto done; switch (mode) { case DEVLINK_ESWITCH_MODE_LEGACY: + for (i = 0; i < pf->num_alloc_vfs; i++) { + vf = &(pf->vf[i]); + i40e_free_vfpr_netdev(vf); + } pf->eswitch_mode = mode; break; + case DEVLINK_ESWITCH_MODE_SWITCHDEV: + for (i = 0; i < pf->num_alloc_vfs; i++) { + vf = &(pf->vf[i]); + i40e_alloc_vfpr_netdev(vf, i); + } + pf->eswitch_mode = mode; + break; default: err = -EOPNOTSUPP; break; diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index a6198b7..6c5b296 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -697,12 +697,16 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type) "Could not add MAC filter %pM for VF %d\n", vf->default_lan_addr.addr, vf->vf_id); } - eth_broadcast_addr(broadcast); - f = i40e_add_filter(vsi, broadcast, - vf->port_vlan_id ? vf->port_vlan_id : -1); - if (!f) - dev_info(&pf->pdev->dev, - "Could not allocate VF broadcast filter\n"); + + /* Add VF broadcast filter only in 'legacy' mode */ + if (vsi->back->eswitch_mode == DEVLINK_ESWITCH_MODE_LEGACY) { + eth_broadcast_addr(broadcast); + f = i40e_add_filter(vsi, broadcast, + vf->port_vlan_id ? vf->port_vlan_id : -1); + if (!f) + dev_info(&pf->pdev->dev, + "Could not allocate VF broadcast filter\n"); + } spin_unlock_bh(&vsi->mac_filter_hash_lock); i40e_write_rx_ctl(&pf->hw, I40E_VFQF_HENA1(0, vf->vf_id), (u32)hena); @@ -1020,6 +1024,136 @@ void i40e_reset_vf(struct i40e_vf *vf, bool flr) } /** + * i40e_vfpr_netdev_open + * @dev: network interface device structure + * + * Called when vfpr netdevice is brought up. + **/ +static int i40e_vfpr_netdev_open(struct net_device *dev) +{ + return 0; +} + +/** + * i40e_vfpr_netdev_stop + * @dev: network interface device structure + * + * Called when vfpr netdevice is brought down. + **/ +static int i40e_vfpr_netdev_stop(struct net_device *dev) +{ + return 0; +} + +static const struct net_device_ops i40e_vfpr_netdev_ops = { + .ndo_open = i40e_vfpr_netdev_open, + .ndo_stop = i40e_vfpr_netdev_stop, +}; + +/** + * i40e_update_vf_broadcast_filter + * @vf: pointer to the VF structure + * @enable: boolean flag indicating add/delete + * + * add/delete VFs broadcast filter + **/ +void i40e_update_vf_broadcast_filter(struct i40e_vf *vf, bool enable) +{ + struct i40e_pf *pf = vf->pf; + struct i40e_vsi *vsi = pf->vsi[vf->lan_vsi_idx]; + u8 broadcast[ETH_ALEN]; + int err; + + spin_lock_bh(&vsi->mac_filter_hash_lock); + eth_broadcast_addr(broadcast); + if (enable) + i40e_add_filter(vsi, broadcast, vf->port_vlan_id ? vf->port_vlan_id : -1); + else + i40e_del_filter(vsi, broadcast, vf->port_vlan_id ? vf->port_vlan_id : -1); + spin_unlock_bh(&vsi->mac_filter_hash_lock); + + /* update broadcast filter */ + err = i40e_sync_vsi_filters(vsi); + if (err) + dev_err(&pf->pdev->dev, "Unable to program bcast filter\n"); +} + +/** + * i40e_alloc_vfpr_netdev + * @vf: pointer to the VF structure + * @vf_num: VF number + * + * Create VF Port representor netdev + **/ +int i40e_alloc_vfpr_netdev(struct i40e_vf *vf, u16 vf_num) +{ + struct net_device *vfpr_netdev; + char netdev_name[IFNAMSIZ]; + struct i40e_vfpr_netdev_priv *priv; + struct i40e_pf *pf = vf->pf; + struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi]; + int err; + + snprintf(netdev_name, IFNAMSIZ, "%s-vf%d", vsi->netdev->name, vf_num); + vfpr_netdev = alloc_netdev(sizeof(struct i40e_vfpr_netdev_priv), + netdev_name, NET_NAME_UNKNOWN, ether_setup); + if (!vfpr_netdev) { + dev_err(&pf->pdev->dev, "alloc_netdev failed for vf:%d\n", + vf_num); + return -ENOMEM; + } + + pf->vf[vf_num].vfpr_netdev = vfpr_netdev; + + priv = netdev_priv(vfpr_netdev); + priv->vf = &(pf->vf[vf_num]); + + vfpr_netdev->netdev_ops = &i40e_vfpr_netdev_ops; + + netif_carrier_off(vfpr_netdev); + netif_tx_disable(vfpr_netdev); + + err = register_netdev(vfpr_netdev); + if (err) { + dev_err(&pf->pdev->dev, "register_netdev failed for vf: %s\n", + vf->vfpr_netdev->name); + free_netdev(vfpr_netdev); + return err; + } + + dev_info(&pf->pdev->dev, "VF Port representor(%s) created for VF %d\n", + vf->vfpr_netdev->name, vf_num); + + /* Delete broadcast filter for VF */ + i40e_update_vf_broadcast_filter(vf, false); + + return 0; +} + +/** + * i40e_free_vfpr_netdev + * @vf: pointer to the VF structure + * + * Free VF Port representor netdev + **/ +void i40e_free_vfpr_netdev(struct i40e_vf *vf) +{ + struct i40e_pf *pf = vf->pf; + + if (!vf->vfpr_netdev) + return; + + dev_info(&pf->pdev->dev, "Freeing VF Port representor(%s)\n", + vf->vfpr_netdev->name); + + unregister_netdev(vf->vfpr_netdev); + free_netdev(vf->vfpr_netdev); + + /* Add broadcast filter to VF */ + i40e_update_vf_broadcast_filter(vf, true); +} + +/** * i40e_free_vfs * @pf: pointer to the PF structure * @@ -1060,6 +1194,9 @@ void i40e_free_vfs(struct i40e_pf *pf) i40e_free_vf_res(&pf->vf[i]); /* disable qp mappings */ i40e_disable_vf_mappings(&pf->vf[i]); + + if (pf->eswitch_mode == DEVLINK_ESWITCH_MODE_SWITCHDEV) + i40e_free_vfpr_netdev(&pf->vf[i]); } kfree(pf->vf); @@ -1127,6 +1264,8 @@ int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs) /* VF resources get allocated during reset */ i40e_reset_vf(&vfs[i], false); + if (pf->eswitch_mode == DEVLINK_ESWITCH_MODE_SWITCHDEV) + i40e_alloc_vfpr_netdev(&vfs[i], i); } pf->num_alloc_vfs = num_alloc_vfs; diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h index 4012d06..1e5def1 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h @@ -72,10 +72,21 @@ enum i40e_vf_capabilities { I40E_VIRTCHNL_VF_CAP_IWARP, }; +/* VF Port representor netdev private structure */ +struct i40e_vfpr_netdev_priv { + struct i40e_vf *vf; +}; + /* VF information structure */ struct i40e_vf { struct i40e_pf *pf; + /* VF Port representor netdev that allows control and configuration + * of VFs from the host. Enables returning VF stats, configuring link + * state, mtu, fdb/vlans etc. + */ + struct net_device *vfpr_netdev; + /* VF id in the PF space */ s16 vf_id; /* all VF vsis connect to the same parent */ @@ -142,4 +153,7 @@ int i40e_ndo_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool enable); void i40e_vc_notify_link_state(struct i40e_pf *pf); void i40e_vc_notify_reset(struct i40e_pf *pf); +int i40e_alloc_vfpr_netdev(struct i40e_vf *vf, u16 vf_num); +void i40e_free_vfpr_netdev(struct i40e_vf *vf); + #endif /* _I40E_VIRTCHNL_PF_H_ */