Esempio n. 1
0
int
if_leave_vrrp_group(sa_family_t family, int sd, interface_t *ifp)
{
	struct ip_mreqn imr;
	struct ipv6_mreq imr6;
	int ret = 0;

	/* If fd is -1 then we add a membership trouble */
	if (sd < 0 || !ifp)
		return -1;

	/* Leaving the VRRP multicast group */
	if (family == AF_INET) {
		memset(&imr, 0, sizeof(imr));
		imr.imr_multiaddr = ((struct sockaddr_in *) &global_data->vrrp_mcast_group4)->sin_addr;
		imr.imr_ifindex = IF_INDEX(ifp);
		ret = setsockopt(sd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
				 (char *) &imr, sizeof(imr));
	} else {
		memset(&imr6, 0, sizeof(imr6));
		imr6.ipv6mr_multiaddr = ((struct sockaddr_in6 *) &global_data->vrrp_mcast_group6)->sin6_addr;
		imr6.ipv6mr_interface = IF_INDEX(ifp);
		ret = setsockopt(sd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP,
				 (char *) &imr6, sizeof(struct ipv6_mreq));
	}

	if (ret < 0) {
		log_message(LOG_INFO, "(%s): cant do IP%s_DROP_MEMBERSHIP errno=%s (%d)",
			    ifp->ifname, (family == AF_INET) ? "" : "V6", strerror(errno), errno);
		return -1;
	}

	return 0;
}
Esempio n. 2
0
int
if_setsockopt_mcast_if(sa_family_t family, int *sd, interface_t *ifp)
{
	int ret;
	unsigned int ifindex;

	if (*sd < 0)
		return -1;

	/* Set interface for sending outbound datagrams */
	ifindex = IF_INDEX(ifp);
	if ( family == AF_INET)
	{
		struct ip_mreqn imr;

		memset(&imr, 0, sizeof(imr));
		imr.imr_ifindex = IF_INDEX(ifp);
		ret = setsockopt(*sd, IPPROTO_IP, IP_MULTICAST_IF, &imr, sizeof(imr));
	}
	else
		ret = setsockopt(*sd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex));

	if (ret < 0) {
		log_message(LOG_INFO, "cant set IP%s_MULTICAST_IF IP option. errno=%d (%m)", (family == AF_INET) ? "" : "V6", errno);
		close(*sd);
		*sd = -1;
	}

	return *sd;
}
Esempio n. 3
0
void set_vrrp_fd_bucket(int old_fd, vrrp_rt *vrrp)
{
	vrrp_rt *vrrp_ptr;
	element e;
	list l = &vrrp_data->vrrp_index_fd[old_fd%1024 + 1];

	for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) {
		vrrp_ptr =  ELEMENT_DATA(e);
		if (IF_INDEX(vrrp_ptr->ifp) == IF_INDEX(vrrp->ifp)) {
			vrrp_ptr->fd_in = vrrp->fd_in;
			vrrp_ptr->fd_out = vrrp->fd_out;
		}
	}
}
Esempio n. 4
0
/* Link layer handling */
static int
netlink_link_setlladdr(vrrp_rt *vrrp)
{
    int status = 1;
    u_char ll_addr[ETH_ALEN] = {0x00, 0x00, 0x5e, 0x00, 0x01, vrrp->vrid};
    struct {
        struct nlmsghdr n;
        struct ifinfomsg ifi;
        char buf[256];
    } req;

    memset(&req, 0, sizeof (req));

    req.n.nlmsg_len = NLMSG_LENGTH(sizeof (struct ifinfomsg));
    req.n.nlmsg_flags = NLM_F_REQUEST;
    req.n.nlmsg_type = RTM_NEWLINK;
    req.ifi.ifi_family = AF_INET;
    req.ifi.ifi_index = IF_INDEX(vrrp->xmit_ifp);

    addattr_l(&req.n, sizeof(req), IFLA_ADDRESS, ll_addr, ETH_ALEN);

    if (netlink_talk(&nl_cmd, &req.n) < 0)
        status = -1;
    else
        memcpy(vrrp->xmit_ifp->hw_addr, ll_addr, ETH_ALEN);

    return status;
}
Esempio n. 5
0
int
netlink_link_down(vrrp_rt *vrrp)
{
    int status = 1;
    struct {
        struct nlmsghdr n;
        struct ifinfomsg ifi;
        char buf[256];
    } req;

    memset(&req, 0, sizeof (req));

    req.n.nlmsg_len = NLMSG_LENGTH(sizeof (struct ifinfomsg));
    req.n.nlmsg_flags = NLM_F_REQUEST;
    req.n.nlmsg_type = RTM_NEWLINK;
    req.ifi.ifi_family = AF_UNSPEC;
    req.ifi.ifi_index = IF_INDEX(vrrp->xmit_ifp);
    req.ifi.ifi_change |= IFF_UP;
    req.ifi.ifi_flags &= ~IFF_UP;

    if (netlink_talk(&nl_cmd, &req.n) < 0)
        status = -1;

    return status;
}
Esempio n. 6
0
int
netlink_link_del_vmac(vrrp_rt *vrrp)
{
	int status = 1;
	struct {
		struct nlmsghdr n;
		struct ifinfomsg ifi;
		char buf[256];
	} req;

	if (!vrrp->ifp)
		return -1;

	memset(&req, 0, sizeof (req));

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof (struct ifinfomsg));
	req.n.nlmsg_flags = NLM_F_REQUEST;
	req.n.nlmsg_type = RTM_DELLINK;
	req.ifi.ifi_family = AF_INET;
	req.ifi.ifi_index = IF_INDEX(vrrp->ifp);

	if (netlink_talk(&nl_cmd, &req.n) < 0)
		status = -1;

	return status;
}
Esempio n. 7
0
int
netlink_link_add_vmac(vrrp_rt *vrrp)
{
	struct rtattr *linkinfo;
	interface *ifp;
	char ifname[IFNAMSIZ];
	struct {
		struct nlmsghdr n;
		struct ifinfomsg ifi;
		char buf[256];
	} req;

	if (!vrrp->ifp)
		return -1;

	memset(&req, 0, sizeof (req));
	memset(ifname, 0, IFNAMSIZ);
	strncpy(ifname, vrrp->vmac_ifname, IFNAMSIZ - 1);

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof (struct ifinfomsg));
	req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
	req.n.nlmsg_type = RTM_NEWLINK;
	req.ifi.ifi_family = AF_INET;

	/* macvlan settings */
	linkinfo = NLMSG_TAIL(&req.n);
	addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
	addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, (void *)ll_kind, strlen(ll_kind));
	linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
	addattr_l(&req.n, sizeof(req), IFLA_LINK, &IF_INDEX(vrrp->ifp), sizeof(uint32_t));
	addattr_l(&req.n, sizeof(req), IFLA_IFNAME, ifname, strlen(ifname));

	if (netlink_talk(&nl_cmd, &req.n) < 0)
		return -1;

	/*
	 * Update interface queue and vrrp instance interface binding.
	 * bring it UP !
	 */
	netlink_interface_lookup();
	ifp = if_get_by_ifname(ifname);
	if (!ifp)
		return -1;
	vrrp->ifp = ifp;
	vrrp->vmac |= 2;
	netlink_link_setlladdr(vrrp);
	netlink_link_up(vrrp);

	/*
	 * By default MACVLAN interface are in VEPA mode which filters
	 * out received packets whose MAC source address matches that
	 * of the MACVLAN interface. Setting MACVLAN interface in private
	 * mode will not filter based on source MAC address.
	 */
	netlink_link_setmode(vrrp);

	return 1;
}
Esempio n. 8
0
int
if_join_vrrp_group(sa_family_t family, int *sd, interface_t *ifp, int proto)
{
	struct ip_mreqn imr;
	struct ipv6_mreq imr6;
	int ret = 0;

	if (*sd < 0)
		return -1;

	/* -> outbound processing option
	 * join the multicast group.
	 * binding the socket to the interface for outbound multicast
	 * traffic.
	 */

	if (family == AF_INET) {
		memset(&imr, 0, sizeof(imr));
		imr.imr_multiaddr.s_addr = htonl(INADDR_VRRP_GROUP);
		imr.imr_address.s_addr = IF_ADDR(ifp);
		imr.imr_ifindex = IF_INDEX(ifp);

		/* -> Need to handle multicast convergance after takeover.
		 * We retry until multicast is available on the interface.
		 */
		ret = setsockopt(*sd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
				 (char *) &imr, sizeof(struct ip_mreqn));
	} else {
		memset(&imr6, 0, sizeof(imr6));
		imr6.ipv6mr_multiaddr.s6_addr16[0] = htons(0xff02);
		imr6.ipv6mr_multiaddr.s6_addr16[7] = htons(0x12);
		imr6.ipv6mr_interface = IF_INDEX(ifp);
		ret = setsockopt(*sd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
				 (char *) &imr6, sizeof(struct ipv6_mreq));
	}

	if (ret < 0) {
		log_message(LOG_INFO, "cant do IP%s_ADD_MEMBERSHIP errno=%s (%d)",
			    (family == AF_INET) ? "" : "V6", strerror(errno), errno);
		close(*sd);
		*sd = -1;
        }

	return *sd;
}
Esempio n. 9
0
int
if_join_vrrp_group(sa_family_t family, int *sd, interface_t *ifp, int proto)
{
	struct ip_mreqn imr;
	struct ipv6_mreq imr6;
	int ret = 0;

	if (*sd < 0)
		return -1;

	/* -> outbound processing option
	 * join the multicast group.
	 * binding the socket to the interface for outbound multicast
	 * traffic.
	 */

	if (family == AF_INET) {
		memset(&imr, 0, sizeof(imr));
		imr.imr_multiaddr = ((struct sockaddr_in *) &global_data->vrrp_mcast_group4)->sin_addr;
		imr.imr_ifindex = IF_INDEX(ifp);

		/* -> Need to handle multicast convergance after takeover.
		 * We retry until multicast is available on the interface.
		 */
		ret = setsockopt(*sd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
				 (char *) &imr, sizeof(struct ip_mreqn));
	} else {
		memset(&imr6, 0, sizeof(imr6));
		imr6.ipv6mr_multiaddr = ((struct sockaddr_in6 *) &global_data->vrrp_mcast_group6)->sin6_addr;
		imr6.ipv6mr_interface = IF_INDEX(ifp);
		ret = setsockopt(*sd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
				 (char *) &imr6, sizeof(struct ipv6_mreq));
	}

	if (ret < 0) {
		log_message(LOG_INFO, "(%s): cant do IP%s_ADD_MEMBERSHIP errno=%s (%d)",
			    ifp->ifname, (family == AF_INET) ? "" : "V6", strerror(errno), errno);
		close(*sd);
		*sd = -1;
	}

	return *sd;
}
Esempio n. 10
0
int
if_leave_vrrp_group(sa_family_t family, int sd, interface_t *ifp)
{
	struct ip_mreqn imr;
	struct ipv6_mreq imr6;
	int ret = 0;

	/* If fd is -1 then we add a membership trouble */
	if (sd < 0 || !ifp)
		return -1;

	/* Leaving the VRRP multicast group */
	if (family == AF_INET) {
		memset(&imr, 0, sizeof(imr));
		/* FIXME: change this to use struct ip_mreq */
		imr.imr_multiaddr.s_addr = htonl(INADDR_VRRP_GROUP);
		imr.imr_address.s_addr = IF_ADDR(ifp);
		imr.imr_ifindex = IF_INDEX(ifp);
		ret = setsockopt(sd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
				 (char *) &imr, sizeof (struct ip_mreqn));
	} else {
		memset(&imr6, 0, sizeof(imr6));
		/* rfc5798.5.1.2.2 : destination IPv6 mcast group is
		 * ff02:0:0:0:0:0:0:12.
		 */
		imr6.ipv6mr_multiaddr.s6_addr16[0] = htons(0xff02);
		imr6.ipv6mr_multiaddr.s6_addr16[7] = htons(0x12);
		imr6.ipv6mr_interface = IF_INDEX(ifp);
		ret = setsockopt(sd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP,
				 (char *) &imr6, sizeof(struct ipv6_mreq));
	}

	if (ret < 0) {
		log_message(LOG_INFO, "cant do IP%s_DROP_MEMBERSHIP errno=%s (%d)",
			    (family == AF_INET) ? "" : "V6", strerror(errno), errno);
		close(sd);
		return -1;
	}

	/* Finally close the desc */
	close(sd);
	return 0;
}
Esempio n. 11
0
static int
netlink_link_setmode(vrrp_rt *vrrp)
{
    int status = 1;
    struct {
        struct nlmsghdr n;
        struct ifinfomsg ifi;
        char buf[256];
    } req;
    struct rtattr *linkinfo;
    struct rtattr *data;

    memset(&req, 0, sizeof (req));

    req.n.nlmsg_len = NLMSG_LENGTH(sizeof (struct ifinfomsg));
    req.n.nlmsg_flags = NLM_F_REQUEST;
    req.n.nlmsg_type = RTM_NEWLINK;
    req.ifi.ifi_family = AF_INET;
    req.ifi.ifi_index = IF_INDEX(vrrp->xmit_ifp);

    linkinfo = NLMSG_TAIL(&req.n);
    addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
    addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, (void *)ll_kind,
              strlen(ll_kind));

    data = NLMSG_TAIL(&req.n);
    addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0);

    /*
     * In private mode, macvlan will receive frames with same MAC addr
     * as configured on the interface.
     */
