Browse Source

[neighbour] Generalise concept of neighbour discovery

Split the protocol-independent portions of arp.c into a separate file
neighbour.c, to allow for sharing of functionality between IPv4+ARP
and IPv6+NDP.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 11 years ago
parent
commit
c6a04085d2
5 changed files with 579 additions and 357 deletions
  1. 21
    3
      src/include/ipxe/arp.h
  2. 1
    0
      src/include/ipxe/errfile.h
  3. 44
    0
      src/include/ipxe/neighbour.h
  4. 34
    354
      src/net/arp.c
  5. 479
    0
      src/net/neighbour.c

+ 21
- 3
src/include/ipxe/arp.h View File

11
 
11
 
12
 #include <ipxe/tables.h>
12
 #include <ipxe/tables.h>
13
 #include <ipxe/netdevice.h>
13
 #include <ipxe/netdevice.h>
14
+#include <ipxe/neighbour.h>
14
 
15
 
15
 /** A network-layer protocol that relies upon ARP */
16
 /** A network-layer protocol that relies upon ARP */
16
 struct arp_net_protocol {
17
 struct arp_net_protocol {
34
 #define __arp_net_protocol __table_entry ( ARP_NET_PROTOCOLS, 01 )
35
 #define __arp_net_protocol __table_entry ( ARP_NET_PROTOCOLS, 01 )
35
 
36
 
36
 extern struct net_protocol arp_protocol __net_protocol;
37
 extern struct net_protocol arp_protocol __net_protocol;
38
+extern struct neighbour_discovery arp_discovery;
37
 
39
 
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 );
40
+/**
41
+ * Transmit packet, determining link-layer address via ARP
42
+ *
43
+ * @v iobuf		I/O buffer
44
+ * @v netdev		Network device
45
+ * @v net_protocol	Network-layer protocol
46
+ * @v net_dest		Destination network-layer address
47
+ * @v net_source	Source network-layer address
48
+ * @v ll_source		Source link-layer address
49
+ * @ret rc		Return status code
50
+ */
51
+static inline int arp_tx ( struct io_buffer *iobuf, struct net_device *netdev,
52
+			   struct net_protocol *net_protocol,
53
+			   const void *net_dest, const void *net_source,
54
+			   const void *ll_source ) {
55
+
56
+	return neighbour_tx ( iobuf, netdev, net_protocol, net_dest,
57
+			      &arp_discovery, net_source, ll_source );
58
+}
41
 
59
 
42
 #endif /* _IPXE_ARP_H */
60
 #endif /* _IPXE_ARP_H */

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

214
 #define ERRFILE_nfs_open		( ERRFILE_NET | 0x00340000 )
214
 #define ERRFILE_nfs_open		( ERRFILE_NET | 0x00340000 )
215
 #define ERRFILE_mount			( ERRFILE_NET | 0x00350000 )
215
 #define ERRFILE_mount			( ERRFILE_NET | 0x00350000 )
216
 #define ERRFILE_oncrpc_iob		( ERRFILE_NET | 0x00360000 )
216
 #define ERRFILE_oncrpc_iob		( ERRFILE_NET | 0x00360000 )
217
+#define ERRFILE_neighbour		( ERRFILE_NET | 0x00370000 )
217
 
218
 
218
 #define ERRFILE_image		      ( ERRFILE_IMAGE | 0x00000000 )
219
 #define ERRFILE_image		      ( ERRFILE_IMAGE | 0x00000000 )
219
 #define ERRFILE_elf		      ( ERRFILE_IMAGE | 0x00010000 )
220
 #define ERRFILE_elf		      ( ERRFILE_IMAGE | 0x00010000 )

+ 44
- 0
src/include/ipxe/neighbour.h View File

1
+#ifndef _IPXE_NEIGHBOUR_H
2
+#define _IPXE_NEIGHBOUR_H
3
+
4
+/** @file
5
+ *
6
+ * Neighbour discovery
7
+ *
8
+ */
9
+
10
+FILE_LICENCE ( GPL2_OR_LATER );
11
+
12
+#include <ipxe/netdevice.h>
13
+
14
+/** A neighbour discovery protocol */
15
+struct neighbour_discovery {
16
+	/** Name */
17
+	const char *name;
18
+	/**
19
+	 * Transmit neighbour discovery request
20
+	 *
21
+	 * @v netdev		Network device
22
+	 * @v net_protocol	Network-layer protocol
23
+	 * @v net_dest		Destination network-layer address
24
+	 * @v net_source	Source network-layer address
25
+	 * @ret rc		Return status code
26
+	 */
27
+	int ( * tx_request ) ( struct net_device *netdev,
28
+			       struct net_protocol *net_protocol,
29
+			       const void *net_dest, const void *net_source );
30
+};
31
+
32
+extern int neighbour_tx ( struct io_buffer *iobuf, struct net_device *netdev,
33
+			  struct net_protocol *net_protocol,
34
+			  const void *net_dest,
35
+			  struct neighbour_discovery *discovery,
36
+			  const void *net_source, const void *ll_source );
37
+extern int neighbour_update ( struct net_device *netdev,
38
+			      struct net_protocol *net_protocol,
39
+			      const void *net_dest, const void *ll_dest );
40
+extern int neighbour_define ( struct net_device *netdev,
41
+			      struct net_protocol *net_protocol,
42
+			      const void *net_dest, const void *ll_dest );
43
+
44
+#endif /* _IPXE_NEIGHBOUR_H */

+ 34
- 354
src/net/arp.c View File

28
 #include <ipxe/if_arp.h>
28
 #include <ipxe/if_arp.h>
29
 #include <ipxe/iobuf.h>
29
 #include <ipxe/iobuf.h>
30
 #include <ipxe/netdevice.h>
30
 #include <ipxe/netdevice.h>
31
-#include <ipxe/list.h>
32
-#include <ipxe/retry.h>
33
-#include <ipxe/timer.h>
34
-#include <ipxe/malloc.h>
35
-#include <ipxe/refcnt.h>
31
+#include <ipxe/neighbour.h>
36
 #include <ipxe/arp.h>
32
 #include <ipxe/arp.h>
37
 
33
 
38
 /** @file
34
 /** @file
45
  *
41
  *
46
  */
42
  */
47
 
43
 
48
-/** ARP minimum timeout */
49
-#define ARP_MIN_TIMEOUT ( TICKS_PER_SEC / 8 )
50
-
51
-/** ARP maximum timeout */
52
-#define ARP_MAX_TIMEOUT ( TICKS_PER_SEC * 3 )
53
-
54
-/** An ARP cache entry */
55
-struct arp_entry {
56
-	/** Reference count */
57
-	struct refcnt refcnt;
58
-	/** List of ARP cache entries */
59
-	struct list_head list;
60
-	/** Network device */
61
-	struct net_device *netdev;
62
-	/** Network-layer protocol */
63
-	struct net_protocol *net_protocol;
64
-	/** Network-layer destination address */
65
-	uint8_t net_dest[MAX_NET_ADDR_LEN];
66
-	/** Network-layer source address */
67
-	uint8_t net_source[MAX_NET_ADDR_LEN];
68
-	/** Link-layer destination address */
69
-	uint8_t ll_dest[MAX_LL_ADDR_LEN];
70
-	/** Retransmission timer */
71
-	struct retry_timer timer;
72
-	/** Pending I/O buffers */
73
-	struct list_head tx_queue;
74
-};
75
-
76
-/** The ARP cache */
77
-static LIST_HEAD ( arp_entries );
78
-
79
 struct net_protocol arp_protocol __net_protocol;
44
 struct net_protocol arp_protocol __net_protocol;
80
 
45
 
81
-static void arp_expired ( struct retry_timer *timer, int over );
82
-
83
-/**
84
- * Free ARP cache entry
85
- *
86
- * @v refcnt		Reference count
87
- */
88
-static void arp_free ( struct refcnt *refcnt ) {
89
-	struct arp_entry *arp =
90
-		container_of ( refcnt, struct arp_entry, refcnt );
91
-
92
-	/* Sanity check */
93
-	assert ( list_empty ( &arp->tx_queue ) );
94
-
95
-	/* Drop reference to network device */
96
-	netdev_put ( arp->netdev );
97
-
98
-	/* Free entry */
99
-	free ( arp );
100
-}
101
-
102
-/**
103
- * Create ARP cache entry
104
- *
105
- * @v netdev		Network device
106
- * @v net_protocol	Network-layer protocol
107
- * @v net_dest		Destination network-layer address
108
- * @v net_source	Source network-layer address
109
- * @ret arp		ARP cache entry, or NULL if allocation failed
110
- */
111
-static struct arp_entry * arp_create ( struct net_device *netdev,
112
-				       struct net_protocol *net_protocol,
113
-				       const void *net_dest,
114
-				       const void *net_source ) {
115
-	struct arp_entry *arp;
116
-
117
-	/* Allocate and initialise entry */
118
-	arp = zalloc ( sizeof ( *arp ) );
119
-	if ( ! arp )
120
-		return NULL;
121
-	ref_init ( &arp->refcnt, arp_free );
122
-	arp->netdev = netdev_get ( netdev );
123
-	arp->net_protocol = net_protocol;
124
-	memcpy ( arp->net_dest, net_dest,
125
-		 net_protocol->net_addr_len );
126
-	memcpy ( arp->net_source, net_source,
127
-		 net_protocol->net_addr_len );
128
-	timer_init ( &arp->timer, arp_expired, &arp->refcnt );
129
-	arp->timer.min_timeout = ARP_MIN_TIMEOUT;
130
-	arp->timer.max_timeout = ARP_MAX_TIMEOUT;
131
-	INIT_LIST_HEAD ( &arp->tx_queue );
132
-
133
-	/* Start timer running to trigger initial transmission */
134
-	start_timer_nodelay ( &arp->timer );
135
-
136
-	/* Transfer ownership to cache */
137
-	list_add ( &arp->list, &arp_entries );
138
-
139
-	DBGC ( arp, "ARP %p %s %s %s created\n", arp, netdev->name,
140
-	       net_protocol->name, net_protocol->ntoa ( net_dest ) );
141
-	return arp;
142
-}
143
-
144
-/**
145
- * Find entry in the ARP cache
146
- *
147
- * @v netdev		Network device
148
- * @v net_protocol	Network-layer protocol
149
- * @v net_dest		Destination network-layer address
150
- * @ret arp		ARP cache entry, or NULL if not found
151
- */
152
-static struct arp_entry * arp_find ( struct net_device *netdev,
153
-				     struct net_protocol *net_protocol,
154
-				     const void *net_dest ) {
155
-	struct arp_entry *arp;
156
-
157
-	list_for_each_entry ( arp, &arp_entries, list ) {
158
-		if ( ( arp->netdev == netdev ) &&
159
-		     ( arp->net_protocol == net_protocol ) &&
160
-		     ( memcmp ( arp->net_dest, net_dest,
161
-				net_protocol->net_addr_len ) == 0 ) ) {
162
-
163
-			/* Move to start of cache */
164
-			list_del ( &arp->list );
165
-			list_add ( &arp->list, &arp_entries );
166
-
167
-			return arp;
168
-		}
169
-	}
170
-	return NULL;
171
-}
172
-
173
-/**
174
- * Destroy ARP cache entry
175
- *
176
- * @v arp		ARP cache entry
177
- * @v rc		Reason for destruction
178
- */
179
-static void arp_destroy ( struct arp_entry *arp, int rc ) {
180
-	struct net_device *netdev = arp->netdev;
181
-	struct net_protocol *net_protocol = arp->net_protocol;
182
-	struct io_buffer *iobuf;
183
-
184
-	/* Take ownership from cache */
185
-	list_del ( &arp->list );
186
-
187
-	/* Stop timer */
188
-	stop_timer ( &arp->timer );
189
-
190
-	/* Discard any outstanding I/O buffers */
191
-	while ( ( iobuf = list_first_entry ( &arp->tx_queue, struct io_buffer,
192
-					     list ) ) != NULL ) {
193
-		DBGC2 ( arp, "ARP %p %s %s %s discarding deferred packet: "
194
-			"%s\n", arp, netdev->name, net_protocol->name,
195
-			net_protocol->ntoa ( arp->net_dest ), strerror ( rc ) );
196
-		list_del ( &iobuf->list );
197
-		netdev_tx_err ( arp->netdev, iobuf, rc );
198
-	}
199
-
200
-	DBGC ( arp, "ARP %p %s %s %s destroyed: %s\n", arp, netdev->name,
201
-	       net_protocol->name, net_protocol->ntoa ( arp->net_dest ),
202
-	       strerror ( rc ) );
203
-
204
-	/* Drop remaining reference */
205
-	ref_put ( &arp->refcnt );
206
-}
207
-
208
 /**
46
 /**
209
- * Test if ARP cache entry has a valid link-layer address
47
+ * Transmit ARP request
210
  *
48
  *
211
- * @v arp		ARP cache entry
212
- * @ret resolved	ARP cache entry is resolved
213
- */
214
-static inline int arp_resolved ( struct arp_entry *arp ) {
215
-	return ( ! timer_running ( &arp->timer ) );
216
-}
217
-
218
-/**
219
- * Transmit packet, determining link-layer address via ARP
220
- *
221
- * @v iobuf		I/O buffer
222
  * @v netdev		Network device
49
  * @v netdev		Network device
223
  * @v net_protocol	Network-layer protocol
50
  * @v net_protocol	Network-layer protocol
224
  * @v net_dest		Destination network-layer address
51
  * @v net_dest		Destination network-layer address
225
  * @v net_source	Source network-layer address
52
  * @v net_source	Source network-layer address
226
- * @v ll_source		Source link-layer address
227
  * @ret rc		Return status code
53
  * @ret rc		Return status code
228
  */
54
  */
229
-int arp_tx ( struct io_buffer *iobuf, struct net_device *netdev,
230
-	     struct net_protocol *net_protocol, const void *net_dest,
231
-	     const void *net_source, const void *ll_source ) {
232
-	struct arp_entry *arp;
233
-
234
-	/* Find or create ARP cache entry */
235
-	arp = arp_find ( netdev, net_protocol, net_dest );
236
-	if ( ! arp ) {
237
-		arp = arp_create ( netdev, net_protocol, net_dest,
238
-				   net_source );
239
-		if ( ! arp )
240
-			return -ENOMEM;
241
-	}
242
-
243
-	/* If a link-layer address is available then transmit
244
-	 * immediately, otherwise queue for later transmission.
245
-	 */
246
-	if ( arp_resolved ( arp ) ) {
247
-		return net_tx ( iobuf, netdev, net_protocol, arp->ll_dest,
248
-				ll_source );
249
-	} else {
250
-		DBGC2 ( arp, "ARP %p %s %s %s deferring packet\n",
251
-			arp, netdev->name, net_protocol->name,
252
-			net_protocol->ntoa ( net_dest ) );
253
-		list_add_tail ( &iobuf->list, &arp->tx_queue );
254
-		return -EAGAIN;
255
-	}
256
-}
257
-
258
-/**
259
- * Update ARP cache entry
260
- *
261
- * @v arp		ARP cache entry
262
- * @v ll_dest		Destination link-layer address
263
- */
264
-static void arp_update ( struct arp_entry *arp, const void *ll_dest ) {
265
-	struct net_device *netdev = arp->netdev;
266
-	struct ll_protocol *ll_protocol = netdev->ll_protocol;
267
-	struct net_protocol *net_protocol = arp->net_protocol;
268
-	struct io_buffer *iobuf;
269
-	int rc;
270
-
271
-	DBGC ( arp, "ARP %p %s %s %s updated => %s\n", arp, netdev->name,
272
-	       net_protocol->name, net_protocol->ntoa ( arp->net_dest ),
273
-	       ll_protocol->ntoa ( ll_dest ) );
274
-
275
-	/* Fill in link-layer address */
276
-	memcpy ( arp->ll_dest, ll_dest, ll_protocol->ll_addr_len );
277
-
278
-	/* Stop retransmission timer */
279
-	stop_timer ( &arp->timer );
280
-
281
-	/* Transmit any packets in queue.  Take out a temporary
282
-	 * reference on the entry to prevent it from going out of
283
-	 * scope during the call to net_tx().
284
-	 */
285
-	ref_get ( &arp->refcnt );
286
-	while ( ( iobuf = list_first_entry ( &arp->tx_queue, struct io_buffer,
287
-					     list ) ) != NULL ) {
288
-		DBGC2 ( arp, "ARP %p %s %s %s transmitting deferred packet\n",
289
-			arp, netdev->name, net_protocol->name,
290
-			net_protocol->ntoa ( arp->net_dest ) );
291
-		list_del ( &iobuf->list );
292
-		if ( ( rc = net_tx ( iobuf, netdev, net_protocol, ll_dest,
293
-				     netdev->ll_addr ) ) != 0 ) {
294
-			DBGC ( arp, "ARP %p could not transmit deferred "
295
-			       "packet: %s\n", arp, strerror ( rc ) );
296
-			/* Ignore error and continue */
297
-		}
298
-	}
299
-	ref_put ( &arp->refcnt );
300
-}
301
-
302
-/**
303
- * Handle ARP timer expiry
304
- *
305
- * @v timer		Retry timer
306
- * @v fail		Failure indicator
307
- */
308
-static void arp_expired ( struct retry_timer *timer, int fail ) {
309
-	struct arp_entry *arp = container_of ( timer, struct arp_entry, timer );
310
-	struct net_device *netdev = arp->netdev;
55
+static int arp_tx_request ( struct net_device *netdev,
56
+			    struct net_protocol *net_protocol,
57
+			    const void *net_dest, const void *net_source ) {
311
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
58
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
312
-	struct net_protocol *net_protocol = arp->net_protocol;
313
 	struct io_buffer *iobuf;
59
 	struct io_buffer *iobuf;
314
 	struct arphdr *arphdr;
60
 	struct arphdr *arphdr;
315
 	int rc;
61
 	int rc;
316
 
62
 
317
-	/* If we have failed, destroy the cache entry */
318
-	if ( fail ) {
319
-		arp_destroy ( arp, -ETIMEDOUT );
320
-		return;
321
-	}
322
-
323
-	/* Restart the timer */
324
-	start_timer ( &arp->timer );
325
-
326
 	/* Allocate ARP packet */
63
 	/* Allocate ARP packet */
327
 	iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *arphdr ) +
64
 	iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *arphdr ) +
328
 			    ( 2 * ( MAX_LL_ADDR_LEN + MAX_NET_ADDR_LEN ) ) );
