Skip to content

Commit b66e27d

Browse files
committed
[ipv6] Expose router address for DHCPv6 leased addresses
The DHCPv6 protocol does not itself provide a router address or a prefix length. This information is instead obtained from the router advertisements. Our IPv6 minirouting table construction logic will first construct an entry for each advertised prefix, and later update the entry to include an address assigned within that prefix via stateful DHCPv6 (if applicable). This logic fails if the address assigned via stateful DHCPv6 does not fall within any of the advertised prefixes (e.g. if the network is configured to use DHCPv6-assigned /128 addresses with no advertised on-link prefixes). We will currently treat this situation as equivalent to having a manually assigned address with no corresponding router address or prefix length: the routing table entry will use the default /64 prefix length and will not include the router address. DHCPv6 is triggered only in response to a router advertisement with the "Managed Address Configuration (M)" or "Other Configuration (O)" flags set, and a router address is therefore available at the point that we initiate DHCPv6. Record the router address when initiating DHCPv6, and expose this router address as part of the DHCPv6 settings block. This allows the routing table entry for any address assigned via stateful DHCPv6 to correctly include the router address, even if the assigned address does not fall within an advertised prefix. Also provide a fixed /128 prefix length as part of the DHCPv6 settings block. When an address assigned via stateful DHCPv6 does not fall within an advertised prefix, this will cause the routing table entry to have a /128 prefix length as expected. (When such an address does fall within an advertised prefix, it will continue to use the advertised prefix length.) Originally-fixed-by: Guvenc Gulce <[email protected]> Signed-off-by: Michael Brown <[email protected]>
1 parent 77acf6b commit b66e27d

File tree

3 files changed

+97
-18
lines changed

3 files changed

+97
-18
lines changed

src/include/ipxe/dhcpv6.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,6 @@ static inline void ipv6_all_dhcp_relay_and_servers ( struct in6_addr *addr ) {
276276
}
277277

278278
extern int start_dhcpv6 ( struct interface *job, struct net_device *netdev,
279-
int stateful );
279+
struct in6_addr *router, int stateful );
280280

281281
#endif /* _IPXE_DHCPV6_H */

