Browse Source

[dhcp] Fall back to using the hardware address to populate the chaddr field

For IPoIB, the chaddr field is too small (16 bytes) to contain the
20-byte IPoIB link-layer address.  RFC4390 mandates that we should
pass an empty chaddr field and rely on the DHCP client identifier
instead.  This has many problems, not least of which is that a client
identifier containing an IPoIB link-layer address is not very useful
from the point of view of creating DHCP reservations, since the QPN
component is assigned at runtime and may vary between boots.

Leave the DHCP client identifier as-is, to avoid breaking existing
setups as far as possible, but expose the real hardware address (the
port GUID) via the DHCP chaddr field, using the broadcast flag to
instruct the DHCP server not to use this chaddr value as a link-layer
address.

This makes it possible (at least with ISC dhcpd) to create DHCP
reservations using host declarations such as:

    host duckling {
        fixed-address 10.252.252.99;
        hardware unknown-32 00:02:c9:02:00:25:a1:b5;
    }
tags/v0.9.8
Michael Brown 15 years ago
parent
commit
444d5550a7
3 changed files with 52 additions and 12 deletions
  1. 2
    0
      src/include/gpxe/dhcp.h
  2. 43
    11
      src/net/udp/dhcp.c
  3. 7
    1
      src/usr/dhcpmgmt.c

+ 2
- 0
src/include/gpxe/dhcp.h View File

601
 /** Setting block name used for BootServerDHCP responses */
601
 /** Setting block name used for BootServerDHCP responses */
602
 #define PXEBS_SETTINGS_NAME "pxebs"
602
 #define PXEBS_SETTINGS_NAME "pxebs"
603
 
603
 
604
+extern void * dhcp_chaddr ( struct net_device *netdev, uint8_t *hlen,
605
+			    uint16_t *flags );
604
 extern int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
606
 extern int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
605
 				struct net_device *netdev, uint8_t msgtype,
607
 				struct net_device *netdev, uint8_t msgtype,
606
 				const void *options, size_t options_len,
608
 				const void *options, size_t options_len,

+ 43
- 11
src/net/udp/dhcp.c View File

826
  *
826
  *
827
  */
827
  */
828
 
828
 
829
+/**
830
+ * Construct DHCP client hardware address field and broadcast flag
831
+ *
832
+ * @v netdev		Network device
833
+ * @v hlen		DHCP hardware address length to fill in
834
+ * @v flags		DHCP flags to fill in
835
+ * @ret chaddr		DHCP client hardware address
836
+ */
837
+void * dhcp_chaddr ( struct net_device *netdev, uint8_t *hlen,
838
+		     uint16_t *flags ) {
839
+	struct ll_protocol *ll_protocol = netdev->ll_protocol;
840
+	typeof ( ( ( struct dhcphdr * ) NULL )->chaddr ) chaddr;
841
+
842
+	/* If the link-layer address cannot fit into the chaddr field
843
+	 * (as is the case for IPoIB) then try using the hardware
844
+	 * address instead.  If we do this, set the broadcast flag,
845
+	 * since chaddr then does not represent a valid link-layer
846
+	 * address for the return path.
847
+	 *
848
+	 * If even the hardware address is too large, use an empty
849
+	 * chaddr field and set the broadcast flag.
850
+	 *
851
+	 * This goes against RFC4390, but RFC4390 mandates that we use
852
+	 * a DHCP client identifier that conforms with RFC4361, which
853
+	 * we cannot do without either persistent (NIC-independent)
854
+	 * storage, or by eliminating the hardware address completely
855
+	 * from the DHCP packet, which seems unfriendly to users.
856
+	 */
857
+	if ( ( *hlen = ll_protocol->ll_addr_len ) <= sizeof ( chaddr ) ) {
858
+		return netdev->ll_addr;
859
+	}
860
+	*flags = htons ( BOOTP_FL_BROADCAST );
861
+	if ( ( *hlen = ll_protocol->hw_addr_len ) <= sizeof ( chaddr ) ) {
862
+		return netdev->hw_addr;
863
+	} else {
864
+		*hlen = 0;
865
+		return NULL;
866
+	}
867
+}
868
+
829
 /**
869
 /**
830
  * Create a DHCP packet
870
  * Create a DHCP packet
831
  *
871
  *
846
 			 const void *options, size_t options_len,
886
 			 const void *options, size_t options_len,
847
 			 void *data, size_t max_len ) {
887
 			 void *data, size_t max_len ) {
848
 	struct dhcphdr *dhcphdr = data;
888
 	struct dhcphdr *dhcphdr = data;
849
-	unsigned int hlen;
889
+	void *chaddr;
850
 	int rc;
890
 	int rc;
851
 
891
 
852
 	/* Sanity check */
892
 	/* Sanity check */
859
 	dhcphdr->magic = htonl ( DHCP_MAGIC_COOKIE );
899
 	dhcphdr->magic = htonl ( DHCP_MAGIC_COOKIE );
860
 	dhcphdr->htype = ntohs ( netdev->ll_protocol->ll_proto );
900
 	dhcphdr->htype = ntohs ( netdev->ll_protocol->ll_proto );
861
 	dhcphdr->op = dhcp_op[msgtype];
901
 	dhcphdr->op = dhcp_op[msgtype];
862
-	/* If hardware length exceeds the chaddr field length, don't
863
-	 * use the chaddr field.  This is as per RFC4390.
864
-	 */
865
-	hlen = netdev->ll_protocol->ll_addr_len;
866
-	if ( hlen > sizeof ( dhcphdr->chaddr ) ) {
867
-		hlen = 0;
868
-		dhcphdr->flags = htons ( BOOTP_FL_BROADCAST );
869
-	}
870
-	dhcphdr->hlen = hlen;
871
-	memcpy ( dhcphdr->chaddr, netdev->ll_addr, hlen );
902
+	chaddr = dhcp_chaddr ( netdev, &dhcphdr->hlen, &dhcphdr->flags );
903
+	memcpy ( dhcphdr->chaddr, chaddr, dhcphdr->hlen );
872
 	memcpy ( dhcphdr->options, options, options_len );
904
 	memcpy ( dhcphdr->options, options, options_len );
873
 
905
 
874
 	/* Initialise DHCP packet structure */
906
 	/* Initialise DHCP packet structure */

+ 7
- 1
src/usr/dhcpmgmt.c View File

37
  */
37
  */
38
 
38
 
39
 int dhcp ( struct net_device *netdev ) {
39
 int dhcp ( struct net_device *netdev ) {
40
+	uint8_t *chaddr;
41
+	uint8_t hlen;
42
+	uint16_t flags;
40
 	int rc;
43
 	int rc;
41
 
44
 
42
 	/* Check we can open the interface first */
45
 	/* Check we can open the interface first */
48
 		return rc;
51
 		return rc;
49
 
52
 
50
 	/* Perform DHCP */
53
 	/* Perform DHCP */
51
-	printf ( "DHCP (%s %s)", netdev->name, netdev_addr ( netdev ) );
54
+	chaddr = dhcp_chaddr ( netdev, &hlen, &flags );
55
+	printf ( "DHCP (%s ", netdev->name );
56
+	while ( hlen-- )
57
+		printf ( "%02x%c", *(chaddr++), ( hlen ? ':' : ')' ) );
52
 	if ( ( rc = start_dhcp ( &monojob, netdev ) ) == 0 )
58
 	if ( ( rc = start_dhcp ( &monojob, netdev ) ) == 0 )
53
 		rc = monojob_wait ( "" );
59
 		rc = monojob_wait ( "" );
54
 
60
 

Loading…
Cancel
Save