65
 			    ( 2 * ( MAX_LL_ADDR_LEN + MAX_NET_ADDR_LEN ) ) );
329
-	if ( ! iobuf ) {
330
-		/* Leave timer running and try again later */
331
-		return;
332
-	}
66
+	if ( ! iobuf )
67
+		return -ENOMEM;
333
 	iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
68
 	iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
334
 
69
 
335
 	/* Build up ARP request */
70
 	/* Build up ARP request */
342
 	memcpy ( iob_put ( iobuf, ll_protocol->ll_addr_len ),
77
 	memcpy ( iob_put ( iobuf, ll_protocol->ll_addr_len ),
343
 		 netdev->ll_addr, ll_protocol->ll_addr_len );
78
 		 netdev->ll_addr, ll_protocol->ll_addr_len );
344
 	memcpy ( iob_put ( iobuf, net_protocol->net_addr_len ),
79
 	memcpy ( iob_put ( iobuf, net_protocol->net_addr_len ),
345
-		 arp->net_source, net_protocol->net_addr_len );
80
+		 net_source, net_protocol->net_addr_len );
346
 	memset ( iob_put ( iobuf, ll_protocol->ll_addr_len ),
81
 	memset ( iob_put ( iobuf, ll_protocol->ll_addr_len ),
347
 		 0, ll_protocol->ll_addr_len );
82
 		 0, ll_protocol->ll_addr_len );
348
 	memcpy ( iob_put ( iobuf, net_protocol->net_addr_len ),
83
 	memcpy ( iob_put ( iobuf, net_protocol->net_addr_len ),
349
-		 arp->net_dest, net_protocol->net_addr_len );
84
+		 net_dest, net_protocol->net_addr_len );
350
 
85
 
351
 	/* Transmit ARP request */
86
 	/* Transmit ARP request */
352
 	if ( ( rc = net_tx ( iobuf, netdev, &arp_protocol,
87
 	if ( ( rc = net_tx ( iobuf, netdev, &arp_protocol,
353
 			     netdev->ll_broadcast, netdev->ll_addr ) ) != 0 ) {
88
 			     netdev->ll_broadcast, netdev->ll_addr ) ) != 0 ) {
354
-		DBGC ( arp, "ARP %p could not transmit request: %s\n",
355
-		       arp, strerror ( rc ) );
356
-		return;
89
+		DBGC ( netdev, "ARP %s %s %s could not transmit request: %s\n",
90
+		       netdev->name, net_protocol->name,
91
+		       net_protocol->ntoa ( net_dest ), strerror ( rc ) );
92
+		return rc;
357
 	}
93
 	}
94
+
95
+	return 0;
358
 }
96
 }
359
 
97
 
98
+/** ARP neighbour discovery protocol */
99
+struct neighbour_discovery arp_discovery = {
100
+	.name = "ARP",
101
+	.tx_request = arp_tx_request,
102
+};
103
+
360
 /**
104
 /**
361
  * Identify ARP protocol
105
  * Identify ARP protocol
362
  *
106
  *
368
 	struct arp_net_protocol *arp_net_protocol;
112
 	struct arp_net_protocol *arp_net_protocol;
369
 
113
 
370
 	for_each_table_entry ( arp_net_protocol, ARP_NET_PROTOCOLS ) {
114
 	for_each_table_entry ( arp_net_protocol, ARP_NET_PROTOCOLS ) {
371
-		if ( arp_net_protocol->net_protocol->net_proto == net_proto ) {
115
+		if ( arp_net_protocol->net_protocol->net_proto == net_proto )
372
 			return arp_net_protocol;
116
 			return arp_net_protocol;
373
-		}
374
 	}
117
 	}
375
 	return NULL;
118
 	return NULL;
376
 }
119
 }
392
 	struct arp_net_protocol *arp_net_protocol;
135
 	struct arp_net_protocol *arp_net_protocol;
393
 	struct net_protocol *net_protocol;
136
 	struct net_protocol *net_protocol;
394
 	struct ll_protocol *ll_protocol;
137
 	struct ll_protocol *ll_protocol;
395
-	struct arp_entry *arp;
396
 	int rc;
138
 	int rc;
397
 
139
 
398
 	/* Identify network-layer and link-layer protocols */
140
 	/* Identify network-layer and link-layer protocols */
412
 		goto done;
154
 		goto done;
413
 	}
155
 	}
414
 
156
 
415
-	/* See if we have an entry for this sender, and update it if so */
416
-	arp = arp_find ( netdev, net_protocol, arp_sender_pa ( arphdr ) );
417
-	if ( arp ) {
418
-		arp_update ( arp, arp_sender_ha ( arphdr ) );
419
-	}
157
+	/* Update neighbour cache entry for this sender, if any */
158
+	neighbour_update ( netdev, net_protocol, arp_sender_pa ( arphdr ),
159
+			   arp_sender_ha ( arphdr ) );
420
 
160
 
421
 	/* If it's not a request, there's nothing more to do */
161
 	/* If it's not a request, there's nothing more to do */
422
 	if ( arphdr->ar_op != htons ( ARPOP_REQUEST ) ) {
162
 	if ( arphdr->ar_op != htons ( ARPOP_REQUEST ) ) {
431
 	}
171
 	}
432
 
172
 
433
 	/* Change request to a reply */
173
 	/* Change request to a reply */
