[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