소스 검색

[aoe] Use an AoE config query to identify the target MAC address

The AoE spec does not specify that the source MAC address of a
received packet actually matches the MAC address of the AoE target.
In principle an AoE server can respond to an AoE request on any
interface available to it, which may not be an address configured to
accept AoE requests.

This issue is resolved by implementing AoE device discovery.  The
purpose of AoE discovery is to find out which addresses an AoE target
can use for requests.  An AoE configuration command is sent when the
AoE attach is attempted.  The AoE target must respond to that
configuration query from an interface that can accept requests.

Based on a patch from Ryan Thomas <ryan@coraid.com>
tags/v0.9.6
Michael Brown 15 년 전
부모
커밋
246ddf5ee4
2개의 변경된 파일173개의 추가작업 그리고 56개의 파일을 삭제
  1. 28
    5
      src/include/gpxe/aoe.h
  2. 145
    51
      src/net/aoe.c

+ 28
- 5
src/include/gpxe/aoe.h 파일 보기

13
 #include <gpxe/retry.h>
13
 #include <gpxe/retry.h>
14
 #include <gpxe/ata.h>
14
 #include <gpxe/ata.h>
15
 
15
 
16
+/** An AoE config command */
17
+struct aoecfg {
18
+	/** AoE Queue depth */
19
+	uint16_t bufcnt;
20
+	/** ATA target firmware version */
21
+	uint16_t fwver;
22
+	/** ATA target sector count */
23
+	uint8_t scnt;
24
+	/** AoE config string subcommand */
25
+	uint8_t aoeccmd;
26
+	/** AoE config string length */
27
+	uint16_t cfglen;
28
+	/** AoE config string */
29
+	uint8_t data[0];
30
+} __attribute__ (( packed ));
31
+
16
 /** An AoE ATA command */
32
 /** An AoE ATA command */
