Sfoglia il codice sorgente

[arp] Maintain an ARP transmission queue

Allow packet transmission to be deferred pending successful ARP
resolution.  This avoids the time spent waiting for a higher-level
protocol (e.g. TCP or TFTP) to attempt retransmission.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 12 anni fa
parent
commit
d620606d3e
3 ha cambiato i file con 354 aggiunte e 152 eliminazioni
  1. 3
    5
      src/include/ipxe/arp.h
  2. 313
    101
      src/net/arp.c
  3. 38
    46
      src/net/ipv4.c

+ 3
- 5
src/include/ipxe/arp.h Vedi File

@@ -35,10 +35,8 @@ struct arp_net_protocol {
35 35
 
36 36
 extern struct net_protocol arp_protocol __net_protocol;
37 37
 
38
-extern int arp_resolve ( struct net_device *netdev,
39
-			 struct net_protocol *net_protocol,
40
-			 const void *dest_net_addr,
41
-			 const void *source_net_addr,
42
-			 void *dest_ll_addr );
38
+extern int arp_tx ( struct io_buffer *iobuf, struct net_device *netdev,
39
+		    struct net_protocol *net_protocol, const void *net_dest,
40
+		    const void *net_source, const void *ll_source );
43 41
 
44 42
 #endif /* _IPXE_ARP_H */

+ 313
- 101
src/net/arp.c Vedi File

@@ -19,6 +19,7 @@
19 19
 FILE_LICENCE ( GPL2_OR_LATER );
20 20
 
21 21
 #include <stdint.h>
22
+#include <stdlib.h>
22 23
 #include <string.h>
23 24
 #include <byteswap.h>
24 25
 #include <errno.h>
@@ -26,6 +27,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
26 27
 #include <ipxe/if_arp.h>
27 28
 #include <ipxe/iobuf.h>
28 29
 #include <ipxe/netdevice.h>
30
+#include <ipxe/list.h>
31
+#include <ipxe/retry.h>
32
+#include <ipxe/timer.h>
33
+#include <ipxe/malloc.h>
29 34
 #include <ipxe/arp.h>
30 35
 
31 36
 /** @file
@@ -38,104 +43,263 @@ FILE_LICENCE ( GPL2_OR_LATER );
38 43
  *
39 44
  */
40 45
 
46
+/** ARP minimum timeout */
47
+#define ARP_MIN_TIMEOUT ( TICKS_PER_SEC / 8 )
48
+
49
+/** ARP maximum timeout */
50
+#define ARP_MAX_TIMEOUT ( TICKS_PER_SEC * 3 )
51
+
41 52
 /** An ARP cache entry */
42 53
 struct arp_entry {
54
+	/** List of ARP cache entries */
55
+	struct list_head list;
56
+	/** Network device */
57
+	struct net_device *netdev;
43 58
 	/** Network-layer protocol */
44 59
 	struct net_protocol *net_protocol;
45
-	/** Link-layer protocol */
46
-	struct ll_protocol *ll_protocol;
47
-	/** Network-layer address */
48
-	uint8_t net_addr[MAX_NET_ADDR_LEN];
49
-	/** Link-layer address */
50
-	uint8_t ll_addr[MAX_LL_ADDR_LEN];
60
+	/** Network-layer destination address */
61
+	uint8_t net_dest[MAX_NET_ADDR_LEN];
62
+	/** Network-layer source address */
63
+	uint8_t net_source[MAX_NET_ADDR_LEN];
64
+	/** Link-layer destination address */
65
+	uint8_t ll_dest[MAX_LL_ADDR_LEN];
66
+	/** Retransmission timer */
67
+	struct retry_timer timer;
68
+	/** Pending I/O buffers */
69
+	struct list_head tx_queue;
51 70
 };
52 71
 
53
-/** Number of entries in the ARP cache
72
+/** The ARP cache */
73
+static LIST_HEAD ( arp_entries );
74
+
75
+struct net_protocol arp_protocol __net_protocol;
76
+
77
+static void arp_expired ( struct retry_timer *timer, int over );
78
+
79
+/**
80
+ * Create ARP cache entry
54 81
  *
55
- * This is a global cache, covering all network interfaces,
56
- * network-layer protocols and link-layer protocols.
82
+ * @v netdev		Network device
83
+ * @v net_protocol	Network-layer protocol
84
+ * @v net_dest		Destination network-layer address
85
+ * @v net_source	Source network-layer address
86
+ * @ret arp		ARP cache entry, or NULL if allocation failed
57 87
  */
58
-#define NUM_ARP_ENTRIES 4
88
+static struct arp_entry * arp_create ( struct net_device *netdev,
89
+				       struct net_protocol *net_protocol,
90
+				       const void *net_dest,
91
+				       const void *net_source ) {
92
+	struct arp_entry *arp;
59 93
 
60
-/** The ARP cache */
61
-static struct arp_entry arp_table[NUM_ARP_ENTRIES];
62
-#define arp_table_end &arp_table[NUM_ARP_ENTRIES]
94
+	/* Allocate entry and add to cache */
95
+	arp = zalloc ( sizeof ( *arp ) );
96
+	if ( ! arp )
97
+		return NULL;
63 98
 
64
-static unsigned int next_new_arp_entry = 0;
99
+	/* Initialise entry and add to cache */
100
+	arp->netdev = netdev_get ( netdev );
101
+	arp->net_protocol = net_protocol;
102
+	memcpy ( arp->net_dest, net_dest,
103
+		 net_protocol->net_addr_len );
104
+	memcpy ( arp->net_source, net_source,
105
+		 net_protocol->net_addr_len );
106
+	timer_init ( &arp->timer, arp_expired, NULL );
107
+	arp->timer.min_timeout = ARP_MIN_TIMEOUT;
108
+	arp->timer.max_timeout = ARP_MAX_TIMEOUT;
109
+	INIT_LIST_HEAD ( &arp->tx_queue );
110
+	list_add ( &arp->list, &arp_entries );
65 111
 
66
-struct net_protocol arp_protocol __net_protocol;
112
+	/* Start timer running to trigger initial transmission */
113
+	start_timer_nodelay ( &arp->timer );
114
+
115
+	DBGC ( arp, "ARP %p %s %s %s created\n", arp, netdev->name,
116
+	       net_protocol->name, net_protocol->ntoa ( net_dest ) );
117
+	return arp;
118
+}
67 119
 
68 120
 /**
69 121
  * Find entry in the ARP cache
70 122
  *
71
- * @v ll_protocol	Link-layer protocol
123
+ * @v netdev		Network device
72 124
  * @v net_protocol	Network-layer protocol
73
- * @v net_addr		Network-layer address
125
+ * @v net_dest		Destination network-layer address
74 126
  * @ret arp		ARP cache entry, or NULL if not found
75
- *
76 127
  */
77
-static struct arp_entry *
78
-arp_find_entry ( struct ll_protocol *ll_protocol,
79
-		 struct net_protocol *net_protocol,
80
-		 const void *net_addr ) {
128
+static struct arp_entry * arp_find ( struct net_device *netdev,
129
+				     struct net_protocol *net_protocol,
130
+				     const void *net_dest ) {
81 131
 	struct arp_entry *arp;
82 132
 
83
-	for ( arp = arp_table ; arp < arp_table_end ; arp++ ) {
84
-		if ( ( arp->ll_protocol == ll_protocol ) &&
133
+	list_for_each_entry ( arp, &arp_entries, list ) {
134
+		if ( ( arp->netdev == netdev ) &&
85 135
 		     ( arp->net_protocol == net_protocol ) &&
86
-		     ( memcmp ( arp->net_addr, net_addr,
87
-				net_protocol->net_addr_len ) == 0 ) )
136
+		     ( memcmp ( arp->net_dest, net_dest,
137
+				net_protocol->net_addr_len ) == 0 ) ) {
138
+
139
+			/* Move to start of cache */
140
+			list_del ( &arp->list );
141
+			list_add ( &arp->list, &arp_entries );
142
+
88 143
 			return arp;
144
+		}
89 145
 	}
90 146
 	return NULL;
91 147
 }
92 148
 
93 149
 /**
94
- * Look up media-specific link-layer address in the ARP cache
150
+ * Destroy ARP cache entry
95 151
  *
152
+ * @v arp		ARP cache entry
153
+ * @v rc		Reason for destruction
154
+ */
155
+static void arp_destroy ( struct arp_entry *arp, int rc ) {
156
+	struct net_device *netdev = arp->netdev;
157
+	struct net_protocol *net_protocol = arp->net_protocol;
158
+	struct io_buffer *iobuf;
159
+	struct io_buffer *tmp;
160
+
161
+	/* Stop timer */
162
+	stop_timer ( &arp->timer );
163
+
164
+	/* Discard any outstanding I/O buffers */
165
+	list_for_each_entry_safe ( iobuf, tmp, &arp->tx_queue, list ) {
166
+		DBGC2 ( arp, "ARP %p %s %s %s discarding deferred packet: "
167
+			"%s\n", arp, netdev->name, net_protocol->name,
168
+			net_protocol->ntoa ( arp->net_dest ), strerror ( rc ) );
169
+		list_del ( &iobuf->list );
170
+		netdev_tx_err ( arp->netdev, iobuf, rc );
171
+	}
172
+
173
+	DBGC ( arp, "ARP %p %s %s %s destroyed: %s\n", arp, netdev->name,
174
+	       net_protocol->name, net_protocol->ntoa ( arp->net_dest ),
175
+	       strerror ( rc ) );
176
+
177
+	/* Drop reference to network device, remove from cache and free */
178
+	netdev_put ( arp->netdev );
179
+	list_del ( &arp->list );
180
+	free ( arp );
181
+}
182
+
183
+/**
184
+ * Test if ARP cache entry has a valid link-layer address
185
+ *
186
+ * @v arp		ARP cache entry
187
+ * @ret resolved	ARP cache entry is resolved
188
+ */
189
+static inline int arp_resolved ( struct arp_entry *arp ) {
190
+	return ( ! timer_running ( &arp->timer ) );
191
+}
192
+
193
+/**
194
+ * Transmit packet, determining link-layer address via ARP
195
+ *
196
+ * @v iobuf		I/O buffer
96 197
  * @v netdev		Network device
97 198
  * @v net_protocol	Network-layer protocol
98
- * @v dest_net_addr	Destination network-layer address
99
- * @v source_net_addr	Source network-layer address
100
- * @ret dest_ll_addr	Destination link layer address
199
+ * @v net_dest		Destination network-layer address
200
+ * @v net_source	Source network-layer address
201
+ * @v ll_source		Source link-layer address
101 202
  * @ret rc		Return status code
203
+ */
204
+int arp_tx ( struct io_buffer *iobuf, struct net_device *netdev,
205
+	     struct net_protocol *net_protocol, const void *net_dest,
206
+	     const void *net_source, const void *ll_source ) {
207
+	struct arp_entry *arp;
208
+
209
+	/* Find or create ARP cache entry */
210
+	arp = arp_find ( netdev, net_protocol, net_dest );
211
+	if ( ! arp ) {
212
+		arp = arp_create ( netdev, net_protocol, net_dest,
213
+				   net_source );
214
+		if ( ! arp )
215
+			return -ENOMEM;
216
+	}
217
+
218
+	/* If a link-layer address is available then transmit
219
+	 * immediately, otherwise queue for later transmission.
220
+	 */
221
+	if ( arp_resolved ( arp ) ) {
222
+		return net_tx ( iobuf, netdev, net_protocol, arp->ll_dest,
223
+				ll_source );
224
+	} else {
225
+		DBGC2 ( arp, "ARP %p %s %s %s deferring packet\n",
226
+			arp, netdev->name, net_protocol->name,
227
+			net_protocol->ntoa ( net_dest ) );
228
+		list_add_tail ( &iobuf->list, &arp->tx_queue );
229
+		return -EAGAIN;
230
+	}
231
+}
232
+
233
+/**
234
+ * Update ARP cache entry
102 235
  *
103
- * This function will use the ARP cache to look up the link-layer
104
- * address for the link-layer protocol associated with the network
105
- * device and the given network-layer protocol and addresses.  If
106
- * found, the destination link-layer address will be filled in in @c
107
- * dest_ll_addr.
236
+ * @v arp		ARP cache entry
237
+ * @v ll_dest		Destination link-layer address
238
+ */
239
+static void arp_update ( struct arp_entry *arp, const void *ll_dest ) {
240
+	struct net_device *netdev = arp->netdev;
241
+	struct ll_protocol *ll_protocol = netdev->ll_protocol;
242
+	struct net_protocol *net_protocol = arp->net_protocol;
243
+	struct io_buffer *iobuf;
244
+	struct io_buffer *tmp;
245
+	int rc;
246
+
247
+	DBGC ( arp, "ARP %p %s %s %s updated => %s\n", arp, netdev->name,
248
+	       net_protocol->name, net_protocol->ntoa ( arp->net_dest ),
249
+	       ll_protocol->ntoa ( ll_dest ) );
250
+
251
+	/* Fill in link-layer address */
252
+	memcpy ( arp->ll_dest, ll_dest, ll_protocol->ll_addr_len );
253
+
254
+	/* Stop retransmission timer */
255
+	stop_timer ( &arp->timer );
256
+
257
+	/* Transmit any packets in queue */
258
+	list_for_each_entry_safe ( iobuf, tmp, &arp->tx_queue, list ) {
259
+		DBGC2 ( arp, "ARP %p %s %s %s transmitting deferred packet\n",
260
+			arp, netdev->name, net_protocol->name,
261
+			net_protocol->ntoa ( arp->net_dest ) );
262
+		list_del ( &iobuf->list );
263
+		if ( ( rc = net_tx ( iobuf, netdev, net_protocol, ll_dest,
264
+				     netdev->ll_addr ) ) != 0 ) {
265
+			DBGC ( arp, "ARP %p could not transmit deferred "
266
+			       "packet: %s\n", arp, strerror ( rc ) );
267
+			/* Ignore error and continue */
268
+		}
269
+	}
270
+}
271
+
272
+/**
273
+ * Handle ARP timer expiry
108 274
  *
109
- * If no address is found in the ARP cache, an ARP request will be
110
- * transmitted on the specified network device and -ENOENT will be
111
- * returned.
275
+ * @v timer		Retry timer
276
+ * @v fail		Failure indicator
112 277
  */
113
-int arp_resolve ( struct net_device *netdev, struct net_protocol *net_protocol,
114
-		  const void *dest_net_addr, const void *source_net_addr,
115
-		  void *dest_ll_addr ) {
278
+static void arp_expired ( struct retry_timer *timer, int fail ) {
279
+	struct arp_entry *arp = container_of ( timer, struct arp_entry, timer );
280
+	struct net_device *netdev = arp->netdev;
116 281
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
117
-	const struct arp_entry *arp;
282
+	struct net_protocol *net_protocol = arp->net_protocol;
118 283
 	struct io_buffer *iobuf;
119 284
 	struct arphdr *arphdr;
120 285
 	int rc;
121 286
 
122
-	/* Look for existing entry in ARP table */
123
-	arp = arp_find_entry ( ll_protocol, net_protocol, dest_net_addr );
124
-	if ( arp ) {
125
-		DBG ( "ARP cache hit: %s %s => %s %s\n",
126
-		      net_protocol->name, net_protocol->ntoa ( arp->net_addr ),
127
-		      ll_protocol->name, ll_protocol->ntoa ( arp->ll_addr ) );
128
-		memcpy ( dest_ll_addr, arp->ll_addr, ll_protocol->ll_addr_len);
129
-		return 0;
287
+	/* If we have failed, destroy the cache entry */
288
+	if ( fail ) {
289
+		arp_destroy ( arp, -ETIMEDOUT );
290
+		return;
130 291
 	}
131
-	DBG ( "ARP cache miss: %s %s\n", net_protocol->name,
132
-	      net_protocol->ntoa ( dest_net_addr ) );
292
+
293
+	/* Restart the timer */
294
+	start_timer ( &arp->timer );
133 295
 
134 296
 	/* Allocate ARP packet */
135 297
 	iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *arphdr ) +
136
-			  2 * ( MAX_LL_ADDR_LEN + MAX_NET_ADDR_LEN ) );
137
-	if ( ! iobuf )
138
-		return -ENOMEM;
298
+			    ( 2 * ( MAX_LL_ADDR_LEN + MAX_NET_ADDR_LEN ) ) );
299
+	if ( ! iobuf ) {
300
+		/* Leave timer running and try again later */
301
+		return;
302
+	}
139 303
 	iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
140 304
 
141 305
 	/* Build up ARP request */
@@ -148,18 +312,19 @@ int arp_resolve ( struct net_device *netdev, struct net_protocol *net_protocol,
148 312
 	memcpy ( iob_put ( iobuf, ll_protocol->ll_addr_len ),
149 313
 		 netdev->ll_addr, ll_protocol->ll_addr_len );
150 314
 	memcpy ( iob_put ( iobuf, net_protocol->net_addr_len ),
151
-		 source_net_addr, net_protocol->net_addr_len );
315
+		 arp->net_source, net_protocol->net_addr_len );
152 316
 	memset ( iob_put ( iobuf, ll_protocol->ll_addr_len ),
153 317
 		 0, ll_protocol->ll_addr_len );
154 318
 	memcpy ( iob_put ( iobuf, net_protocol->net_addr_len ),
155
-		 dest_net_addr, net_protocol->net_addr_len );
319
+		 arp->net_dest, net_protocol->net_addr_len );
156 320
 
157 321
 	/* Transmit ARP request */
158 322
 	if ( ( rc = net_tx ( iobuf, netdev, &arp_protocol,
159
-			     netdev->ll_broadcast, netdev->ll_addr ) ) != 0 )
160
-		return rc;
161
-
162
-	return -ENOENT;
323
+			     netdev->ll_broadcast, netdev->ll_addr ) ) != 0 ) {
324
+		DBGC ( arp, "ARP %p could not transmit request: %s\n",
325
+		       arp, strerror ( rc ) );
326
+		return;
327
+	}
163 328
 }
