]> git.puffer.fish Git - mirror/frr.git/commitdiff
vrrpd: interface tracking
authorQuentin Young <qlyoung@cumulusnetworks.com>
Thu, 14 Feb 2019 22:28:51 +0000 (22:28 +0000)
committerQuentin Young <qlyoung@cumulusnetworks.com>
Fri, 17 May 2019 00:27:08 +0000 (00:27 +0000)
* Dynamically bind interfaces when they become available
* Automatically start VRRP sessions when their interfaces are added or
  come up
* Automatically shut down VRRP sessions when their interfaces are
  deleted or go down
* Automatically unbind interfaces when they are deleted

Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
vrrpd/vrrp.c
vrrpd/vrrp.h
vrrpd/vrrp_vty.c
vrrpd/vrrp_zebra.c

index bb24bc9510f03b7e06054ca60a783daf0048cbfc..bf4f0f1ec90a7441376a935f0e822728a99103ae 100644 (file)
@@ -128,8 +128,146 @@ static bool vrrp_is_owner(struct interface *ifp, struct ipaddr *addr)
        return !!connected_lookup_prefix_exact(ifp, &p);
 }
 
+/*
+ * Whether an interface has a MAC address that matches the VRRP RFC.
+ *
+ * ifp
+ *    Interface to check
+ *
+ * Returns:
+ *    Whether the interface has a VRRP mac or not
+ */
+static bool vrrp_ifp_has_vrrp_mac(struct interface *ifp)
+{
+       struct ethaddr vmac4;
+       struct ethaddr vmac6;
+       vrrp_mac_set(&vmac4, 0, 0x00);
+       vrrp_mac_set(&vmac6, 1, 0x00);
+
+       return !memcmp(ifp->hw_addr, vmac4.octet, sizeof(vmac4.octet) - 1)
+              || !memcmp(ifp->hw_addr, vmac6.octet, sizeof(vmac6.octet) - 1);
+}
+
+/*
+ * Lookup a Virtual Router instance given a macvlan subinterface.
+ *
+ * The VRID is extracted from the interface MAC and the 2-tuple (iface, vrid)
+ * is used to look up any existing instances that match the interface. It does
+ * not matter whether the instance is already bound to the interface or not.
+ *
+ * mvl_ifp
+ *    Interface pointer to use to lookup. Should be a macvlan device.
+ *
+ * Returns:
+ *    Virtual Router, if found
+ *    NULL otherwise
+ */
+static struct vrrp_vrouter *vrrp_lookup_by_if_mvl(struct interface *mvl_ifp)
+{
+       struct interface *p;
+
+       if (!mvl_ifp || !mvl_ifp->link_ifindex
+           || !vrrp_ifp_has_vrrp_mac(mvl_ifp))
+               return NULL;
+
+       p = if_lookup_by_index(mvl_ifp->link_ifindex, VRF_DEFAULT);
+       uint8_t vrid = mvl_ifp->hw_addr[5];
+
+       return vrrp_lookup(p, vrid);
+}
+
+/*
+ * Lookup the Virtual Router instances configured on a particular interface.
+ *
+ * ifp
+ *    Interface pointer to use to lookup. Should not be a macvlan device.
+ *
+ * Returns:
+ *    List of virtual routers found
+ */
+static struct list *vrrp_lookup_by_if(struct interface *ifp)
+{
+       struct list *l = hash_to_list(vrrp_vrouters_hash);
+       struct listnode *ln, *nn;
+       struct vrrp_vrouter *vr;
+
+       for (ALL_LIST_ELEMENTS(l, ln, nn, vr))
+               if (vr->ifp != ifp)
+                       list_delete_node(l, ln);
+
+       return l;
+}
+
+/*
+ * Lookup any Virtual Router instances associated with a particular interface.
+ * This is a combination of the results from vrrp_lookup_by_if_mvl and
+ * vrrp_lookup_by_if.
+ *
+ * Suppose the system interface list looks like the following:
+ *
+ * eth0
+ * \- eth0-v0 00:00:5e:00:01:01
+ * \- eth0-v1 00:00:5e:00:02:01
+ * \- eth0-v2 00:00:5e:00:01:0a
+ *
+ * Passing eth0-v2 to this function will give you the VRRP instance configured
+ * on eth0 with VRID 10. Passing eth0-v0 or eth0-v1 will give you the VRRP
+ * instance configured on eth0 with VRID 1. Passing eth0 will give you both.
+ *
+ * ifp
+ *    Interface pointer to use to lookup. Can be any interface.
+ *
+ * Returns:
+ *    List of virtual routers found
+ */
+static struct list *vrrp_lookup_by_if_any(struct interface *ifp)
+{
+       struct vrrp_vrouter *vr;
+       struct list *vrs;
+
+       vr = vrrp_lookup_by_if_mvl(ifp);
+       vrs = vr ? list_new() : vrrp_lookup_by_if(ifp);
+
+       if (vr)
+               listnode_add(vrs, vr);
+
+       return vrs;
+}
+
 /* Configuration controllers ----------------------------------------------- */
 
