diff -urN keepalived-1.1.19.excludedipv6/keepalived/include/vrrp_icmp6.h keepalived-1.1.19.v6.neighbor.advertisement/keepalived/include/vrrp_icmp6.h --- keepalived-1.1.19.excludedipv6/keepalived/include/vrrp_icmp6.h 1970-01-01 01:00:00.000000000 +0100 +++ keepalived-1.1.19.v6.neighbor.advertisement/keepalived/include/vrrp_icmp6.h 2010-04-14 12:19:51.669502339 +0200 @@ -0,0 +1,56 @@ +#ifndef _VRRP_ICMP6_H +#define _VRRP_ICMP6_H + +/* system includes */ +#include +#include + +/* local includes */ +#include "vrrp.h" +#include "vrrp_ipaddress.h" + +/* local definitions */ +#define ETHERNET_HW_LEN 6 + +/* types definition */ +typedef struct _m_ipv6hdr { + unsigned char priority:4, + version:4; + unsigned char flow_lbl[3]; + unsigned short int payload_len; + unsigned char nexthdr; + unsigned char hop_limit; + + struct in6_addr saddr; + struct in6_addr daddr; + +} m_ipv6hdr; + +/* types definition */ +typedef struct _m_icmp6 { + unsigned char type; + unsigned char code; + unsigned short int cksum; + unsigned int reserved:5, + override:1, + solicited:1, + router:1, + reserved2:24; + + struct in6_addr target; + unsigned char opt_header[2]; + unsigned char opt_lladdr[6]; + +} m_icmp6; + + +/* Global vars exported */ +extern char *aicmp6_buffer; +extern int aicmp6_fd; + +/* prototypes */ +extern void ngbadv_icmp6_init(void); +extern void ngbadv_icmp6_close(void); +extern int send_ngbadv_icmp6(ip_address * ipaddress); + +#endif diff -urN keepalived-1.1.19.excludedipv6/keepalived/vrrp/Makefile.in keepalived-1.1.19.v6.neighbor.advertisement/keepalived/vrrp/Makefile.in --- keepalived-1.1.19.excludedipv6/keepalived/vrrp/Makefile.in 2009-09-28 12:56:54.000000000 +0200 +++ keepalived-1.1.19.v6.neighbor.advertisement/keepalived/vrrp/Makefile.in 2010-04-14 12:03:40.901511497 +0200 @@ -13,7 +13,7 @@ OBJS = vrrp_daemon.o vrrp_data.o vrrp_parser.o \ vrrp.o vrrp_notify.o vrrp_scheduler.o vrrp_sync.o vrrp_index.o \ - vrrp_netlink.o vrrp_arp.o vrrp_if.o vrrp_track.o vrrp_ipaddress.o \ + vrrp_netlink.o vrrp_arp.o vrrp_icmp6.o vrrp_if.o vrrp_track.o vrrp_ipaddress.o \ vrrp_iproute.o vrrp_ipsecah.o HEADERS = $(OBJS:.o=.h) @@ -29,7 +29,7 @@ rm -f Makefile vrrp_daemon.o: vrrp_daemon.c ../include/vrrp_daemon.h ../include/vrrp_scheduler.h \ - ../include/vrrp_if.h ../include/vrrp_arp.h ../include/vrrp_netlink.h ../include/vrrp_iproute.h \ + ../include/vrrp_if.h ../include/vrrp_arp.h ../include/vrrp_icmp6.h ../include/vrrp_netlink.h ../include/vrrp_iproute.h \ ../include/vrrp_iproute.h ../include/vrrp_parser.h ../include/vrrp_data.h \ ../include/vrrp.h ../include/global_data.h ../include/pidfile.h ../include/daemon.h \ ../include/ipvswrapper.h ../../lib/list.h ../../lib/memory.h ../../lib/parser.h \ @@ -44,7 +44,7 @@ vrrp.o: vrrp.c ../include/vrrp.h ../include/vrrp_scheduler.h \ ../include/vrrp_notify.h ../include/ipvswrapper.h ../../lib/memory.h \ ../../lib/list.h ../include/vrrp_data.h ../include/vrrp_sync.h ../include/vrrp_index.h \ - ../include/vrrp_arp.h ../../lib/utils.h + ../include/vrrp_arp.h ../include/vrrp_icmp6.h ../../lib/utils.h vrrp_notify.o: vrrp_notify.c ../include/vrrp_notify.h ../../lib/memory.h \ ../../lib/notify.h vrrp_scheduler.o: vrrp_scheduler.c ../include/vrrp_scheduler.h \ @@ -60,6 +60,7 @@ ../include/vrrp_if.h ../../lib/memory.h ../../lib/scheduler.h \ ../../lib/utils.h vrrp_arp.o: vrrp_arp.c ../include/vrrp_arp.h +vrrp_icmp6.o: vrrp_icmp6.c ../include/vrrp_icmp6.h vrrp_track.o: vrrp_track.c ../include/vrrp_track.h ../include/vrrp_if.h \ ../include/vrrp_data.h ../../lib/memory.h vrrp_if.o: vrrp_if.c ../include/vrrp_if.h ../include/vrrp_netlink.h \ diff -urN keepalived-1.1.19.excludedipv6/keepalived/vrrp/vrrp.c keepalived-1.1.19.v6.neighbor.advertisement/keepalived/vrrp/vrrp.c --- keepalived-1.1.19.excludedipv6/keepalived/vrrp/vrrp.c 2010-04-14 12:24:48.105499163 +0200 +++ keepalived-1.1.19.v6.neighbor.advertisement/keepalived/vrrp/vrrp.c 2010-04-14 12:21:02.949533316 +0200 @@ -27,6 +27,7 @@ #include #include #include "vrrp_arp.h" +#include "vrrp_icmp6.h" #include "vrrp_scheduler.h" #include "vrrp_notify.h" #include "ipvswrapper.h" @@ -597,8 +598,12 @@ if (!LIST_ISEMPTY(vrrp->evip)) for (e = LIST_HEAD(vrrp->evip); e; ELEMENT_NEXT(e)) { ipaddress = ELEMENT_DATA(e); - if (IP_ISV6(ipaddress)) /* no arp on ipv6 */ + if (IP_ISV6(ipaddress)) { + /* ipv6 use icmp6 insteed arp */ + send_ngbadv_icmp6(ipaddress); continue; + } + if (0 == j && debug & 32) log_message(LOG_INFO, "VRRP_Instance(%s) Sending gratuitous ARPs " diff -urN keepalived-1.1.19.excludedipv6/keepalived/vrrp/vrrp_daemon.c keepalived-1.1.19.v6.neighbor.advertisement/keepalived/vrrp/vrrp_daemon.c --- keepalived-1.1.19.excludedipv6/keepalived/vrrp/vrrp_daemon.c 2010-04-14 12:24:48.109579012 +0200 +++ keepalived-1.1.19.v6.neighbor.advertisement/keepalived/vrrp/vrrp_daemon.c 2010-04-14 12:20:36.709498272 +0200 @@ -24,6 +24,7 @@ #include "vrrp_scheduler.h" #include "vrrp_if.h" #include "vrrp_arp.h" +#include "vrrp_icmp6.h" #include "vrrp_netlink.h" #include "vrrp_ipaddress.h" #include "vrrp_iproute.h" @@ -62,6 +63,7 @@ shutdown_vrrp_instances(); free_interface_queue(); gratuitous_arp_close(); + ngbadv_icmp6_close(); /* Stop daemon */ pidfile_rm(vrrp_pidfile); @@ -96,6 +98,7 @@ init_interface_queue(); kernel_netlink_init(); gratuitous_arp_init(); + ngbadv_icmp6_init(); #ifdef _WITH_LVS_ /* Initialize ipvs related */ @@ -199,6 +202,7 @@ free_interface_queue(); free_vrrp_buffer(); gratuitous_arp_close(); + ngbadv_icmp6_close(); /* Save previous conf data */ old_vrrp_data = vrrp_data; diff -urN keepalived-1.1.19.excludedipv6/keepalived/vrrp/vrrp_icmp6.c keepalived-1.1.19.v6.neighbor.advertisement/keepalived/vrrp/vrrp_icmp6.c --- keepalived-1.1.19.excludedipv6/keepalived/vrrp/vrrp_icmp6.c 1970-01-01 01:00:00.000000000 +0100 +++ keepalived-1.1.19.v6.neighbor.advertisement/keepalived/vrrp/vrrp_icmp6.c 2010-04-14 12:21:59.685500259 +0200 @@ -0,0 +1,137 @@ +/* local includes */ +#include "vrrp_icmp6.h" +#include "logger.h" +#include "memory.h" +#include "utils.h" + +/* system includes */ +#include + +/* global vars */ +char *aicmp6_buffer; +int aicmp6_fd; + +/* Make shared socket */ +void ngbadv_icmp6_init(void) +{ + /* Initalize shared buffer */ + aicmp6_buffer = (char *)MALLOC( ETHER_HDR_LEN + sizeof(m_ipv6hdr) + sizeof(m_icmp6) ); + + /* Create the socket descriptor */ + aicmp6_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IPV6)); + +} +void ngbadv_icmp6_close(void) +{ + FREE(aicmp6_buffer); + close(aicmp6_fd); +} + +/* Send the update neig advt message */ +static int send_ngbadv(ip_address *ipaddress) +{ + struct sockaddr_ll sll; + int len; + + /* Build the dst device */ + memset(&sll, 0, sizeof(sll)); + sll.sll_family = AF_PACKET; + memcpy(sll.sll_addr, IF_HWADDR(ipaddress->ifp), ETH_ALEN); + sll.sll_halen = ETHERNET_HW_LEN; + sll.sll_ifindex = IF_INDEX(ipaddress->ifp); + + /* Send packet */ + len = sendto(aicmp6_fd, aicmp6_buffer, sizeof(m_ipv6hdr) + sizeof(m_icmp6) + ETHER_HDR_LEN + , 0, (struct sockaddr *)&sll, sizeof(sll)); + if (len < 0) + log_message(LOG_INFO, "Error sending update neig icmp6 update on %s" + , IF_NAME(ipaddress->ifp)); + return len; +} + +static unsigned int icmp6_cksum(const m_ipv6hdr *ipv6h, const m_icmp6 *icmp6, unsigned int len) +{ + size_t i; + const unsigned short *icmpmsg; + unsigned int sum; + union { + struct { + struct in6_addr saddr; + struct in6_addr daddr; + unsigned int payload_len; + unsigned char zero[3]; + unsigned char nexthdr; + } fields; + unsigned short word[20]; + } pseudoh; + + /* pseudo-header */ + memset(&pseudoh, 0, sizeof(pseudoh)); + + memcpy(&pseudoh.fields.saddr, &ipv6h->saddr, sizeof(struct in6_addr)); + memcpy(&pseudoh.fields.daddr, &ipv6h->daddr, sizeof(struct in6_addr)); + pseudoh.fields.payload_len = ipv6h->payload_len; + pseudoh.fields.nexthdr = ipv6h->nexthdr; + + sum = 0; + for (i = 0; i < 20; i++) + sum += pseudoh.word[i]; + + icmpmsg = (const unsigned short *)icmp6; + + for (i = 0; i < (len & ~1); i += 2) + sum += *icmpmsg++; + + if (len & 1) + sum += htons((*(const unsigned char *)icmpmsg) << 8); + + while (sum > 0xffff) + sum = (sum & 0xffff) + (sum >> 16); + sum = ~sum & 0xffff; + + return sum; +} + +/* Build a gratuitous ARP message over a specific interface */ +int send_ngbadv_icmp6(ip_address *ipaddress) +{ + struct ether_header *eth = (struct ether_header *) aicmp6_buffer; + m_ipv6hdr *ipv6h = (m_ipv6hdr *) (aicmp6_buffer + ETHER_HDR_LEN); + m_icmp6 *icmp6 = (m_icmp6 *) (aicmp6_buffer + sizeof(m_ipv6hdr) + ETHER_HDR_LEN); + char *hwaddr = (char *) IF_HWADDR(ipaddress->ifp); + int len; + + /* Ethernet header */ + memset(eth->ether_dhost, 0xFF, ETH_ALEN); + memcpy(eth->ether_shost, hwaddr, ETH_ALEN); + eth->ether_type = htons(0x86DD); + + /* IPV6 */ + ipv6h->version = 6; + ipv6h->payload_len = htons(sizeof(m_icmp6)); + ipv6h->nexthdr = 0x3a; /* ICMPv6 */ + ipv6h->hop_limit = 255; + memcpy(&ipv6h->saddr, &ipaddress->addrv6, sizeof(struct in6_addr)); + ipv6h->daddr.s6_addr16[0] = 0x02ff; + ipv6h->daddr.s6_addr16[7] = 0x0100; + + /* ICMP6 */ + icmp6->type = 136; + icmp6->override = 1; + memcpy(&icmp6->target, &ipaddress->addrv6, sizeof(struct in6_addr)); + icmp6->opt_header[0] = 2; + icmp6->opt_header[1] = 1; + memcpy(icmp6->opt_lladdr, hwaddr, ETH_ALEN); + + /* Compute checksum */ + icmp6->cksum = icmp6_cksum(ipv6h, icmp6, sizeof(m_icmp6)); + + /* Send the neighbor advertisement message */ + len = send_ngbadv(ipaddress); + + /* Cleanup room for next round */ + memset(aicmp6_buffer, 0, sizeof(m_ipv6hdr) + sizeof(m_icmp6) + ETHER_HDR_LEN); + + return len; +} +