Przeglądaj źródła

Added diatribe about the mismatch between the PXE spec and the TFTP

protocol, and how we will work around it.
tags/v0.9.3
Michael Brown 19 lat temu
rodzic
commit
2ffc960e67
1 zmienionych plików z 86 dodań i 19 usunięć
  1. 86
    19
      src/interface/pxe/pxe_tftp.c

+ 86
- 19
src/interface/pxe/pxe_tftp.c Wyświetl plik

@@ -30,14 +30,14 @@
30 30
  * @v tftp_open				Pointer to a struct s_PXENV_TFTP_OPEN
31 31
  * @v s_PXENV_TFTP_OPEN::ServerIPAddress TFTP server IP address
32 32
  * @v s_PXENV_TFTP_OPEN::GatewayIPAddress Relay agent IP address, or 0.0.0.0
33
- * @v s_PXENV_TFTP_OPEN::Filename	Name of file to open
33
+ * @v s_PXENV_TFTP_OPEN::FileName	Name of file to open
34 34
  * @v s_PXENV_TFTP_OPEN::TFTPPort	TFTP server UDP port
35 35
  * @v s_PXENV_TFTP_OPEN::PacketSize	TFTP blksize option to request
36 36
  * @ret #PXENV_EXIT_SUCCESS		File was opened
37 37
  * @ret #PXENV_EXIT_FAILURE		File was not opened
38 38
  * @ret s_PXENV_TFTP_OPEN::Status	PXE status code
39
- * @ret s_PXENV_TFTP_OPEN::PacketSize	Negotiated 
40
- * @err .......				..........
39
+ * @ret s_PXENV_TFTP_OPEN::PacketSize	Negotiated blksize
40
+ * @err #PXENV_STATUS_TFTP_INVALID_PACKET_SIZE Requested blksize too small
41 41
  *
42 42
  * Opens a TFTP connection for downloading a file a block at a time
43 43
  * using pxenv_tftp_read().
@@ -46,11 +46,21 @@
46 46
  * routing will take place.  See the relevant
47 47
  * @ref pxe_routing "implementation note" for more details.
48 48
  *
49
- * s_PXENV_TFTP_OPEN::PacketSize must be at least 512.
49
+ * The blksize negotiated with the TFTP server will be returned in
50
+ * s_PXENV_TFTP_OPEN::PacketSize, and will be the size of data blocks
51
+ * returned by subsequent calls to pxenv_tftp_read().  The TFTP server
52
+ * may negotiate a smaller blksize than the caller requested.
53
+ *
54
+ * Some TFTP servers do not support TFTP options, and will therefore
55
+ * not be able to use anything other than a fixed 512-byte blksize.
56
+ * The PXE specification version 2.1 requires that the caller must
57
+ * pass in s_PXENV_TFTP_OPEN::PacketSize with a value of 512 or
58
+ * greater.
50 59
  *
51 60
  * You can only have one TFTP connection open at a time, because the
52
- * PXE API requires the PXE stack to keep state about the open TFTP
53
- * connection (rather than letting the caller do so).
61
+ * PXE API requires the PXE stack to keep state (e.g. local and remote
62
+ * port numbers, data block index) about the open TFTP connection,
63
+ * rather than letting the caller do so.
54 64
  *
55 65
  * It is unclear precisely what constitutes a "TFTP open" operation.
56 66
  * Clearly, we must send the TFTP open request to the server.  Since
@@ -65,7 +75,15 @@
65 75
  * solution to this problem.
66 76
  *
67 77
  * 
68
-
78
+ * @note If you pass in a value less than 512 for
79
+ * s_PXENV_TFTP_OPEN::PacketSize, Etherboot will attempt to negotiate
80
+ * this blksize with the TFTP server, even though such a value is not
81
+ * permitted according to the PXE specification.  If the TFTP server
82
+ * ends up dictating a blksize larger than the value requested by the
83
+ * caller (which is very probable in the case of a requested blksize
84
+ * less than 512), then Etherboot will return the error
85
+ * #PXENV_STATUS_TFTP_INVALID_PACKET_SIZE.
86
+ *
69 87
  * @note According to the PXE specification version 2.1, this call
70 88
  * "opens a file for reading/writing", though how writing is to be
71 89
  * achieved without the existence of an API call %pxenv_tftp_write()
@@ -253,44 +271,48 @@ file" operations.  The problem is the unreliable nature of UDP
253 271
 transmissions and the lock-step mechanism employed by TFTP to
254 272
 guarantee file transfer.  The lock-step mechanism requires that if we
255 273
 time out waiting for a packet to arrive, we must trigger its
256
-retransmission by retransmitting our previously transmitted packet.
274
+retransmission by retransmitting our own previously transmitted
275
+packet.
257 276
 
258 277
 For example, suppose that pxenv_tftp_read() is called to read the
259 278
 first data block of a file from a server that does not support TFTP
260 279
 options, and that no data block is received within the timeout period.
261
-In order to trigger the retransmission of this data block
280
+In order to trigger the retransmission of this data block,
262 281
 pxenv_tftp_read() must retransmit the TFTP open request.  However, the
263 282
 information used to build the TFTP open request is not available at
