Browse Source

[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 13 years ago
parent
commit
d620606d3e
3 changed files with 354 additions and 152 deletions
  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 View File

35
 
35
 
36
 extern struct net_protocol arp_protocol __net_protocol;
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
 #endif /* _IPXE_ARP_H */
42
 #endif /* _IPXE_ARP_H */

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

19
 FILE_LICENCE ( GPL2_OR_LATER );
19
 FILE_LICENCE ( GPL2_OR_LATER );
20
 
20
 
21
 #include <stdint.h>
21
 #include <stdint.h>
22
+#include <stdlib.h>
22
 #include <string.h>
23
 #include <string.h>
23
 #include <byteswap.h>
24
 #include <byteswap.h>
24
 #include <errno.h>
25
 #include <errno.h>
26
 #include <ipxe/if_arp.h>
27
 #include <ipxe/if_arp.h>
27
 #include <ipxe/iobuf.h>
28
 #include <ipxe/iobuf.h>
28
 #include <ipxe/netdevice.h>
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
 #include <ipxe/arp.h>
34
 #include <ipxe/arp.h>
30
 
35
 
31
 /** @file
36
 /** @file
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
 /** An ARP cache entry */
52
 /** An ARP cache entry */
42
 struct arp_entry {
53
 struct arp_entry {
54
+	/** List of ARP cache entries */
55
+	struct list_head list;
56
+	/** Network device */
57
+	struct net_device *netdev;
43
 	/** Network-layer protocol */
58
 	/** Network-layer protocol */
44
 	struct net_protocol *net_protocol;
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
  * Find entry in the ARP cache
121
  * Find entry in the ARP cache
70
  *
122
  *
71
- * @v ll_protocol	Link-layer protocol
123
+ * @v netdev		Network device
72
  * @v net_protocol	Network-layer protocol
124
  * @v net_protocol	Network-layer protocol
73
- * @v net_addr		Network-layer address
125
+ * @v net_dest		Destination network-layer address
74
  * @ret arp		ARP cache entry, or NULL if not found
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
 	struct arp_entry *arp;
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
 		     ( arp->net_protocol == net_protocol ) &&
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
 			return arp;
143
 			return arp;
144
+		}
89
 	}
145
 	}
90
 	return NULL;
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
  * @v netdev		Network device
197
  * @v netdev		Network device
97
  * @v net_protocol	Network-layer protocol
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
  * @ret rc		Return status code
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
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
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
 	struct io_buffer *iobuf;
283
 	struct io_buffer *iobuf;
119
 	struct arphdr *arphdr;
284
 	struct arphdr *arphdr;
120
 	int rc;
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
 	/* Allocate ARP packet */
296
 	/* Allocate ARP packet */
135
 	iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *arphdr ) +
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
 	iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
303
 	iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
140
 
304
 
141
 	/* Build up ARP request */
305
 	/* Build up ARP request */
148
 	memcpy ( iob_put ( iobuf, ll_protocol->ll_addr_len ),
312
 	memcpy ( iob_put ( iobuf, ll_protocol->ll_addr_len ),
149
 		 netdev->ll_addr, ll_protocol->ll_addr_len );
313
 		 netdev->ll_addr, ll_protocol->ll_addr_len );
