Browse Source

[xen] Cope with unexpected initial backend states

Under some circumstances (e.g. if iPXE itself is booted via iSCSI, or
after an unclean reboot), the backend may not be in the expected
InitWait state when iPXE starts up.

There is no generic reset mechanism for Xenbus devices.  Recent
versions of xen-netback will gracefully perform all of the required
steps if the frontend sets its state to Initialising.  Older versions
(such as that found in XenServer 6.2.0) require the frontend to
transition through Closed before reaching Initialising.

Add a reset mechanism for netfront devices which does the following:

 - read current backend state

 - if backend state is anything other than InitWait, then set the
   frontend state to Closed and wait for the backend to also reach
   Closed

 - set the frontend state to Initialising and wait for the backend to
   reach InitWait.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 10 years ago
parent
commit
8b2942a7db
3 changed files with 66 additions and 11 deletions
  1. 64
    10
      src/drivers/net/netfront.c
  2. 1
    0
      src/include/ipxe/xenbus.h
  3. 1
    1
      src/interface/xen/xenbus.c

+ 64
- 10
src/drivers/net/netfront.c View File

62
  ******************************************************************************
62
  ******************************************************************************
63
  */
63
  */
64
 
64
 
65
+/**
66
+ * Reset device
67
+ *
68
+ * @v netfront		Netfront device
69
+ * @ret rc		Return status code
70
+ */
71
+static int netfront_reset ( struct netfront_nic *netfront ) {
72
+	struct xen_device *xendev = netfront->xendev;
73
+	int state;
74
+	int rc;
75
+
76
+	/* Get current backend state */
77
+	if ( ( state = xenbus_backend_state ( xendev ) ) < 0 ) {
78
+		rc = state;
79
+		DBGC ( netfront, "NETFRONT %s could not read backend state: "
80
+		       "%s\n", xendev->key, strerror ( rc ) );
81
+		return rc;
82
+	}
83
+
84
+	/* If the backend is not already in InitWait, then mark
85
+	 * frontend as Closed to shut down the backend.
86
+	 */
87
+	if ( state != XenbusStateInitWait ) {
88
+
89
+		/* Set state to Closed */
90
+		xenbus_set_state ( xendev, XenbusStateClosed );
91
+
92
+		/* Wait for backend to reach Closed */
93
+		if ( ( rc = xenbus_backend_wait ( xendev,
94
+						  XenbusStateClosed ) ) != 0 ) {
95
+			DBGC ( netfront, "NETFRONT %s backend did not reach "
96
+			       "Closed: %s\n", xendev->key, strerror ( rc ) );
97
+			return rc;
98
+		}
99
+	}
100
+
101
+	/* Reset state to Initialising */
102
+	xenbus_set_state ( xendev, XenbusStateInitialising );
103
+
104
+	/* Wait for backend to reach InitWait */
105
+	if ( ( rc = xenbus_backend_wait ( xendev, XenbusStateInitWait ) ) != 0){
106
+		DBGC ( netfront, "NETFRONT %s backend did not reach InitWait: "
107
+		       "%s\n", xendev->key, strerror ( rc ) );
108
+		return rc;
109
+	}
110
+
111
+	return 0;
112
+}
113
+
65
 /**
114
 /**
66
  * Fetch MAC address
115
  * Fetch MAC address
67
  *
116
  *
510
 	struct xen_device *xendev = netfront->xendev;
559
 	struct xen_device *xendev = netfront->xendev;
511
 	int rc;
560
 	int rc;
512
 
561
 
562
+	/* Ensure device is in a suitable initial state */
563
+	if ( ( rc = netfront_reset ( netfront ) ) != 0 )
564
+		goto err_reset;
565
+
513
 	/* Create transmit descriptor ring */
566
 	/* Create transmit descriptor ring */
514
 	if ( ( rc = netfront_create_ring ( netfront, &netfront->tx ) ) != 0 )
567
 	if ( ( rc = netfront_create_ring ( netfront, &netfront->tx ) ) != 0 )
515
 		goto err_create_tx;
568
 		goto err_create_tx;
563
 	return 0;
616
 	return 0;
564
 
617
 
565
  err_backend_wait:
618
  err_backend_wait:
566
-	xenbus_set_state ( xendev, XenbusStateInitialising );
619
+	netfront_reset ( netfront );
567
  err_set_state:
620
  err_set_state:
568
 	netfront_rm ( netfront, "feature-no-csum-offload" );
621
 	netfront_rm ( netfront, "feature-no-csum-offload" );
569
  err_feature_no_csum_offload:
622
  err_feature_no_csum_offload:
575
  err_create_rx:
628
  err_create_rx:
576
 	netfront_destroy_ring ( netfront, &netfront->tx, NULL );
629
 	netfront_destroy_ring ( netfront, &netfront->tx, NULL );
577
  err_create_tx:
630
  err_create_tx:
631
+ err_reset:
578
 	return rc;
632
 	return rc;
579
 }
633
 }
580
 
634
 
588
 	struct xen_device *xendev = netfront->xendev;
642
 	struct xen_device *xendev = netfront->xendev;
589
 	int rc;
643
 	int rc;
590
 
644
 
591
-	/* Set state to Closed */
592
-	xenbus_set_state ( xendev, XenbusStateClosed );
593
-
594
-	/* Wait for backend to close, thereby ensuring that grant
595
-	 * references are no longer in use, etc.
645
+	/* Reset devic, thereby ensuring that grant references are no
646
+	 * longer in use, etc.
596
 	 */
647
 	 */
597
-	if ( ( rc = xenbus_backend_wait ( xendev, XenbusStateClosed ) ) != 0 ) {
648
+	if ( ( rc = netfront_reset ( netfront ) ) != 0 ) {
598
 		DBGC ( netfront, "NETFRONT %s could not disconnect from "
649
 		DBGC ( netfront, "NETFRONT %s could not disconnect from "
599
 		       "backend: %s\n", xendev->key, strerror ( rc ) );
650
 		       "backend: %s\n", xendev->key, strerror ( rc ) );
600
 		/* Things will probably go _very_ badly wrong if this
651
 		/* Things will probably go _very_ badly wrong if this
609
 		netdev_link_down ( netdev );
660
 		netdev_link_down ( netdev );
610
 	}
661
 	}
611
 
662
 
612
-	/* Reset state to Initialising */
613
-	xenbus_set_state ( xendev, XenbusStateInitialising );
614
-
615
 	/* Delete flags */
663
 	/* Delete flags */
616
 	netfront_rm ( netfront, "feature-no-csum-offload" );
664
 	netfront_rm ( netfront, "feature-no-csum-offload" );
617
 	netfront_rm ( netfront, "request-rx-copy" );
665
 	netfront_rm ( netfront, "request-rx-copy" );
835
 	if ( ( rc = netfront_read_mac ( netfront, netdev->hw_addr ) ) != 0 )
883
 	if ( ( rc = netfront_read_mac ( netfront, netdev->hw_addr ) ) != 0 )
836
 		goto err_read_mac;
884
 		goto err_read_mac;
837
 
885
 
886
+	/* Reset device.  Ignore failures; allow the device to be
887
+	 * registered so that reset errors can be observed by the user
888
+	 * when attempting to open the device.
889
+	 */
890
+	netfront_reset ( netfront );
891
+
838
 	/* Register network device */
892
 	/* Register network device */
839
 	if ( ( rc = register_netdev ( netdev ) ) != 0 )
893
 	if ( ( rc = register_netdev ( netdev ) ) != 0 )
840
 		goto err_register_netdev;
894
 		goto err_register_netdev;

+ 1
- 0
src/include/ipxe/xenbus.h View File

78
 }
78
 }
79
 
79
 
80
 extern int xenbus_set_state ( struct xen_device *xendev, int state );
80
 extern int xenbus_set_state ( struct xen_device *xendev, int state );
81
+extern int xenbus_backend_state ( struct xen_device *xendev );
81
 extern int xenbus_backend_wait ( struct xen_device *xendev, int state );
82
 extern int xenbus_backend_wait ( struct xen_device *xendev, int state );
82
 extern int xenbus_probe ( struct xen_hypervisor *xen, struct device *parent );
83
 extern int xenbus_probe ( struct xen_hypervisor *xen, struct device *parent );
83
 extern void xenbus_remove ( struct xen_hypervisor *xen, struct device *parent );
84
 extern void xenbus_remove ( struct xen_hypervisor *xen, struct device *parent );

+ 1
- 1
src/interface/xen/xenbus.c View File

118
  * @v xendev		Xen device
118
  * @v xendev		Xen device
119
  * @ret state		Backend state, or negative error
119
  * @ret state		Backend state, or negative error
120
  */
120
  */
121
-static int xenbus_backend_state ( struct xen_device *xendev ) {
121
+int xenbus_backend_state ( struct xen_device *xendev ) {
122
 	unsigned long state;
122
 	unsigned long state;
123
 	int rc;
123
 	int rc;
124
 
124
 

Loading…
Cancel
Save