Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle failure to add IPv6 link-local addres to a VMAC #2353

Merged
merged 3 commits into from
Oct 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions keepalived/core/keepalived_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -1184,6 +1184,14 @@ netlink_if_address_filter(__attribute__((unused)) struct sockaddr_nl *snl, struc
IF_ISUP(ifp)) &&
#endif
(!__test_bit(VRRP_FLAG_SADDR_FROM_CONFIG, &vrrp->flags) || is_tracking_saddr)) {
/* Don't attempt to send an IPv6 advert if no address on the interface */
if (vrrp->saddr.ss_family == AF_INET6
#ifdef _HAVE_VRRP_VMAC_
&& !__test_bit(VRRP_VMAC_XMITBASE_BIT, &vrrp->flags)
#endif
)
vrrp->saddr.ss_family = AF_UNSPEC;

down_instance(vrrp);
vrrp->saddr.ss_family = AF_UNSPEC;
}
Expand Down
15 changes: 11 additions & 4 deletions keepalived/vrrp/vrrp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1814,7 +1814,10 @@ vrrp_state_leave_master(vrrp_t * vrrp, bool advF)
}
else if (vrrp->wantstate == VRRP_STATE_FAULT) {
log_message(LOG_INFO, "(%s) Entering FAULT STATE", vrrp->iname);
vrrp_send_adv(vrrp, VRRP_PRIO_STOP);

/* If there is no address on the interface we cannot sent an IPv6 advert */
if (vrrp->family == AF_INET || vrrp->saddr.ss_family != AF_UNSPEC)
vrrp_send_adv(vrrp, VRRP_PRIO_STOP);
}
else {
log_message(LOG_INFO, "(%s) vrrp_state_leave_master called with invalid wantstate %d", vrrp->iname, vrrp->wantstate);
Expand Down Expand Up @@ -4292,8 +4295,7 @@ set_vrrp_src_addr(void)
if (vrrp->family == AF_INET) {
if (!(VRRP_CONFIGURED_IFP(vrrp))->sin_addr.s_addr)
addr_missing = true;
}
else {
} else {
#ifdef _HAVE_VRRP_VMAC_
if (!__test_bit(VRRP_VMAC_BIT, &vrrp->flags))
#endif
Expand All @@ -4311,8 +4313,13 @@ set_vrrp_src_addr(void)
else if (vrrp->family == AF_INET)
inet_ip4tosockaddr(&VRRP_CONFIGURED_IFP(vrrp)->sin_addr, &vrrp->saddr);
else if (vrrp->family == AF_INET6) {
#ifdef _HAVE_VRRP_VMAC_
if (!__test_bit(VRRP_VMAC_XMITBASE_BIT, &vrrp->flags) &&
(
#ifdef _HAVE_VRRP_IPVLAN_
if (__test_bit(VRRP_IPVLAN_BIT, &vrrp->flags)) {
__test_bit(VRRP_IPVLAN_BIT, &vrrp->flags) ||
#endif
__test_bit(VRRP_VMAC_BIT, &vrrp->flags))) {
if (!IN6_IS_ADDR_UNSPECIFIED(&vrrp->ifp->sin6_addr))
inet_ip6tosockaddr(&vrrp->ifp->sin6_addr, &vrrp->saddr);
} else
Expand Down
7 changes: 5 additions & 2 deletions keepalived/vrrp/vrrp_vmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ netlink_link_add_vmac(vrrp_t *vrrp, const interface_t *old_interface)
} req;
u_char if_ll_addr[ETH_ALEN];
bool update_interface = false;
bool ret = true;

if (!vrrp->ifp || __test_bit(VRRP_VMAC_UP_BIT, &vrrp->flags) || !vrrp->vrid)
return false;
Expand Down Expand Up @@ -495,8 +496,10 @@ netlink_link_add_vmac(vrrp_t *vrrp, const interface_t *old_interface)

if (vrrp->family == AF_INET6 &&
!__test_bit(VRRP_VMAC_XMITBASE_BIT, &vrrp->flags)) {
if (!set_link_local_address(vrrp) && create_interface)
if (!set_link_local_address(vrrp) && create_interface) {
log_message(LOG_INFO, "(%s) adding link-local address to %s failed", vrrp->iname, vrrp->ifp->ifname);
ret = false;
}
}

/* If the base interface does not implement IFF_UNICAST_FLT, for example
Expand Down Expand Up @@ -543,7 +546,7 @@ netlink_link_add_vmac(vrrp_t *vrrp, const interface_t *old_interface)
* as we progress */
kernel_netlink_poll();

return true;
return ret;
}

#ifdef _INCLUDE_UNUSED_CODE_
Expand Down
65 changes: 47 additions & 18 deletions test/mk_if
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ BR_NAME=br
CHAINS=
DEFAULT_CHAINS="TESTIN TESTOUT"
SCRIPT=
FIXED_LEN=0
NUM_LEN=

CMD=add
LOW=0
Expand All @@ -33,6 +35,7 @@ $0 - Usage: $0 CMD [OPTIONS]
-h Show this!
-f NUM First interface number
-l NUM Last interface number
-p fixed interface name lenths
-n "NS NS .." List of namespaces (default: high medium low default)
-b NS Specify namespace for bridge (default: medium)
-r NS Specify root namespace (default: default)
Expand All @@ -50,7 +53,7 @@ $0 - Usage: $0 CMD [OPTIONS]
EOF
}

while getopts ":hf:l:n:b:r:N:eb:r:Rc:i:4:6:q:Q:I:s:" opt; do
while getopts ":hf:l:n:pb:r:N:eb:r:Rc:i:4:6:q:Q:I:s:" opt; do
case $opt in
h)
show_help
Expand All @@ -65,6 +68,9 @@ while getopts ":hf:l:n:b:r:N:eb:r:Rc:i:4:6:q:Q:I:s:" opt; do
l)
HIGH=$OPTARG
;;
p)
FIXED_LEN=1
;;
n)
NS_LIST=$OPTARG
;;
Expand Down Expand Up @@ -120,6 +126,17 @@ done

