diff --git a/keepalived/core/keepalived_netlink.c b/keepalived/core/keepalived_netlink.c index 1bde1e63ae..251b353d93 100644 --- a/keepalived/core/keepalived_netlink.c +++ b/keepalived/core/keepalived_netlink.c @@ -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; } diff --git a/keepalived/vrrp/vrrp.c b/keepalived/vrrp/vrrp.c index 9448b38a26..e0891a6691 100644 --- a/keepalived/vrrp/vrrp.c +++ b/keepalived/vrrp/vrrp.c @@ -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); @@ -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 @@ -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 diff --git a/keepalived/vrrp/vrrp_vmac.c b/keepalived/vrrp/vrrp_vmac.c index 546ebf0f59..86ff25d1ad 100644 --- a/keepalived/vrrp/vrrp_vmac.c +++ b/keepalived/vrrp/vrrp_vmac.c @@ -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; @@ -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 @@ -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_ diff --git a/test/mk_if b/test/mk_if index 2ddbaf6fd6..6b7536d097 100755 --- a/test/mk_if +++ b/test/mk_if @@ -15,6 +15,8 @@ BR_NAME=br CHAINS= DEFAULT_CHAINS="TESTIN TESTOUT" SCRIPT= +FIXED_LEN=0 +NUM_LEN= CMD=add LOW=0 @@ -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) @@ -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 @@ -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 ;; @@ -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 @@ -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 @@ -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 @@ -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