434
-	DBGC ( netdev, "ARP reply %s %s %s => %s %s\n",
435
-	       netdev->name, net_protocol->name,
436
-	       net_protocol->ntoa ( arp_target_pa ( arphdr ) ),
437
-	       ll_protocol->name, ll_protocol->ntoa ( netdev->ll_addr ) );
174
+	DBGC2 ( netdev, "ARP %s %s %s reply => %s %s\n",
175
+		netdev->name, net_protocol->name,
176
+		net_protocol->ntoa ( arp_target_pa ( arphdr ) ),
177
+		ll_protocol->name, ll_protocol->ntoa ( netdev->ll_addr ) );
438
 	arphdr->ar_op = htons ( ARPOP_REPLY );
178
 	arphdr->ar_op = htons ( ARPOP_REPLY );
439
 	memswap ( arp_sender_ha ( arphdr ), arp_target_ha ( arphdr ),
179
 	memswap ( arp_sender_ha ( arphdr ), arp_target_ha ( arphdr ),
440
 		 arphdr->ar_hln + arphdr->ar_pln );
180
 		 arphdr->ar_hln + arphdr->ar_pln );
444
 	if ( ( rc = net_tx ( iob_disown ( iobuf ), netdev, &arp_protocol,
184
 	if ( ( rc = net_tx ( iob_disown ( iobuf ), netdev, &arp_protocol,
445
 			     arp_target_ha ( arphdr ),
185
 			     arp_target_ha ( arphdr ),
446
 			     netdev->ll_addr ) ) != 0 ) {
186
 			     netdev->ll_addr ) ) != 0 ) {
447
-		DBGC ( netdev, "ARP could not transmit reply via %s: %s\n",
448
-		       netdev->name, strerror ( rc ) );
187
+		DBGC ( netdev, "ARP %s %s %s could not transmit reply: %s\n",
188
+		       netdev->name, net_protocol->name,
189
+		       net_protocol->ntoa ( arp_target_pa ( arphdr ) ),
190
+		       strerror ( rc ) );
449
 		goto done;
191
 		goto done;
450
 	}
192
 	}
451
 
193
 
469
 	return "<ARP>";
211
 	return "<ARP>";
470
 }
212
 }
471
 
213
 
472
-/** ARP protocol */
214
+/** ARP network protocol */
473
 struct net_protocol arp_protocol __net_protocol = {
215
 struct net_protocol arp_protocol __net_protocol = {
474
 	.name = "ARP",
216
 	.name = "ARP",
475
 	.net_proto = htons ( ETH_P_ARP ),
217
 	.net_proto = htons ( ETH_P_ARP ),
476
 	.rx = arp_rx,
218
 	.rx = arp_rx,
477
 	.ntoa = arp_ntoa,
219
 	.ntoa = arp_ntoa,
478
 };
220
 };
479
-
480
-/**
481
- * Update ARP cache on network device creation
482
- *
483
- * @v netdev		Network device
484
- */
485
-static int arp_probe ( struct net_device *netdev __unused ) {
486
-	/* Nothing to do */
487
-	return 0;
488
-}
489
-
490
-/**
491
- * Update ARP cache on network device state change or removal
492
- *
493
- * @v netdev		Network device
494
- */
495
-static void arp_flush ( struct net_device *netdev ) {
496
-	struct arp_entry *arp;
497
-	struct arp_entry *tmp;
498
-
499
-	/* Remove all ARP cache entries when a network device is closed */
500
-	if ( ! netdev_is_open ( netdev ) ) {
501
-		list_for_each_entry_safe ( arp, tmp, &arp_entries, list )
502
-			arp_destroy ( arp, -ENODEV );
503
-	}
504
-}
505
-
506
-/** ARP driver (for net device notifications) */
507
-struct net_driver arp_net_driver __net_driver = {
508
-	.name = "ARP",
509
-	.probe = arp_probe,
510
-	.notify = arp_flush,
511
-	.remove = arp_flush,
512
-};
513
-
514
-/**
515
- * Discard some cached ARP entries
516
- *
517
- * @ret discarded	Number of cached items discarded
518
- */
519
-static unsigned int arp_discard ( void ) {
520
-	struct arp_entry *arp;
521
-
522
-	/* Drop oldest cache entry, if any */
523
-	arp = list_last_entry ( &arp_entries, struct arp_entry, list );
524
-	if ( arp ) {
525
-		arp_destroy ( arp, -ENOBUFS );
526
-		return 1;
527
-	} else {
528
-		return 0;
529
-	}
530
-}
531
-
532
-/** ARP cache discarder
533
- *
534
- * ARP cache entries are deemed to have a high replacement cost, since
535
- * flushing an active ARP cache entry midway through a TCP transfer
536
- * will cause substantial disruption.
537
- */
538
-struct cache_discarder arp_discarder __cache_discarder ( CACHE_EXPENSIVE ) = {
539
-	.discard = arp_discard,
540
-};

+ 479
- 0
src/net/neighbour.c View File