164 329
 
165 330
 /**
@@ -188,12 +353,6 @@ static struct arp_net_protocol * arp_find_protocol ( uint16_t net_proto ) {
188 353
  * @v ll_source		Link-layer source address
189 354
  * @v flags		Packet flags
190 355
  * @ret rc		Return status code
191
- *
192
- * This handles ARP requests and responses as detailed in RFC826.  The
193
- * method detailed within the RFC is pretty optimised, handling
194
- * requests and responses with basically a single code path and
195
- * avoiding the need for extraneous ARP requests; read the RFC for
196
- * details.
197 356
  */
198 357
 static int arp_rx ( struct io_buffer *iobuf, struct net_device *netdev,
199 358
 		    const void *ll_dest __unused,
@@ -204,71 +363,68 @@ static int arp_rx ( struct io_buffer *iobuf, struct net_device *netdev,
204 363
 	struct net_protocol *net_protocol;
205 364
 	struct ll_protocol *ll_protocol;
206 365
 	struct arp_entry *arp;
207
-	int merge = 0;
366
+	int rc;
208 367
 
209 368
 	/* Identify network-layer and link-layer protocols */
210 369
 	arp_net_protocol = arp_find_protocol ( arphdr->ar_pro );
211
-	if ( ! arp_net_protocol )
370
+	if ( ! arp_net_protocol ) {
371
+		rc = -EPROTONOSUPPORT;
212 372
 		goto done;
373
+	}
213 374
 	net_protocol = arp_net_protocol->net_protocol;
214 375
 	ll_protocol = netdev->ll_protocol;
215 376
 
216 377
 	/* Sanity checks */
217 378
 	if ( ( arphdr->ar_hrd != ll_protocol->ll_proto ) ||
218 379
 	     ( arphdr->ar_hln != ll_protocol->ll_addr_len ) ||
219
-	     ( arphdr->ar_pln != net_protocol->net_addr_len ) )
380
+	     ( arphdr->ar_pln != net_protocol->net_addr_len ) ) {
381
+		rc = -EINVAL;
220 382
 		goto done;
383
+	}
221 384
 
222 385
 	/* See if we have an entry for this sender, and update it if so */
223
-	arp = arp_find_entry ( ll_protocol, net_protocol,
224
-			       arp_sender_pa ( arphdr ) );
386
+	arp = arp_find ( netdev, net_protocol, arp_sender_pa ( arphdr ) );
225 387
 	if ( arp ) {
226
-		memcpy ( arp->ll_addr, arp_sender_ha ( arphdr ),
227
-			 arphdr->ar_hln );
228
-		merge = 1;
229
-		DBG ( "ARP cache update: %s %s => %s %s\n",
230
-		      net_protocol->name, net_protocol->ntoa ( arp->net_addr ),
231
-		      ll_protocol->name, ll_protocol->ntoa ( arp->ll_addr ) );
388
+		arp_update ( arp, arp_sender_ha ( arphdr ) );
232 389
 	}
233 390
 
234
-	/* See if we own the target protocol address */
235
-	if ( arp_net_protocol->check ( netdev, arp_target_pa ( arphdr ) ) != 0)
391
+	/* If it's not a request, there's nothing more to do */
392
+	if ( arphdr->ar_op != htons ( ARPOP_REQUEST ) ) {
393
+		rc = 0;
236 394
 		goto done;
237
-	
238
-	/* Create new ARP table entry if necessary */
239
-	if ( ! merge ) {
240
-		arp = &arp_table[next_new_arp_entry++ % NUM_ARP_ENTRIES];
241
-		arp->ll_protocol = ll_protocol;
242
-		arp->net_protocol = net_protocol;
243
-		memcpy ( arp->ll_addr, arp_sender_ha ( arphdr ),
244
-			 arphdr->ar_hln );
245
-		memcpy ( arp->net_addr, arp_sender_pa ( arphdr ),
246
-			 arphdr->ar_pln);
247
-		DBG ( "ARP cache add: %s %s => %s %s\n",
248
-		      net_protocol->name, net_protocol->ntoa ( arp->net_addr ),
249
-		      ll_protocol->name, ll_protocol->ntoa ( arp->ll_addr ) );
250 395
 	}
251 396
 
252
-	/* If it's not a request, there's nothing more to do */
253
-	if ( arphdr->ar_op != htons ( ARPOP_REQUEST ) )
397
+	/* See if we own the target protocol address */
398
+	if ( arp_net_protocol->check ( netdev, arp_target_pa ( arphdr ) ) != 0){
399
+		rc = 0;
254 400
 		goto done;
401
+	}
255 402
 
256 403
 	/* Change request to a reply */
257
-	DBG ( "ARP reply: %s %s => %s %s\n", net_protocol->name,
258
-	      net_protocol->ntoa ( arp_target_pa ( arphdr ) ),
259
-	      ll_protocol->name, ll_protocol->ntoa ( netdev->ll_addr ) );
404
+	DBGC ( netdev, "ARP reply %s %s %s => %s %s\n",
405
+	       netdev->name, net_protocol->name,
406
+	       net_protocol->ntoa ( arp_target_pa ( arphdr ) ),
407
+	       ll_protocol->name, ll_protocol->ntoa ( netdev->ll_addr ) );
260 408
 	arphdr->ar_op = htons ( ARPOP_REPLY );
261 409
 	memswap ( arp_sender_ha ( arphdr ), arp_target_ha ( arphdr ),
262 410
 		 arphdr->ar_hln + arphdr->ar_pln );
263 411
 	memcpy ( arp_sender_ha ( arphdr ), netdev->ll_addr, arphdr->ar_hln );
264 412
 
265 413
 	/* Send reply */
266
-	net_tx ( iob_disown ( iobuf ), netdev, &arp_protocol,
267
-		 arp_target_ha ( arphdr ), netdev->ll_addr );
414
+	if ( ( rc = net_tx ( iob_disown ( iobuf ), netdev, &arp_protocol,
415
+			     arp_target_ha ( arphdr ),
416
+			     netdev->ll_addr ) ) != 0 ) {
417
+		DBGC ( netdev, "ARP could not transmit reply via %s: %s\n",
418
+		       netdev->name, strerror ( rc ) );
419
+		goto done;
420
+	}
421
+
422
+	/* Success */
423
+	rc = 0;
268 424
 
269 425
  done:
270 426
 	free_iob ( iobuf );
271
-	return 0;
427
+	return rc;
272 428
 }
273 429
 
274 430
 /**
@@ -290,3 +446,59 @@ struct net_protocol arp_protocol __net_protocol = {
290 446
 	.rx = arp_rx,
291 447
 	.ntoa = arp_ntoa,
292 448
 };
449
+
450
+/**
451
+ * Update ARP cache on network device creation
452
+ *
453
+ * @v netdev		Network device
454
+ */
455
+static int arp_probe ( struct net_device *netdev __unused ) {
456
+	/* Nothing to do */
457
+	return 0;
458
+}
459
+
460
+/**
461
+ * Update ARP cache on network device state change or removal
462
+ *
463
+ * @v netdev		Network device
464
+ */
465
+static void arp_flush ( struct net_device *netdev ) {
466
+	struct arp_entry *arp;
467
+	struct arp_entry *tmp;
468
+
469
+	/* Remove all ARP cache entries when a network device is closed */
470
+	if ( ! netdev_is_open ( netdev ) ) {
471
+		list_for_each_entry_safe ( arp, tmp, &arp_entries, list )
472
+			arp_destroy ( arp, -ENODEV );
473
+	}
474
+}
475
+
476
+/** ARP driver (for net device notifications) */
477
+struct net_driver arp_net_driver __net_driver = {
478
+	.name = "ARP",
479
+	.probe = arp_probe,
480
+	.notify = arp_flush,
481
+	.remove = arp_flush,
482
+};
483
+
484
+/**
485
+ * Discard some cached ARP entries
486
+ *
487
+ * @ret discarded	Number of cached items discarded
488
+ */
489
+static unsigned int arp_discard ( void ) {
490
+	struct arp_entry *arp;
491
+
492
+	/* Drop oldest cache entry, if any */
493
+	list_for_each_entry_reverse ( arp, &arp_entries, list ) {
494
+		arp_destroy ( arp, -ENOBUFS );
495
+		return 1;
496
+	}
497
+
498
+	return 0;
499
+}
500
+
501
+/** ARP cache discarder */
502
+struct cache_discarder arp_cache_discarder __cache_discarder = {
503
+	.discard = arp_discard,
504
+};

+ 38
- 46
src/net/ipv4.c Vedi File

@@ -281,35 +281,6 @@ static uint16_t ipv4_pshdr_chksum ( struct io_buffer *iobuf, uint16_t csum ) {
281 281
 	return tcpip_continue_chksum ( csum, &pshdr, sizeof ( pshdr ) );
282 282
 }
283 283
 
284
-/**
285
- * Determine link-layer address
286
- *
287
- * @v dest		IPv4 destination address
288
- * @v src		IPv4 source address
289
- * @v netmask		IPv4 subnet mask
290
- * @v netdev		Network device
291
- * @v ll_dest		Link-layer destination address buffer
292
- * @ret rc		Return status code
293
- */
294
-static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src,
295
-			  struct in_addr netmask, struct net_device *netdev,
296
-			  uint8_t *ll_dest ) {
297
-	struct ll_protocol *ll_protocol = netdev->ll_protocol;
298
-
299
-	if ( ( ( dest.s_addr ^ INADDR_BROADCAST ) & ~netmask.s_addr ) == 0 ) {
300
-		/* Broadcast address */
301
-		memcpy ( ll_dest, netdev->ll_broadcast,
302
-			 ll_protocol->ll_addr_len );
303
-		return 0;
304
-	} else if ( IN_MULTICAST ( ntohl ( dest.s_addr ) ) ) {
305
-		return ll_protocol->mc_hash ( AF_INET, &dest, ll_dest );
306
-	} else {
307
-		/* Unicast address: resolve via ARP */
308
-		return arp_resolve ( netdev, &ipv4_protocol, &dest,
309
-				     &src, ll_dest );
310
-	}
311
-}
312
-
313 284
 /**
314 285
  * Transmit IP packet
315 286
  *
@@ -335,7 +306,8 @@ static int ipv4_tx ( struct io_buffer *iobuf,
335 306
 	struct ipv4_miniroute *miniroute;
336 307
 	struct in_addr next_hop;
337 308
 	struct in_addr netmask = { .s_addr = 0 };
338
-	uint8_t ll_dest[MAX_LL_ADDR_LEN];
309
+	uint8_t ll_dest_buf[MAX_LL_ADDR_LEN];
310
+	const void *ll_dest;
339 311
 	int rc;
340 312
 
341 313
 	/* Fill up the IP header, except source address */