#ifndef MACVLAN_MODE_VRRP
#define MACVLAN_MODE_VRRP 16
#endif
    addattr32(&req.n, sizeof(req), IFLA_MACVLAN_MODE,
              MACVLAN_MODE_VRRP);
    data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;

    linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;

    if (netlink_talk(&nl_cmd, &req.n) < 0)
        status = -1;

    return status;
}
Esempio n. 12
0
/* Send the gratuitous ARP message */
static int send_arp(ip_address_t *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(garp_fd, garp_buffer, sizeof(arphdr_t) + ETHER_HDR_LEN
		     , 0, (struct sockaddr *)&sll, sizeof(sll));
	if (len < 0)
		log_message(LOG_INFO, "Error sending gratuitous ARP on %s for %s",
			    IF_NAME(ipaddress->ifp), inet_ntop2(ipaddress->u.sin.sin_addr.s_addr));
	return len;
}
Esempio n. 13
0
int
if_setsockopt_mcast_if(sa_family_t family, int *sd, interface_t *ifp)
{
	int ret;
	unsigned int ifindex;

	/* Not applicable for IPv4 */
	if (*sd < 0 || family == AF_INET)
		return -1;

	/* Include IP header into RAW protocol packet */
	ifindex = IF_INDEX(ifp);
	ret = setsockopt(*sd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex));
	if (ret < 0) {
		log_message(LOG_INFO, "cant set IPV6_MULTICAST_IF IP option. errno=%d (%m)", errno);
		close(*sd);
		*sd = -1;
	}

	return *sd;
}
Esempio n. 14
0
int
netlink_link_add_vmac(vrrp_rt *vrrp)
{
    struct rtattr *linkinfo;
    interface *ifp;
    char ifname[IFNAMSIZ];
    struct {
        struct nlmsghdr n;
        struct ifinfomsg ifi;
        char buf[256];
    } req;

    if (!vrrp->ifp)
        return -1;

    memset(&req, 0, sizeof (req));
    memset(ifname, 0, IFNAMSIZ);
    strncpy(ifname, vrrp->vmac_ifname, IFNAMSIZ - 1);

    /*
     * Check to see if this vmac interface was created
     * by a previous instance.
     */
    if (reload && (ifp = if_get_by_ifname(ifname))) {
        vrrp->xmit_ifp = ifp;
        /* Save ifindex for use on delete */
        vrrp->vmac_ifindex = IF_INDEX(vrrp->xmit_ifp);
        vrrp->vmac |= 2;
        return 1;
    }

    req.n.nlmsg_len = NLMSG_LENGTH(sizeof (struct ifinfomsg));
    req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
    req.n.nlmsg_type = RTM_NEWLINK;
    req.ifi.ifi_family = AF_INET;

    /* macvlan settings */
    linkinfo = NLMSG_TAIL(&req.n);
    addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
    addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, (void *)ll_kind, strlen(ll_kind));
    linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
    addattr_l(&req.n, sizeof(req), IFLA_LINK, &IF_INDEX(vrrp->ifp), sizeof(uint32_t));
    addattr_l(&req.n, sizeof(req), IFLA_IFNAME, ifname, strlen(ifname));

    if (netlink_talk(&nl_cmd, &req.n) < 0)
        return -1;

    /*
     * Update interface queue and vrrp instance interface binding.
     * bring it UP !
     */
    netlink_interface_lookup();
    ifp = if_get_by_ifname(ifname);
    if (!ifp)
        return -1;
    vrrp->xmit_ifp = ifp;
    vrrp->vmac_ifindex = IF_INDEX(vrrp->xmit_ifp); /* For use on delete */
    vrrp->vmac |= 2;
    netlink_link_setlladdr(vrrp);
    vyatta_if_setup(ifname);
    netlink_link_up(vrrp);
    netlink_link_setmode(vrrp);

    return 1;
}
Esempio n. 15
0
int
netlink_link_add_vmac(vrrp_t *vrrp)
{
	struct rtattr *linkinfo;
	struct rtattr *data;
	unsigned int base_ifindex;
	interface_t *ifp;
	interface_t *base_ifp;
	char ifname[IFNAMSIZ];
	struct {
		struct nlmsghdr n;
		struct ifinfomsg ifi;
		char buf[256];
	} req;

	if (!vrrp->ifp || __test_bit(VRRP_VMAC_UP_BIT, &vrrp->vmac_flags) || !vrrp->vrid)
		return -1;

	if (vrrp->family == AF_INET6)
		ll_addr[4] = 0x02;
	else
		ll_addr[4] = 0x01;

	ll_addr[ETH_ALEN-1] = vrrp->vrid;

	memset(&req, 0, sizeof (req));
	memset(ifname, 0, IFNAMSIZ);
	strncpy(ifname, vrrp->vmac_ifname, IFNAMSIZ - 1);

	/*
	 * Check to see if this vmac interface was created
	 * by a previous instance.
	 */
	if ((ifp = if_get_by_ifname(ifname))) {
		/* Check to see whether this interface has wrong mac ? */
		if (memcmp((const void *) ifp->hw_addr,
			   (const void *) ll_addr, ETH_ALEN) != 0) {
			/* We have found a VIF but the vmac do not match */
			log_message(LOG_INFO, "vmac: Removing old VMAC interface %s due to conflicting "
					      "interface MAC for vrrp_instance %s!!!"
					    , vrrp->vmac_ifname, vrrp->iname);

			/* Request that NETLINK remove the VIF interface first */
			memset(&req, 0, sizeof (req));
			req.n.nlmsg_len = NLMSG_LENGTH(sizeof (struct ifinfomsg));
			req.n.nlmsg_flags = NLM_F_REQUEST;
			req.n.nlmsg_type = RTM_DELLINK;
			req.ifi.ifi_family = AF_INET;
			req.ifi.ifi_index = IF_INDEX(ifp);

			if (netlink_talk(&nl_cmd, &req.n) < 0) {
				log_message(LOG_INFO, "vmac: Error removing VMAC interface %s for "
						      "vrrp_instance %s!!!"
						    , vrrp->vmac_ifname, vrrp->iname);
				return -1;
			}

			/* Interface successfully removed, now recreate */
		}
	}

	/* Request that NETLINK create the VIF interface */
	req.n.nlmsg_len = NLMSG_LENGTH(sizeof (struct ifinfomsg));
	req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
	req.n.nlmsg_type = RTM_NEWLINK;
	req.ifi.ifi_family = AF_INET;

	/* macvlan settings */
	linkinfo = NLMSG_TAIL(&req.n);
	addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
	addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, (void *)macvlan_ll_kind, strlen(macvlan_ll_kind));
	data = NLMSG_TAIL(&req.n);
	addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0);

	/*
	 * In private mode, macvlan will receive frames with same MAC addr
	 * as configured on the interface.
	 */
	addattr32(&req.n, sizeof(req), IFLA_MACVLAN_MODE,
		  MACVLAN_MODE_PRIVATE);
	data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;
	linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
	addattr_l(&req.n, sizeof(req), IFLA_LINK, &IF_INDEX(vrrp->ifp), sizeof(uint32_t));
	addattr_l(&req.n, sizeof(req), IFLA_IFNAME, ifname, strlen(ifname));
	addattr_l(&req.n, sizeof(req), IFLA_ADDRESS, ll_addr, ETH_ALEN);

	if (netlink_talk(&nl_cmd, &req.n) < 0) {
		log_message(LOG_INFO, "vmac: Error creating VMAC interface %s for vrrp_instance %s!!!"
				    , ifname, vrrp->iname);
		return -1;
	}

	log_message(LOG_INFO, "vmac: Success creating VMAC interface %s for vrrp_instance %s"
			    , ifname, vrrp->iname);

	/*
	 * Update interface queue and vrrp instance interface binding.
	 */
	netlink_interface_lookup();
	ifp = if_get_by_ifname(ifname);
	if (!ifp)
		return -1;
	base_ifp = vrrp->ifp;
	base_ifindex = vrrp->ifp->ifindex;
	ifp->flags = vrrp->ifp->flags; /* Copy base interface flags */
	vrrp->ifp = ifp;
	vrrp->ifp->base_ifindex = base_ifindex;
	vrrp->ifp->vmac = 1;
	vrrp->vmac_ifindex = IF_INDEX(vrrp->ifp); /* For use on delete */

	if (vrrp->family == AF_INET) {
		/* Set the necessary kernel parameters to make macvlans work for us */
		set_interface_parameters(ifp, base_ifp);

		/* We don't want IPv6 running on the interface unless we have some IPv6
		 * eVIPs, so disable it if not needed */
		if (!vrrp->evip_add_ipv6)
			link_disable_ipv6(ifp);
	}
	if (vrrp->family == AF_INET6 || vrrp->evip_add_ipv6) {
		// We don't want a link-local address auto assigned - see RFC5798 paragraph 7.4.
		// If we have a sufficiently recent kernel, we can stop a link local address
		// based on the MAC address being automatically assigned. If not, then we have
		// to delete the generated address after bringing the interface up (see below).
#ifdef IFLA_INET6_ADDR_GEN_MODE		/* Since Linux 3.17 */
		memset(&req, 0, sizeof (req));
		req.n.nlmsg_len = NLMSG_LENGTH(sizeof (struct ifinfomsg));
		req.n.nlmsg_flags = NLM_F_REQUEST ;
		req.n.nlmsg_type = RTM_NEWLINK;
		req.ifi.ifi_family = AF_UNSPEC;
		req.ifi.ifi_index = vrrp->vmac_ifindex;

		u_char val = IN6_ADDR_GEN_MODE_NONE;
		struct rtattr* spec;

		spec = NLMSG_TAIL(&req.n);
		addattr_l(&req.n, sizeof(req), IFLA_AF_SPEC, NULL,0);
		data = NLMSG_TAIL(&req.n);
		addattr_l(&req.n, sizeof(req), AF_INET6, NULL,0);
		addattr_l(&req.n, sizeof(req), IFLA_INET6_ADDR_GEN_MODE, &val, sizeof(val));
		data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;
		spec->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)spec;

		if (netlink_talk(&nl_cmd, &req.n) < 0)
			log_message(LOG_INFO, "vmac: Error setting ADDR_GEN_MODE to NONE");