17
-struct aoecmd {
33
+struct aoeata {
18
 	/** AoE command flags */
34
 	/** AoE command flags */
19
 	uint8_t aflags;
35
 	uint8_t aflags;
20
 	/** ATA error/feature register */
36
 	/** ATA error/feature register */
37
 #define AOE_FL_ASYNC	0x02	/**< Asynchronous write */
53
 #define AOE_FL_ASYNC	0x02	/**< Asynchronous write */
38
 #define AOE_FL_WRITE	0x01	/**< Write command */
54
 #define AOE_FL_WRITE	0x01	/**< Write command */
39
 
55
 
56
+/** An AoE command */
57
+union aoecmd {
58
+	/** Config command */
59
+	struct aoecfg cfg;
60
+	/** ATA command */
61
+	struct aoeata ata;
62
+};
63
+
40
 /** An AoE header */
64
 /** An AoE header */
41
 struct aoehdr {
65
 struct aoehdr {
42
 	/** Protocol version number and flags */
66
 	/** Protocol version number and flags */
52
 	/** Tag, in network byte order */
76
 	/** Tag, in network byte order */
53
 	uint32_t tag;
77
 	uint32_t tag;
54
 	/** Payload */
78
 	/** Payload */
55
-	union {
56
-		/** ATA command */
57
-		struct aoecmd command[0];
58
-	} arg;
79
+	union aoecmd cmd[0];
59
 } __attribute__ (( packed ));
80
 } __attribute__ (( packed ));
60
 
81
 
61
 #define AOE_VERSION	0x10	/**< Version 1 */
82
 #define AOE_VERSION	0x10	/**< Version 1 */
99
 	/** Tag for current AoE command */
120
 	/** Tag for current AoE command */
100
 	uint32_t tag;
121
 	uint32_t tag;
101
 
122
 
123
+	/** Current AOE command */
124
+	uint8_t aoe_cmd_type;
102
 	/** Current ATA command */
125
 	/** Current ATA command */
103
 	struct ata_command *command;
126
 	struct ata_command *command;
104
 	/** Overall status of current ATA command */
127
 	/** Overall status of current ATA command */

+ 145
- 51
src/net/aoe.c 파일 보기

64
 static void aoe_done ( struct aoe_session *aoe, int rc ) {
64
 static void aoe_done ( struct aoe_session *aoe, int rc ) {
65
 
65
 
66
 	/* Record overall command status */
66
 	/* Record overall command status */
67
-	aoe->command->cb.cmd_stat = aoe->status;
68
-	aoe->command = NULL;
67
+	if ( aoe->command ) {
68
+		aoe->command->cb.cmd_stat = aoe->status;
69
+		aoe->command = NULL;
70
+	}
71
+
72
+	/* Stop retransmission timer */
73
+	stop_timer ( &aoe->timer );
69
 
74
 
70
 	/* Mark operation as complete */
75
 	/* Mark operation as complete */
71
 	aoe->rc = rc;
76
 	aoe->rc = rc;
84
 	struct ata_command *command = aoe->command;
89
 	struct ata_command *command = aoe->command;
85
 	struct io_buffer *iobuf;
90
 	struct io_buffer *iobuf;
86
 	struct aoehdr *aoehdr;
91
 	struct aoehdr *aoehdr;
87
-	struct aoecmd *aoecmd;
92
+	union aoecmd *aoecmd;
93
+	struct aoeata *aoeata;
88
 	unsigned int count;
94
 	unsigned int count;
89
 	unsigned int data_out_len;
95
 	unsigned int data_out_len;
96
+	unsigned int aoecmdlen;
90
 
97
 
91
 	/* Fail immediately if we have no netdev to send on */
98
 	/* Fail immediately if we have no netdev to send on */
92
 	if ( ! aoe->netdev ) {
99
 	if ( ! aoe->netdev ) {
102
 	start_timer ( &aoe->timer );
109
 	start_timer ( &aoe->timer );
103
 
110
 
104
 	/* Calculate count and data_out_len for this subcommand */
111
 	/* Calculate count and data_out_len for this subcommand */
105
-	count = command->cb.count.native;
106
-	if ( count > AOE_MAX_COUNT )
107
-		count = AOE_MAX_COUNT;
108
-	data_out_len = ( command->data_out ? ( count * ATA_SECTOR_SIZE ) : 0 );
112
+	switch ( aoe->aoe_cmd_type ) {
113
+	case AOE_CMD_ATA:
114
+		count = command->cb.count.native;
115
+		if ( count > AOE_MAX_COUNT )
116
+			count = AOE_MAX_COUNT;
117
+		data_out_len = ( command->data_out ?
118
+				 ( count * ATA_SECTOR_SIZE ) : 0 );
119
+		aoecmdlen = sizeof ( aoecmd->ata );
120
+		break;
121
+	case AOE_CMD_CONFIG:
122
+		count = 0;
123
+		data_out_len = 0;
124
+		aoecmdlen = sizeof ( aoecmd->cfg );
125
+		break;
126
+	default:
127
+		return -ENOTSUP;
128
+	}
109
 
129
 
110
 	/* Create outgoing I/O buffer */
130
 	/* Create outgoing I/O buffer */
111
 	iobuf = alloc_iob ( ETH_HLEN + sizeof ( *aoehdr ) +
131
 	iobuf = alloc_iob ( ETH_HLEN + sizeof ( *aoehdr ) +
112
-			    sizeof ( *aoecmd ) + data_out_len );
132
+			    aoecmdlen + data_out_len );
133
+
113
 	if ( ! iobuf )
134
 	if ( ! iobuf )
114
 		return -ENOMEM;
135
 		return -ENOMEM;
115
 	iob_reserve ( iobuf, ETH_HLEN );
136
 	iob_reserve ( iobuf, ETH_HLEN );
116
 	aoehdr = iob_put ( iobuf, sizeof ( *aoehdr ) );
137
 	aoehdr = iob_put ( iobuf, sizeof ( *aoehdr ) );
117
-	aoecmd = iob_put ( iobuf, sizeof ( *aoecmd ) );
118
-	memset ( aoehdr, 0, ( sizeof ( *aoehdr ) + sizeof ( *aoecmd ) ) );
138
+	aoecmd = iob_put ( iobuf, aoecmdlen );
139
+	memset ( aoehdr, 0, ( sizeof ( *aoehdr ) + aoecmdlen ) );
119
 
140
 
120
 	/* Fill AoE header */
141
 	/* Fill AoE header */
121
 	aoehdr->ver_flags = AOE_VERSION;
142
 	aoehdr->ver_flags = AOE_VERSION;
122
 	aoehdr->major = htons ( aoe->major );
143
 	aoehdr->major = htons ( aoe->major );
123
 	aoehdr->minor = aoe->minor;
144
 	aoehdr->minor = aoe->minor;
145
+	aoehdr->command = aoe->aoe_cmd_type;
124
 	aoehdr->tag = htonl ( ++aoe->tag );
146
 	aoehdr->tag = htonl ( ++aoe->tag );
125
 
147
 
126
-	/* Fill AoE command */
127
-	linker_assert ( AOE_FL_DEV_HEAD	== ATA_DEV_SLAVE, __fix_ata_h__ );
128
-	aoecmd->aflags = ( ( command->cb.lba48 ? AOE_FL_EXTENDED : 0 ) |
129
-			   ( command->cb.device & ATA_DEV_SLAVE ) |
130
-			   ( data_out_len ? AOE_FL_WRITE : 0 ) );
131
-	aoecmd->err_feat = command->cb.err_feat.bytes.cur;
132
-	aoecmd->count = count;
133
-	aoecmd->cmd_stat = command->cb.cmd_stat;
134
-	aoecmd->lba.u64 = cpu_to_le64 ( command->cb.lba.native );
135
-	if ( ! command->cb.lba48 )
136
-		aoecmd->lba.bytes[3] |= ( command->cb.device & ATA_DEV_MASK );
137
-
138
-	/* Fill data payload */
139
-	copy_from_user ( iob_put ( iobuf, data_out_len ), command->data_out,
140
-			 aoe->command_offset, data_out_len );
148
+	/* Fill AoE payload */
149
+	switch ( aoe->aoe_cmd_type ) {
150
+	case AOE_CMD_ATA:
151
+		/* Fill AoE command */
152
+		aoeata = &aoecmd->ata;
153
+		linker_assert ( AOE_FL_DEV_HEAD	== ATA_DEV_SLAVE,
154
+				__fix_ata_h__ );
155
+		aoeata->aflags = ( ( command->cb.lba48 ? AOE_FL_EXTENDED : 0 )|
156
+				   ( command->cb.device & ATA_DEV_SLAVE ) |
157
+				   ( data_out_len ? AOE_FL_WRITE : 0 ) );
158
+		aoeata->err_feat = command->cb.err_feat.bytes.cur;
159
+		aoeata->count = count;
160
+		aoeata->cmd_stat = command->cb.cmd_stat;
161
+		aoeata->lba.u64 = cpu_to_le64 ( command->cb.lba.native );
162
+		if ( ! command->cb.lba48 )
163
+			aoeata->lba.bytes[3] |=
164
+				( command->cb.device & ATA_DEV_MASK );
165
+
166
+		/* Fill data payload */
167
+		copy_from_user ( iob_put ( iobuf, data_out_len ),
168
+				 command->data_out, aoe->command_offset,
169
+				 data_out_len );
170
+		break;
171
+	case AOE_CMD_CONFIG:
172
+		/* Nothing to do */
173
+		break;
174
+	default:
175
+		assert ( 0 );
176
+	}
141
 
177
 
142
 	/* Send packet */
178
 	/* Send packet */
143
 	return net_tx ( iobuf, aoe->netdev, &aoe_protocol, aoe->target );
179
 	return net_tx ( iobuf, aoe->netdev, &aoe_protocol, aoe->target );
161
 }
197
 }
162
 
198
 
163
 /**
199
 /**
164
- * Handle AoE response
200
+ * Handle AoE configuration command response
201
+ *
202
+ * @v aoe		AoE session
203
+ * @v ll_source		Link-layer source address
204
+ * @ret rc		Return status code
205
+ */
206
+static int aoe_rx_cfg ( struct aoe_session *aoe, const void *ll_source ) {
207
+
208
+	/* Record target MAC address */
209
+	memcpy ( aoe->target, ll_source, sizeof ( aoe->target ) );
210
+	DBGC ( aoe, "AoE %p target MAC address %s\n",
211
+	       aoe, eth_ntoa ( aoe->target ) );
212
+
213
+	/* Mark config request as complete */
214
+	aoe_done ( aoe, 0 );
215
+
216
+	return 0;
217
+}
218
+
219
+/**
220
+ * Handle AoE ATA command response
165
  *
221
  *
166
  * @v aoe		AoE session
222
  * @v aoe		AoE session
167
- * @v aoehdr		AoE header
223
+ * @v aoeata		AoE ATA command
224
+ * @v len		Length of AoE ATA command
168
  * @ret rc		Return status code
225
  * @ret rc		Return status code
169
  */
226
  */
170
-static int aoe_rx_response ( struct aoe_session *aoe, struct aoehdr *aoehdr,
171
-			     unsigned int len ) {
172
-	struct aoecmd *aoecmd = aoehdr->arg.command;
227
+static int aoe_rx_ata ( struct aoe_session *aoe, struct aoeata *aoeata,
228
+			size_t len ) {
173
 	struct ata_command *command = aoe->command;
229
 	struct ata_command *command = aoe->command;
174
 	unsigned int rx_data_len;
230
 	unsigned int rx_data_len;
175
 	unsigned int count;
231
 	unsigned int count;
176
 	unsigned int data_len;
232
 	unsigned int data_len;
177
-	
233
+
178
 	/* Sanity check */
234
 	/* Sanity check */
179
-	if ( len < ( sizeof ( *aoehdr ) + sizeof ( *aoecmd ) ) ) {
235
+	if ( len < sizeof ( *aoeata ) ) {
180
 		/* Ignore packet; allow timer to trigger retransmit */
236
 		/* Ignore packet; allow timer to trigger retransmit */
181
 		return -EINVAL;
237
 		return -EINVAL;
182
 	}
238
 	}
183
-	rx_data_len = ( len - sizeof ( *aoehdr ) - sizeof ( *aoecmd ) );
184
-
185
-	/* Stop retry timer.  After this point, every code path must
186
-	 * either terminate the AoE operation via aoe_done(), or
187
-	 * transmit a new packet.
188
-	 */
189
-	stop_timer ( &aoe->timer );
190
-
191
-	/* Check for fatal errors */
192
-	if ( aoehdr->ver_flags & AOE_FL_ERROR ) {
193
-		aoe_done ( aoe, -EIO );
194
-		return 0;
195
-	}
239
+	rx_data_len = ( len - sizeof ( *aoeata ) );
196
 
240
 
197
 	/* Calculate count and data_len for this subcommand */
241
 	/* Calculate count and data_len for this subcommand */
198
 	count = command->cb.count.native;
242
 	count = command->cb.count.native;
201
 	data_len = count * ATA_SECTOR_SIZE;
245
 	data_len = count * ATA_SECTOR_SIZE;
202
 
246
 
203
 	/* Merge into overall ATA status */
247
 	/* Merge into overall ATA status */
204
-	aoe->status |= aoecmd->cmd_stat;
248
+	aoe->status |= aoeata->cmd_stat;
205
 
249
 
206
 	/* Copy data payload */
250
 	/* Copy data payload */
207
 	if ( command->data_in ) {
251
 	if ( command->data_in ) {
208
 		if ( rx_data_len > data_len )
252
 		if ( rx_data_len > data_len )
209
 			rx_data_len = data_len;
253
 			rx_data_len = data_len;
210
 		copy_to_user ( command->data_in, aoe->command_offset,
254
 		copy_to_user ( command->data_in, aoe->command_offset,
211
-			       aoecmd->data, rx_data_len );
255
+			       aoeata->data, rx_data_len );
212
 	}
256
 	}
213
 
257
 
214
 	/* Update ATA command and offset */
258
 	/* Update ATA command and offset */
223
 	}
267
 	}
224
 
268
 
225
 	/* Transmit next portion of request */
269
 	/* Transmit next portion of request */
270
+	stop_timer ( &aoe->timer );
226
 	aoe_send_command ( aoe );
271
 	aoe_send_command ( aoe );
227
 
272
 
228
 	return 0;
273
 	return 0;
241
 		    struct net_device *netdev __unused,
286
 		    struct net_device *netdev __unused,
242
 		    const void *ll_source ) {
287
 		    const void *ll_source ) {
243
 	struct aoehdr *aoehdr = iobuf->data;
288
 	struct aoehdr *aoehdr = iobuf->data;
244
-	unsigned int len = iob_len ( iobuf );
245
 	struct aoe_session *aoe;
289
 	struct aoe_session *aoe;
246
 	int rc = 0;
290
 	int rc = 0;
247
 
291
 
248
 	/* Sanity checks */
292
 	/* Sanity checks */
249
-	if ( len < sizeof ( *aoehdr ) ) {
293
+	if ( iob_len ( iobuf ) < sizeof ( *aoehdr ) ) {
250
 		rc = -EINVAL;
294
 		rc = -EINVAL;
251
 		goto done;
295
 		goto done;
252
 	}
296
 	}
258
 		/* Ignore AoE requests that we happen to see */
302
 		/* Ignore AoE requests that we happen to see */
259
 		goto done;
303
 		goto done;
260
 	}
304
 	}
305
+	iob_pull ( iobuf, sizeof ( *aoehdr ) );
261
 
306
 
262
 	/* Demultiplex amongst active AoE sessions */
307
 	/* Demultiplex amongst active AoE sessions */
263
 	list_for_each_entry ( aoe, &aoe_sessions, list ) {
308
 	list_for_each_entry ( aoe, &aoe_sessions, list ) {
267
 			continue;
312
 			continue;
268
 		if ( ntohl ( aoehdr->tag ) != aoe->tag )
313
 		if ( ntohl ( aoehdr->tag ) != aoe->tag )
269
 			continue;
314
 			continue;
270
-		memcpy ( aoe->target, ll_source, sizeof ( aoe->target ) );
271
-		rc = aoe_rx_response ( aoe, aoehdr, len );
315
+		if ( aoehdr->ver_flags & AOE_FL_ERROR ) {
316
+			aoe_done ( aoe, -EIO );
317
+			break;
318
+		}
319
+		switch ( aoehdr->command ) {
320
+		case AOE_CMD_ATA:
321
+			rc = aoe_rx_ata ( aoe, iobuf->data, iob_len ( iobuf ));
322
+			break;
323
+		case AOE_CMD_CONFIG:
324
+			rc = aoe_rx_cfg ( aoe, ll_source );
325
+			break;
326
+		default:
327
+			DBGC ( aoe, "AoE %p ignoring command %02x\n",
328
+			       aoe, aoehdr->command );
329
+			break;
330
+		}
272
 		break;
331
 		break;
273
 	}
332
 	}
274
 
333
 
300
 	aoe->command = command;
359
 	aoe->command = command;
301
 	aoe->status = 0;
360
 	aoe->status = 0;
302
 	aoe->command_offset = 0;
361
 	aoe->command_offset = 0;
362
+	aoe->aoe_cmd_type = AOE_CMD_ATA;
363
+
364
+	aoe_send_command ( aoe );
365
+
366
+	aoe->rc = -EINPROGRESS;
367
+	while ( aoe->rc == -EINPROGRESS )
368
+		step();
369
+	rc = aoe->rc;
370
+
371
+	return rc;
372
+}
373
+
374
+
375
+/**
376
+ * Issue AoE config query for AoE target discovery
377
+ *
378
+ * @v aoe		AoE session
379
+ * @ret rc		Return status code
380
+ */
381
+static int aoe_discover ( struct aoe_session *aoe ) {
382
+	int rc;
383
+
384
+	aoe->status = 0;
385
+	aoe->aoe_cmd_type = AOE_CMD_CONFIG;
386
+	aoe->command = NULL;
387
+
303
 	aoe_send_command ( aoe );
388
 	aoe_send_command ( aoe );
304
 
389
 
305
 	aoe->rc = -EINPROGRESS;
390
 	aoe->rc = -EINPROGRESS;
374
 	ata->backend = ref_get ( &aoe->refcnt );
459
 	ata->backend = ref_get ( &aoe->refcnt );
375
 	ata->command = aoe_command;
460
 	ata->command = aoe_command;
376
 	list_add ( &aoe->list, &aoe_sessions );
461
 	list_add ( &aoe->list, &aoe_sessions );
462
+
463
+	/* Send discovery packet to find the target MAC address.
464
+	 * Ideally, this ought to be done asynchronously, but the
465
+	 * block device interface does not yet support asynchronous
466
+	 * operation.
467
+	 */
468
+	if ( ( rc = aoe_discover( aoe ) ) != 0 )
469
+	       goto err;
470
+
377
 	return 0;
471
 	return 0;
378
 
472
 
379
  err:
473
  err:

Loading…
취소
저장