[SCM] CTDB repository - branch ipv6-test updated - 0a38ea11af9237501f2951fee698a59b46f8750d

Ronnie Sahlberg sahlberg at samba.org
Tue Aug 19 08:46:58 GMT 2008


The branch, ipv6-test has been updated
       via  0a38ea11af9237501f2951fee698a59b46f8750d (commit)
      from  bf6effef0cc9e5f2eeeb38fce855a90624a76239 (commit)

http://gitweb.samba.org/?p=sahlberg/ctdb.git;a=shortlog;h=ipv6-test


- Log -----------------------------------------------------------------
commit 0a38ea11af9237501f2951fee698a59b46f8750d
Author: Ronnie Sahlberg <ronniesahlberg at gmail.com>
Date:   Tue Aug 19 18:24:08 2008 +1000

    fix the ipv6 checksum calculation for pseudoheader so that it actually works
    
    add support to send ipv6 "gratious arp" aka neighbor solicitation packets from ctdb
    
    Signed-off-by: Ronnie Sahlberg <ronniesahlberg at gmail.com>

-----------------------------------------------------------------------

Summary of changes:
 common/system_linux.c |  158 ++++++++++++++++++++++++++++++++++--------------
 tests/nodes.txt       |    3 -
 2 files changed, 112 insertions(+), 49 deletions(-)


Changeset truncated at 500 lines:

diff --git a/common/system_linux.c b/common/system_linux.c
index 760877f..c7e66eb 100644
--- a/common/system_linux.c
+++ b/common/system_linux.c
@@ -26,9 +26,58 @@
 #include "lib/events/events.h"
 #include <netinet/if_ether.h>
 #include <netinet/ip6.h>
+#include <netinet/icmp6.h>
 #include <net/if_arp.h>
 
 
+#ifndef ETHERTYPE_IP6
+#define ETHERTYPE_IP6 0x86dd
+#endif
+
+/*
+  uint16 checksum for n bytes
+ */
+static uint32_t uint16_checksum(uint16_t *data, size_t n)
+{
+	uint32_t sum=0;
+	while (n>=2) {
+		sum += (uint32_t)ntohs(*data);
+		data++;
+		n -= 2;
+	}
+	if (n == 1) {
+		sum += (uint32_t)ntohs(*(uint8_t *)data);
+	}
+	return sum;
+}
+
+/*
+  calculate the tcp checksum for tcp over ipv6
+*/
+static uint16_t tcp_checksum6(uint16_t *data, size_t n, struct ip6_hdr *ip6)
+{
+	uint32_t phdr[2];
+	uint32_t sum = 0;
+	uint16_t sum2;
+
+	sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_src, 16);
+	sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_dst, 16);
+
+	phdr[0] = htonl(n);
+	phdr[1] = htonl(ip6->ip6_nxt);
+	sum += uint16_checksum((uint16_t *)phdr, 8);
+
+	sum += uint16_checksum(data, n);
+
+	sum = (sum & 0xFFFF) + (sum >> 16);
+	sum = (sum & 0xFFFF) + (sum >> 16);
+	sum2 = htons(sum);
+	sum2 = ~sum2;
+	if (sum2 == 0) {
+		return 0xFFFF;
+	}
+	return sum2;
+}
 
 /*
   send gratuitous arp reply after we have taken over an ip address
@@ -42,8 +91,10 @@ int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
 	struct sockaddr sa;
 	struct ether_header *eh;
 	struct arphdr *ah;
+	struct ip6_hdr *ip6;
+	struct icmp6_hdr *icmp6;
 	struct ifreq if_hwaddr;
-	unsigned char buffer[64]; /*minimum eth frame size */
+	unsigned char buffer[78]; /* ipv6 neigh solicitation size */
 	char *ptr;
 
 	ZERO_STRUCT(sa);
@@ -131,8 +182,66 @@ int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
 
 		close(s);
 		break;