CMD=${!OPTIND}

# Work out number length of interface names
if [[ $FIXED_LEN -eq 1 ]]; then
NUM_LEN=1
LAST=$HIGH
while [[ $(( LAST /= 10 )) -gt 0 ]]; do
: $((NUM_LEN++))
done
fi

[[ $IF_NAME != eth ]] && BR_NAME=br${IF_NAME:2}

# Check if system is using iptables or nftables
USE_IPTABLES=1
type -f iptables >/dev/null
Expand Down Expand Up @@ -156,9 +173,13 @@ fi
if [[ $CMD = add ]]; then
for n in $NS_LIST; do
[[ .$n = .$ROOT_NS ]] && continue
ip netns | grep $n >/dev/null 2>/dev/null
[[ $? -eq 0 ]] && continue

$ECHO unshare -n ip netns add $n
$ECHO ip netns exec $n ip link set up lo

NEW_NS+=" $n"
done
fi

Expand All @@ -176,12 +197,20 @@ if [[ $USE_IPTABLES -eq 1 ]]; then
fi

for n in $(seq $LOW $HIGH); do
if [[ -n $NUM_LEN ]]; then
IF=${IF_NAME}$(printf "%${NUM_LEN}.${NUM_LEN}d" $n)
BR=${BR_NAME}$(printf "%${NUM_LEN}.${NUM_LEN}d" $n)
else
IF=${IF_NAME}$n
BR=${BR_NAME}$n
fi

