diff options
author | Quentin Young <qlyoung@cumulusnetworks.com> | 2019-03-14 16:18:20 +0100 |
---|---|---|
committer | Quentin Young <qlyoung@cumulusnetworks.com> | 2019-05-17 02:27:08 +0200 |
commit | 958b1487639ea67a5c2acefe8ac79fd118c9dba5 (patch) | |
tree | 2fda6a08ff54b02fa2888f51156538edcda1cb65 /vrrpd | |
parent | vrrpd: fix v2 master_down_interval computation (diff) | |
download | frr-958b1487639ea67a5c2acefe8ac79fd118c9dba5.tar.xz frr-958b1487639ea67a5c2acefe8ac79fd118c9dba5.zip |
vrrpd: late bind to Tx address
Stupid stupid stupid. I can just bind to the Tx address right before I
Tx, since if I've gotten there I know my link is up.
Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
Diffstat (limited to 'vrrpd')
-rw-r--r-- | vrrpd/vrrp.c | 179 |
1 files changed, 94 insertions, 85 deletions
diff --git a/vrrpd/vrrp.c b/vrrpd/vrrp.c index 4ab660591..3ffa2fbf6 100644 --- a/vrrpd/vrrp.c +++ b/vrrpd/vrrp.c @@ -624,6 +624,92 @@ static int vrrp_adver_timer_expire(struct thread *thread); static int vrrp_master_down_timer_expire(struct thread *thread); /* + * Finds the first connected address of the appropriate family on a VRRP + * router's interface and binds the Tx socket of the VRRP router to that + * address. + * + * Also sets src field of vrrp_router. + * + * r + * VRRP router to operate on + * + * Returns: + * 0 on success + * -1 on failure + */ +static int vrrp_bind_to_primary_connected(struct vrrp_router *r) +{ + char ipstr[INET6_ADDRSTRLEN]; + struct interface *ifp; + + /* + * A slight quirk: the RFC specifies that advertisements under IPv6 must + * be transmitted using the link local address of the source interface + */ + ifp = r->family == AF_INET ? r->vr->ifp : r->mvl_ifp; + + struct listnode *ln; + struct connected *c = NULL; + for (ALL_LIST_ELEMENTS_RO(ifp->connected, ln, c)) + if (c->address->family == r->family) { + if (r->family == AF_INET6 + && IN6_IS_ADDR_LINKLOCAL(&c->address->u.prefix6)) + break; + else if (r->family == AF_INET) + break; + } + + if (c == NULL) { + zlog_err(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM + "Failed to find address to bind on %s", + r->vr->vrid, family2str(r->family), ifp->name); + return -1; + } + + union sockunion su; + memset(&su, 0x00, sizeof(su)); + + switch (r->family) { + case AF_INET: + r->src.ipa_type = IPADDR_V4; + r->src.ipaddr_v4 = c->address->u.prefix4; + su.sin.sin_family = AF_INET; + su.sin.sin_addr = c->address->u.prefix4; + break; + case AF_INET6: + r->src.ipa_type = IPADDR_V6; + r->src.ipaddr_v6 = c->address->u.prefix6; + su.sin6.sin6_family = AF_INET6; + su.sin6.sin6_scope_id = ifp->ifindex; + su.sin6.sin6_addr = c->address->u.prefix6; + break; + } + + sockopt_reuseaddr(r->sock_tx); + if (bind(r->sock_tx, (const struct sockaddr *)&su, sizeof(su)) < 0) { + zlog_err( + VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM + "Failed to bind Tx socket to primary IP address %s: %s", + r->vr->vrid, family2str(r->family), + inet_ntop(r->family, + (const void *)&c->address->u.prefix, ipstr, + sizeof(ipstr)), + safe_strerror(errno)); + return -1; + } else { + DEBUGD(&vrrp_dbg_sock, + VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM + "Bound Tx socket to primary IP address %s", + r->vr->vrid, family2str(r->family), + inet_ntop(r->family, (const void *)&c->address->u.prefix, + ipstr, sizeof(ipstr))); + } + + return 0; +} + + +/* * Create and multicast a VRRP ADVERTISEMENT message. * * r @@ -636,6 +722,10 @@ static void vrrp_send_advertisement(struct vrrp_router *r) struct ipaddr *addrs[r->addrs->count]; union sockunion dest; + if (r->src.ipa_type == IPADDR_NONE + && vrrp_bind_to_primary_connected(r) < 0) + return; + list_to_array(r->addrs, (void **)addrs, r->addrs->count); pktsz = vrrp_pkt_adver_build(&pkt, &r->src, r->vr->version, r->vr->vrid, @@ -904,91 +994,6 @@ done: } /* - * Finds the first connected address of the appropriate family on a VRRP - * router's interface and binds the Tx socket of the VRRP router to that - * address. - * - * Also sets src field of vrrp_router. - * - * r - * VRRP router to operate on - * - * Returns: - * 0 on success - * -1 on failure - */ -static int vrrp_bind_to_primary_connected(struct vrrp_router *r) -{ - char ipstr[INET6_ADDRSTRLEN]; - struct interface *ifp; - - /* - * A slight quirk: the RFC specifies that advertisements under IPv6 must - * be transmitted using the link local address of the source interface - */ - ifp = r->family == AF_INET ? r->vr->ifp : r->mvl_ifp; - - struct listnode *ln; - struct connected *c = NULL; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, ln, c)) - if (c->address->family == r->family) { - if (r->family == AF_INET6 - && IN6_IS_ADDR_LINKLOCAL(&c->address->u.prefix6)) - break; - else if (r->family == AF_INET) - break; - } - - if (c == NULL) { - zlog_err(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM - "Failed to find address to bind on %s", - r->vr->vrid, family2str(r->family), ifp->name); - return -1; - } - - union sockunion su; - memset(&su, 0x00, sizeof(su)); - - switch (r->family) { - case AF_INET: - r->src.ipa_type = IPADDR_V4; - r->src.ipaddr_v4 = c->address->u.prefix4; - su.sin.sin_family = AF_INET; - su.sin.sin_addr = c->address->u.prefix4; - break; - case AF_INET6: - r->src.ipa_type = IPADDR_V6; - r->src.ipaddr_v6 = c->address->u.prefix6; - su.sin6.sin6_family = AF_INET6; - su.sin6.sin6_scope_id = ifp->ifindex; - su.sin6.sin6_addr = c->address->u.prefix6; - break; - } - - sockopt_reuseaddr(r->sock_tx); - if (bind(r->sock_tx, (const struct sockaddr *)&su, sizeof(su)) < 0) { - zlog_err( - VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM - "Failed to bind Tx socket to primary IP address %s: %s", - r->vr->vrid, family2str(r->family), - inet_ntop(r->family, - (const void *)&c->address->u.prefix, ipstr, - sizeof(ipstr)), - safe_strerror(errno)); - return -1; - } else { - DEBUGD(&vrrp_dbg_sock, - VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM - "Bound Tx socket to primary IP address %s", - r->vr->vrid, family2str(r->family), - inet_ntop(r->family, (const void *)&c->address->u.prefix, - ipstr, sizeof(ipstr))); - } - - return 0; -} - -/* * Creates and configures VRRP router sockets. * * This function: @@ -1328,6 +1333,7 @@ static void vrrp_change_state_backup(struct vrrp_router *r) r->advert_pending = false; r->garp_pending = false; r->ndisc_pending = false; + memset(&r->src, 0x00, sizeof(r->src)); vrrp_zclient_send_interface_protodown(r->mvl_ifp, true); } @@ -1560,6 +1566,9 @@ static int vrrp_shutdown(struct vrrp_router *r) /* Protodown macvlan */ vrrp_zclient_send_interface_protodown(r->mvl_ifp, true); + /* Throw away our source address */ + memset(&r->src, 0x00, sizeof(r->src)); + if (r->sock_rx > 0) { close(r->sock_rx); r->sock_rx = -1; |