]> git.puffer.fish Git - mirror/frr.git/commitdiff
vrrpd: late bind to Tx address
authorQuentin Young <qlyoung@cumulusnetworks.com>
Thu, 14 Mar 2019 15:18:20 +0000 (15:18 +0000)
committerQuentin Young <qlyoung@cumulusnetworks.com>
Fri, 17 May 2019 00:27:08 +0000 (00:27 +0000)
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>
vrrpd/vrrp.c

index 4ab660591806760d8ed4f42b979f1e225cde4d75..3ffa2fbf681e4711098c300e2a78a725b4fdb505 100644 (file)
@@ -623,6 +623,92 @@ static void vrrp_change_state(struct vrrp_router *r, int to);
 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.
  *
@@ -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,
@@ -903,91 +993,6 @@ done:
        return 0;
 }
 
-/*
- * 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.
  *
@@ -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;