@@ -373,16 +345,6 @@ static int ipv4_tx ( struct io_buffer *iobuf,
373 345
 			       ( ( netdev->rx_stats.bad & 0xf ) << 4 ) |
374 346
 			       ( ( netdev->rx_stats.good & 0xf ) << 0 ) );
375 347
 
376
-	/* Determine link-layer destination address */
377
-	if ( ( rc = ipv4_ll_addr ( next_hop, iphdr->src, netmask, netdev,
378
-				   ll_dest ) ) != 0 ) {
379
-		DBGC ( sin_dest->sin_addr, "IPv4 has no link-layer address for "
380
-		       "%s: %s\n", inet_ntoa ( next_hop ), strerror ( rc ) );
381
-		/* Record error for diagnosis */
382
-		netdev_tx_err ( netdev, iob_disown ( iobuf ), rc );
383
-		goto err;
384
-	}
385
-
386 348
 	/* Fix up checksums */
387 349
 	if ( trans_csum )
388 350
 		*trans_csum = ipv4_pshdr_chksum ( iobuf, *trans_csum );
@@ -395,12 +357,42 @@ static int ipv4_tx ( struct io_buffer *iobuf,
395 357
 		iphdr->protocol, ntohs ( iphdr->ident ),
396 358
 		ntohs ( iphdr->chksum ) );