src/net/ndp.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -1221,7 +1221,7 @@ ipv6conf_rx_router_advertisement ( struct net_device *netdev,
12211221
/* Start DHCPv6 if required */
12221222
if ( radv->flags & ( NDP_ROUTER_MANAGED | NDP_ROUTER_OTHER ) ) {
12231223
stateful = ( radv->flags & NDP_ROUTER_MANAGED );
1224-
if ( ( rc = start_dhcpv6 ( &ipv6conf->dhcp, netdev,
1224+
if ( ( rc = start_dhcpv6 ( &ipv6conf->dhcp, netdev, router,
12251225
stateful ) ) != 0 ) {
12261226
DBGC ( netdev, "NDP %s could not start state%s DHCPv6: "
12271227
"%s\n", netdev->name,

src/net/udp/dhcpv6.c

+95-16
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,8 @@ struct dhcpv6_settings {
268268
struct settings settings;
269269
/** Leased address */
270270
struct in6_addr lease;
271+
/** Router address */
272+
struct in6_addr router;
271273
/** Option list */
272274
struct dhcpv6_option_list options;
273275
};
@@ -283,25 +285,21 @@ static int dhcpv6_applies ( struct settings *settings __unused,
283285
const struct setting *setting ) {
284286

285287
return ( ( setting->scope == &dhcpv6_scope ) ||
286-
( setting_cmp ( setting, &ip6_setting ) == 0 ) );
288+
( setting->scope == &ipv6_settings_scope ) );
287289
}
288290

289291
/**
290292
* Fetch value of DHCPv6 leased address
291293
*
292-
* @v dhcpset DHCPv6 settings
294+
* @v dhcpv6set DHCPv6 settings
293295
* @v data Buffer to fill with setting data
294296
* @v len Length of buffer
295297
* @ret len Length of setting data, or negative error
296298
*/
297-
static int dhcpv6_fetch_lease ( struct dhcpv6_settings *dhcpv6set,
298-
void *data, size_t len ) {
299+
static int dhcpv6_fetch_ip6 ( struct dhcpv6_settings *dhcpv6set,
300+
void *data, size_t len ) {
299301
struct in6_addr *lease = &dhcpv6set->lease;
300302

301-
/* Do nothing unless a leased address exists */
302-
if ( IN6_IS_ADDR_UNSPECIFIED ( lease ) )
303-
return -ENOENT;
304-
305303
/* Copy leased address */
306304
if ( len > sizeof ( *lease ) )
307305
len = sizeof ( *lease );
@@ -310,6 +308,72 @@ static int dhcpv6_fetch_lease ( struct dhcpv6_settings *dhcpv6set,
310308
return sizeof ( *lease );
311309
}
312310

311+
/**
312+
* Fetch value of DHCPv6 implicit address prefix length
313+
*
314+
* @v dhcpv6set DHCPv6 settings
315+
* @v data Buffer to fill with setting data
316+
* @v len Length of buffer
317+
* @ret len Length of setting data, or negative error
318+
*/
319+
static int dhcpv6_fetch_len6 ( struct dhcpv6_settings *dhcpv6set __unused,
320+
void *data, size_t len ) {
321+
uint8_t *len6 = data;
322+
323+
/* Default to assuming this is the only address on the link.
324+
* If the address falls within a known prefix, then the IPv6
325+
* routing table construction logic will match it against that
326+
* prefix.
327+
*/
328+
if ( len )
329+
*len6 = IPV6_MAX_PREFIX_LEN;
330+
331+
return sizeof ( *len6 );
332+
}
333+
334+
/**
335+
* Fetch value of DHCPv6 router address
336+
*
337+
* @v dhcpv6set DHCPv6 settings
338+
* @v data Buffer to fill with setting data
339+
* @v len Length of buffer
340+
* @ret len Length of setting data, or negative error
341+
*/
342+
static int dhcpv6_fetch_gateway6 ( struct dhcpv6_settings *dhcpv6set,
343+
void *data, size_t len ) {
344+
struct in6_addr *router = &dhcpv6set->router;
345+
346+
/* Copy router address */
347+
if ( len > sizeof ( *router ) )
348+
len = sizeof ( *router );
349+
memcpy ( data, router, len );
350+
351+
return sizeof ( *router );
352+
}
353+
354+
/** A DHCPv6 address setting operation */
355+
struct dhcpv6_address_operation {
356+
/** Generic setting */
357+
const struct setting *setting;
358+
/**
359+
* Fetch value of setting
360+
*
361+
* @v dhcpv6set DHCPv6 settings
362+
* @v data Buffer to fill with setting data
363+
* @v len Length of buffer
364+
* @ret len Length of setting data, or negative error
365+
*/
366+
int ( * fetch ) ( struct dhcpv6_settings *dhcpv6set,
367+
void *data, size_t len );
368+
};
369+
370+
/** DHCPv6 address settings operations */
371+
static struct dhcpv6_address_operation dhcpv6_address_operations[] = {
372+
{ &ip6_setting, dhcpv6_fetch_ip6 },
373+
{ &len6_setting, dhcpv6_fetch_len6 },
374+
{ &gateway6_setting, dhcpv6_fetch_gateway6 },
375+
};
376+
313377
/**
314378
* Fetch value of DHCPv6 setting
315379
*
@@ -325,11 +389,20 @@ static int dhcpv6_fetch ( struct settings *settings,
325389
struct dhcpv6_settings *dhcpv6set =
326390
container_of ( settings, struct dhcpv6_settings, settings );
327391
const union dhcpv6_any_option *option;
392+
struct dhcpv6_address_operation *op;
328393
size_t option_len;
329-
330-
/* Handle leased address */
331-
if ( setting_cmp ( setting, &ip6_setting ) == 0 )
332-
return dhcpv6_fetch_lease ( dhcpv6set, data, len );
394+
unsigned int i;
395+
396+
/* Handle address settings */
397+
for ( i = 0 ; i < ( sizeof ( dhcpv6_address_operations ) /
398+
sizeof ( dhcpv6_address_operations[0] ) ) ; i++ ) {
399+
op = &dhcpv6_address_operations[i];
400+
if ( setting_cmp ( setting, op->setting ) != 0 )
401+
continue;
402+
if ( IN6_IS_ADDR_UNSPECIFIED ( &dhcpv6set->lease ) )
403+
return -ENOENT;
404+
return op->fetch ( dhcpv6set, data, len );
405+
}
333406

334407
/* Find option */
335408
option = dhcpv6_option ( &dhcpv6set->options, setting->tag );
@@ -354,11 +427,12 @@ static struct settings_operations dhcpv6_settings_operations = {
354427
* Register DHCPv6 options as network device settings
355428
*
356429
* @v lease DHCPv6 leased address
430+
* @v router DHCPv6 router address
357431
* @v options DHCPv6 option list
358432
* @v parent Parent settings block
359433
* @ret rc Return status code
360434
*/
361-
static int dhcpv6_register ( struct in6_addr *lease,
435+
static int dhcpv6_register ( struct in6_addr *lease, struct in6_addr *router,
362436
struct dhcpv6_option_list *options,
363437
struct settings *parent ) {
364438
struct dhcpv6_settings *dhcpv6set;
@@ -382,6 +456,7 @@ static int dhcpv6_register ( struct in6_addr *lease,
382456
dhcpv6set->options.data = data;
383457
dhcpv6set->options.len = len;
384458
memcpy ( &dhcpv6set->lease, lease, sizeof ( dhcpv6set->lease ) );
459+
memcpy ( &dhcpv6set->router, router, sizeof ( dhcpv6set->router ) );
385460

386461
/* Register settings */
387462
if ( ( rc = register_settings ( &dhcpv6set->settings, parent,
@@ -501,6 +576,8 @@ struct dhcpv6_session {
501576

502577
/** Network device being configured */
503578
struct net_device *netdev;
579+
/** Router address */
580+
struct in6_addr router;
504581
/** Transaction ID */
505582
uint8_t xid[3];
506583
/** Identity association ID */
@@ -876,8 +953,8 @@ static int dhcpv6_rx ( struct dhcpv6_session *dhcpv6,
876953
}
877954

878955
/* Register settings */
879-
if ( ( rc = dhcpv6_register ( &dhcpv6->lease, &options,
880-
parent ) ) != 0 ) {
956+
if ( ( rc = dhcpv6_register ( &dhcpv6->lease, &dhcpv6->router,
957+
&options, parent ) ) != 0 ) {
881958
DBGC ( dhcpv6, "DHCPv6 %s could not register settings: %s\n",
882959
dhcpv6->netdev->name, strerror ( rc ) );
883960
goto done;
@@ -915,11 +992,12 @@ static struct interface_descriptor dhcpv6_xfer_desc =
915992
*
916993
* @v job Job control interface
917994
* @v netdev Network device
995+
* @v router Router address
918996
* @v stateful Perform stateful address autoconfiguration
919997
* @ret rc Return status code
920998
*/
921999
int start_dhcpv6 ( struct interface *job, struct net_device *netdev,
922-
int stateful ) {
1000+
struct in6_addr *router, int stateful ) {
9231001
struct ll_protocol *ll_protocol = netdev->ll_protocol;
9241002
struct dhcpv6_session *dhcpv6;
9251003
struct {
@@ -944,6 +1022,7 @@ int start_dhcpv6 ( struct interface *job, struct net_device *netdev,
9441022
intf_init ( &dhcpv6->job, &dhcpv6_job_desc, &dhcpv6->refcnt );
9451023
intf_init ( &dhcpv6->xfer, &dhcpv6_xfer_desc, &dhcpv6->refcnt );
9461024
dhcpv6->netdev = netdev_get ( netdev );
1025+
memcpy ( &dhcpv6->router, router, sizeof ( dhcpv6->router ) );
9471026
xid = random();
9481027
memcpy ( dhcpv6->xid, &xid, sizeof ( dhcpv6->xid ) );
9491028
dhcpv6->start = currticks();

0 commit comments

Comments
 (0)