Commit f37107ae authored by KY Srinivasan's avatar KY Srinivasan Committed by Tim Gardner

hv_netvsc: Implement support for VF drivers on Hyper-V

BugLink: http://bugs.launchpad.net/bugs/1616677

Support VF drivers on Hyper-V. On Hyper-V, each VF instance presented to
the guest has an associated synthetic interface that shares the MAC address
with the VF instance. Typically these are bonded together to support
live migration. By default, the host delivers all the incoming packets
on the synthetic interface. Once the VF is up, we need to explicitly switch
the data path on the host to divert traffic onto the VF interface. Even after
switching the data path, broadcast and multicast packets are always delivered
on the synthetic interface and these will have to be injected back onto the
VF interface (if VF is up).
This patch implements the necessary support in netvsc to support Linux
VF drivers.
Signed-off-by: default avatarK. Y. Srinivasan <kys@microsoft.com>
Reviewed-by: default avatarHaiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
(cherry picked from commit 84bf9cef)
Signed-off-by: default avatarTim Gardner <tim.gardner@canonical.com>
Acked-by: default avatarBrad Figg <brad.figg@canonical.com>
Acked-by: default avatarKamal Mostafa <kamal@canonical.com>
parent 3d60e969
......@@ -202,6 +202,8 @@ int rndis_filter_receive(struct hv_device *dev,
int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter);
int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac);
void netvsc_switch_datapath(struct netvsc_device *nv_dev, bool vf);
#define NVSP_INVALID_PROTOCOL_VERSION ((u32)0xFFFFFFFF)
#define NVSP_PROTOCOL_VERSION_1 2
......@@ -641,6 +643,12 @@ struct netvsc_reconfig {
u32 event;
};
struct garp_wrk {
struct work_struct dwrk;
struct net_device *netdev;
struct netvsc_device *netvsc_dev;
};
/* The context of the netvsc device */
struct net_device_context {
/* point back to our device context */
......@@ -656,6 +664,7 @@ struct net_device_context {
struct work_struct work;
u32 msg_enable; /* debug level */
struct garp_wrk gwrk;
struct netvsc_stats __percpu *tx_stats;
struct netvsc_stats __percpu *rx_stats;
......@@ -730,6 +739,11 @@ struct netvsc_device {
u32 vf_alloc;
/* Serial number of the VF to team with */
u32 vf_serial;
atomic_t open_cnt;
/* State to manage the associated VF interface. */
bool vf_inject;
struct net_device *vf_netdev;
atomic_t vf_use_cnt;
};
/* NdisInitialize message */
......
......@@ -33,6 +33,30 @@
#include "hyperv_net.h"
/*
* Switch the data path from the synthetic interface to the VF
* interface.
*/
void netvsc_switch_datapath(struct netvsc_device *nv_dev, bool vf)
{
struct nvsp_message *init_pkt = &nv_dev->channel_init_pkt;
struct hv_device *dev = nv_dev->dev;
memset(init_pkt, 0, sizeof(struct nvsp_message));
init_pkt->hdr.msg_type = NVSP_MSG4_TYPE_SWITCH_DATA_PATH;
if (vf)
init_pkt->msg.v4_msg.active_dp.active_datapath =
NVSP_DATAPATH_VF;
else
init_pkt->msg.v4_msg.active_dp.active_datapath =
NVSP_DATAPATH_SYNTHETIC;
vmbus_sendpacket(dev->channel, init_pkt,
sizeof(struct nvsp_message),
(unsigned long)init_pkt,
VM_PKT_DATA_INBAND, 0);
}
static struct netvsc_device *alloc_net_device(struct hv_device *device)
{
......@@ -52,11 +76,16 @@ static struct netvsc_device *alloc_net_device(struct hv_device *device)
init_waitqueue_head(&net_device->wait_drain);
net_device->start_remove = false;
net_device->destroy = false;
atomic_set(&net_device->open_cnt, 0);
atomic_set(&net_device->vf_use_cnt, 0);
net_device->dev = device;
net_device->ndev = ndev;
net_device->max_pkt = RNDIS_MAX_PKT_DEFAULT;
net_device->pkt_align = RNDIS_PKT_ALIGN_DEFAULT;
net_device->vf_netdev = NULL;
net_device->vf_inject = false;
hv_set_drvdata(device, net_device);
return net_device;
}
......
This diff is collapsed.
......@@ -1229,6 +1229,9 @@ int rndis_filter_open(struct hv_device *dev)
if (!net_device)
return -EINVAL;
if (atomic_inc_return(&net_device->open_cnt) != 1)
return 0;
return rndis_filter_open_device(net_device->extension);
}
......@@ -1239,5 +1242,8 @@ int rndis_filter_close(struct hv_device *dev)
if (!nvdev)
return -EINVAL;
if (atomic_dec_return(&nvdev->open_cnt) != 0)
return 0;
return rndis_filter_close_device(nvdev->extension);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment