Browse Source

[ipv6] Create routing table based on IPv6 settings

Use the IPv6 settings to construct the routing table, in a matter
analogous to the construction of the IPv4 routing table.

This allows for manual assignment of IPv6 addresses via e.g.

  set net0/ip6 2001:ba8:0:1d4::6950:5845
  set net0/len6 64
  set net0/gateway6 fe80::226:bff:fedd:d3c0

The prefix length ("len6") may be omitted, in which case a default
prefix length of 64 will be assumed.

Multiple IPv6 addresses may be assigned manually by implicitly
creating child settings blocks.  For example:

  set net0/ip6 2001:ba8:0:1d4::6950:5845
  set net0.ula/ip6 fda4:2496:e992::6950:5845

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 8 years ago
parent
commit
c34d1518eb
4 changed files with 138 additions and 191 deletions
  1. 6
    4
      src/include/ipxe/ipv6.h
  2. 129
    118
      src/net/ipv6.c
  3. 2
    53
      src/net/ndp.c
  4. 1
    16
      src/net/udp/dhcpv6.c

+ 6
- 4
src/include/ipxe/ipv6.h View File

@@ -25,6 +25,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 25
 /** IPv6 maximum hop limit */
26 26
 #define IPV6_HOP_LIMIT 0xff
27 27
 
28
+/** IPv6 default prefix length */
29
+#define IPV6_DEFAULT_PREFIX_LEN 64
30
+
31
+/** IPv6 maximum prefix length */
32
+#define IPV6_MAX_PREFIX_LEN 128
33
+
28 34
 /** IPv6 header */
