Commit d0922bf7 authored by Haiyang Zhang's avatar Haiyang Zhang Committed by David S. Miller

hv_netvsc: Add error handling while switching data path

Add error handling in case of failure to send switching data path message
to the host.
Reported-by: default avatarShachar Raindel <shacharr@microsoft.com>
Signed-off-by: default avatarHaiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d24f511b
...@@ -269,7 +269,7 @@ int rndis_filter_receive(struct net_device *ndev, ...@@ -269,7 +269,7 @@ int rndis_filter_receive(struct net_device *ndev,
int rndis_filter_set_device_mac(struct netvsc_device *ndev, int rndis_filter_set_device_mac(struct netvsc_device *ndev,
const char *mac); const char *mac);
void netvsc_switch_datapath(struct net_device *nv_dev, bool vf); int netvsc_switch_datapath(struct net_device *nv_dev, bool vf);
#define NVSP_INVALID_PROTOCOL_VERSION ((u32)0xFFFFFFFF) #define NVSP_INVALID_PROTOCOL_VERSION ((u32)0xFFFFFFFF)
...@@ -1718,4 +1718,8 @@ struct rndis_message { ...@@ -1718,4 +1718,8 @@ struct rndis_message {
#define TRANSPORT_INFO_IPV6_TCP 0x10 #define TRANSPORT_INFO_IPV6_TCP 0x10
#define TRANSPORT_INFO_IPV6_UDP 0x20 #define TRANSPORT_INFO_IPV6_UDP 0x20
#define RETRY_US_LO 5000
#define RETRY_US_HI 10000
#define RETRY_MAX 2000 /* >10 sec */
#endif /* _HYPERV_NET_H */ #endif /* _HYPERV_NET_H */
...@@ -31,12 +31,13 @@ ...@@ -31,12 +31,13 @@
* Switch the data path from the synthetic interface to the VF * Switch the data path from the synthetic interface to the VF
* interface. * interface.
*/ */
void netvsc_switch_datapath(struct net_device *ndev, bool vf) int netvsc_switch_datapath(struct net_device *ndev, bool vf)
{ {
struct net_device_context *net_device_ctx = netdev_priv(ndev); struct net_device_context *net_device_ctx = netdev_priv(ndev);
struct hv_device *dev = net_device_ctx->device_ctx; struct hv_device *dev = net_device_ctx->device_ctx;
struct netvsc_device *nv_dev = rtnl_dereference(net_device_ctx->nvdev); struct netvsc_device *nv_dev = rtnl_dereference(net_device_ctx->nvdev);
struct nvsp_message *init_pkt = &nv_dev->channel_init_pkt; struct nvsp_message *init_pkt = &nv_dev->channel_init_pkt;
int ret, retry = 0;
/* Block sending traffic to VF if it's about to be gone */ /* Block sending traffic to VF if it's about to be gone */
if (!vf) if (!vf)
...@@ -51,15 +52,41 @@ void netvsc_switch_datapath(struct net_device *ndev, bool vf) ...@@ -51,15 +52,41 @@ void netvsc_switch_datapath(struct net_device *ndev, bool vf)
init_pkt->msg.v4_msg.active_dp.active_datapath = init_pkt->msg.v4_msg.active_dp.active_datapath =
NVSP_DATAPATH_SYNTHETIC; NVSP_DATAPATH_SYNTHETIC;
again:
trace_nvsp_send(ndev, init_pkt); trace_nvsp_send(ndev, init_pkt);
vmbus_sendpacket(dev->channel, init_pkt, ret = vmbus_sendpacket(dev->channel, init_pkt,
sizeof(struct nvsp_message), sizeof(struct nvsp_message),
(unsigned long)init_pkt, (unsigned long)init_pkt, VM_PKT_DATA_INBAND,
VM_PKT_DATA_INBAND,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
/* If failed to switch to/from VF, let data_path_is_vf stay false,
* so we use synthetic path to send data.
*/
if (ret) {
if (ret != -EAGAIN) {
netdev_err(ndev,
"Unable to send sw datapath msg, err: %d\n",
ret);
return ret;
}
if (retry++ < RETRY_MAX) {
usleep_range(RETRY_US_LO, RETRY_US_HI);
goto again;
} else {
netdev_err(
ndev,
"Retry failed to send sw datapath msg, err: %d\n",
ret);
return ret;
}
}
wait_for_completion(&nv_dev->channel_init_wait); wait_for_completion(&nv_dev->channel_init_wait);
net_device_ctx->data_path_is_vf = vf; net_device_ctx->data_path_is_vf = vf;
return 0;
} }
/* Worker to setup sub channels on initial setup /* Worker to setup sub channels on initial setup
......
...@@ -38,9 +38,6 @@ ...@@ -38,9 +38,6 @@
#include "hyperv_net.h" #include "hyperv_net.h"
#define RING_SIZE_MIN 64 #define RING_SIZE_MIN 64
#define RETRY_US_LO 5000
#define RETRY_US_HI 10000
#define RETRY_MAX 2000 /* >10 sec */
#define LINKCHANGE_INT (2 * HZ) #define LINKCHANGE_INT (2 * HZ)
#define VF_TAKEOVER_INT (HZ / 10) #define VF_TAKEOVER_INT (HZ / 10)
...@@ -2402,6 +2399,7 @@ static int netvsc_vf_changed(struct net_device *vf_netdev, unsigned long event) ...@@ -2402,6 +2399,7 @@ static int netvsc_vf_changed(struct net_device *vf_netdev, unsigned long event)
struct netvsc_device *netvsc_dev; struct netvsc_device *netvsc_dev;
struct net_device *ndev; struct net_device *ndev;
bool vf_is_up = false; bool vf_is_up = false;
int ret;
if (event != NETDEV_GOING_DOWN) if (event != NETDEV_GOING_DOWN)
vf_is_up = netif_running(vf_netdev); vf_is_up = netif_running(vf_netdev);
...@@ -2418,9 +2416,17 @@ static int netvsc_vf_changed(struct net_device *vf_netdev, unsigned long event) ...@@ -2418,9 +2416,17 @@ static int netvsc_vf_changed(struct net_device *vf_netdev, unsigned long event)
if (net_device_ctx->data_path_is_vf == vf_is_up) if (net_device_ctx->data_path_is_vf == vf_is_up)
return NOTIFY_OK; return NOTIFY_OK;
netvsc_switch_datapath(ndev, vf_is_up); ret = netvsc_switch_datapath(ndev, vf_is_up);
netdev_info(ndev, "Data path switched %s VF: %s\n",
vf_is_up ? "to" : "from", vf_netdev->name); if (ret) {
netdev_err(ndev,
"Data path failed to switch %s VF: %s, err: %d\n",
vf_is_up ? "to" : "from", vf_netdev->name, ret);
return NOTIFY_DONE;
} else {
netdev_info(ndev, "Data path switched %s VF: %s\n",
vf_is_up ? "to" : "from", vf_netdev->name);
}
return NOTIFY_OK; return NOTIFY_OK;
} }
......
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