if [[ $CMD = add || $CMD = remake ]]; then
if [[ $CMD = add ]]; then
$ECHO ip netns exec $BRIDGE_NS ip link add ${BR_NAME}${n} type bridge
$ECHO ip netns exec $BRIDGE_NS ip link set ${BR_NAME}${n} up
$ECHO ip netns exec $BRIDGE_NS ip addr add ${IP_BASE_ADDR}.${n}.${ip[medium]}/24 broadcast + dev ${BR_NAME}${n}
$ECHO ip netns exec $BRIDGE_NS ip addr add ${IP6_BASE_ADDR}:$((100 + $n))::${ip[medium]}/64 dev ${BR_NAME}${n}
$ECHO ip netns exec $BRIDGE_NS ip link add ${BR} type bridge
$ECHO ip netns exec $BRIDGE_NS ip link set ${BR} up
$ECHO ip netns exec $BRIDGE_NS ip addr add ${IP_BASE_ADDR}.${n}.${ip[medium]}/24 broadcast + dev ${BR}
$ECHO ip netns exec $BRIDGE_NS ip addr add ${IP6_BASE_ADDR}:$((100 + $n))::${ip[medium]}/64 dev ${BR}
NS=$NS_LIST
else
NS=$SIDE
Expand All @@ -190,29 +219,29 @@ for n in $(seq $LOW $HIGH); do
for p in $NS; do
[[ $p = $BRIDGE_NS ]] && continue

$ECHO ip netns exec $BRIDGE_NS ip link add ${IF_NAME}${n}.$p type veth peer name ${IF_NAME}${n}
$ECHO ip netns exec $BRIDGE_NS ip link set ${IF_NAME}${n}.$p master ${BR_NAME}${n}
$ECHO ip netns exec $BRIDGE_NS ip link set ${IF_NAME}${n}.$p up
$ECHO ip netns exec $BRIDGE_NS ip link add ${IF}.$p type veth peer name ${IF}
$ECHO ip netns exec $BRIDGE_NS ip link set ${IF}.$p master ${BR}
$ECHO ip netns exec $BRIDGE_NS ip link set ${IF}.$p up

$ECHO ip netns exec $BRIDGE_NS ip link set ${IF_NAME}${n} netns ${p/$ROOT_NS/1}
$ECHO ip netns exec $BRIDGE_NS ip link set ${IF} netns ${p/$ROOT_NS/1}

[[ $p = $ROOT_NS ]] && NETNS_CMD= || NETNS_CMD="ip netns exec $p"
$ECHO $NETNS_CMD ip link set ${IF_NAME}${n} up
$ECHO $NETNS_CMD ip addr add ${IP_BASE_ADDR}.${n}.${ip[$p]}/24 broadcast + dev ${IF_NAME}${n}
$ECHO $NETNS_CMD ip addr add ${IP6_BASE_ADDR}:$((100 + $n))::${ip[$p]}/64 dev ${IF_NAME}${n}
$ECHO $NETNS_CMD ip link set ${IF} up
$ECHO $NETNS_CMD ip addr add ${IP_BASE_ADDR}.${n}.${ip[$p]}/24 broadcast + dev ${IF}
$ECHO $NETNS_CMD ip addr add ${IP6_BASE_ADDR}:$((100 + $n))::${ip[$p]}/64 dev ${IF}
done

$ECHO ip netns exec $BRIDGE_NS ip link add ${IF_NAME}${n} type dummy
$ECHO ip netns exec $BRIDGE_NS ip link set ${IF_NAME}${n} master ${BR_NAME}${n}
$ECHO ip netns exec $BRIDGE_NS ip link set up ${IF_NAME}${n}
$ECHO ip netns exec $BRIDGE_NS ip link add ${IF} type dummy
$ECHO ip netns exec $BRIDGE_NS ip link set ${IF} master ${BR}
$ECHO ip netns exec $BRIDGE_NS ip link set up ${IF}
elif [[ $CMD = del ]]; then
for p in $NS_LIST; do
[[ $p = $BRIDGE_NS ]] && continue

$ECHO ip netns exec $BRIDGE_NS ip link del ${IF_NAME}${n}.$p
$ECHO ip netns exec $BRIDGE_NS ip link del ${IF}.$p
done
$ECHO ip netns exec $BRIDGE_NS ip link del ${IF_NAME}${n}
$ECHO ip netns exec $BRIDGE_NS ip link del ${BR_NAME}${n}
$ECHO ip netns exec $BRIDGE_NS ip link del ${IF}
$ECHO ip netns exec $BRIDGE_NS ip link del ${BR}
else
echo Unknown command $CMD
fi
Expand Down
Loading