Skip to content

Commit

Permalink
vrrp: Make VMAC IPv6 link local address mirror parent interface
Browse files Browse the repository at this point in the history
If the link local address on the parent interface of a VMAC is
changed, keepalived will now change the link local address of the
VMAC so that it is the same as the parent interface's.

There was also an inconsistency in keepalived's behaviour. If the
parent interface's link local address was deleted, keepalived
generated a link local address for the VMAC based on the MAC address
of the parent interface. However, if when keepalived started the
parent interface didn't have a link local address, then one was not
assigned to the VMAC. keepalived will now generate a link local
address on startup if the parent interface does not have a link local
address.

Signed-off-by: Quentin Armitage <quentin@armitage.org.uk>
  • Loading branch information
pqarmitage committed Jul 25, 2021
1 parent 5c1ffdd commit 4c7a94a
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 22 deletions.
34 changes: 25 additions & 9 deletions keepalived/core/keepalived_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -1003,20 +1003,31 @@ netlink_if_address_filter(__attribute__((unused)) struct sockaddr_nl *snl, struc
try_up_instance(vrrp, false);
}
#ifdef _HAVE_VRRP_VMAC_
/* If IPv6 link local and vmac doesn't have an address, add it to the vmac */
/* If IPv6 link local and vmac doesn't have an address or we have
* created one ourselves, add/replace the new address on the vmac */
else if (vrrp->family == AF_INET6 &&
vrrp->ifp &&
ifp == vrrp->ifp->base_ifp &&
IS_MAC_IP_VLAN(vrrp->ifp) &&
!__test_bit(VRRP_VMAC_XMITBASE_BIT, &vrrp->vmac_flags) &&
vrrp->num_script_if_fault &&
vrrp->family == ifa->ifa_family &&
vrrp->saddr.ss_family == AF_UNSPEC &&
(!vrrp->saddr_from_config || is_tracking_saddr)) {
if (add_link_local_address(vrrp->ifp, addr.in6)) {
ifa->ifa_family == AF_INET6 &&
vrrp->ifp->is_ours) {
inet_ip6tosockaddr(addr.in6, &vrrp->saddr);
try_up_instance(vrrp, false);
}
#if 0
if (IN6_IS_ADDR_UNSPECIFIED(&vrrp->ifp->sin6_addr)) {
/* This should never happen with the current code since we always
* create a link local address on the VMAC interface.
* However, if in future it is decided not to automatically create
* a link local address on the VMAC interface if the parent interface
* does not have one, then we will need the following code
*/
if (add_link_local_address(vrrp->ifp, addr.in6) &&
vrrp->num_script_if_fault &&
(!vrrp->saddr_from_config || is_tracking_saddr))
try_up_instance(vrrp, false);
} else
#endif
reset_link_local_address(&vrrp->ifp->sin6_addr, vrrp);
}
#endif
}
Expand Down Expand Up @@ -1063,11 +1074,16 @@ netlink_if_address_filter(__attribute__((unused)) struct sockaddr_nl *snl, struc

list_for_each_entry(top, &ifp->tracking_vrrp, e_list) {
vrrp = top->obj.vrrp;
if (vrrp->ifp != ifp)
if (vrrp->ifp != ifp && ifp != vrrp->ifp->base_ifp)
continue;
if (vrrp->family != AF_INET6 || vrrp->saddr_from_config)
continue;
inet_ip6tosockaddr(&ifp->sin6_addr, &vrrp->saddr);
#ifdef _HAVE_VRRP_VMAC_
/* If vrrp->ifp is one of our VMACs, change its address */
if (ifp == vrrp->ifp->base_ifp && vrrp->ifp->is_ours)
reset_link_local_address(addr.in6, vrrp);
#endif
}
}
} else {
Expand Down
1 change: 1 addition & 0 deletions keepalived/include/vrrp_vmac.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ extern u_char ll_addr[ETH_ALEN];
extern bool add_link_local_address(interface_t *, struct in6_addr*);
extern bool del_link_local_address(interface_t *);
extern bool replace_link_local_address(interface_t *);
extern bool reset_link_local_address(struct in6_addr*, vrrp_t *);
#if !HAVE_DECL_IFLA_INET6_ADDR_GEN_MODE
extern void remove_vmac_auto_gen_addr(interface_t *, struct in6_addr *);
#endif
Expand Down
42 changes: 29 additions & 13 deletions keepalived/vrrp/vrrp_vmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,24 +117,16 @@ del_link_local_address(interface_t *ifp)
return true;
}

bool
replace_link_local_address(interface_t *ifp)
static bool
change_link_local_address(interface_t *ifp, struct in6_addr *old_addr, struct in6_addr *new_addr)
{
ip_address_t ipaddress;
struct in6_addr ipaddress_new;

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

/* Create a new address */
make_link_local_address(&ipaddress_new, ifp->base_ifp->hw_addr);

/* There is no point in replacing the address with the same address */
if (inaddr_equal(AF_INET6, &ipaddress_new, &ifp->sin6_addr))
return true;

/* Delete the old address */
ipaddress.ifp = ifp;
ipaddress.u.sin6_addr = ifp->sin6_addr;
ipaddress.u.sin6_addr = *old_addr;

ipaddress.ifa.ifa_family = AF_INET6;
ipaddress.ifa.ifa_prefixlen = 64;
Expand All @@ -145,20 +137,44 @@ replace_link_local_address(interface_t *ifp)
else
CLEAR_IP6_ADDR(&ifp->sin6_addr);

ipaddress.u.sin6_addr = ipaddress_new;
ipaddress.u.sin6_addr = *new_addr;
if (netlink_ipaddress(&ipaddress, IPADDRESS_ADD) != 1) {
log_message(LOG_INFO, "Adding link-local address to vmac failed");
CLEAR_IP6_ADDR(&ifp->sin6_addr);

return false;
}

return true;
}

bool
replace_link_local_address(interface_t *ifp)
{
struct in6_addr ipaddress_new;

/* Create a new address */
make_link_local_address(&ipaddress_new, ifp->base_ifp->hw_addr);

/* There is no point in replacing the address with the same address */
if (inaddr_equal(AF_INET6, &ipaddress_new, &ifp->sin6_addr))
return true;

if (!change_link_local_address(ifp, &ifp->sin6_addr, &ipaddress_new))
return false;

/* Save the new address */
ifp->sin6_addr = ipaddress.u.sin6_addr;
ifp->sin6_addr = ipaddress_new;

return true;
}

bool
reset_link_local_address(struct in6_addr *old_addr, vrrp_t *vrrp)
{
return change_link_local_address(vrrp->ifp, old_addr, &PTR_CAST(struct sockaddr_in6, &vrrp->saddr)->sin6_addr);
}

#if !HAVE_DECL_IFLA_INET6_ADDR_GEN_MODE
void
remove_vmac_auto_gen_addr(interface_t *ifp, struct in6_addr *addr)
Expand Down

0 comments on commit 4c7a94a

Please sign in to comment.