+void vrrp_check_start(struct vrrp_vrouter *vr)
+{
+       struct vrrp_router *r;
+       bool start;
+
+       if (vr->shutdown || vr->ifp == NULL)
+               return;
+
+       r = vr->v4;
+       start = r->fsm.state == VRRP_STATE_INITIALIZE;
+       start = start && (vr->ifp != NULL);
+       start = start && (CHECK_FLAG(vr->ifp->flags, IFF_UP));
+       start = start && vr->ifp->connected->count > 0;
+       start = start && (r->mvl_ifp != NULL);
+       start = start && (CHECK_FLAG(r->mvl_ifp->flags, IFF_UP));
+       start = start && r->addrs->count > 0;
+       if (start)
+               vrrp_event(r, VRRP_EVENT_STARTUP);
+
+       r = vr->v6;
+       start = r->fsm.state == VRRP_STATE_INITIALIZE;
+       start = start && (vr->ifp != NULL);
+       start = start && (CHECK_FLAG(vr->ifp->flags, IFF_UP));
+       start = start && vr->ifp->connected->count;
+       start = start && (r->mvl_ifp != NULL);
+       start = start && (CHECK_FLAG(r->mvl_ifp->flags, IFF_UP));
+       start = start && (r->mvl_ifp->connected->count > 0);
+       start = start && r->addrs->count > 0;
+       if (start)
+               vrrp_event(r, VRRP_EVENT_STARTUP);
+}
+
 void vrrp_set_priority(struct vrrp_vrouter *vr, uint8_t priority)
 {
        vr->priority = priority;
@@ -161,7 +299,7 @@ static bool vrrp_has_ip(struct vrrp_vrouter *vr, struct ipaddr *ip)
        return false;
 }
 
-int vrrp_add_ip(struct vrrp_router *r, struct ipaddr *ip, bool activate)
+int vrrp_add_ip(struct vrrp_router *r, struct ipaddr *ip)
 {
        int af = (ip->ipa_type == IPADDR_V6) ? AF_INET6 : AF_INET;
 
@@ -185,15 +323,7 @@ int vrrp_add_ip(struct vrrp_router *r, struct ipaddr *ip, bool activate)
        *new = *ip;
        listnode_add(r->addrs, new);
 
-       bool do_activate = (activate && r->fsm.state == VRRP_STATE_INITIALIZE);
-       int ret = 0;
-
-       if (do_activate) {
-               ret = vrrp_event(r, VRRP_EVENT_STARTUP);
-               if (ret)
-                       listnode_delete(r->addrs, new);
-       }
-       else if (r->fsm.state == VRRP_STATE_MASTER) {
+       if (r->fsm.state == VRRP_STATE_MASTER) {
                switch (r->family) {
                case AF_INET:
                        vrrp_garp_send(r, &new->ipaddr_v4);
@@ -204,26 +334,26 @@ int vrrp_add_ip(struct vrrp_router *r, struct ipaddr *ip, bool activate)
                }
        }
 
-       return ret;
+       return 0;
 }
 
-int vrrp_add_ipv4(struct vrrp_vrouter *vr, struct in_addr v4, bool activate)
+int vrrp_add_ipv4(struct vrrp_vrouter *vr, struct in_addr v4)
 {
        struct ipaddr ip;
        ip.ipa_type = IPADDR_V4;
        ip.ipaddr_v4 = v4;
-       return vrrp_add_ip(vr->v4, &ip, activate);
+       return vrrp_add_ip(vr->v4, &ip);
 }
 
-int vrrp_add_ipv6(struct vrrp_vrouter *vr, struct in6_addr v6, bool activate)
+int vrrp_add_ipv6(struct vrrp_vrouter *vr, struct in6_addr v6)
 {
        struct ipaddr ip;
        ip.ipa_type = IPADDR_V6;
        ip.ipaddr_v6 = v6;
-       return vrrp_add_ip(vr->v6, &ip, activate);
+       return vrrp_add_ip(vr->v6, &ip);
 }
 
-int vrrp_del_ip(struct vrrp_router *r, struct ipaddr *ip, bool deactivate)
+int vrrp_del_ip(struct vrrp_router *r, struct ipaddr *ip)
 {
        struct listnode *ln, *nn;
        struct ipaddr *iter;
@@ -232,37 +362,36 @@ int vrrp_del_ip(struct vrrp_router *r, struct ipaddr *ip, bool deactivate)
        if (!vrrp_has_ip(r->vr, ip))
                return 0;
 
-       if (deactivate && r->addrs->count == 1
-           && r->fsm.state != VRRP_STATE_INITIALIZE)
-               ret = vrrp_event(r, VRRP_EVENT_SHUTDOWN);
+       for (ALL_LIST_ELEMENTS(r->addrs, ln, nn, iter))
+               if (!memcmp(&iter->ip, &ip->ip, IPADDRSZ(ip)))
+                       list_delete_node(r->addrs, ln);
 
        /*
-        * Don't delete IP if we failed to deactivate, otherwise we'll run into
-        * issues later trying to build a VRRP advertisement with no IPs
+        * NB: Deleting the last address and then issuing a shutdown will cause
+        * transmission of a priority 0 VRRP Advertisement - as per the RFC -
+        * but it will have no addresses. This is not forbidden in the RFC but
+        * might confuse other implementations.
         */
-       if (ret == 0) {
-               for (ALL_LIST_ELEMENTS(r->addrs, ln, nn, iter))
-                       if (!memcmp(&iter->ip, &ip->ip, IPADDRSZ(ip)))
-                               list_delete_node(r->addrs, ln);
-       }
+       if (r->addrs->count == 0 && r->fsm.state != VRRP_STATE_INITIALIZE)
+               ret = vrrp_event(r, VRRP_EVENT_SHUTDOWN);
 
        return ret;
 }
 
-int vrrp_del_ipv6(struct vrrp_vrouter *vr, struct in6_addr v6, bool deactivate)
+int vrrp_del_ipv6(struct vrrp_vrouter *vr, struct in6_addr v6)
 {
        struct ipaddr ip;
        ip.ipa_type = IPADDR_V6;
        ip.ipaddr_v6 = v6;
-       return vrrp_del_ip(vr->v6, &ip, deactivate);
+       return vrrp_del_ip(vr->v6, &ip);
 }
 
-int vrrp_del_ipv4(struct vrrp_vrouter *vr, struct in_addr v4, bool deactivate)
+int vrrp_del_ipv4(struct vrrp_vrouter *vr, struct in_addr v4)
 {
        struct ipaddr ip;
        ip.ipa_type = IPADDR_V4;
        ip.ipaddr_v4 = v4;
-       return vrrp_del_ip(vr->v4, &ip, deactivate);
+       return vrrp_del_ip(vr->v4, &ip);
 }
 
 
@@ -1363,7 +1492,7 @@ static void vrrp_autoconfig_autoaddrupdate(struct vrrp_vrouter *vr)
                                DEBUGD(&vrrp_dbg_auto,
                                       VRRP_LOGPFX VRRP_LOGPFX_VRID "Adding %s",
                                       vr->vrid, ipbuf);
-                               vrrp_add_ipv4(vr, c->address->u.prefix4, true);
+                               vrrp_add_ipv4(vr, c->address->u.prefix4);
                        }
        }
 
