[dhcp] Support for IPoIB (IP over InfiniBand) interfaces (#660681)

Jiří Popelka jpopelka at fedoraproject.org
Mon Sep 19 10:28:32 UTC 2011


commit bd3a57b466f51c1f214a42296cd8c14295c612af
Author: Jiri Popelka <jpopelka at redhat.com>
Date:   Mon Sep 19 12:27:55 2011 +0200

    Support for IPoIB (IP over InfiniBand) interfaces (#660681)

 dhcp-4.2.2-gpxe-cid.patch     |  132 ++++++++++
 dhcp-4.2.2-improved-xid.patch |  138 +++++++++++
 dhcp-4.2.2-lpf-ib.patch       |  538 +++++++++++++++++++++++++++++++++++++++++
 dhcp.spec                     |   28 ++-
 4 files changed, 826 insertions(+), 10 deletions(-)
---
diff --git a/dhcp-4.2.2-gpxe-cid.patch b/dhcp-4.2.2-gpxe-cid.patch
new file mode 100644
index 0000000..c0be4c2
--- /dev/null
+++ b/dhcp-4.2.2-gpxe-cid.patch
@@ -0,0 +1,132 @@
+diff -up dhcp-4.2.2/client/dhclient.c.gpxe-cid dhcp-4.2.2/client/dhclient.c
+--- dhcp-4.2.2/client/dhclient.c.gpxe-cid	2011-09-16 18:23:20.190453902 +0200
++++ dhcp-4.2.2/client/dhclient.c	2011-09-16 18:27:15.568463599 +0200
+@@ -58,6 +58,13 @@ const char *path_dhclient_pid = NULL;
+ static char path_dhclient_script_array[] = _PATH_DHCLIENT_SCRIPT;
+ char *path_dhclient_script = path_dhclient_script_array;
+ 
++/* Default Prefix */
++static unsigned char default_prefix[12] = {
++	0xff, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x02, 0x00,
++	0x00, 0x02, 0xc9, 0x00
++};
++
+ /* False (default) => we write and use a pid file */
+ isc_boolean_t no_pid_file = ISC_FALSE;
+ 
+@@ -1250,6 +1257,12 @@ int find_subnet (struct subnet **sp,
+ static void setup_ib_interface(struct interface_info *ip)
+ {
+ 	struct group *g;
++	struct hardware *hw = &ip->hw_address;
++	char client_id[64];
++	char *arg_conf = NULL;
++	int arg_conf_len = 0;
++	isc_result_t status;
++	struct parse *cfile = (struct parse *)0;
+ 
+ 	/* Set the broadcast flag */
+ 	ip->client->config->bootp_broadcast_always = 1;
+@@ -1266,8 +1279,39 @@ static void setup_ib_interface(struct in
+ 		}
+ 	}
+ 
+-	/* No client ID specified */
+-	log_fatal("dhcp-client-identifier must be specified for InfiniBand");
++	/*
++	 * No client ID specified, make up one based on a default
++	 * "prefix" and the port GUID.
++	 *
++	 * NOTE: This is compatible with what gpxe does.
++	 */
++	sprintf(client_id, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
++		default_prefix[0], default_prefix[1], default_prefix[2],
++		default_prefix[3], default_prefix[4], default_prefix[5],
++		default_prefix[6], default_prefix[7], default_prefix[8],
++		default_prefix[9], default_prefix[10], default_prefix[11],
++		hw->hbuf[1], hw->hbuf[2], hw->hbuf[3], hw->hbuf[4],
++		hw->hbuf[5], hw->hbuf[6], hw->hbuf[7], hw->hbuf[8]);
++
++	arg_conf_len = asprintf(&arg_conf,
++				"send dhcp-client-identifier %s;",
++				client_id);
++
++	if ((arg_conf == 0) || (arg_conf_len <= 0))
++		log_fatal("Unable to send option dhcp-client-identifier");
++
++	status = new_parse(&cfile, -1, arg_conf, arg_conf_len,
++			   "Automatic Infiniband client identifier", 0);
++
++	if ((status != ISC_R_SUCCESS) || (cfile->warnings_occurred))
++		log_fatal("Failed to parse Infiniband client identifier");
++
++	parse_client_statement(cfile, NULL, ip->client->config);
++
++	if (cfile->warnings_occurred)
++		log_fatal("Failed to parse Infiniband client identifier");
++
++	end_parse(&cfile);
+ }
+ 
+ /* Individual States:
+diff -up dhcp-4.2.2/common/lpf.c.gpxe-cid dhcp-4.2.2/common/lpf.c
+--- dhcp-4.2.2/common/lpf.c.gpxe-cid	2011-09-16 18:23:20.183453996 +0200
++++ dhcp-4.2.2/common/lpf.c	2011-09-16 18:25:28.235804421 +0200
+@@ -591,6 +591,37 @@ void maybe_setup_fallback ()
+ 	}
+ }
+ 
++static unsigned char * get_ib_hw_addr(char * name)
++{
++	struct ifaddrs *ifaddrs;
++	struct ifaddrs *ifa;
++	struct sockaddr_ll *sll = NULL;
++	static unsigned char hw_addr[8];
++
++	if (getifaddrs(&ifaddrs) == -1)
++		return NULL;
++
++	for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
++		if (ifa->ifa_addr == NULL)
++			continue;
++		if (ifa->ifa_addr->sa_family != AF_PACKET)
++			continue;
++		if (ifa->ifa_flags & IFF_LOOPBACK)
++			continue;
++		if (strcmp(ifa->ifa_name, name) == 0) {
++			sll = (struct sockaddr_ll *)(void *)ifa->ifa_addr;
++			break;
++		}
++	}
++	if (sll == NULL) {
++		freeifaddrs(ifaddrs);
++		return NULL;
++	}
++	memcpy(hw_addr, &sll->sll_addr[sll->sll_halen - 8], 8);
++	freeifaddrs(ifaddrs);
++	return (unsigned char *)&hw_addr;
++}
++
+ void
+ get_hw_addr(struct interface_info *info)
+ {
+@@ -599,6 +630,7 @@ get_hw_addr(struct interface_info *info)
+ 	struct ifaddrs *ifaddrs;
+ 	struct ifaddrs *ifa;
+ 	struct sockaddr_ll *sll = NULL;
++	unsigned char *hw_addr;
+ 
+ 	if (getifaddrs(&ifaddrs) == -1)
+ 		log_fatal("Failed to get interfaces");
+@@ -660,6 +692,10 @@ get_hw_addr(struct interface_info *info)
+ 
+ 			hw->hlen = 1;
+ 			hw->hbuf[0] = HTYPE_INFINIBAND;
++			hw_addr = get_ib_hw_addr(name);
++			if (!hw_addr)
++				log_fatal("Failed getting %s hw addr", name);
++			memcpy (&hw->hbuf [1], hw_addr, 8);
+ 			break;
+ #if defined(ARPHRD_PPP)
+ 		case ARPHRD_PPP:
diff --git a/dhcp-4.2.2-improved-xid.patch b/dhcp-4.2.2-improved-xid.patch
new file mode 100644
index 0000000..f49fc78
--- /dev/null
+++ b/dhcp-4.2.2-improved-xid.patch
@@ -0,0 +1,138 @@
+diff -up dhcp-4.2.2/client/dhclient.c.improved-xid dhcp-4.2.2/client/dhclient.c
+--- dhcp-4.2.2/client/dhclient.c.improved-xid	2011-09-16 18:18:00.649730661 +0200
++++ dhcp-4.2.2/client/dhclient.c	2011-09-16 18:22:36.815035513 +0200
+@@ -898,6 +898,26 @@ main(int argc, char **argv) {
+ 		}
+ 	}
+ 
++	/* We create a backup seed before rediscovering interfaces in order to
++	   have a seed built using all of the available interfaces
++	   It's interesting if required interfaces doesn't let us defined
++	   a really unique seed due to a lack of valid HW addr later
++	   (this is the case with DHCP over IB)
++	   We only use the last device as using a sum could broke the
++	   uniqueness of the seed among multiple nodes
++	 */
++	unsigned backup_seed = 0;
++	for (ip = interfaces; ip; ip = ip -> next) {
++		int junk;
++		if ( ip -> hw_address.hlen <= sizeof seed )
++		  continue;
++		memcpy (&junk,
++			&ip -> hw_address.hbuf [ip -> hw_address.hlen -
++						sizeof seed], sizeof seed);
++		backup_seed = junk;
++	}
++
++
+ 	/* At this point, all the interfaces that the script thinks
+ 	   are relevant should be running, so now we once again call
+ 	   discover_interfaces(), and this time ask it to actually set
+@@ -912,14 +932,36 @@ main(int argc, char **argv) {
+ 	   Not much entropy, but we're booting, so we're not likely to
+ 	   find anything better. */
+ 	seed = 0;
++	int seed_flag = 0;
+ 	for (ip = interfaces; ip; ip = ip->next) {
+ 		int junk;
++		if ( ip -> hw_address.hlen <= sizeof seed )
++		  continue;
+ 		memcpy(&junk,
+ 		       &ip->hw_address.hbuf[ip->hw_address.hlen -
+ 					    sizeof seed], sizeof seed);
+ 		seed += junk;
++		seed_flag = 1;
+ 	}
+-	srandom(seed + cur_time + (unsigned)getpid());
++	if ( seed_flag == 0 ) {
++		if ( backup_seed != 0 ) {
++		  seed = backup_seed;
++		  log_info ("xid: rand init seed (0x%x) built using all"
++			    " available interfaces",seed);
++		}
++		else {
++		  seed = cur_time^((unsigned) gethostid()) ;
++		  log_info ("xid: warning: no netdev with useable HWADDR found"
++			    " for seed's uniqueness enforcement");
++		  log_info ("xid: rand init seed (0x%x) built using gethostid",
++			    seed);
++		}
++		/* we only use seed and no current time as a broadcast reply */
++		/* will certainly be used by the hwaddrless interface */
++		srandom(seed);
++	}
++	else
++	        srandom(seed + cur_time + (unsigned)getpid());
+ 
+ 	/* Setup specific Infiniband options */
+ 	for (ip = interfaces; ip; ip = ip->next) {
+@@ -1457,7 +1499,7 @@ void dhcpack (packet)
+ 		return;
+ 	}
+ 
+-	log_info ("DHCPACK from %s", piaddr (packet -> client_addr));
++	log_info ("DHCPACK from %s (xid=0x%x)", piaddr (packet -> client_addr), client -> xid);
+ 
+ 	lease = packet_to_lease (packet, client);
+ 	if (!lease) {
+@@ -2174,7 +2216,7 @@ void dhcpnak (packet)
+ 		return;
+ 	}
+ 
+-	log_info ("DHCPNAK from %s", piaddr (packet -> client_addr));
++	log_info ("DHCPNAK from %s (xid=0x%x)", piaddr (packet -> client_addr), client -> xid);
+ 
+ 	if (!client -> active) {
+ #if defined (DEBUG)
+@@ -2300,10 +2342,10 @@ void send_discover (cpp)
+ 		client -> packet.secs = htons (65535);
+ 	client -> secs = client -> packet.secs;
+ 
+-	log_info ("DHCPDISCOVER on %s to %s port %d interval %ld",
++	log_info ("DHCPDISCOVER on %s to %s port %d interval %ld (xid=0x%x)",
+ 	      client -> name ? client -> name : client -> interface -> name,
+ 	      inet_ntoa (sockaddr_broadcast.sin_addr),
+-	      ntohs (sockaddr_broadcast.sin_port), (long)(client -> interval));
++	      ntohs (sockaddr_broadcast.sin_port), (long)(client -> interval), client -> xid);
+ 
+ 	/* Send out a packet. */
+ 	result = send_packet (client -> interface, (struct packet *)0,
+@@ -2584,10 +2626,10 @@ void send_request (cpp)
+ 			client -> packet.secs = htons (65535);
+ 	}
+ 
+-	log_info ("DHCPREQUEST on %s to %s port %d",
++	log_info ("DHCPREQUEST on %s to %s port %d (xid=0x%x)",
+ 	      client -> name ? client -> name : client -> interface -> name,
+ 	      inet_ntoa (destination.sin_addr),
+-	      ntohs (destination.sin_port));
++	      ntohs (destination.sin_port), client -> xid);
+ 
+ 	if (destination.sin_addr.s_addr != INADDR_BROADCAST &&
+ 	    fallback_interface)
+@@ -2618,10 +2660,10 @@ void send_decline (cpp)
+ 
+ 	int result;
+ 
+-	log_info ("DHCPDECLINE on %s to %s port %d",
++	log_info ("DHCPDECLINE on %s to %s port %d (xid=0x%x)",
+ 	      client -> name ? client -> name : client -> interface -> name,
+ 	      inet_ntoa (sockaddr_broadcast.sin_addr),
+-	      ntohs (sockaddr_broadcast.sin_port));
++	      ntohs (sockaddr_broadcast.sin_port), client -> xid);
+ 
+ 	/* Send out a packet. */
+ 	result = send_packet (client -> interface, (struct packet *)0,
+@@ -2661,10 +2703,10 @@ void send_release (cpp)
+ 		return;
+ 	}
+ 
+-	log_info ("DHCPRELEASE on %s to %s port %d",
++	log_info ("DHCPRELEASE on %s to %s port %d (xid=0x%x)",
+ 	      client -> name ? client -> name : client -> interface -> name,
+ 	      inet_ntoa (destination.sin_addr),
+-	      ntohs (destination.sin_port));
++	      ntohs (destination.sin_port), client -> xid);
+ 
+ 	if (fallback_interface)
+ 		result = send_packet (fallback_interface,
diff --git a/dhcp-4.2.2-lpf-ib.patch b/dhcp-4.2.2-lpf-ib.patch
new file mode 100644
index 0000000..4034028
--- /dev/null
+++ b/dhcp-4.2.2-lpf-ib.patch
@@ -0,0 +1,538 @@
+diff -up dhcp-4.2.2/client/dhclient.c.lpf-ib dhcp-4.2.2/client/dhclient.c
+--- dhcp-4.2.2/client/dhclient.c.lpf-ib	2011-09-19 11:24:08.693775799 +0200
++++ dhcp-4.2.2/client/dhclient.c	2011-09-19 11:24:08.703775541 +0200
+@@ -113,6 +113,8 @@ static int check_domain_name_list(const 
+ static int check_option_values(struct universe *universe, unsigned int opt,
+ 			       const char *ptr, size_t len);
+ 
++static void setup_ib_interface(struct interface_info *ip);
++
+ int
+ main(int argc, char **argv) {
+ 	int fd;
+@@ -919,6 +921,14 @@ main(int argc, char **argv) {
+ 	}
+ 	srandom(seed + cur_time + (unsigned)getpid());
+ 
++	/* Setup specific Infiniband options */
++	for (ip = interfaces; ip; ip = ip->next) {
++		if (ip->client &&
++		    (ip->hw_address.hbuf[0] == HTYPE_INFINIBAND)) {
++			setup_ib_interface(ip);
++		}
++	}
++
+ 	/* Start a configuration state machine for each interface. */
+ #ifdef DHCPv6
+ 	if (local_family == AF_INET6) {
+@@ -1195,6 +1205,29 @@ int find_subnet (struct subnet **sp,
+ 	return 0;
+ }
+ 
++static void setup_ib_interface(struct interface_info *ip)
++{
++	struct group *g;
++
++	/* Set the broadcast flag */
++	ip->client->config->bootp_broadcast_always = 1;
++
++	/*
++	 * Find out if a dhcp-client-identifier option was specified either
++	 * in the config file or on the command line
++	 */
++	for (g = ip->client->config->on_transmission; g != NULL; g = g->next) {
++		if ((g->statements != NULL) &&
++		    (strcmp(g->statements->data.option->option->name,
++			    "dhcp-client-identifier") == 0)) {
++			return;
++		}
++	}
++
++	/* No client ID specified */
++	log_fatal("dhcp-client-identifier must be specified for InfiniBand");
++}
++
+ /* Individual States:
+  *
+  * Each routine is called from the dhclient_state_machine() in one of
+diff -up dhcp-4.2.2/common/bpf.c.lpf-ib dhcp-4.2.2/common/bpf.c
+--- dhcp-4.2.2/common/bpf.c.lpf-ib	2011-09-19 11:24:08.694775773 +0200
++++ dhcp-4.2.2/common/bpf.c	2011-09-19 11:24:08.704775516 +0200
+@@ -198,11 +198,44 @@ struct bpf_insn dhcp_bpf_filter [] = {
+ 	BPF_STMT(BPF_RET+BPF_K, 0),
+ };
+ 
++/* Packet filter program for DHCP over Infiniband.
++ *
++ * XXX
++ * Changes to the filter program may require changes to the constant offsets
++ * used in lpf_gen_filter_setup to patch the port in the BPF program!
++ * XXX
++ */
++struct bpf_insn dhcp_ib_bpf_filter [] = {
++	/* Packet filter for Infiniband */
++	/* Make sure it's a UDP packet... */
++	BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 9),
++	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6),
++
++	/* Make sure this isn't a fragment... */
++	BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 6),
++	BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0),
++
++	/* Get the IP header length... */
++	BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 0),
++
++	/* Make sure it's to the right port... */
++	BPF_STMT(BPF_LD + BPF_H + BPF_IND, 2),
++	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1),
++
++	/* If we passed all the tests, ask for the whole packet. */
++	BPF_STMT(BPF_RET + BPF_K, (u_int)-1),
++
++	/* Otherwise, drop it. */
++	BPF_STMT(BPF_RET + BPF_K, 0),
++};
++
+ #if defined (DEC_FDDI)
+ struct bpf_insn *bpf_fddi_filter;
+ #endif
+ 
+ int dhcp_bpf_filter_len = sizeof dhcp_bpf_filter / sizeof (struct bpf_insn);
++int dhcp_ib_bpf_filter_len = sizeof dhcp_ib_bpf_filter / sizeof (struct bpf_insn);
++
+ #if defined (HAVE_TR_SUPPORT)
+ struct bpf_insn dhcp_bpf_tr_filter [] = {
+         /* accept all token ring packets due to variable length header */
+diff -up dhcp-4.2.2/common/lpf.c.lpf-ib dhcp-4.2.2/common/lpf.c
+--- dhcp-4.2.2/common/lpf.c.lpf-ib	2011-09-19 11:24:08.694775773 +0200
++++ dhcp-4.2.2/common/lpf.c	2011-09-19 11:26:15.107109935 +0200
+@@ -42,6 +42,7 @@
+ #include "includes/netinet/udp.h"
+ #include "includes/netinet/if_ether.h"
+ #include <net/if.h>
++#include <ifaddrs.h>
+ 
+ #ifndef PACKET_AUXDATA
+ #define PACKET_AUXDATA 8
+@@ -59,6 +60,15 @@ struct tpacket_auxdata
+ /* Reinitializes the specified interface after an address change.   This
+    is not required for packet-filter APIs. */
+ 
++/* Default broadcast address for IPoIB */
++static unsigned char default_ib_bcast_addr[20] = {
++ 	0x00, 0xff, 0xff, 0xff,
++	0xff, 0x12, 0x40, 0x1b,
++	0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00,
++	0xff, 0xff, 0xff, 0xff
++};
++
+ #ifdef USE_LPF_SEND
+ void if_reinitialize_send (info)
+ 	struct interface_info *info;
+@@ -86,10 +96,21 @@ int if_register_lpf (info)
+ 		struct sockaddr common;
+ 	} sa;
+ 	struct ifreq ifr;
++	int type;
++	int protocol;
+ 
+ 	/* Make an LPF socket. */
+-	if ((sock = socket(PF_PACKET, SOCK_RAW,
+-			   htons((short)ETH_P_ALL))) < 0) {
++	get_hw_addr(info);
++
++	if (info->hw_address.hbuf[0] == HTYPE_INFINIBAND) {
++		type = SOCK_DGRAM;
++		protocol = ETHERTYPE_IP;
++	} else {
++		type = SOCK_RAW;
++		protocol = ETH_P_ALL;
++	}
++
++	if ((sock = socket(PF_PACKET, type, htons((short)protocol))) < 0) {
+ 		if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
+ 		    errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
+ 		    errno == EAFNOSUPPORT || errno == EINVAL) {
+@@ -112,6 +133,7 @@ int if_register_lpf (info)
+ 	/* Bind to the interface name */
+ 	memset (&sa, 0, sizeof sa);
+ 	sa.ll.sll_family = AF_PACKET;
++	sa.ll.sll_protocol = htons(protocol);
+ 	sa.ll.sll_ifindex = ifr.ifr_ifindex;
+ 	if (bind (sock, &sa.common, sizeof sa)) {
+ 		if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
+@@ -127,8 +149,6 @@ int if_register_lpf (info)
+ 		log_fatal ("Bind socket to interface: %m");
+ 	}
+ 
+-	get_hw_addr(info->name, &info->hw_address);
+-
+ 	return sock;
+ }
+ #endif /* USE_LPF_SEND || USE_LPF_RECEIVE */
+@@ -183,6 +203,8 @@ void if_deregister_send (info)
+    in bpf includes... */
+ extern struct sock_filter dhcp_bpf_filter [];
+ extern int dhcp_bpf_filter_len;
++extern struct sock_filter dhcp_ib_bpf_filter [];
++extern int dhcp_ib_bpf_filter_len;
+ 
+ #if defined (HAVE_TR_SUPPORT)
+ extern struct sock_filter dhcp_bpf_tr_filter [];
+@@ -200,11 +222,13 @@ void if_register_receive (info)
+ 	/* Open a LPF device and hang it on this interface... */
+ 	info -> rfdesc = if_register_lpf (info);
+ 
+-	val = 1;
+-	if (setsockopt (info -> rfdesc, SOL_PACKET, PACKET_AUXDATA, &val,
+-			sizeof val) < 0) {
+-		if (errno != ENOPROTOOPT)
+-			log_fatal ("Failed to set auxiliary packet data: %m");
++	if (info->hw_address.hbuf[0] != HTYPE_INFINIBAND) {
++		val = 1;
++		if (setsockopt (info -> rfdesc, SOL_PACKET, PACKET_AUXDATA,
++				&val, sizeof val) < 0) {
++			if (errno != ENOPROTOOPT)
++				log_fatal ("Failed to set auxiliary packet data: %m");
++		}
+ 	}
+ 
+ #if defined (HAVE_TR_SUPPORT)
+@@ -250,15 +274,28 @@ static void lpf_gen_filter_setup (info)
+ 
+ 	memset(&p, 0, sizeof(p));
+ 
+-	/* Set up the bpf filter program structure.    This is defined in
+-	   bpf.c */
+-	p.len = dhcp_bpf_filter_len;
+-	p.filter = dhcp_bpf_filter;
+-
+-        /* Patch the server port into the LPF  program...
+-	   XXX changes to filter program may require changes
+-	   to the insn number(s) used below! XXX */
+-	dhcp_bpf_filter [8].k = ntohs ((short)local_port);
++	if (info->hw_address.hbuf[0] == HTYPE_INFINIBAND) {
++		/* Set up the bpf filter program structure. */
++		p.len = dhcp_ib_bpf_filter_len;
++		p.filter = dhcp_ib_bpf_filter;
++
++		/* Patch the server port into the LPF program...
++		   XXX
++		   changes to filter program may require changes
++		   to the insn number(s) used below!
++		   XXX */
++		dhcp_ib_bpf_filter[6].k = ntohs ((short)local_port);
++	} else {
++		/* Set up the bpf filter program structure.
++		   This is defined in bpf.c */
++		p.len = dhcp_bpf_filter_len;
++		p.filter = dhcp_bpf_filter;
++
++		/* Patch the server port into the LPF  program...
++		   XXX changes to filter program may require changes
++		   to the insn number(s) used below! XXX */
++		dhcp_bpf_filter [8].k = ntohs ((short)local_port);
++	}
+ 
+ 	if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
+ 			sizeof p) < 0) {
+@@ -315,6 +352,54 @@ static void lpf_tr_filter_setup (info)
+ #endif /* USE_LPF_RECEIVE */
+ 
+ #ifdef USE_LPF_SEND
++ssize_t send_packet_ib(interface, packet, raw, len, from, to, hto)
++	struct interface_info *interface;
++	struct packet *packet;
++	struct dhcp_packet *raw;
++	size_t len;
++	struct in_addr from;
++	struct sockaddr_in *to;
++	struct hardware *hto;
++{
++	unsigned ibufp = 0;
++	double ih [1536 / sizeof (double)];
++	unsigned char *buf = (unsigned char *)ih;
++	ssize_t result;
++
++	union sockunion {
++		struct sockaddr sa;
++		struct sockaddr_ll sll;
++		struct sockaddr_storage ss;
++	} su;
++
++	assemble_udp_ip_header (interface, buf, &ibufp, from.s_addr,
++				to->sin_addr.s_addr, to->sin_port,
++				(unsigned char *)raw, len);
++	memcpy (buf + ibufp, raw, len);
++
++	memset(&su, 0, sizeof(su));
++	su.sll.sll_family = AF_PACKET;
++	su.sll.sll_protocol = htons(ETHERTYPE_IP);
++
++	if (!(su.sll.sll_ifindex = if_nametoindex(interface->name))) {
++		errno = ENOENT;
++		log_error ("send_packet_ib: %m - failed to get if index");
++		return -1;
++	}
++
++	su.sll.sll_hatype = htons(HTYPE_INFINIBAND);
++	su.sll.sll_halen = sizeof(interface->bcast_addr);
++	memcpy(&su.sll.sll_addr, interface->bcast_addr, 20);
++
++	result = sendto(interface->wfdesc, buf, ibufp + len, 0,
++			&su.sa, sizeof(su));
++
++	if (result < 0)
++		log_error ("send_packet_ib: %m");
++
++	return result;
++}
++
+ ssize_t send_packet (interface, packet, raw, len, from, to, hto)
+ 	struct interface_info *interface;
+ 	struct packet *packet;
+@@ -335,6 +420,11 @@ ssize_t send_packet (interface, packet, 
+ 		return send_fallback (interface, packet, raw,
+ 				      len, from, to, hto);
+ 
++	if (interface->hw_address.hbuf[0] == HTYPE_INFINIBAND) {
++		return send_packet_ib(interface, packet, raw, len, from,
++				      to, hto);
++	}
++
+ 	if (hto == NULL && interface->anycast_mac_addr.hlen)
+ 		hto = &interface->anycast_mac_addr;
+ 
+@@ -356,6 +446,42 @@ ssize_t send_packet (interface, packet, 
+ #endif /* USE_LPF_SEND */
+ 
+ #ifdef USE_LPF_RECEIVE
++ssize_t receive_packet_ib (interface, buf, len, from, hfrom)
++	struct interface_info *interface;
++	unsigned char *buf;
++	size_t len;
++	struct sockaddr_in *from;
++	struct hardware *hfrom;
++{
++	int length = 0;
++	int offset = 0;
++	unsigned char ibuf [1536];
++	unsigned bufix = 0;
++	unsigned paylen;
++
++	length = read(interface->rfdesc, ibuf, sizeof(ibuf));
++
++	if (length <= 0)
++		return length;
++
++	offset = decode_udp_ip_header(interface, ibuf, bufix, from,
++				       (unsigned)length, &paylen, 0);
++
++	if (offset < 0)
++		return 0;
++
++	bufix += offset;
++	length -= offset;
++
++	if (length < paylen)
++		log_fatal("Internal inconsistency at %s:%d.", MDL);
++
++	/* Copy out the data in the packet... */
++	memcpy(buf, &ibuf[bufix], paylen);
++
++	return (ssize_t)paylen;
++}
++
+ ssize_t receive_packet (interface, buf, len, from, hfrom)
+ 	struct interface_info *interface;
+ 	unsigned char *buf;
+@@ -382,6 +508,10 @@ ssize_t receive_packet (interface, buf, 
+ 	};
+ 	struct cmsghdr *cmsg;
+ 
++	if (interface->hw_address.hbuf[0] == HTYPE_INFINIBAND) {
++		return receive_packet_ib(interface, buf, len, from, hfrom);
++	}
++
+ 	length = recvmsg (interface -> rfdesc, &msg, 0);
+ 	if (length <= 0)
+ 		return length;
+@@ -462,33 +592,44 @@ void maybe_setup_fallback ()
+ }
+ 
+ void
+-get_hw_addr(const char *name, struct hardware *hw) {
+-	int sock;
+-	struct ifreq tmp;
+-	struct sockaddr *sa;
++get_hw_addr(struct interface_info *info)
++{
++	struct hardware *hw = &info->hw_address;
++	char *name = info->name;
++	struct ifaddrs *ifaddrs;
++	struct ifaddrs *ifa;
++	struct sockaddr_ll *sll = NULL;
+ 
+-	if (strlen(name) >= sizeof(tmp.ifr_name)) {
+-		log_fatal("Device name too long: \"%s\"", name);
+-	}
++	if (getifaddrs(&ifaddrs) == -1)
++		log_fatal("Failed to get interfaces");
+ 
+-	sock = socket(AF_INET, SOCK_DGRAM, 0);
+-	if (sock < 0) {
+-		log_fatal("Can't create socket for \"%s\": %m", name);
++	for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
++
++		if (ifa->ifa_addr == NULL)
++			continue;
++
++		if (ifa->ifa_addr->sa_family != AF_PACKET)
++			continue;
++
++		if (ifa->ifa_flags & IFF_LOOPBACK)
++			continue;
++
++		if (strcmp(ifa->ifa_name, name) == 0) {
++			sll = (struct sockaddr_ll *)(void *)ifa->ifa_addr;
++			break;
++		}
+ 	}
+ 
+-	memset(&tmp, 0, sizeof(tmp));
+-	strcpy(tmp.ifr_name, name);
+-	if (ioctl(sock, SIOCGIFHWADDR, &tmp) < 0) {
+-		log_fatal("Error getting hardware address for \"%s\": %m", 
+-			  name);
++	if (sll == NULL) {
++		freeifaddrs(ifaddrs);
++		log_fatal("Failed to get HW address for %s\n", name);
+ 	}
+ 
+-	sa = &tmp.ifr_hwaddr;
+-	switch (sa->sa_family) {
++	switch (sll->sll_hatype) {
+ 		case ARPHRD_ETHER:
+ 			hw->hlen = 7;
+ 			hw->hbuf[0] = HTYPE_ETHER;
+-			memcpy(&hw->hbuf[1], sa->sa_data, 6);
++			memcpy(&hw->hbuf[1], sll->sll_addr, 6);
+ 			break;
+ 		case ARPHRD_IEEE802:
+ #ifdef ARPHRD_IEEE802_TR
+@@ -496,18 +637,35 @@ get_hw_addr(const char *name, struct har
+ #endif /* ARPHRD_IEEE802_TR */
+ 			hw->hlen = 7;
+ 			hw->hbuf[0] = HTYPE_IEEE802;
+-			memcpy(&hw->hbuf[1], sa->sa_data, 6);
++			memcpy(&hw->hbuf[1], sll->sll_addr, 6);
+ 			break;
+ 		case ARPHRD_FDDI:
+ 			hw->hlen = 17;
+ 			hw->hbuf[0] = HTYPE_FDDI;
+-			memcpy(&hw->hbuf[1], sa->sa_data, 16);
++			memcpy(&hw->hbuf[1], sll->sll_addr, 16);
++			break;
++		case ARPHRD_INFINIBAND:
++			/* For Infiniband, save the broadcast address and store
++			 * the port GUID into the hardware address.
++			 */
++			if (ifa->ifa_flags & IFF_BROADCAST) {
++				struct sockaddr_ll *bll;
++
++				bll = (struct sockaddr_ll *)ifa->ifa_broadaddr;
++				memcpy(&info->bcast_addr, bll->sll_addr, 20);
++			} else {
++				memcpy(&info->bcast_addr, default_ib_bcast_addr,
++				       20);
++			}
++
++			hw->hlen = 1;
++			hw->hbuf[0] = HTYPE_INFINIBAND;
+ 			break;
+ #if defined(ARPHRD_PPP)
+ 		case ARPHRD_PPP:
+ 			if (local_family != AF_INET6)
+-				log_fatal("Unsupported device type %d for \"%s\"",
+-				           sa->sa_family, name);
++				log_fatal("Unsupported device type %ld for \"%s\"",
++					  (long int)sll->sll_family, name);
+ 			hw->hlen = 0;
+ 			hw->hbuf[0] = HTYPE_RESERVED;
+ 			/* 0xdeadbeef should never occur on the wire,
+@@ -520,10 +678,11 @@ get_hw_addr(const char *name, struct har
+ 			break;
+ #endif
+ 		default:
++			freeifaddrs(ifaddrs);
+ 			log_fatal("Unsupported device type %ld for \"%s\"",
+-				  (long int)sa->sa_family, name);
++				  (long int)sll->sll_family, name);
+ 	}
+ 
+-	close(sock);
++	freeifaddrs(ifaddrs);
+ }
+ #endif
+diff -up dhcp-4.2.2/common/socket.c.lpf-ib dhcp-4.2.2/common/socket.c
+--- dhcp-4.2.2/common/socket.c.lpf-ib	2011-06-27 18:18:20.000000000 +0200
++++ dhcp-4.2.2/common/socket.c	2011-09-19 11:24:08.705775490 +0200
+@@ -324,7 +324,7 @@ void if_register_send (info)
+ 	info->wfdesc = if_register_socket(info, AF_INET, 0);
+ 	/* If this is a normal IPv4 address, get the hardware address. */
+ 	if (strcmp(info->name, "fallback") != 0)
+-		get_hw_addr(info->name, &info->hw_address);
++		get_hw_addr(info);
+ #if defined (USE_SOCKET_FALLBACK)
+ 	/* Fallback only registers for send, but may need to receive as
+ 	   well. */
+@@ -387,7 +387,7 @@ void if_register_receive (info)
+ #endif /* IP_PKTINFO... */
+ 	/* If this is a normal IPv4 address, get the hardware address. */
+ 	if (strcmp(info->name, "fallback") != 0)
+-		get_hw_addr(info->name, &info->hw_address);
++		get_hw_addr(info);
+ 
+ 	if (!quiet_interface_discovery)
+ 		log_info ("Listening on Socket/%s%s%s",
+@@ -497,7 +497,7 @@ if_register6(struct interface_info *info
+ 	if (req_multi)
+ 		if_register_multicast(info);
+ 
+-	get_hw_addr(info->name, &info->hw_address);
++	get_hw_addr(info);
+ 
+ 	if (!quiet_interface_discovery) {
+ 		if (info->shared_network != NULL) {
+diff -up dhcp-4.2.2/includes/dhcpd.h.lpf-ib dhcp-4.2.2/includes/dhcpd.h
+--- dhcp-4.2.2/includes/dhcpd.h.lpf-ib	2011-09-19 11:24:08.696775721 +0200
++++ dhcp-4.2.2/includes/dhcpd.h	2011-09-19 11:24:08.707775438 +0200
+@@ -1243,6 +1243,7 @@ struct interface_info {
+ 	struct shared_network *shared_network;
+ 				/* Networks connected to this interface. */
+ 	struct hardware hw_address;	/* Its physical address. */
++	u_int8_t bcast_addr[20];	/* Infiniband broadcast address */
+ 	struct in_addr *addresses;	/* Addresses associated with this
+ 					 * interface.
+ 					 */
+@@ -2356,7 +2357,7 @@ void print_dns_status (int, struct dhcp_
+ #endif
+ const char *print_time(TIME);
+ 
+-void get_hw_addr(const char *name, struct hardware *hw);
++void get_hw_addr(struct interface_info *info);
+ 
+ /* socket.c */
+ #if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_RECEIVE) \
+diff -up dhcp-4.2.2/includes/dhcp.h.lpf-ib dhcp-4.2.2/includes/dhcp.h
+--- dhcp-4.2.2/includes/dhcp.h.lpf-ib	2011-09-19 11:24:08.696775721 +0200
++++ dhcp-4.2.2/includes/dhcp.h	2011-09-19 11:24:08.707775438 +0200
+@@ -79,6 +79,7 @@ struct dhcp_packet {
+ #define HTYPE_ETHER	1               /* Ethernet 10Mbps              */
+ #define HTYPE_IEEE802	6               /* IEEE 802.2 Token Ring...	*/
+ #define HTYPE_FDDI	8		/* FDDI...			*/
++#define HTYPE_INFINIBAND 32		/* Infiniband IPoIB		*/
+ 
+ #define HTYPE_RESERVED  0               /* RFC 5494 */
+ 
diff --git a/dhcp.spec b/dhcp.spec
index 623ee6b..72cdaaa 100644
--- a/dhcp.spec
+++ b/dhcp.spec
@@ -16,7 +16,7 @@
 Summary:  Dynamic host configuration protocol software
 Name:     dhcp
 Version:  4.2.2
-Release:  6%{?dist}
+Release:  7%{?dist}
 # NEVER CHANGE THE EPOCH on this package.  The previous maintainer (prior to
 # dcantrell maintaining the package) made incorrect use of the epoch and
 # that's why it is at 12 now.  It should have never been used, but it was.
@@ -65,6 +65,9 @@ Patch28:  dhcp-4.2.0-noprefixavail.patch
 Patch29:  dhcp-4.2.2-remove-bind.patch
 Patch30:  dhcp-4.2.2-sharedlib.patch
 Patch31:  dhcp-4.2.0-PPP.patch
+Patch32:  dhcp-4.2.2-lpf-ib.patch
+Patch33:  dhcp-4.2.2-improved-xid.patch
+Patch34:  dhcp-4.2.2-gpxe-cid.patch
 
 BuildRequires: autoconf
 BuildRequires: automake
@@ -300,6 +303,12 @@ rm bind/bind.tar.gz
 # DHCPv6 over PPP support (#626514)
 %patch31 -p1 -b .PPP
 
+# IPoIB support (#660681)
+# (Submitted to dhcp-bugs at isc.org - [ISC-Bugs #24249])
+%patch32 -p1 -b .lpf-ib
+%patch33 -p1 -b .improved-xid
+%patch34 -p1 -b .gpxe-cid
+
 # Copy in the Fedora/RHEL dhclient script
 %{__install} -p -m 0755 %{SOURCE4} client/scripts/linux
 %{__install} -p -m 0644 %{SOURCE5} .
@@ -456,16 +465,11 @@ find ${RPM_BUILD_ROOT}/%{_libdir} -name '*.la' -exec '/bin/rm' '-f' '{}' ';';
 
 %pre
 # /usr/share/doc/setup/uidgid
-if ! getent group dhcpd >/dev/null ; then
-  if ! getent group 177 >/dev/null ; then
-    groupadd --system --gid 177 dhcpd
-  else
-    groupadd --system dhcpd
-  fi
-fi
+%global gid_uid 177
+getent group dhcpd >/dev/null || groupadd --force --gid %{gid_uid} --system dhcpd
 if ! getent passwd dhcpd >/dev/null ; then
-    if ! getent passwd 177 >/dev/null ; then
-      useradd --system --uid 177 --gid dhcpd --home / --shell /sbin/nologin --comment "DHCP server" dhcpd
+    if ! getent passwd %{gid_uid} >/dev/null ; then
+      useradd --system --uid %{gid_uid} --gid dhcpd --home / --shell /sbin/nologin --comment "DHCP server" dhcpd
     else
       useradd --system --gid dhcpd --home / --shell /sbin/nologin --comment "DHCP server" dhcpd
     fi
@@ -635,6 +639,10 @@ fi
 %{_initddir}/dhcrelay
 
 %changelog
+* Mon Sep 19 2011 Jiri Popelka <jpopelka at redhat.com> - 12:4.2.2-7
+- Support for IPoIB (IP over InfiniBand) interfaces (#660681)
+- Hopefully last tweak of adding of user and group (#699713)
+
 * Fri Sep 09 2011 Jiri Popelka <jpopelka at redhat.com> - 12:4.2.2-6
 - PIE-RELRO.patch is not needed anymore, defining _hardened_build does the same
 - One more tweak of adding of user and group (#699713)


More information about the scm-commits mailing list