]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
hv_netvsc: Add error handling while switching data path
authorHaiyang Zhang <haiyangz@microsoft.com>
Mon, 29 Mar 2021 23:21:35 +0000 (16:21 -0700)
committerDavid S. Miller <davem@davemloft.net>
Mon, 29 Mar 2021 23:35:59 +0000 (16:35 -0700)
Add error handling in case of failure to send switching data path message
to the host.

Reported-by: Shachar Raindel <shacharr@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/hyperv/hyperv_net.h
drivers/net/hyperv/netvsc.c
drivers/net/hyperv/netvsc_drv.c

index 59ac04a610adbf6670611a2db7b1d7cdeb2474b4..442c520ab8f30b8e6aed61d6b8d6bc088b80b888 100644 (file)
@@ -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 */
index 5bce247315027eb89e83aeb6ccddbf34c1c7c8a8..9d07c9ce4be28b68ca49ffa8e62c179102f59d13 100644 (file)
  * 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
index 97b5c9b60503dc505505fbb34dadda38f9e5e32f..7349a70af0838bb3491a5a3ad806dd51a96c16f1 100644 (file)
@@ -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);
-       netdev_info(ndev, "Data path switched %s VF: %s\n",
-                   vf_is_up ? "to" : "from", vf_netdev->name);
+       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;
 }