+	case AF_INET6:
+		s = socket(AF_INET, SOCK_PACKET, htons(ETHERTYPE_IP6));
+		if (s == -1){
+			DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket\n"));
+			return -1;
+		}
+
+		/* get the mac address */
+		strcpy(if_hwaddr.ifr_name, iface);
+		ret = ioctl(s, SIOCGIFHWADDR, &if_hwaddr);
+		if ( ret < 0 ) {
+			close(s);
+			DEBUG(DEBUG_CRIT,(__location__ " ioctl failed\n"));
+			return -1;
+		}
+		if (ARPHRD_LOOPBACK == if_hwaddr.ifr_hwaddr.sa_family) {
+			DEBUG(DEBUG_DEBUG,("Ignoring loopback arp request\n"));
+			close(s);
+			return 0;
+		}
+		if (if_hwaddr.ifr_hwaddr.sa_family != AF_LOCAL) {
+			close(s);
+			errno = EINVAL;
+			DEBUG(DEBUG_CRIT,(__location__ " not an ethernet address family (0x%x)\n",
+				 if_hwaddr.ifr_hwaddr.sa_family));
+			return -1;
+		}
+
+		memset(buffer, 0 , sizeof(buffer));
+		eh = (struct ether_header *)buffer;
+		memset(eh->ether_dhost, 0xff, ETH_ALEN);
+		memcpy(eh->ether_shost, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
+		eh->ether_type = htons(ETHERTYPE_IP6);
+
+		ip6 = (struct ip6_hdr *)(eh+1);
+		ip6->ip6_vfc  = 0x60;
+		ip6->ip6_plen = htons(24);
+		ip6->ip6_nxt  = IPPROTO_ICMPV6;
+		ip6->ip6_hlim = 255;
+		ip6->ip6_dst  = addr->ip6.sin6_addr;
+
+		icmp6 = (struct icmp6_hdr *)(ip6+1);
+		icmp6->icmp6_type = ND_NEIGHBOR_SOLICIT;
+		icmp6->icmp6_code = 0;
+		memcpy(&icmp6->icmp6_data32[1], &addr->ip6.sin6_addr, 16);
+
+		icmp6->icmp6_cksum = tcp_checksum6((uint16_t *)icmp6, ntohs(ip6->ip6_plen), ip6);
+
+		strncpy(sa.sa_data, iface, sizeof(sa.sa_data));
+		ret = sendto(s, buffer, 78, 0, &sa, sizeof(sa));
+		if (ret < 0 ){
+			close(s);
+			DEBUG(DEBUG_CRIT,(__location__ " failed sendto\n"));
+			return -1;
+		}	
+
+		close(s);
+		break;
 	default:
-		DEBUG(DEBUG_CRIT,(__location__ " not an ipv4 address (family is %u)\n", addr->ip.sin_family));
+		DEBUG(DEBUG_CRIT,(__location__ " not an ipv4/ipv6 address (family is %u)\n", addr->ip.sin_family));
 		return -1;
 	}
 
@@ -141,23 +250,6 @@ int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
 
 
 /*
-  uint16 checksum for n bytes
- */
-static uint32_t uint16_checksum(uint16_t *data, size_t n)
-{
-	uint32_t sum=0;
-	while (n>=2) {
-		sum += (uint32_t)ntohs(*data);
-		data++;
-		n -= 2;
-	}
-	if (n == 1) {
-		sum += (uint32_t)ntohs(*(uint8_t *)data);
-	}
-	return sum;
-}
-
-/*
   simple TCP checksum - assumes data is multiple of 2 bytes long
  */
 static uint16_t tcp_checksum(uint16_t *data, size_t n, struct iphdr *ip)
@@ -180,29 +272,6 @@ static uint16_t tcp_checksum(uint16_t *data, size_t n, struct iphdr *ip)
 }
 
 /*
-  calculate the tcp checksum for tcp over ipv6
-*/
-static uint16_t tcp_checksum6(uint16_t *data, size_t n, struct ip6_hdr *ip6)
-{
-	uint32_t sum = uint16_checksum(data, n);
-	uint16_t sum2;
-
-	sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_src, 16);
-	sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_dst, 16);
-	sum += ip6->ip6_plen;
-	sum += ip6->ip6_nxt;
-			
-	sum = (sum & 0xFFFF) + (sum >> 16);
-	sum = (sum & 0xFFFF) + (sum >> 16);
-	sum2 = htons(sum);
-	sum2 = ~sum2;
-	if (sum2 == 0) {
-		return 0xFFFF;
-	}
-	return sum2;
-}
-
-/*
   Send tcp segment from the specified IP/port to the specified
   destination IP/port. 
 
@@ -285,7 +354,7 @@ int ctdb_sys_send_tcp(const ctdb_sock_addr *dest,
 	case AF_INET6:
 		ZERO_STRUCT(ip6pkt);
 		ip6pkt.ip6.ip6_vfc  = 0x60;
-		ip6pkt.ip6.ip6_plen = 20;
+		ip6pkt.ip6.ip6_plen = htons(20);
 		ip6pkt.ip6.ip6_nxt  = IPPROTO_TCP;
 		ip6pkt.ip6.ip6_hlim = 64;
 		ip6pkt.ip6.ip6_src  = src->ip6.sin6_addr;
@@ -451,9 +520,6 @@ int ctdb_sys_read_tcp_packet(int s, void *private_data,
 		*seq                    = tcp->seq;
 
 		return 0;
-#ifndef ETHERTYPE_IP6
-#define ETHERTYPE_IP6 0x86dd
-#endif
 	} else if (ntohs(eth->ether_type) == ETHERTYPE_IP6) {
 		/* IP6 */
 		ip6 = (struct ip6_hdr *)(eth+1);
diff --git a/tests/nodes.txt b/tests/nodes.txt
index 2563adc..20e29b1 100644
--- a/tests/nodes.txt
+++ b/tests/nodes.txt
@@ -1,4 +1 @@
 ::1
-::2
-::3
-::4


-- 
CTDB repository


More information about the samba-cvs mailing list