summaryrefslogtreecommitdiffstats
path: root/src/net
diff options
context:
space:
mode:
authorMichael Brown2016-07-19 18:49:50 +0200
committerMichael Brown2016-07-20 14:02:44 +0200
commitc34d1518eb446d596087ed2b9dda33a513f7e980 (patch)
treea15c1ffcaccdbe92803a55e0d41784039db46643 /src/net
parent[ipv6] Match user expectations for IPv6 settings priorities (diff)
downloadipxe-c34d1518eb446d596087ed2b9dda33a513f7e980.tar.gz
ipxe-c34d1518eb446d596087ed2b9dda33a513f7e980.tar.xz
ipxe-c34d1518eb446d596087ed2b9dda33a513f7e980.zip
[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>
Diffstat (limited to 'src/net')
-rw-r--r--src/net/ipv6.c247
-rw-r--r--src/net/ndp.c55
-rw-r--r--src/net/udp/dhcpv6.c17
3 files changed, 132 insertions, 187 deletions
diff --git a/src/net/ipv6.c b/src/net/ipv6.c
index 04ba3d8b..d2a17312 100644
--- a/src/net/ipv6.c
+++ b/src/net/ipv6.c
@@ -164,107 +164,85 @@ static struct ipv6_miniroute * ipv6_miniroute ( struct net_device *netdev,
* @v netdev Network device
* @v address IPv6 address (or prefix)
* @v prefix_len Prefix length
- * @v flags Flags
- * @ret miniroute Routing table entry, or NULL on failure
+ * @v router Router address (if any)
+ * @ret rc Return status code
*/
-static struct ipv6_miniroute * ipv6_add_miniroute ( struct net_device *netdev,
- struct in6_addr *address,
- unsigned int prefix_len,
- unsigned int flags ) {
+static int ipv6_add_miniroute ( struct net_device *netdev,
+ struct in6_addr *address,
+ unsigned int prefix_len,
+ struct in6_addr *router ) {
struct ipv6_miniroute *miniroute;
uint8_t *prefix_mask;
+ unsigned int remaining;
+ unsigned int i;
- /* Create routing table entry */
- miniroute = zalloc ( sizeof ( *miniroute ) );
- if ( ! miniroute )
- return NULL;
- miniroute->netdev = netdev_get ( netdev );
- memcpy ( &miniroute->address, address, sizeof ( miniroute->address ) );
- miniroute->prefix_len = prefix_len;
- assert ( prefix_len <= ( 8 * sizeof ( miniroute->prefix_mask ) ) );
- for ( prefix_mask = miniroute->prefix_mask.s6_addr ; prefix_len >= 8 ;
- prefix_mask++, prefix_len -= 8 ) {
- *prefix_mask = 0xff;
- }
- if ( prefix_len )
- *prefix_mask <<= ( 8 - prefix_len );
- miniroute->flags = flags;
- list_add ( &miniroute->list, &ipv6_miniroutes );
- ipv6_dump_miniroute ( miniroute );
-
- return miniroute;
-}
+ /* Find or create routing table entry */
+ miniroute = ipv6_miniroute ( netdev, address );
+ if ( ! miniroute ) {
+
+ /* Create new routing table entry */
+ miniroute = zalloc ( sizeof ( *miniroute ) );
+ if ( ! miniroute )
+ return -ENOMEM;
+ miniroute->netdev = netdev_get ( netdev );
+ memcpy ( &miniroute->address, address,
+ sizeof ( miniroute->address ) );
+
+ /* Default to prefix length of 64 if none specified */
+ if ( ! prefix_len )
+ prefix_len = IPV6_DEFAULT_PREFIX_LEN;
+ miniroute->prefix_len = prefix_len;
+ assert ( prefix_len <= IPV6_MAX_PREFIX_LEN );
+
+ /* Construct prefix mask */
+ remaining = prefix_len;
+ for ( prefix_mask = miniroute->prefix_mask.s6_addr ;
+ remaining >= 8 ; prefix_mask++, remaining -= 8 ) {
+ *prefix_mask = 0xff;
+ }
+ if ( remaining )
+ *prefix_mask <<= ( 8 - remaining );
-/**
- * Define IPv6 on-link prefix
- *
- * @v netdev Network device
- * @v prefix IPv6 address prefix
- * @v prefix_len Prefix length
- * @v router Router address (or NULL)
- * @ret rc Return status code
- */
-int ipv6_set_prefix ( struct net_device *netdev, struct in6_addr *prefix,
- unsigned int prefix_len, struct in6_addr *router ) {
- struct ipv6_miniroute *miniroute;
- int changed;
+ /* Add to list of routes */
+ list_add ( &miniroute->list, &ipv6_miniroutes );
+ }
- /* Find or create routing table entry */
- miniroute = ipv6_miniroute ( netdev, prefix );
- if ( ! miniroute )
- miniroute = ipv6_add_miniroute ( netdev, prefix, prefix_len, 0);
- if ( ! miniroute )
- return -ENOMEM;
+ /* Set or update address, if applicable */
+ for ( i = 0 ; i < ( sizeof ( address->s6_addr32 ) /
+ sizeof ( address->s6_addr32[0] ) ) ; i++ ) {
+ if ( ( address->s6_addr32[i] &
+ ~miniroute->prefix_mask.s6_addr32[i] ) != 0 ) {
+ memcpy ( &miniroute->address, address,
+ sizeof ( miniroute->address ) );
+ miniroute->flags |= IPV6_HAS_ADDRESS;
+ }
+ }
+ if ( miniroute->prefix_len == IPV6_MAX_PREFIX_LEN )
+ miniroute->flags |= IPV6_HAS_ADDRESS;
- /* Record router and add to start or end of list as appropriate */
- list_del ( &miniroute->list );
+ /* Set or update router, if applicable */
if ( router ) {
- changed = ( ( ! ( miniroute->flags & IPV6_HAS_ROUTER ) ) ||
- ( memcmp ( &miniroute->router, router,
- sizeof ( miniroute->router ) ) != 0 ) );
- miniroute->flags |= IPV6_HAS_ROUTER;
memcpy ( &miniroute->router, router,
sizeof ( miniroute->router ) );
+ miniroute->flags |= IPV6_HAS_ROUTER;
+ list_del ( &miniroute->list );
list_add_tail ( &miniroute->list, &ipv6_miniroutes );
- } else {
- changed = ( miniroute->flags & IPV6_HAS_ROUTER );
- miniroute->flags &= ~IPV6_HAS_ROUTER;
- list_add ( &miniroute->list, &ipv6_miniroutes );
}
- if ( changed )
- ipv6_dump_miniroute ( miniroute );
+ ipv6_dump_miniroute ( miniroute );
return 0;
}
/**
- * Add IPv6 on-link address
+ * Delete IPv6 minirouting table entry
*
- * @v netdev Network device
- * @v address IPv6 address
- * @ret rc Return status code
- *
- * An on-link prefix for the address must already exist.
+ * @v miniroute Routing table entry
*/
-int ipv6_set_address ( struct net_device *netdev, struct in6_addr *address ) {
- struct ipv6_miniroute *miniroute;
- int changed;
-
- /* Find routing table entry */
- miniroute = ipv6_miniroute ( netdev, address );
- if ( ! miniroute )
- return -EADDRNOTAVAIL;
+static void ipv6_del_miniroute ( struct ipv6_miniroute *miniroute ) {
- /* Record address */
- changed = ( ( ! ( miniroute->flags & IPV6_HAS_ADDRESS ) ) ||
- ( memcmp ( &miniroute->address, address,
- sizeof ( miniroute->address ) ) != 0 ) );
- memcpy ( &miniroute->address, address, sizeof ( miniroute->address ) );
- miniroute->flags |= IPV6_HAS_ADDRESS;
- if ( changed )
- ipv6_dump_miniroute ( miniroute );
-
- return 0;
+ netdev_put ( miniroute->netdev );
+ list_del ( &miniroute->list );
+ free ( miniroute );
}
/**
@@ -1198,65 +1176,98 @@ static int ipv6_register_settings ( struct net_device *netdev ) {
return rc;
}
+/** IPv6 network device driver */
+struct net_driver ipv6_driver __net_driver = {
+ .name = "IPv6",
+ .probe = ipv6_register_settings,
+};
+
/**
- * Create IPv6 network device
+ * Create IPv6 routing table based on configured settings
*
* @v netdev Network device
+ * @v settings Settings block
* @ret rc Return status code
*/
-static int ipv6_probe ( struct net_device *netdev ) {
- struct ipv6_miniroute *miniroute;
- struct in6_addr address;
- int prefix_len;
+static int ipv6_create_routes ( struct net_device *netdev,
+ struct settings *settings ) {
+ struct settings *child;
+ struct settings *origin;
+ struct in6_addr ip6_buf;
+ struct in6_addr gateway6_buf;
+ struct in6_addr *ip6 = &ip6_buf;
+ struct in6_addr *gateway6 = &gateway6_buf;
+ uint8_t len6;
+ size_t len;
int rc;
- /* Construct link-local address from EUI-64 as per RFC 2464 */
- memset ( &address, 0, sizeof ( address ) );
- prefix_len = ipv6_link_local ( &address, netdev );
- if ( prefix_len < 0 ) {
- rc = prefix_len;
- DBGC ( netdev, "IPv6 %s could not construct link-local "
- "address: %s\n", netdev->name, strerror ( rc ) );
+ /* First, create routing table for any child settings. We do
+ * this depth-first and in reverse order so that the end
+ * result reflects the relative priorities of the settings
+ * blocks.
+ */
+ list_for_each_entry_reverse ( child, &settings->children, siblings )
+ ipv6_create_routes ( netdev, child );
+
+ /* Fetch IPv6 address, if any */
+ len = fetch_setting ( settings, &ip6_setting, &origin, NULL,
+ ip6, sizeof ( *ip6 ) );
+ if ( ( len != sizeof ( *ip6 ) ) || ( origin != settings ) )
+ return 0;
+
+ /* Fetch prefix length, if defined */
+ len = fetch_setting ( settings, &len6_setting, &origin, NULL,
+ &len6, sizeof ( len6 ) );
+ if ( ( len != sizeof ( len6 ) ) || ( origin != settings ) )
+ len6 = 0;
+ if ( len6 > IPV6_MAX_PREFIX_LEN )
+ len6 = IPV6_MAX_PREFIX_LEN;
+
+ /* Fetch gateway, if defined */
+ len = fetch_setting ( settings, &gateway6_setting, &origin, NULL,
+ gateway6, sizeof ( *gateway6 ) );
+ if ( ( len != sizeof ( *gateway6 ) ) || ( origin != settings ) )
+ gateway6 = NULL;
+
+ /* Create or update route */
+ if ( ( rc = ipv6_add_miniroute ( netdev, ip6, len6, gateway6 ) ) != 0){
+ DBGC ( netdev, "IPv6 %s could not add route: %s\n",
+ netdev->name, strerror ( rc ) );
return rc;
}
- /* Create link-local address for this network device */
- miniroute = ipv6_add_miniroute ( netdev, &address, prefix_len,
- IPV6_HAS_ADDRESS );
- if ( ! miniroute )
- return -ENOMEM;
-
- /* Register link-local address settings */
- if ( ( rc = ipv6_register_settings ( netdev ) ) != 0 )
- return rc;
-
return 0;
}
/**
- * Destroy IPv6 network device
+ * Create IPv6 routing table based on configured settings
*
- * @v netdev Network device
+ * @ret rc Return status code
*/
-static void ipv6_remove ( struct net_device *netdev ) {
+static int ipv6_create_all_routes ( void ) {
struct ipv6_miniroute *miniroute;
struct ipv6_miniroute *tmp;
+ struct net_device *netdev;
+ struct settings *settings;
+ int rc;
- /* Delete all miniroutes for this network device */
- list_for_each_entry_safe ( miniroute, tmp, &ipv6_miniroutes, list ) {
- if ( miniroute->netdev == netdev ) {
- netdev_put ( miniroute->netdev );
- list_del ( &miniroute->list );
- free ( miniroute );
- }
+ /* Delete all existing routes */
+ list_for_each_entry_safe ( miniroute, tmp, &ipv6_miniroutes, list )
+ ipv6_del_miniroute ( miniroute );
+
+ /* Create routes for each configured network device */
+ for_each_netdev ( netdev ) {
+ settings = netdev_settings ( netdev );
+ if ( ( rc = ipv6_create_routes ( netdev, settings ) ) != 0 )
+ return rc;
}
+
+ return 0;
}
-/** IPv6 network device driver */
-struct net_driver ipv6_driver __net_driver = {
- .name = "IPv6",
- .probe = ipv6_probe,
- .remove = ipv6_remove,
+/** IPv6 settings applicator */
+struct settings_applicator ipv6_settings_applicator __settings_applicator = {
+ .apply = ipv6_create_all_routes,
};
/* Drag in objects via ipv6_protocol */
diff --git a/src/net/ndp.c b/src/net/ndp.c
index a35a1219..21bbd999 100644
--- a/src/net/ndp.c
+++ b/src/net/ndp.c
@@ -342,11 +342,6 @@ ndp_rx_router_advertisement_prefix ( struct net_device *netdev,
union ndp_option *option, size_t len ) {
struct ndp_router_advertisement_header *radv = &ndp->radv;
struct ndp_prefix_information_option *prefix_opt = &option->prefix;
- struct in6_addr *router = &sin6_src->sin6_addr;
- struct in6_addr address;
- struct ipv6conf *ipv6conf;
- int prefix_len;
- int rc;
/* Sanity check */
if ( sizeof ( *prefix_opt ) > len ) {
@@ -355,59 +350,13 @@ ndp_rx_router_advertisement_prefix ( struct net_device *netdev,
return -EINVAL;
}
- /* Identify IPv6 configurator, if any */
- ipv6conf = ipv6conf_demux ( netdev );
DBGC ( netdev, "NDP %s found %sdefault router %s ",
netdev->name, ( radv->lifetime ? "" : "non-" ),
inet6_ntoa ( &sin6_src->sin6_addr ) );
- DBGC ( netdev, "for %s-link %sautonomous prefix %s/%d%s\n",
+ DBGC ( netdev, "for %s-link %sautonomous prefix %s/%d\n",
( ( prefix_opt->flags & NDP_PREFIX_ON_LINK ) ? "on" : "off" ),
( ( prefix_opt->flags & NDP_PREFIX_AUTONOMOUS ) ? "" : "non-" ),
- inet6_ntoa ( &prefix_opt->prefix ),
- prefix_opt->prefix_len, ( ipv6conf ? "" : " (ignored)" ) );
-
- /* Do nothing unless IPv6 autoconfiguration is in progress */
- if ( ! ipv6conf )
- return 0;
-
- /* Ignore off-link prefixes */
- if ( ! ( prefix_opt->flags & NDP_PREFIX_ON_LINK ) )
- return 0;
-
- /* Define prefix */
- if ( ( rc = ipv6_set_prefix ( netdev, &prefix_opt->prefix,
- prefix_opt->prefix_len,
- ( radv->lifetime ?
- router : NULL ) ) ) != 0 ) {
- DBGC ( netdev, "NDP %s could not define prefix %s/%d: %s\n",
- netdev->name, inet6_ntoa ( &prefix_opt->prefix ),
- prefix_opt->prefix_len, strerror ( rc ) );
- return rc;
- }
-
- /* Perform stateless address autoconfiguration, if applicable */
- if ( prefix_opt->flags & NDP_PREFIX_AUTONOMOUS ) {
- memcpy ( &address, &prefix_opt->prefix, sizeof ( address ) );
- prefix_len = ipv6_eui64 ( &address, netdev );
- if ( prefix_len < 0 ) {
- rc = prefix_len;
- DBGC ( netdev, "NDP %s could not construct SLAAC "
- "address: %s\n", netdev->name, strerror ( rc ) );
- return rc;
- }
- if ( prefix_len != prefix_opt->prefix_len ) {
- DBGC ( netdev, "NDP %s incorrect SLAAC prefix length "
- "%d (expected %d)\n", netdev->name,
- prefix_opt->prefix_len, prefix_len );
- return -EINVAL;
- }
- if ( ( rc = ipv6_set_address ( netdev, &address ) ) != 0 ) {
- DBGC ( netdev, "NDP %s could not set address %s: %s\n",
- netdev->name, inet6_ntoa ( &address ),
- strerror ( rc ) );
- return rc;
- }
- }
+ inet6_ntoa ( &prefix_opt->prefix ), prefix_opt->prefix_len );
return 0;
}
diff --git a/src/net/udp/dhcpv6.c b/src/net/udp/dhcpv6.c
index a2c69aaa..253032e4 100644
--- a/src/net/udp/dhcpv6.c
+++ b/src/net/udp/dhcpv6.c
@@ -462,8 +462,6 @@ enum dhcpv6_session_state_flags {
DHCPV6_RX_RECORD_SERVER_ID = 0x04,
/** Record received IPv6 address */
DHCPV6_RX_RECORD_IAADDR = 0x08,
- /** Apply received IPv6 address */
- DHCPV6_RX_APPLY_IAADDR = 0x10,
};
/** DHCPv6 request state */
@@ -471,7 +469,7 @@ static struct dhcpv6_session_state dhcpv6_request = {
.tx_type = DHCPV6_REQUEST,
.rx_type = DHCPV6_REPLY,
.flags = ( DHCPV6_TX_IA_NA | DHCPV6_TX_IAADDR |
- DHCPV6_RX_RECORD_IAADDR | DHCPV6_RX_APPLY_IAADDR ),
+ DHCPV6_RX_RECORD_IAADDR ),
.next = NULL,
};
@@ -870,19 +868,6 @@ static int dhcpv6_rx ( struct dhcpv6_session *dhcpv6,
dhcpv6->server_duid_len );
}
- /* Apply identity association address, if applicable */
- if ( dhcpv6->state->flags & DHCPV6_RX_APPLY_IAADDR ) {
- if ( ( rc = ipv6_set_address ( dhcpv6->netdev,
- &dhcpv6->lease ) ) != 0 ) {
- DBGC ( dhcpv6, "DHCPv6 %s could not apply %s: %s\n",
- dhcpv6->netdev->name,
- inet6_ntoa ( &dhcpv6->lease ), strerror ( rc ) );
- /* This is plausibly the error we want to return */
- dhcpv6->rc = rc;
- goto done;
- }
- }
-
/* Transition to next state, if applicable */
if ( dhcpv6->state->next ) {
dhcpv6_set_state ( dhcpv6, dhcpv6->state->next );