150
 	memcpy ( iob_put ( iobuf, net_protocol->net_addr_len ),
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
 	memset ( iob_put ( iobuf, ll_protocol->ll_addr_len ),
316
 	memset ( iob_put ( iobuf, ll_protocol->ll_addr_len ),
153
 		 0, ll_protocol->ll_addr_len );
317
 		 0, ll_protocol->ll_addr_len );
154
 	memcpy ( iob_put ( iobuf, net_protocol->net_addr_len ),
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
 	/* Transmit ARP request */
321
 	/* Transmit ARP request */
158
 	if ( ( rc = net_tx ( iobuf, netdev, &arp_protocol,
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
  * @v ll_source		Link-layer source address
353
  * @v ll_source		Link-layer source address
189
  * @v flags		Packet flags
354
  * @v flags		Packet flags
190
  * @ret rc		Return status code
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
 static int arp_rx ( struct io_buffer *iobuf, struct net_device *netdev,
357
 static int arp_rx ( struct io_buffer *iobuf, struct net_device *netdev,
199
 		    const void *ll_dest __unused,
358
 		    const void *ll_dest __unused,
204
 	struct net_protocol *net_protocol;
363
 	struct net_protocol *net_protocol;
205
 	struct ll_protocol *ll_protocol;
364
 	struct ll_protocol *ll_protocol;
206
 	struct arp_entry *arp;
365
 	struct arp_entry *arp;
207
-	int merge = 0;
366
+	int rc;
208
 
367
 
209
 	/* Identify network-layer and link-layer protocols */
368
 	/* Identify network-layer and link-layer protocols */
210
 	arp_net_protocol = arp_find_protocol ( arphdr->ar_pro );
369
 	arp_net_protocol = arp_find_protocol ( arphdr->ar_pro );
211
-	if ( ! arp_net_protocol )
370
+	if ( ! arp_net_protocol ) {
371
+		rc = -EPROTONOSUPPORT;
212
 		goto done;
372
 		goto done;
373
+	}
213
 	net_protocol = arp_net_protocol->net_protocol;
374
 	net_protocol = arp_net_protocol->net_protocol;
214
 	ll_protocol = netdev->ll_protocol;
375
 	ll_protocol = netdev->ll_protocol;
215
 
376
 
216
 	/* Sanity checks */
377
 	/* Sanity checks */
217
 	if ( ( arphdr->ar_hrd != ll_protocol->ll_proto ) ||
378
 	if ( ( arphdr->ar_hrd != ll_protocol->ll_proto ) ||
218
 	     ( arphdr->ar_hln != ll_protocol->ll_addr_len ) ||
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
 		goto done;
382
 		goto done;
383
+	}
221
 
384
 
222
 	/* See if we have an entry for this sender, and update it if so */
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
 	if ( arp ) {
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
 		goto done;
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
 		goto done;
400
 		goto done;
401
+	}
255
 
402
 
256
 	/* Change request to a reply */
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
 	arphdr->ar_op = htons ( ARPOP_REPLY );
408
 	arphdr->ar_op = htons ( ARPOP_REPLY );
261
 	memswap ( arp_sender_ha ( arphdr ), arp_target_ha ( arphdr ),
409
 	memswap ( arp_sender_ha ( arphdr ), arp_target_ha ( arphdr ),
262
 		 arphdr->ar_hln + arphdr->ar_pln );
410
 		 arphdr->ar_hln + arphdr->ar_pln );
263
 	memcpy ( arp_sender_ha ( arphdr ), netdev->ll_addr, arphdr->ar_hln );
411
 	memcpy ( arp_sender_ha ( arphdr ), netdev->ll_addr, arphdr->ar_hln );
264
 
412
 
265
 	/* Send reply */
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
  done:
425
  done:
270
 	free_iob ( iobuf );
426
 	free_iob ( iobuf );
271
-	return 0;
427
+	return rc;
272
 }
428
 }
273
 
429
 
274
 /**
430
 /**
290
 	.rx = arp_rx,
446
 	.rx = arp_rx,
291
 	.ntoa = arp_ntoa,
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 View File

281
 	return tcpip_continue_chksum ( csum, &pshdr, sizeof ( pshdr ) );
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
  * Transmit IP packet
285
  * Transmit IP packet
315
  *
286
  *
335
 	struct ipv4_miniroute *miniroute;
306
 	struct ipv4_miniroute *miniroute;
336
 	struct in_addr next_hop;
307
 	struct in_addr next_hop;
337
 	struct in_addr netmask = { .s_addr = 0 };
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
 	int rc;
311
 	int rc;
340
 
312
 
341
 	/* Fill up the IP header, except source address */
313
 	/* Fill up the IP header, except source address */
373
 			       ( ( netdev->rx_stats.bad & 0xf ) << 4 ) |
345
 			       ( ( netdev->rx_stats.bad & 0xf ) << 4 ) |
374
 			       ( ( netdev->rx_stats.good & 0xf ) << 0 ) );
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
 	/* Fix up checksums */
348
 	/* Fix up checksums */
387
 	if ( trans_csum )
349
 	if ( trans_csum )
388
 		*trans_csum = ipv4_pshdr_chksum ( iobuf, *trans_csum );
350
 		*trans_csum = ipv4_pshdr_chksum ( iobuf, *trans_csum );
395
 		iphdr->protocol, ntohs ( iphdr->ident ),
357
 		iphdr->protocol, ntohs ( iphdr->ident ),
396
 		ntohs ( iphdr->chksum ) );
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
 	return 0;
398
 	return 0;

Loading…
Cancel
Save