#endif

		if (vrrp->family == AF_INET6) {
			/* Add link-local address. If a source address has been specified, use it,
			 * else use link-local address from underlying interface to vmac if there is one,
			 * otherwise construct a link-local address based on underlying interface's
			 * MAC address.
			 * This is so that VRRP advertisements will be sent from a non-VIP address, but
			 * using the VRRP MAC address */
			ip_address_t ipaddress;

			memset(&ipaddress, 0, sizeof(ipaddress));

			ipaddress.ifp = ifp;
			if (vrrp->saddr.ss_family == AF_INET6)
				ipaddress.u.sin6_addr = ((struct sockaddr_in6*)&vrrp->saddr)->sin6_addr;
			else if (base_ifp->sin6_addr.s6_addr32[0])
				ipaddress.u.sin6_addr = base_ifp->sin6_addr;
			else
				make_link_local_address(&ipaddress.u.sin6_addr, base_ifp->hw_addr);
			ipaddress.ifa.ifa_family = AF_INET6;
			ipaddress.ifa.ifa_prefixlen = 64;
			ipaddress.ifa.ifa_index = vrrp->vmac_ifindex;

			if (netlink_ipaddress(&ipaddress, IPADDRESS_ADD) != 1)
				log_message(LOG_INFO, "Adding link-local address to vmac failed");

			/* Save the address as source for vrrp packets */
			if (vrrp->saddr.ss_family == AF_UNSPEC)
				inet_ip6tosockaddr(&ipaddress.u.sin6_addr, &vrrp->saddr);
			inet_ip6scopeid(vrrp->vmac_ifindex, &vrrp->saddr);
		}
	}

	/* bring it UP ! */
	__set_bit(VRRP_VMAC_UP_BIT, &vrrp->vmac_flags);
	netlink_link_up(vrrp);

#ifndef IFLA_INET6_ADDR_GEN_MODE
	if (vrrp->family == AF_INET6 || vrrp->evip_add_ipv6) {
		/* Delete the automatically created link-local address based on the
		 * MAC address if we weren't able to configure the interface not to
		 * create the address (see above).
		 * This isn't ideal, since the invalid address will exist momentarily,
		 * but is there any better way to do it? probably not otherwise
		 * ADDR_GEN_MODE wouldn't have been added to the kernel. */
		ip_address_t ipaddress;

		memset(&ipaddress, 0, sizeof(ipaddress));

		ipaddress.u.sin6_addr = base_ifp->sin6_addr;
		make_link_local_address(&ipaddress.u.sin6_addr, ll_addr);
		ipaddress.ifa.ifa_family = AF_INET6;
		ipaddress.ifa.ifa_prefixlen = 64;
		ipaddress.ifa.ifa_index = vrrp->vmac_ifindex;

		if (netlink_ipaddress(&ipaddress, IPADDRESS_DEL) != 1)
			log_message(LOG_INFO, "Deleting auto link-local address from vmac failed");
	}
#endif

	return 1;
}