1
+/*
2
+ * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ */
19
+
20
+FILE_LICENCE ( GPL2_OR_LATER );
21
+
22
+#include <stdint.h>
23
+#include <stdlib.h>
24
+#include <string.h>
25
+#include <errno.h>
26
+#include <ipxe/refcnt.h>
27
+#include <ipxe/list.h>
28
+#include <ipxe/iobuf.h>
29
+#include <ipxe/retry.h>
30
+#include <ipxe/timer.h>
31
+#include <ipxe/malloc.h>
32
+#include <ipxe/neighbour.h>
33
+
34
+/** @file
35
+ *
36
+ * Neighbour discovery
37
+ *
38
+ * This file implements the abstract functions of neighbour discovery,
39
+ * independent of the underlying network protocol (e.g. ARP or NDP).
40
+ *
41
+ */
42
+
43
+/** A neighbour cache entry */
44
+struct neighbour {
45
+	/** Reference count */
46
+	struct refcnt refcnt;
47
+	/** List of neighbour cache entries */
48
+	struct list_head list;
49
+
50
+	/** Network device */
51
+	struct net_device *netdev;
52
+	/** Network-layer protocol */
53
+	struct net_protocol *net_protocol;
54
+	/** Network-layer destination address */
55
+	uint8_t net_dest[MAX_NET_ADDR_LEN];
56
+	/** Link-layer destination address */
57
+	uint8_t ll_dest[MAX_LL_ADDR_LEN];
58
+
59
+	/** Neighbour discovery protocol (if any) */
60
+	struct neighbour_discovery *discovery;
61
+	/** Network-layer source address (if any) */
62
+	uint8_t net_source[MAX_NET_ADDR_LEN];
63
+	/** Retransmission timer */
64
+	struct retry_timer timer;
65
+
66
+	/** Pending I/O buffers */
67
+	struct list_head tx_queue;
68
+};
69
+
70
+/** Neighbour discovery minimum timeout */
71
+#define NEIGHBOUR_MIN_TIMEOUT ( TICKS_PER_SEC / 8 )
72
+
73
+/** Neighbour discovery maximum timeout */
74
+#define NEIGHBOUR_MAX_TIMEOUT ( TICKS_PER_SEC * 3 )
75
+
76
+/** The neighbour cache */
77
+static LIST_HEAD ( neighbours );
78
+
79
+static void neighbour_expired ( struct retry_timer *timer, int over );
80
+
81
+/**
82
+ * Free neighbour cache entry
83
+ *
84
+ * @v refcnt		Reference count
85
+ */
86
+static void neighbour_free ( struct refcnt *refcnt ) {
87
+	struct neighbour *neighbour =
88
+		container_of ( refcnt, struct neighbour, refcnt );
89
+
90
+	/* Sanity check */
91
+	assert ( list_empty ( &neighbour->tx_queue ) );
92
+
93
+	/* Drop reference to network device */
94
+	netdev_put ( neighbour->netdev );
95
+
96
+	/* Free neighbour */
97
+	free ( neighbour );
98
+}
99
+
100
+/**
101
+ * Test if neighbour cache entry has a valid link-layer address
102
+ *
103
+ * @v neighbour		Neighbour cache entry
104
+ * @ret has_ll_dest	Neighbour cache entry has a valid link-layer address
105
+ */
106
+static inline __attribute__ (( always_inline )) int
107
+neighbour_has_ll_dest ( struct neighbour *neighbour ) {
108
+	return ( ! timer_running ( &neighbour->timer ) );
109
+}
110
+
111
+/**
112
+ * Create neighbour cache entry
113
+ *
114
+ * @v netdev		Network device
115
+ * @v net_protocol	Network-layer protocol
116
+ * @v net_dest		Destination network-layer address
117
+ * @ret neighbour	Neighbour cache entry, or NULL if allocation failed
118
+ */
119
+static struct neighbour * neighbour_create ( struct net_device *netdev,
120
+					     struct net_protocol *net_protocol,
121
+					     const void *net_dest ) {
122
+	struct neighbour *neighbour;
123
+
124
+	/* Allocate and initialise entry */
125
+	neighbour = zalloc ( sizeof ( *neighbour ) );
126
+	if ( ! neighbour )
127
+		return NULL;
128
+	ref_init ( &neighbour->refcnt, neighbour_free );
129
+	neighbour->netdev = netdev_get ( netdev );
130
+	neighbour->net_protocol = net_protocol;
131
+	memcpy ( neighbour->net_dest, net_dest,
132
+		 net_protocol->net_addr_len );
133
+	timer_init ( &neighbour->timer, neighbour_expired, &neighbour->refcnt );
134
+	neighbour->timer.min_timeout = NEIGHBOUR_MIN_TIMEOUT;
135
+	neighbour->timer.max_timeout = NEIGHBOUR_MAX_TIMEOUT;
136
+	INIT_LIST_HEAD ( &neighbour->tx_queue );
137
+
138
+	/* Transfer ownership to cache */
139
+	list_add ( &neighbour->list, &neighbours );
140
+
141
+	DBGC ( neighbour, "NEIGHBOUR %s %s %s created\n", netdev->name,
142
+	       net_protocol->name, net_protocol->ntoa ( net_dest ) );
143
+	return neighbour;
144
+}
145
+
146
+/**
147
+ * Find neighbour cache entry
148
+ *
149
+ * @v netdev		Network device
150
+ * @v net_protocol	Network-layer protocol
151
+ * @v net_dest		Destination network-layer address
152
+ * @ret neighbour	Neighbour cache entry, or NULL if not found
153
+ */
154
+static struct neighbour * neighbour_find ( struct net_device *netdev,
155
+					   struct net_protocol *net_protocol,
156
+					   const void *net_dest ) {
157
+	struct neighbour *neighbour;
158
+
159
+	list_for_each_entry ( neighbour, &neighbours, list ) {
160
+		if ( ( neighbour->netdev == netdev ) &&
161
+		     ( neighbour->net_protocol == net_protocol ) &&
162
+		     ( memcmp ( neighbour->net_dest, net_dest,
163
+				net_protocol->net_addr_len ) == 0 ) ) {
164
+
165
+			/* Move to start of cache */
166
+			list_del ( &neighbour->list );
167
+			list_add ( &neighbour->list, &neighbours );
168
+
169
+			return neighbour;
170
+		}
171
+	}
172
+	return NULL;
173
+}
174
+
175
+/**
176
+ * Start neighbour discovery
177
+ *
178
+ * @v neighbour		Neighbour cache entry
179
+ * @v discovery		Neighbour discovery protocol
180
+ * @v net_source	Source network-layer address
181
+ */
182
+static void neighbour_discover ( struct neighbour *neighbour,
183
+				 struct neighbour_discovery *discovery,
184
+				 const void *net_source ) {
185
+	struct net_device *netdev = neighbour->netdev;
186
+	struct net_protocol *net_protocol = neighbour->net_protocol;
187
+
188
+	/* Record discovery protocol and source network-layer address */
189
+	neighbour->discovery = discovery;
190
+	memcpy ( neighbour->net_source, net_source,
191
+		 net_protocol->net_addr_len );
192
+
193
+	/* Start timer to trigger neighbour discovery */
194
+	start_timer_nodelay ( &neighbour->timer );
195
+
196
+	DBGC ( neighbour, "NEIGHBOUR %s %s %s discovering via %s\n",
197
+	       netdev->name, net_protocol->name,
198
+	       net_protocol->ntoa ( neighbour->net_dest ),
199
+	       neighbour->discovery->name );
200
+}
201
+
202
+/**
203
+ * Complete neighbour discovery
204
+ *
205
+ * @v neighbour		Neighbour cache entry
206
+ * @v ll_dest		Destination link-layer address
207
+ */
208
+static void neighbour_discovered ( struct neighbour *neighbour,
209
+				   const void *ll_dest ) {
210
+	struct net_device *netdev = neighbour->netdev;
211
+	struct ll_protocol *ll_protocol = netdev->ll_protocol;
212
+	struct net_protocol *net_protocol = neighbour->net_protocol;
213
+	struct io_buffer *iobuf;
214
+	int rc;
215
+
216
+	/* Fill in link-layer address */
217
+	memcpy ( neighbour->ll_dest, ll_dest, ll_protocol->ll_addr_len );
218
+	DBGC ( neighbour, "NEIGHBOUR %s %s %s is %s %s\n", netdev->name,
219
+	       net_protocol->name, net_protocol->ntoa ( neighbour->net_dest ),
220
+	       ll_protocol->name, ll_protocol->ntoa ( neighbour->ll_dest ) );
221
+
222
+	/* Stop retransmission timer */
223
+	stop_timer ( &neighbour->timer );
224
+
225
+	/* Transmit any packets in queue.  Take out a temporary
226
+	 * reference on the entry to prevent it from going out of
227
+	 * scope during the call to net_tx().
228
+	 */
229
+	ref_get ( &neighbour->refcnt );
230
+	while ( ( iobuf = list_first_entry ( &neighbour->tx_queue,
231
+					     struct io_buffer, list )) != NULL){
232
+		DBGC2 ( neighbour, "NEIGHBOUR %s %s %s transmitting deferred "
233
+			"packet\n", netdev->name, net_protocol->name,
234
+			net_protocol->ntoa ( neighbour->net_dest ) );
235
+		list_del ( &iobuf->list );
236
+		if ( ( rc = net_tx ( iobuf, netdev, net_protocol, ll_dest,
237
+				     netdev->ll_addr ) ) != 0 ) {
238
+			DBGC ( neighbour, "NEIGHBOUR %s %s %s could not "
239
+			       "transmit deferred packet: %s\n",
240
+			       netdev->name, net_protocol->name,
241
+			       net_protocol->ntoa ( neighbour->net_dest ),
242
+			       strerror ( rc ) );
243
+			/* Ignore error and continue */
244
+		}
245
+	}
246
+	ref_put ( &neighbour->refcnt );
247
+}
248
+
249
+/**
250
+ * Destroy neighbour cache entry
251
+ *
252
+ * @v neighbour		Neighbour cache entry
253
+ * @v rc		Reason for destruction
254
+ */
255
+static void neighbour_destroy ( struct neighbour *neighbour, int rc ) {
256
+	struct net_device *netdev = neighbour->netdev;
257
+	struct net_protocol *net_protocol = neighbour->net_protocol;
258
+	struct io_buffer *iobuf;
259
+
260
+	/* Take ownership from cache */
261
+	list_del ( &neighbour->list );
262
+
263
+	/* Stop timer */
264
+	stop_timer ( &neighbour->timer );
265
+
266
+	/* Discard any outstanding I/O buffers */
267
+	while ( ( iobuf = list_first_entry ( &neighbour->tx_queue,
268
+					     struct io_buffer, list )) != NULL){
269
+		DBGC2 ( neighbour, "NEIGHBOUR %s %s %s discarding deferred "
270
+			"packet: %s\n", netdev->name, net_protocol->name,
271
+			net_protocol->ntoa ( neighbour->net_dest ),
272
+			strerror ( rc ) );
273
+		list_del ( &iobuf->list );
274
+		netdev_tx_err ( neighbour->netdev, iobuf, rc );
275
+	}
276
+
277
+	DBGC ( neighbour, "NEIGHBOUR %s %s %s destroyed: %s\n", netdev->name,
278
+	       net_protocol->name, net_protocol->ntoa ( neighbour->net_dest ),
279
+	       strerror ( rc ) );
280
+
281
+	/* Drop remaining reference */
282
+	ref_put ( &neighbour->refcnt );
283
+}
284
+
285
+/**
286
+ * Handle neighbour timer expiry
287
+ *
288
+ * @v timer		Retry timer
289
+ * @v fail		Failure indicator
290
+ */
291
+static void neighbour_expired ( struct retry_timer *timer, int fail ) {
292
+	struct neighbour *neighbour =
293
+		container_of ( timer, struct neighbour, timer );
294
+	struct net_device *netdev = neighbour->netdev;
295
+	struct net_protocol *net_protocol = neighbour->net_protocol;
296
+	struct neighbour_discovery *discovery =
297
+		neighbour->discovery;
298
+	const void *net_dest = neighbour->net_dest;
299
+	const void *net_source = neighbour->net_source;
300
+	int rc;
301
+
302
+	/* If we have failed, destroy the cache entry */
303
+	if ( fail ) {
304
+		neighbour_destroy ( neighbour, -ETIMEDOUT );
305
+		return;
306
+	}
307
+
308
+	/* Restart the timer */
309
+	start_timer ( &neighbour->timer );
310
+
311
+	/* Transmit neighbour request */
312
+	if ( ( rc = discovery->tx_request ( netdev, net_protocol, net_dest,
313
+					    net_source ) ) != 0 ) {
314
+		DBGC ( neighbour, "NEIGHBOUR %s %s %s could not transmit %s "
315
+		       "request: %s\n", netdev->name, net_protocol->name,
316
+		       net_protocol->ntoa ( neighbour->net_dest ),
317
+		       neighbour->discovery->name, strerror ( rc ) );
318
+		/* Retransmit when timer expires */
319
+		return;
320
+	}
321
+}
322
+
323
+/**
324
+ * Transmit packet, determining link-layer address via neighbour discovery
325
+ *
326
+ * @v iobuf		I/O buffer
327
+ * @v netdev		Network device
328
+ * @v discovery		Neighbour discovery protocol
329
+ * @v net_protocol	Network-layer protocol
330
+ * @v net_dest		Destination network-layer address
331
+ * @v net_source	Source network-layer address
332
+ * @v ll_source		Source link-layer address
333
+ * @ret rc		Return status code
334
+ */
335
+int neighbour_tx ( struct io_buffer *iobuf, struct net_device *netdev,
336
+		   struct net_protocol *net_protocol, const void *net_dest,
337
+		   struct neighbour_discovery *discovery,
338
+		   const void *net_source, const void *ll_source ) {
339
+	struct neighbour *neighbour;
340
+
341
+	/* Find or create neighbour cache entry */
342
+	neighbour = neighbour_find ( netdev, net_protocol, net_dest );
343
+	if ( ! neighbour ) {
344
+		neighbour = neighbour_create ( netdev, net_protocol, net_dest );
345
+		if ( ! neighbour )
346
+			return -ENOMEM;
347
+		neighbour_discover ( neighbour, discovery, net_source );
348
+	}
349
+
350
+	/* If a link-layer address is available then transmit
351
+	 * immediately, otherwise queue for later transmission.
352
+	 */
353
+	if ( neighbour_has_ll_dest ( neighbour ) ) {
354
+		return net_tx ( iobuf, netdev, net_protocol, neighbour->ll_dest,
355
+				ll_source );
356
+	} else {
357
+		DBGC2 ( neighbour, "NEIGHBOUR %s %s %s deferring packet\n",
358
+			netdev->name, net_protocol->name,
359
+			net_protocol->ntoa ( net_dest ) );
360
+		list_add_tail ( &iobuf->list, &neighbour->tx_queue );
361
+		return -EAGAIN;
362
+	}
363
+}
364
+
365
+/**
366
+ * Update existing neighbour cache entry
367
+ *
368
+ * @v netdev		Network device
369
+ * @v net_protocol	Network-layer protocol
370
+ * @v net_dest		Destination network-layer address
371
+ * @v ll_dest		Destination link-layer address
372
+ * @ret rc		Return status code
373
+ */
374
+int neighbour_update ( struct net_device *netdev,
375
+		       struct net_protocol *net_protocol,
376
+		       const void *net_dest, const void *ll_dest ) {
377
+	struct neighbour *neighbour;
378
+
379
+	/* Find neighbour cache entry */
380
+	neighbour = neighbour_find ( netdev, net_protocol, net_dest );
381
+	if ( ! neighbour )
382
+		return -ENOENT;
383
+
384
+	/* Set destination address */
385
+	neighbour_discovered ( neighbour, ll_dest );
386
+
387
+	return 0;
388
+}
389
+
390
+/**
391
+ * Define neighbour cache entry
392
+ *
393
+ * @v netdev		Network device
394
+ * @v net_protocol	Network-layer protocol
395
+ * @v net_dest		Destination network-layer address
396
+ * @v ll_dest		Destination link-layer address, if known
397
+ * @ret rc		Return status code
398
+ */
399
+int neighbour_define ( struct net_device *netdev,
400
+		       struct net_protocol *net_protocol,
401
+		       const void *net_dest, const void *ll_dest ) {
402
+	struct neighbour *neighbour;
403
+
404
+	/* Find or create neighbour cache entry */
405
+	neighbour = neighbour_find ( netdev, net_protocol, net_dest );
406
+	if ( ! neighbour ) {
407
+		neighbour = neighbour_create ( netdev, net_protocol, net_dest );
408
+		if ( ! neighbour )
409
+			return -ENOMEM;
410
+	}
411
+
412
+	/* Set destination address */
413
+	neighbour_discovered ( neighbour, ll_dest );
414
+
415
+	return 0;
416
+}
417
+
418
+/**
419
+ * Update neighbour cache on network device creation
420
+ *
421
+ * @v netdev		Network device
422
+ */
423
+static int neighbour_probe ( struct net_device *netdev __unused ) {
424
+	/* Nothing to do */
425
+	return 0;
426
+}
427
+
428
+/**
429
+ * Update neighbour cache on network device state change or removal
430
+ *
431
+ * @v netdev		Network device
432
+ */
433
+static void neighbour_flush ( struct net_device *netdev ) {
434
+	struct neighbour *neighbour;
435
+	struct neighbour *tmp;
436
+
437
+	/* Remove all neighbour cache entries when a network device is closed */
438
+	if ( ! netdev_is_open ( netdev ) ) {
439
+		list_for_each_entry_safe ( neighbour, tmp, &neighbours, list )
440
+			neighbour_destroy ( neighbour, -ENODEV );
441
+	}
442
+}
443
+
444
+/** Neighbour driver (for net device notifications) */
445
+struct net_driver neighbour_net_driver __net_driver = {
446
+	.name = "Neighbour",
447
+	.probe = neighbour_probe,
448
+	.notify = neighbour_flush,
449
+	.remove = neighbour_flush,
450
+};
451
+
452
+/**
453
+ * Discard some cached neighbour entries
454
+ *
455
+ * @ret discarded	Number of cached items discarded
456
+ */
457
+static unsigned int neighbour_discard ( void ) {
458
+	struct neighbour *neighbour;
459
+
460
+	/* Drop oldest cache entry, if any */
461
+	neighbour = list_last_entry ( &neighbours, struct neighbour, list );
462
+	if ( neighbour ) {
463
+		neighbour_destroy ( neighbour, -ENOBUFS );
464
+		return 1;
465
+	} else {
466
+		return 0;
467
+	}
468
+}
469
+
470
+/**
471
+ * Neighbour cache discarder
472
+ *
473
+ * Neighbour cache entries are deemed to have a high replacement cost,
474
+ * since flushing an active neighbour cache entry midway through a TCP
475
+ * transfer will cause substantial disruption.
476
+ */
477
+struct cache_discarder neighbour_discarder __cache_discarder (CACHE_EXPENSIVE)={
478
+	.discard = neighbour_discard,
479
+};

Loading…
Cancel
Save