264
-this time; it was provided only to the pxenv_tftp_open() call.
283
+this time; it was provided only to the pxenv_tftp_open() call.  Even
284
+if we were able to retransmit a TFTP open request, we would have to
285
+allocate a new local port number (and be prepared for data to arrive
286
+from a new remote port number) in order to avoid violating the TFTP
287
+protocol specification.
265 288
 
266 289
 The question of when to transmit the ACK packets is also awkward.  At
267 290
 a first glance, it would seem to be fairly simple: acknowledge a
268 291
 packet immediately after receiving it.  However, since the ACK packet
269 292
 may itself be lost, the next call to pxenv_tftp_read() must be
270
-prepared to re-acknowledge the packet.
293
+prepared to retransmit the acknowledgement.
271 294
 
272 295
 Another problem to consider is that the pxenv_tftp_open() API call
273 296
 must return an indication of whether or not the TFTP open request
274 297
 succeeded.  In the case of a TFTP server that doesn't support TFTP
275 298
 options, the only indication of a successful open is the reception of
276 299
 the first data block.  However, the pxenv_tftp_open() API provides no
277
-way to return this data block at this time.  Pretending that we lost
278
-the data block and requesting retransmission is problematic, because
279
-the only way to request retransmission of the first data block in such
280
-a case is to reissue the TFTP open request, which has side effects
281
-such as requiring the allocation of a new local port number.
300
+way to return this data block at this time.
282 301
 
283 302
 At least some PXE stacks (e.g. NILO) solve this problem by violating
284 303
 the TFTP protocol and never bothering with retransmissions, relying on
285 304
 the TFTP server to retransmit when it times out waiting for an ACK.
286
-This approach is dubious at best.
305
+This approach is dubious at best; if, for example, the initial TFTP
306
+open request is lost then NILO will believe that it has opened the
307
+file and will eventually time out and give up while waiting for the
308
+first packet to arrive.
287 309
 
288 310
 The only viable solution seems to be to allocate a buffer for the
289 311
 storage of the first data packet returned by the TFTP server, since we
290 312
 may receive this packet during the pxenv_tftp_open() call but have to
291 313
 return it from the subsequent pxenv_tftp_read() call.  This buffer
292 314
 must be statically allocated and must be dedicated to providing a
293
-temporary home to TFTP packets.  There is nothing in the PXE
315
+temporary home for TFTP packets.  There is nothing in the PXE
294 316
 specification that prevents a caller from calling
295 317
 e.g. pxenv_undi_transmit() between calls to the TFTP API, so we cannot
296 318
 use the normal transmit/receive buffer for this purpose.
@@ -334,6 +356,51 @@ acknowledgement packet.)
334 356
 In order to set up this invariant condition for the first call to
335 357
 pxenv_tftp_read(), pxenv_tftp_open() must do the following:
336 358
 
337
-  - 
359
+  - Construct and transmit the TFTP open request.
360
+
361
+  - Retransmit the TFTP open request (using a new local port number as
362
+    necessary) until a response (DATA, OACK, or ERROR) is received.
363
+
364
+  - If the response is an OACK, acknowledge the OACK and retransmit
365
+    the acknowledgement until the first DATA packet arrives.
366
+
367
+  - If we have a DATA packet, store it in a buffer ready for the first
368
+    call to pxenv_tftp_read().
369
+
370
+This approach has the advantage of being fully compliant with both
371
+RFC1350 (TFTP) and RFC2347 (TFTP options).  It avoids unnecessary
372
+retransmissions.  The cost is approximately 1500 bytes of
373
+uninitialised storage.  Since there is demonstrably no way to avoid
374
+paying this cost without either violating the protocol specifications
375
+or introducing unnecessary retransmissions, we deem this to be a cost
376
+worth paying.
377
+
378
+A small performance gain may be obtained by adding a single extra
379
+"send ACK" in both pxenv_tftp_open() and pxenv_tftp_read() immediately
380
+after receiving the DATA packet and copying it into the internal
381
+buffer.   The sequence of events for pxenv_tftp_read() then becomes:
382
+
383
+  - Copy the data packet from our buffer to the caller's buffer.
384
+
385
+  - If this was the last data packet, return immediately.
386
+
387
+  - Check to see if a TFTP data packet is waiting.  If not, send an
388
+    ACK for the data packet that we have just copied, and retransmit
389
+    this ACK until the next data packet arrives.
390
+
391
+  - Copy the packet into our internal buffer, ready for the next call
392
+    to pxenv_tftp_read().
393
+
394
+  - Send a single ACK for this data packet.
395
+
396
+Sending the ACK at this point allows the server to transmit the next
397
+data block while our caller is processing the current packet.  If this
398
+ACK is lost, or the DATA packet it triggers is lost or is consumed by
399
+something other than pxenv_tftp_read() (e.g. by calls to
400
+pxenv_undi_isr()), then the next call to pxenv_tftp_read() will not
401
+find a TFTP data packet waiting and will retransmit the ACK anyway.
402
+
403
+Note to future API designers at Intel: try to understand the
404
+underlying network protocol first!
338 405
 
339 406
 */

Ładowanie…
Anuluj
Zapisz