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; }
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; }
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; } } }
/* 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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
/* 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; }
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; }
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; }
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; }