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

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
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -269,7 +269,7 @@ int rndis_filter_receive(struct net_device *ndev,
int rndis_filter_set_device_mac(struct netvsc_device *ndev,
				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)

@@ -1718,4 +1718,8 @@ struct rndis_message {
#define TRANSPORT_INFO_IPV6_TCP 0x10
#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 */
+31 −4
Original line number Diff line number Diff line
@@ -31,12 +31,13 @@
 * Switch the data path from the synthetic interface to the VF
 * 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 hv_device *dev = net_device_ctx->device_ctx;
	struct netvsc_device *nv_dev = rtnl_dereference(net_device_ctx->nvdev);
	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 */
	if (!vf)
@@ -51,15 +52,41 @@ void netvsc_switch_datapath(struct net_device *ndev, bool vf)
		init_pkt->msg.v4_msg.active_dp.active_datapath =
			NVSP_DATAPATH_SYNTHETIC;

again:
	trace_nvsp_send(ndev, init_pkt);

	vmbus_sendpacket(dev->channel, init_pkt,
	ret = vmbus_sendpacket(dev->channel, init_pkt,
			       sizeof(struct nvsp_message),
			       (unsigned long)init_pkt,
			       VM_PKT_DATA_INBAND,
			       (unsigned long)init_pkt, VM_PKT_DATA_INBAND,
			       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);
	net_device_ctx->data_path_is_vf = vf;

	return 0;
}

/* Worker to setup sub channels on initial setup
+12 −6
Original line number Diff line number Diff line
@@ -38,9 +38,6 @@
#include "hyperv_net.h"

#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 VF_TAKEOVER_INT (HZ / 10)
@@ -2402,6 +2399,7 @@ static int netvsc_vf_changed(struct net_device *vf_netdev, unsigned long event)
	struct netvsc_device *netvsc_dev;
	struct net_device *ndev;
	bool vf_is_up = false;
	int ret;

	if (event != NETDEV_GOING_DOWN)
		vf_is_up = netif_running(vf_netdev);
@@ -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)
		return NOTIFY_OK;

	netvsc_switch_datapath(ndev, vf_is_up);
	ret = netvsc_switch_datapath(ndev, vf_is_up);

	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;
}