@@ -1380,10 +1509,12 @@ static void vrrp_autoconfig_autoaddrupdate(struct vrrp_vrouter *vr)
                                DEBUGD(&vrrp_dbg_auto,
                                       VRRP_LOGPFX VRRP_LOGPFX_VRID "Adding %s",
                                       vr->vrid, ipbuf);
-                               vrrp_add_ipv6(vr, c->address->u.prefix6, true);
+                               vrrp_add_ipv6(vr, c->address->u.prefix6);
                        }
        }
 
+       vrrp_check_start(vr);
+
        if (vr->v4->addrs->count == 0
            && vr->v4->fsm.state != VRRP_STATE_INITIALIZE) {
                DEBUGD(&vrrp_dbg_auto,
@@ -1436,32 +1567,21 @@ vrrp_autoconfig_autocreate(struct interface *mvl_ifp)
        return vr;
 }
 
-static bool vrrp_ifp_has_vrrp_mac(struct interface *ifp)
-{
-       struct ethaddr vmac4;
-       struct ethaddr vmac6;
-       vrrp_mac_set(&vmac4, 0, 0x00);
-       vrrp_mac_set(&vmac6, 1, 0x00);
-
-       return !memcmp(ifp->hw_addr, vmac4.octet, sizeof(vmac4.octet) - 1)
-              || !memcmp(ifp->hw_addr, vmac6.octet, sizeof(vmac6.octet) - 1);
-}
-
-static struct vrrp_vrouter *vrrp_lookup_by_mvlif(struct interface *mvl_ifp)
-{
-       struct interface *p;
-
-       if (!mvl_ifp || !mvl_ifp->link_ifindex
-           || !vrrp_ifp_has_vrrp_mac(mvl_ifp))
-               return NULL;
-
-       p = if_lookup_by_index(mvl_ifp->link_ifindex, VRF_DEFAULT);
-       uint8_t vrid = mvl_ifp->hw_addr[5];
-
-       return vrrp_lookup(p, vrid);
-}
-
-int vrrp_autoconfig_if_add(struct interface *ifp)
+/*
+ * Callback to notify autoconfig of interface add.
+ *
+ * If the interface is a VRRP-compatible device, and there is no existing VRRP
+ * router running on it, one is created. All addresses on the interface are
+ * added to the router.
+ *
+ * ifp
+ *    Interface to operate on
+ *
+ * Returns:
+ *    -1 on failure
+ *     0 otherwise
+ */
+static int vrrp_autoconfig_if_add(struct interface *ifp)
 {
        bool created = false;
        struct vrrp_vrouter *vr;
@@ -1472,7 +1592,7 @@ int vrrp_autoconfig_if_add(struct interface *ifp)
        if (!ifp || !ifp->link_ifindex || !vrrp_ifp_has_vrrp_mac(ifp))
                return -1;
 
-       vr = vrrp_lookup_by_mvlif(ifp);
+       vr = vrrp_lookup_by_if_mvl(ifp);
 
        if (!vr) {
                vr = vrrp_autoconfig_autocreate(ifp);
@@ -1485,66 +1605,73 @@ int vrrp_autoconfig_if_add(struct interface *ifp)
        if (vr->autoconf == false)
                return 0;
        else if (!created) {
-               vrrp_attach_interface(vr->v4);
-               vrrp_attach_interface(vr->v6);
                vrrp_autoconfig_autoaddrupdate(vr);
        }
 
        return 0;
 }
 
-int vrrp_autoconfig_if_del(struct interface *ifp)
+/*
+ * Callback to notify autoconfig of interface delete.
+ *
+ * If the interface is a VRRP-compatible device, and a VRRP router is running
+ * on it, and that VRRP router was automatically configured, it will be
+ * deleted. If that was the last router for the corresponding VRID (i.e., if
+ * this interface was a v4 VRRP interface and no v6 router is configured for
+ * the same VRID) then the entire virtual router is deleted.
+ *
+ * ifp
+ *    Interface to operate on
+ *
+ * Returns:
+ *    -1 on failure
+ *     0 otherwise
+ */
+static int vrrp_autoconfig_if_del(struct interface *ifp)
 {
        if (!vrrp_autoconfig_is_on)
                return 0;
 
-       struct vrrp_vrouter *vr = vrrp_lookup_by_mvlif(ifp);
-
-       if (!vr)
-               return 0;
+       struct vrrp_vrouter *vr;
+       struct listnode *ln;
+       struct list *vrs;
 
-       if (vr && vr->autoconf == false)
-               return 0;
+       vrs = vrrp_lookup_by_if_any(ifp);
 
-       if (vr && vr->v4->mvl_ifp == ifp) {
-               if (vr->v4->fsm.state != VRRP_STATE_INITIALIZE) {
+       for (ALL_LIST_ELEMENTS_RO(vrs, ln, vr))
+               if (vr->autoconf
+                   && (!vr->ifp || (!vr->v4->mvl_ifp && !vr->v6->mvl_ifp))) {
                        DEBUGD(&vrrp_dbg_auto,
                               VRRP_LOGPFX VRRP_LOGPFX_VRID
-                              "Interface %s deleted; shutting down IPv4 VRRP router",
-                              vr->vrid, ifp->name);
-                       vrrp_event(vr->v4, VRRP_EVENT_SHUTDOWN);
-               }
-               vr->v4->mvl_ifp = NULL;
-       }
-       if (vr && vr->v6->mvl_ifp == ifp) {
-               if (vr->v6->fsm.state != VRRP_STATE_INITIALIZE) {
-                       DEBUGD(&vrrp_dbg_auto,
-                              VRRP_LOGPFX VRRP_LOGPFX_VRID
-                              "Interface %s deleted; shutting down IPv6 VRRP router",
-                              vr->vrid, ifp->name);
-                       vrrp_event(vr->v6, VRRP_EVENT_SHUTDOWN);
+                              "All VRRP interfaces for instance deleted; destroying autoconfigured VRRP router",
+                              vr->vrid);
+                       vrrp_vrouter_destroy(vr);
                }
-               vr->v6->mvl_ifp = NULL;
-       }
 
-       if (vr->v4->mvl_ifp == NULL && vr->v6->mvl_ifp == NULL) {
-               DEBUGD(&vrrp_dbg_auto,
-                      VRRP_LOGPFX VRRP_LOGPFX_VRID
-                      "All VRRP interfaces for instance deleted; destroying autoconfigured VRRP router",
-                      vr->vrid);
-               vrrp_vrouter_destroy(vr);
-               vr = NULL;
-       }
+       list_delete(&vrs);
 
        return 0;
 }
 
-int vrrp_autoconfig_if_up(struct interface *ifp)
+/*
+ * Callback to notify autoconfig of interface up.
+ *
+ * Roughly equivalent to vrrp_autoconfig_if_add, except that addresses are
+ * refreshed if an autoconfigured virtual router already exists.
+ *
+ * ifp
+ *    Interface to operate on
+ *
+ * Returns:
+ *    -1 on failure
+ *     0 otherwise
+ */
+static int vrrp_autoconfig_if_up(struct interface *ifp)
 {
        if (!vrrp_autoconfig_is_on)
                return 0;
 
-       struct vrrp_vrouter *vr = vrrp_lookup_by_mvlif(ifp);
+       struct vrrp_vrouter *vr = vrrp_lookup_by_if_mvl(ifp);
 
        if (vr && !vr->autoconf)
                return 0;
@@ -1554,14 +1681,27 @@ int vrrp_autoconfig_if_up(struct interface *ifp)
                return 0;
        }
 
-       vrrp_attach_interface(vr->v4);
-       vrrp_attach_interface(vr->v6);
        vrrp_autoconfig_autoaddrupdate(vr);
 
        return 0;
 }
 
-int vrrp_autoconfig_if_down(struct interface *ifp)
+/*
+ * Callback to notify autoconfig of interface down.
+ *
+ * Does nothing. An interface down event is accompanied by address deletion
+ * events for all the addresses on the interface; if an autoconfigured VRRP
+ * router exists on this interface, then it will have all its addresses deleted
+ * and end up in Initialize.
+ *
+ * ifp
+ *    Interface to operate on
+ *
+ * Returns:
+ *    -1 on failure
+ *     0 otherwise
+ */
+static int vrrp_autoconfig_if_down(struct interface *ifp)
 {
        if (!vrrp_autoconfig_is_on)
                return 0;
@@ -1569,12 +1709,27 @@ int vrrp_autoconfig_if_down(struct interface *ifp)
        return 0;
 }
 
-int vrrp_autoconfig_if_address_add(struct interface *ifp)
+/*
+ * Callback to notify autoconfig of a new interface address.
+ *
+ * If a VRRP router exists on this interface, its address list is updated to
+ * match the new address list. If no addresses remain, a Shutdown event is
+ * issued to the VRRP router.
+ *
+ * ifp
+ *    Interface to operate on
+ *
+ * Returns:
+ *    -1 on failure
+ *     0 otherwise
+ *
+ */
+static int vrrp_autoconfig_if_address_add(struct interface *ifp)
 {
        if (!vrrp_autoconfig_is_on)
                return 0;
 
-       struct vrrp_vrouter *vr = vrrp_lookup_by_mvlif(ifp);
+       struct vrrp_vrouter *vr = vrrp_lookup_by_if_mvl(ifp);
 
        if (vr && vr->autoconf)
                vrrp_autoconfig_autoaddrupdate(vr);
@@ -1582,12 +1737,27 @@ int vrrp_autoconfig_if_address_add(struct interface *ifp)
        return 0;
 }
 
-int vrrp_autoconfig_if_address_del(struct interface *ifp)
+/*
+ * Callback to notify autoconfig of a removed interface address.
+ *
+ * If a VRRP router exists on this interface, its address list is updated to
+ * match the new address list. If no addresses remain, a Shutdown event is
+ * issued to the VRRP router.
+ *
+ * ifp
+ *    Interface to operate on
+ *
+ * Returns:
+ *    -1 on failure
+ *     0 otherwise
+ *
+ */
+static int vrrp_autoconfig_if_address_del(struct interface *ifp)
 {
        if (!vrrp_autoconfig_is_on)
                return 0;
 
-       struct vrrp_vrouter *vr = vrrp_lookup_by_mvlif(ifp);
+       struct vrrp_vrouter *vr = vrrp_lookup_by_if_mvl(ifp);
 
        if (vr && vr->autoconf)
                vrrp_autoconfig_autoaddrupdate(vr);
@@ -1633,6 +1803,142 @@ void vrrp_autoconfig_off(void)
        list_delete(&ll);
 }
 
+/* Interface tracking ------------------------------------------------------ */
+
+/*
+ * Bind any pending interfaces.
+ *
+ * mvl_ifp
+ *    macvlan interface that some VRRP instances might want to bind to
+ */
+static void vrrp_bind_pending(struct interface *mvl_ifp)
+{
+       struct vrrp_vrouter *vr;
+
+       vr = vrrp_lookup_by_if_mvl(mvl_ifp);
+
+       if (vr) {
+               if (mvl_ifp->hw_addr[4] == 0x01 && !vr->v4->mvl_ifp)
+                       vrrp_attach_interface(vr->v4);
+               else if (mvl_ifp->hw_addr[4] == 0x02 && !vr->v6->mvl_ifp)
+                       vrrp_attach_interface(vr->v6);
+       }
+}
+
+void vrrp_if_up(struct interface *ifp)
+{
+       struct vrrp_vrouter *vr;
+       struct listnode *ln;
+       struct list *vrs;
+
+       vrrp_bind_pending(ifp);
+
+       vrs = vrrp_lookup_by_if_any(ifp);
+
+       for (ALL_LIST_ELEMENTS_RO(vrs, ln, vr))
+               vrrp_check_start(vr);
+
+       list_delete(&vrs);
+
+       vrrp_autoconfig_if_up(ifp);
+}
+
+void vrrp_if_down(struct interface *ifp)
+{
+       struct vrrp_vrouter *vr;
+       struct listnode *ln;
+       struct list *vrs;
+
+       vrs = vrrp_lookup_by_if_any(ifp);
+
+       for (ALL_LIST_ELEMENTS_RO(vrs, ln, vr)) {
+               if (vr->v4->mvl_ifp == ifp || vr->ifp == ifp) {
+                       if (vr->v4->fsm.state != VRRP_STATE_INITIALIZE) {
+                               DEBUGD(&vrrp_dbg_auto,
+                                      VRRP_LOGPFX VRRP_LOGPFX_VRID
+                                      "Interface %s down; shutting down IPv4 VRRP router",
+                                      vr->vrid, ifp->name);
+                               vrrp_event(vr->v4, VRRP_EVENT_SHUTDOWN);
+                       }
+               }
+
+               if (vr->v6->mvl_ifp == ifp || vr->ifp == ifp) {
+                       if (vr->v6->fsm.state != VRRP_STATE_INITIALIZE) {
+                               DEBUGD(&vrrp_dbg_auto,
+                                      VRRP_LOGPFX VRRP_LOGPFX_VRID
+                                      "Interface %s down; shutting down IPv6 VRRP router",
+                                      vr->vrid, ifp->name);
+                               vrrp_event(vr->v6, VRRP_EVENT_SHUTDOWN);
+                       }
+               }
+       }
+
+       list_delete(&vrs);
+
+       vrrp_autoconfig_if_down(ifp);
+}
+
+void vrrp_if_add(struct interface *ifp)
+{
+       vrrp_bind_pending(ifp);
+
+       /* thanks, zebra */
+       if (CHECK_FLAG(ifp->flags, IFF_UP))
+               vrrp_if_up(ifp);
+
+       vrrp_autoconfig_if_add(ifp);
+}
+
+void vrrp_if_del(struct interface *ifp)
+{
+       struct listnode *ln;
+       struct vrrp_vrouter *vr;
+       struct list *vrs = vrrp_lookup_by_if_any(ifp);
+
+       vrrp_if_down(ifp);
+
+       for (ALL_LIST_ELEMENTS_RO(vrs, ln, vr)) {
+               if (vr->ifp == ifp)
+                       vr->ifp = NULL;
+               else if (vr->v4->mvl_ifp == ifp)
+                       vr->v4->mvl_ifp = NULL;
+               else if (vr->v6->mvl_ifp == ifp)
+                       vr->v6->mvl_ifp = NULL;
+       }
+
+       list_delete(&vrs);
+
+       vrrp_autoconfig_if_del(ifp);
+}
+
+void vrrp_if_address_add(struct interface *ifp)
+{
+       struct vrrp_vrouter *vr;
+       struct listnode *ln;
+       struct list *vrs;
+
+       /*
+        * We have to do a wide search here, because we need to know when a v6
+        * macvlan device gets a new address. This is because the macvlan link
+        * local is used as the source address for v6 advertisements, and hence
+        * "do I have a link local" constitutes an activation condition for v6
+        * virtual routers.
+        */
+       vrs = vrrp_lookup_by_if_any(ifp);
+
+       for (ALL_LIST_ELEMENTS_RO(vrs, ln, vr))
+               vrrp_check_start(vr);
+
+       list_delete(&vrs);
+
+       vrrp_autoconfig_if_address_add(ifp);
+}
+
+void vrrp_if_address_del(struct interface *ifp)
+{
+       vrrp_autoconfig_if_address_del(ifp);
+}
+
 /* Other ------------------------------------------------------------------- */
 
 int vrrp_config_write_interface(struct vty *vty)
index eabb23fe75a32ee5336a3bcc9156b7205bb4dff2..45f4e4ecb745b07a3ff514693c84d789e32bdd0d 100644 (file)
@@ -168,6 +168,9 @@ struct vrrp_vrouter {
        /* Whether this instance was automatically configured */
        bool autoconf;
 
+       /* Whether this VRRP router is in administrative shutdown */
+       bool shutdown;
+
        /* Interface */
        struct interface *ifp;
 
@@ -234,6 +237,14 @@ void vrrp_vrouter_destroy(struct vrrp_vrouter *vr);
 
 /* Configuration controllers ----------------------------------------------- */
 
+/*
+ * Check if a Virtual Router ought to be started, and if so, start it.
+ *
+ * vr
+ *    Virtual Router to checkstart
+ */
+void vrrp_check_start(struct vrrp_vrouter *vr);
+
 /*
  * Change the configured priority of a VRRP Virtual Router.
  *
@@ -279,7 +290,7 @@ void vrrp_set_advertisement_interval(struct vrrp_vrouter *vr,
  *    -1 on error
  *     0 otherwise
  */
-int vrrp_add_ip(struct vrrp_router *r, struct ipaddr *ip, bool activate);
+int vrrp_add_ip(struct vrrp_router *r, struct ipaddr *ip);
 
 /*
  * Add an IPv4 address to a VRRP Virtual Router.
@@ -298,7 +309,7 @@ int vrrp_add_ip(struct vrrp_router *r, struct ipaddr *ip, bool activate);
  *    -1 on error
  *     0 otherwise
  */
-int vrrp_add_ipv4(struct vrrp_vrouter *vr, struct in_addr v4, bool activate);
+int vrrp_add_ipv4(struct vrrp_vrouter *vr, struct in_addr v4);
 
 /*
  * Add an IPv6 address to a VRRP Virtual Router.
@@ -317,7 +328,7 @@ int vrrp_add_ipv4(struct vrrp_vrouter *vr, struct in_addr v4, bool activate);
  *    -1 on error
  *     0 otherwise
  */
-int vrrp_add_ipv6(struct vrrp_vrouter *vr, struct in6_addr v6, bool activate);
+int vrrp_add_ipv6(struct vrrp_vrouter *vr, struct in6_addr v6);
 
 /*
  * Remove an IP address from a VRRP Virtual Router.
@@ -338,7 +349,7 @@ int vrrp_add_ipv6(struct vrrp_vrouter *vr, struct in6_addr v6, bool activate);
  *    -1 on error
  *     0 otherwise
  */
-int vrrp_del_ip(struct vrrp_router *r, struct ipaddr *ip, bool deactivate);
+int vrrp_del_ip(struct vrrp_router *r, struct ipaddr *ip);
 
 /*
  * Remove an IPv4 address from a VRRP Virtual Router.
@@ -359,7 +370,7 @@ int vrrp_del_ip(struct vrrp_router *r, struct ipaddr *ip, bool deactivate);
  *    -1 on error
  *     0 otherwise
  */
-int vrrp_del_ipv4(struct vrrp_vrouter *vr, struct in_addr v4, bool deactivate);
+int vrrp_del_ipv4(struct vrrp_vrouter *vr, struct in_addr v4);
 
 /*
  * Remove an IPv6 address from a VRRP Virtual Router.
@@ -380,7 +391,7 @@ int vrrp_del_ipv4(struct vrrp_vrouter *vr, struct in_addr v4, bool deactivate);
  *    -1 on error
  *     0 otherwise
  */
-int vrrp_del_ipv6(struct vrrp_vrouter *vr, struct in6_addr v6, bool deactivate);
+int vrrp_del_ipv6(struct vrrp_vrouter *vr, struct in6_addr v6);
 
 /* State machine ----------------------------------------------------------- */
 
@@ -457,105 +468,14 @@ void vrrp_autoconfig_on(int version);
  */
 void vrrp_autoconfig_off(void);
 
-/*
- * Callback to notify autoconfig of interface add.
- *
- * If the interface is a VRRP-compatible device, and there is no existing VRRP
- * router running on it, one is created. All addresses on the interface are
- * added to the router.
- *
- * ifp
- *    Interface to operate on
- *
- * Returns:
- *    -1 on failure
- *     0 otherwise
- */
-int vrrp_autoconfig_if_add(struct interface *ifp);
-
-/*
- * Callback to notify autoconfig of interface delete.
- *
- * If the interface is a VRRP-compatible device, and a VRRP router is running
- * on it, and that VRRP router was automatically configured, it will be
- * deleted. If that was the last router for the corresponding VRID (i.e., if
- * this interface was a v4 VRRP interface and no v6 router is configured for
- * the same VRID) then the entire virtual router is deleted.
- *
- * ifp
- *    Interface to operate on
- *
- * Returns:
- *    -1 on failure
- *     0 otherwise
- */
-int vrrp_autoconfig_if_del(struct interface *ifp);
-
-/*
- * Callback to notify autoconfig of interface up.
- *
- * Roughly equivalent to vrrp_autoconfig_if_add, except that addresses are
- * refreshed if an autoconfigured virtual router already exists.
- *
- * ifp
- *    Interface to operate on
- *
- * Returns:
- *    -1 on failure
- *     0 otherwise
- */
-int vrrp_autoconfig_if_up(struct interface *ifp);
-
-/*
- * Callback to notify autoconfig of interface down.
- *
- * Does nothing. An interface down event is accompanied by address deletion
- * events for all the addresses on the interface; if an autoconfigured VRRP
- * router exists on this interface, then it will have all its addresses deleted
- * and end up in Initialize.
- *
- * ifp
- *    Interface to operate on
- *
- * Returns:
- *    -1 on failure
- *     0 otherwise
- */
-int vrrp_autoconfig_if_down(struct interface *ifp);
+/* Interface Tracking ------------------------------------------------------ */
 
-/*
- * Callback to notify autoconfig of a new interface address.
- *
- * If a VRRP router exists on this interface, its address list is updated to
- * match the new address list. If no addresses remain, a Shutdown event is
- * issued to the VRRP router.
- *
- * ifp
- *    Interface to operate on
- *
- * Returns:
- *    -1 on failure
- *     0 otherwise
- *
- */
-int vrrp_autoconfig_if_address_add(struct interface *ifp);
-
-/*
- * Callback to notify autoconfig of a removed interface address.
- *
- * If a VRRP router exists on this interface, its address list is updated to
- * match the new address list. If no addresses remain, a Shutdown event is
- * issued to the VRRP router.
- *
- * ifp
- *    Interface to operate on
- *
- * Returns:
- *    -1 on failure
- *     0 otherwise
- *
- */
-int vrrp_autoconfig_if_address_del(struct interface *ifp);
+void vrrp_if_add(struct interface *ifp);
+void vrrp_if_del(struct interface *ifp);
+void vrrp_if_up(struct interface *ifp);
+void vrrp_if_down(struct interface *ifp);
+void vrrp_if_address_add(struct interface *ifp);
+void vrrp_if_address_del(struct interface *ifp);
 
 /* Other ------------------------------------------------------------------- */
 
index eacf4a14c3d1d2f918f57966a9782ad4133cbcbd..4f1d5dfa088cfc49521a1a8b5be57622a2d3346f 100644 (file)
@@ -146,12 +146,14 @@ DEFPY(vrrp_ip,
 
        if (no) {
                int oldstate = vr->v4->fsm.state;
-               failed = vrrp_del_ipv4(vr, ip, true);
+               failed = vrrp_del_ipv4(vr, ip);
+               vrrp_check_start(vr);
                deactivated = (vr->v4->fsm.state == VRRP_STATE_INITIALIZE
                               && oldstate != VRRP_STATE_INITIALIZE);
        } else {
                int oldstate = vr->v4->fsm.state;
-               failed = vrrp_add_ipv4(vr, ip, true);
+               failed = vrrp_add_ipv4(vr, ip);
+               vrrp_check_start(vr);
                activated = (vr->v4->fsm.state != VRRP_STATE_INITIALIZE
                             && oldstate == VRRP_STATE_INITIALIZE);
        }
@@ -203,12 +205,12 @@ DEFPY(vrrp_ip6,
 
        if (no) {
                int oldstate = vr->v6->fsm.state;
-               failed = vrrp_del_ipv6(vr, ipv6, true);
+               failed = vrrp_del_ipv6(vr, ipv6);
                deactivated = (vr->v6->fsm.state == VRRP_STATE_INITIALIZE
                               && oldstate != VRRP_STATE_INITIALIZE);
        } else {
                int oldstate = vr->v6->fsm.state;
-               failed = vrrp_add_ipv6(vr, ipv6, true);
+               failed = vrrp_add_ipv6(vr, ipv6);
                activated = (vr->v6->fsm.state != VRRP_STATE_INITIALIZE
                             && oldstate == VRRP_STATE_INITIALIZE);
        }
index a4e115801035bb86b887b487d601cc0eac004405..1baeb41ba49e0bcca61c36846f64554b3b7b8f71 100644 (file)
@@ -61,7 +61,7 @@ static int vrrp_zebra_if_add(int command, struct zclient *zclient,
        if (!ifp)
                return 0;
 
-       vrrp_autoconfig_if_add(ifp);
+       vrrp_if_add(ifp);
 
        return 0;
 }
@@ -75,7 +75,7 @@ static int vrrp_zebra_if_del(int command, struct zclient *zclient,
        if (!ifp)
                return 0;
 
-       vrrp_autoconfig_if_del(ifp);
+       vrrp_if_del(ifp);
 
 #if 0
        if (VRRP_DEBUG_ZEBRA) {
@@ -104,7 +104,7 @@ static int vrrp_zebra_if_state_up(int command, struct zclient *zclient,
        if (!ifp)
                return 0;
 
-       vrrp_autoconfig_if_up(ifp);
+       vrrp_if_up(ifp);
 
 #if 0
        if (VRRP_DEBUG_ZEBRA) {
@@ -132,7 +132,7 @@ static int vrrp_zebra_if_state_down(int command, struct zclient *zclient,
        if (!ifp)
                return 0;
 
-       vrrp_autoconfig_if_down(ifp);
+       vrrp_if_down(ifp);
 
 #if 0
        if (VRRP_DEBUG_ZEBRA) {
@@ -189,7 +189,7 @@ static int vrrp_zebra_if_address_add(int command, struct zclient *zclient,
        if (!c)
                return 0;
 
-       vrrp_autoconfig_if_address_add(c->ifp);
+       vrrp_if_address_add(c->ifp);
 
 #if 0
        if (VRRP_DEBUG_ZEBRA) {
@@ -225,7 +225,7 @@ static int vrrp_zebra_if_address_del(int command, struct zclient *client,
        if (!c)
                return 0;
 
-       vrrp_autoconfig_if_address_del(c->ifp);
+       vrrp_if_address_del(c->ifp);
 
        return 0;
 }