29 35
 struct ipv6_header {
30 36
 	/** Version (4 bits), Traffic class (8 bits), Flow label (20 bits) */
@@ -258,10 +264,6 @@ extern struct list_head ipv6_miniroutes;
258 264
 extern struct net_protocol ipv6_protocol __net_protocol;
259 265
 
260 266
 extern int ipv6_has_addr ( struct net_device *netdev, struct in6_addr *addr );
261
-extern int ipv6_set_prefix ( struct net_device *netdev, struct in6_addr *prefix,
262
-			     unsigned int prefix_len, struct in6_addr *router );
263
-extern int ipv6_set_address ( struct net_device *netdev,
264
-			      struct in6_addr *address );
265 267
 extern int parse_ipv6_setting ( const struct setting_type *type,
266 268
 				const char *value, void *buf, size_t len );
267 269
 extern int format_ipv6_setting ( const struct setting_type *type,

+ 129
- 118
src/net/ipv6.c View File

@@ -164,107 +164,85 @@ static struct ipv6_miniroute * ipv6_miniroute ( struct net_device *netdev,
164 164
  * @v netdev		Network device
165 165
  * @v address		IPv6 address (or prefix)
166 166
  * @v prefix_len	Prefix length
167
- * @v flags		Flags
168
- * @ret miniroute	Routing table entry, or NULL on failure
167
+ * @v router		Router address (if any)
168
+ * @ret rc		Return status code
169 169
  */
170
-static struct ipv6_miniroute * ipv6_add_miniroute ( struct net_device *netdev,
171
-						    struct in6_addr *address,
172
-						    unsigned int prefix_len,
173
-						    unsigned int flags ) {
170
+static int ipv6_add_miniroute ( struct net_device *netdev,
171
+				struct in6_addr *address,
172
+				unsigned int prefix_len,
173
+				struct in6_addr *router ) {
174 174
 	struct ipv6_miniroute *miniroute;
175 175
 	uint8_t *prefix_mask;
176
+	unsigned int remaining;
177
+	unsigned int i;
176 178
 
177
-	/* Create routing table entry */
178
-	miniroute = zalloc ( sizeof ( *miniroute ) );
179
-	if ( ! miniroute )
180
-		return NULL;
181
-	miniroute->netdev = netdev_get ( netdev );
182
-	memcpy ( &miniroute->address, address, sizeof ( miniroute->address ) );
183
-	miniroute->prefix_len = prefix_len;
184
-	assert ( prefix_len <= ( 8 * sizeof ( miniroute->prefix_mask ) ) );
185
-	for ( prefix_mask = miniroute->prefix_mask.s6_addr ; prefix_len >= 8 ;
186
-	      prefix_mask++, prefix_len -= 8 ) {
187
-		*prefix_mask = 0xff;
188
-	}
189
-	if ( prefix_len )
190
-		*prefix_mask <<= ( 8 - prefix_len );
191
-	miniroute->flags = flags;
192
-	list_add ( &miniroute->list, &ipv6_miniroutes );
193
-	ipv6_dump_miniroute ( miniroute );
194
-
195
-	return miniroute;
196
-}
179
+	/* Find or create routing table entry */
180
+	miniroute = ipv6_miniroute ( netdev, address );
181
+	if ( ! miniroute ) {
182
+
183
+		/* Create new routing table entry */
184
+		miniroute = zalloc ( sizeof ( *miniroute ) );
185
+		if ( ! miniroute )
186
+			return -ENOMEM;
187
+		miniroute->netdev = netdev_get ( netdev );
188
+		memcpy ( &miniroute->address, address,
189
+			 sizeof ( miniroute->address ) );
190
+
191
+		/* Default to prefix length of 64 if none specified */
192
+		if ( ! prefix_len )
193
+			prefix_len = IPV6_DEFAULT_PREFIX_LEN;
194
+		miniroute->prefix_len = prefix_len;
195
+		assert ( prefix_len <= IPV6_MAX_PREFIX_LEN );
196
+
197
+		/* Construct prefix mask */
198
+		remaining = prefix_len;
199
+		for ( prefix_mask = miniroute->prefix_mask.s6_addr ;
200
+		      remaining >= 8 ; prefix_mask++, remaining -= 8 ) {
201
+			*prefix_mask = 0xff;
202
+		}
203
+		if ( remaining )
204
+			*prefix_mask <<= ( 8 - remaining );
197 205
 
198
-/**
199
- * Define IPv6 on-link prefix
200
- *
201
- * @v netdev		Network device
202
- * @v prefix		IPv6 address prefix
203
- * @v prefix_len	Prefix length
204
- * @v router		Router address (or NULL)
205
- * @ret rc		Return status code
206
- */
207
-int ipv6_set_prefix ( struct net_device *netdev, struct in6_addr *prefix,
208
-		      unsigned int prefix_len, struct in6_addr *router ) {
209
-	struct ipv6_miniroute *miniroute;
210
-	int changed;
206
+		/* Add to list of routes */
207
+		list_add ( &miniroute->list, &ipv6_miniroutes );
208
+	}
211 209
 
212
-	/* Find or create routing table entry */
213
-	miniroute = ipv6_miniroute ( netdev, prefix );
214
-	if ( ! miniroute )
215
-		miniroute = ipv6_add_miniroute ( netdev, prefix, prefix_len, 0);
216
-	if ( ! miniroute )
217
-		return -ENOMEM;
210
+	/* Set or update address, if applicable */
211
+	for ( i = 0 ; i < ( sizeof ( address->s6_addr32 ) /
212
+			    sizeof ( address->s6_addr32[0] ) ) ; i++ ) {
213
+		if ( ( address->s6_addr32[i] &
214
+		       ~miniroute->prefix_mask.s6_addr32[i] ) != 0 ) {
215
+			memcpy ( &miniroute->address, address,
216
+				 sizeof ( miniroute->address ) );
217
+			miniroute->flags |= IPV6_HAS_ADDRESS;
218
+		}
219
+	}
220
+	if ( miniroute->prefix_len == IPV6_MAX_PREFIX_LEN )
221
+		miniroute->flags |= IPV6_HAS_ADDRESS;
218 222
 
219
-	/* Record router and add to start or end of list as appropriate */
220
-	list_del ( &miniroute->list );
223
+	/* Set or update router, if applicable */
221 224
 	if ( router ) {
222
-		changed = ( ( ! ( miniroute->flags & IPV6_HAS_ROUTER ) ) ||
223
-			    ( memcmp ( &miniroute->router, router,
224
-				       sizeof ( miniroute->router ) ) != 0 ) );
225
-		miniroute->flags |= IPV6_HAS_ROUTER;
226 225
 		memcpy ( &miniroute->router, router,
227 226
 			 sizeof ( miniroute->router ) );
227
+		miniroute->flags |= IPV6_HAS_ROUTER;
228
+		list_del ( &miniroute->list );
228 229
 		list_add_tail ( &miniroute->list, &ipv6_miniroutes );
229
-	} else {
230
-		changed = ( miniroute->flags & IPV6_HAS_ROUTER );
231
-		miniroute->flags &= ~IPV6_HAS_ROUTER;
232
-		list_add ( &miniroute->list, &ipv6_miniroutes );
233 230
 	}
234
-	if ( changed )
235
-		ipv6_dump_miniroute ( miniroute );
236 231
 
232
+	ipv6_dump_miniroute ( miniroute );
237 233
 	return 0;
238 234
 }
239 235
 
240 236
 /**
241
- * Add IPv6 on-link address
237
+ * Delete IPv6 minirouting table entry
242 238
  *
243
- * @v netdev		Network device
244
- * @v address		IPv6 address
245
- * @ret rc		Return status code
246
- *
247
- * An on-link prefix for the address must already exist.
239
+ * @v miniroute		Routing table entry
248 240
  */
249
-int ipv6_set_address ( struct net_device *netdev, struct in6_addr *address ) {
250
-	struct ipv6_miniroute *miniroute;
251
-	int changed;
252
-
253
-	/* Find routing table entry */
254
-	miniroute = ipv6_miniroute ( netdev, address );
255
-	if ( ! miniroute )
256
-		return -EADDRNOTAVAIL;
241
+static void ipv6_del_miniroute ( struct ipv6_miniroute *miniroute ) {
257 242
 
258
-	/* Record address */
259
-	changed = ( ( ! ( miniroute->flags & IPV6_HAS_ADDRESS ) ) ||
260
-		    ( memcmp ( &miniroute->address, address,
261
-			       sizeof ( miniroute->address ) ) != 0 ) );
262
-	memcpy ( &miniroute->address, address, sizeof ( miniroute->address ) );
263
-	miniroute->flags |= IPV6_HAS_ADDRESS;
264
-	if ( changed )
265
-		ipv6_dump_miniroute ( miniroute );
266
-
267
-	return 0;
243
+	netdev_put ( miniroute->netdev );
244
+	list_del ( &miniroute->list );
245
+	free ( miniroute );
268 246
 }
269 247
 
270 248
 /**
@@ -1198,65 +1176,98 @@ static int ipv6_register_settings ( struct net_device *netdev ) {
1198 1176
 	return rc;
1199 1177
 }
1200 1178
 
1179
+/** IPv6 network device driver */
1180
+struct net_driver ipv6_driver __net_driver = {
1181
+	.name = "IPv6",
1182
+	.probe = ipv6_register_settings,
1183
+};
1184
+
1201 1185
 /**
1202
- * Create IPv6 network device
1186
+ * Create IPv6 routing table based on configured settings
1203 1187
  *
1204 1188
  * @v netdev		Network device
1189
+ * @v settings		Settings block
1205 1190
  * @ret rc		Return status code
1206 1191
  */
1207
-static int ipv6_probe ( struct net_device *netdev ) {
1208
-	struct ipv6_miniroute *miniroute;
1209
-	struct in6_addr address;
1210
-	int prefix_len;
1192
+static int ipv6_create_routes ( struct net_device *netdev,
1193
+				struct settings *settings ) {
1194
+	struct settings *child;
1195
+	struct settings *origin;
1196
+	struct in6_addr ip6_buf;
1197
+	struct in6_addr gateway6_buf;
1198
+	struct in6_addr *ip6 = &ip6_buf;
1199
+	struct in6_addr *gateway6 = &gateway6_buf;
1200
+	uint8_t len6;
1201
+	size_t len;
1211 1202
 	int rc;
1212 1203
 
1213
-	/* Construct link-local address from EUI-64 as per RFC 2464 */
1214
-	memset ( &address, 0, sizeof ( address ) );
1215
-	prefix_len = ipv6_link_local ( &address, netdev );
1216
-	if ( prefix_len < 0 ) {
1217
-		rc = prefix_len;
1218
-		DBGC ( netdev, "IPv6 %s could not construct link-local "
1219
-		       "address: %s\n", netdev->name, strerror ( rc ) );
1204
+	/* First, create routing table for any child settings.  We do
1205
+	 * this depth-first and in reverse order so that the end
1206
+	 * result reflects the relative priorities of the settings
1207
+	 * blocks.
1208
+	 */
1209
+	list_for_each_entry_reverse ( child, &settings->children, siblings )
1210
+		ipv6_create_routes ( netdev, child );
1211
+
1212
+	/* Fetch IPv6 address, if any */
1213
+	len = fetch_setting ( settings, &ip6_setting, &origin, NULL,
1214
+			      ip6, sizeof ( *ip6 ) );
1215
+	if ( ( len != sizeof ( *ip6 ) ) || ( origin != settings ) )
1216
+		return 0;
1217
+
1218
+	/* Fetch prefix length, if defined */
1219
+	len = fetch_setting ( settings, &len6_setting, &origin, NULL,
1220
+			      &len6, sizeof ( len6 ) );
1221
+	if ( ( len != sizeof ( len6 ) ) || ( origin != settings ) )
1222
+		len6 = 0;
1223
+	if ( len6 > IPV6_MAX_PREFIX_LEN )
1224
+		len6 = IPV6_MAX_PREFIX_LEN;
1225
+
1226
+	/* Fetch gateway, if defined */
1227
+	len = fetch_setting ( settings, &gateway6_setting, &origin, NULL,
1228
+			      gateway6, sizeof ( *gateway6 ) );
1229
+	if ( ( len != sizeof ( *gateway6 ) ) || ( origin != settings ) )
1230
+		gateway6 = NULL;
1231
+
1232
+	/* Create or update route */
1233
+	if ( ( rc = ipv6_add_miniroute ( netdev, ip6, len6, gateway6 ) ) != 0){
1234
+		DBGC ( netdev, "IPv6 %s could not add route: %s\n",
1235
+		       netdev->name, strerror ( rc ) );
1220 1236
 		return rc;
1221 1237
 	}
1222 1238
 
1223
-	/* Create link-local address for this network device */
1224
-	miniroute = ipv6_add_miniroute ( netdev, &address, prefix_len,
1225
-					 IPV6_HAS_ADDRESS );
1226
-	if ( ! miniroute )
1227
-		return -ENOMEM;
1228
-
1229
-	/* Register link-local address settings */
1230
-	if ( ( rc = ipv6_register_settings ( netdev ) ) != 0 )
1231
-		return rc;
1232
-
1233 1239
 	return 0;
1234 1240
 }
1235 1241
 
1236 1242
 /**
1237
- * Destroy IPv6 network device
1243
+ * Create IPv6 routing table based on configured settings
1238 1244
  *
1239
- * @v netdev		Network device
1245
+ * @ret rc		Return status code
1240 1246
  */
1241
-static void ipv6_remove ( struct net_device *netdev ) {
1247
+static int ipv6_create_all_routes ( void ) {
1242 1248
 	struct ipv6_miniroute *miniroute;
1243 1249
 	struct ipv6_miniroute *tmp;
1250
+	struct net_device *netdev;
1251
+	struct settings *settings;
1252
+	int rc;
1244 1253
 
1245
-	/* Delete all miniroutes for this network device */
1246
-	list_for_each_entry_safe ( miniroute, tmp, &ipv6_miniroutes, list ) {
1247
-		if ( miniroute->netdev == netdev ) {
1248
-			netdev_put ( miniroute->netdev );
1249
-			list_del ( &miniroute->list );
1250
-			free ( miniroute );
1251
-		}
1254
+	/* Delete all existing routes */
1255
+	list_for_each_entry_safe ( miniroute, tmp, &ipv6_miniroutes, list )
1256
+		ipv6_del_miniroute ( miniroute );
1257
+
1258
+	/* Create routes for each configured network device */
1259
+	for_each_netdev ( netdev ) {
1260
+		settings = netdev_settings ( netdev );
1261
+		if ( ( rc = ipv6_create_routes ( netdev, settings ) ) != 0 )
1262
+			return rc;
1252 1263
 	}
1264
+
1265
+	return 0;
1253 1266
 }
1254 1267
 
1255
-/** IPv6 network device driver */
1256
-struct net_driver ipv6_driver __net_driver = {
1257
-	.name = "IPv6",
1258
-	.probe = ipv6_probe,
1259
-	.remove = ipv6_remove,
1268
+/** IPv6 settings applicator */
1269
+struct settings_applicator ipv6_settings_applicator __settings_applicator = {
1270
+	.apply = ipv6_create_all_routes,
1260 1271
 };
1261 1272
 
1262 1273
 /* Drag in objects via ipv6_protocol */

+ 2
- 53
src/net/ndp.c View File

@@ -342,11 +342,6 @@ ndp_rx_router_advertisement_prefix ( struct net_device *netdev,
342 342
 				     union ndp_option *option, size_t len ) {
343 343
 	struct ndp_router_advertisement_header *radv = &ndp->radv;
344 344
 	struct ndp_prefix_information_option *prefix_opt = &option->prefix;
345
-	struct in6_addr *router = &sin6_src->sin6_addr;
346
-	struct in6_addr address;
347
-	struct ipv6conf *ipv6conf;
348
-	int prefix_len;
349
-	int rc;
350 345
 
351 346
 	/* Sanity check */
352 347
 	if ( sizeof ( *prefix_opt ) > len ) {
@@ -355,59 +350,13 @@ ndp_rx_router_advertisement_prefix ( struct net_device *netdev,
355 350
 		return -EINVAL;
356 351
 	}
357 352
 
358
-	/* Identify IPv6 configurator, if any */
359
-	ipv6conf = ipv6conf_demux ( netdev );
360 353
 	DBGC ( netdev, "NDP %s found %sdefault router %s ",
361 354
 	       netdev->name, ( radv->lifetime ? "" : "non-" ),
362 355
 	       inet6_ntoa ( &sin6_src->sin6_addr ) );
363
-	DBGC ( netdev, "for %s-link %sautonomous prefix %s/%d%s\n",
356
+	DBGC ( netdev, "for %s-link %sautonomous prefix %s/%d\n",
364 357
 	       ( ( prefix_opt->flags & NDP_PREFIX_ON_LINK ) ? "on" : "off" ),
365 358
 	       ( ( prefix_opt->flags & NDP_PREFIX_AUTONOMOUS ) ? "" : "non-" ),
366
-	       inet6_ntoa ( &prefix_opt->prefix ),
367
-	       prefix_opt->prefix_len, ( ipv6conf ? "" : " (ignored)" ) );
368
-
369
-	/* Do nothing unless IPv6 autoconfiguration is in progress */
370
-	if ( ! ipv6conf )
371
-		return 0;
372
-
373
-	/* Ignore off-link prefixes */
374
-	if ( ! ( prefix_opt->flags & NDP_PREFIX_ON_LINK ) )
375
-		return 0;
376
-
377
-	/* Define prefix */
378
-	if ( ( rc = ipv6_set_prefix ( netdev, &prefix_opt->prefix,
379
-				      prefix_opt->prefix_len,
380
-				      ( radv->lifetime ?
381
-					router : NULL ) ) ) != 0 ) {
382
-		DBGC ( netdev, "NDP %s could not define prefix %s/%d: %s\n",
383
-		       netdev->name, inet6_ntoa ( &prefix_opt->prefix ),
384
-		       prefix_opt->prefix_len, strerror ( rc ) );
385
-		return rc;
386
-	}
387
-
388
-	/* Perform stateless address autoconfiguration, if applicable */
389
-	if ( prefix_opt->flags & NDP_PREFIX_AUTONOMOUS ) {
390
-		memcpy ( &address, &prefix_opt->prefix, sizeof ( address ) );
391
-		prefix_len = ipv6_eui64 ( &address, netdev );
392
-		if ( prefix_len < 0 ) {
393
-			rc = prefix_len;
394
-			DBGC ( netdev, "NDP %s could not construct SLAAC "
395
-			       "address: %s\n", netdev->name, strerror ( rc ) );
396
-			return rc;
397
-		}
398
-		if ( prefix_len != prefix_opt->prefix_len ) {
399
-			DBGC ( netdev, "NDP %s incorrect SLAAC prefix length "
400
-			       "%d (expected %d)\n", netdev->name,
401
-			       prefix_opt->prefix_len, prefix_len );
402
-			return -EINVAL;
403
-		}
404
-		if ( ( rc = ipv6_set_address ( netdev, &address ) ) != 0 ) {
405
-			DBGC ( netdev, "NDP %s could not set address %s: %s\n",
406
-			       netdev->name, inet6_ntoa ( &address ),
407
-			       strerror ( rc ) );
408
-			return rc;
409
-		}
410
-	}
359
+	       inet6_ntoa ( &prefix_opt->prefix ), prefix_opt->prefix_len );
411 360
 
412 361
 	return 0;
413 362
 }

+ 1
- 16
src/net/udp/dhcpv6.c View File

@@ -462,8 +462,6 @@ enum dhcpv6_session_state_flags {
462 462
 	DHCPV6_RX_RECORD_SERVER_ID = 0x04,
463 463
 	/** Record received IPv6 address */
464 464
 	DHCPV6_RX_RECORD_IAADDR = 0x08,
465
-	/** Apply received IPv6 address */
466
-	DHCPV6_RX_APPLY_IAADDR = 0x10,
467 465
 };
468 466
 
469 467
 /** DHCPv6 request state */
@@ -471,7 +469,7 @@ static struct dhcpv6_session_state dhcpv6_request = {
471 469
 	.tx_type = DHCPV6_REQUEST,
472 470
 	.rx_type = DHCPV6_REPLY,
473 471
 	.flags = ( DHCPV6_TX_IA_NA | DHCPV6_TX_IAADDR |
474
-		   DHCPV6_RX_RECORD_IAADDR | DHCPV6_RX_APPLY_IAADDR ),
472
+		   DHCPV6_RX_RECORD_IAADDR ),
475 473
 	.next = NULL,
476 474
 };
477 475
 
@@ -870,19 +868,6 @@ static int dhcpv6_rx ( struct dhcpv6_session *dhcpv6,
870 868
 			 dhcpv6->server_duid_len );
871 869
 	}
872 870
 
873
-	/* Apply identity association address, if applicable */
874
-	if ( dhcpv6->state->flags & DHCPV6_RX_APPLY_IAADDR ) {
875
-		if ( ( rc = ipv6_set_address ( dhcpv6->netdev,
876
-					       &dhcpv6->lease ) ) != 0 ) {
877
-			DBGC ( dhcpv6, "DHCPv6 %s could not apply %s: %s\n",
878
-			       dhcpv6->netdev->name,
879
-			       inet6_ntoa ( &dhcpv6->lease ), strerror ( rc ) );
880
-			/* This is plausibly the error we want to return */
881
-			dhcpv6->rc = rc;
882
-			goto done;
883
-		}
884
-	}
885
-
886 871
 	/* Transition to next state, if applicable */
887 872
 	if ( dhcpv6->state->next ) {
888 873
 		dhcpv6_set_state ( dhcpv6, dhcpv6->state->next );

Loading…
Cancel
Save