397 359
 
398
-	/* Hand off to link layer */
399
-	if ( ( rc = net_tx ( iobuf, netdev, &ipv4_protocol, ll_dest,
400
-			     netdev->ll_addr ) ) != 0 ) {
401
-		DBGC ( sin_dest->sin_addr, "IPv4 could not transmit packet "
402
-		       "via %s: %s\n", netdev->name, strerror ( rc ) );
403
-		return rc;
360
+	/* Calculate link-layer destination address, if possible */
361
+	if ( ( ( next_hop.s_addr ^ INADDR_BROADCAST ) & ~netmask.s_addr ) == 0){
362
+		/* Broadcast address */
363
+		ll_dest = netdev->ll_broadcast;
364
+	} else if ( IN_MULTICAST ( ntohl ( next_hop.s_addr ) ) ) {
365
+		/* Multicast address */
366
+		if ( ( rc = netdev->ll_protocol->mc_hash ( AF_INET, &next_hop,
367
+							   ll_dest_buf ) ) !=0){
368
+			DBGC ( sin_dest->sin_addr, "IPv4 could not hash "
369
+			       "multicast %s: %s\n",
370
+			       inet_ntoa ( next_hop ), strerror ( rc ) );
371
+			return rc;
372
+		}
373
+		ll_dest = ll_dest_buf;
374
+	} else {
375
+		/* Unicast address */
376
+		ll_dest = NULL;
377
+	}
378
+
379
+	/* Hand off to link layer (via ARP if applicable) */
380
+	if ( ll_dest ) {
381
+		if ( ( rc = net_tx ( iobuf, netdev, &ipv4_protocol, ll_dest,
382
+				     netdev->ll_addr ) ) != 0 ) {
383
+			DBGC ( sin_dest->sin_addr, "IPv4 could not transmit "
384
+			       "packet via %s: %s\n",
385
+			       netdev->name, strerror ( rc ) );
386
+			return rc;
387
+		}
388
+	} else {
389
+		if ( ( rc = arp_tx ( iobuf, netdev, &ipv4_protocol, &next_hop,
390
+				     &iphdr->src, netdev->ll_addr ) ) != 0 ) {
391
+			DBGC ( sin_dest->sin_addr, "IPv4 could not transmit "
392
+			       "packet via %s: %s\n",
393
+			       netdev->name, strerror ( rc ) );
394
+			return rc;
395
+		}
404 396
 	}
405 397
 
406 398
 	return 0;

Loading…
Annulla
Salva