]> git.puffer.fish Git - matthieu/frr.git/commitdiff
vrrpd: autoconfig support, continued
authorQuentin Young <qlyoung@cumulusnetworks.com>
Mon, 11 Feb 2019 20:44:49 +0000 (20:44 +0000)
committerQuentin Young <qlyoung@cumulusnetworks.com>
Fri, 17 May 2019 00:27:08 +0000 (00:27 +0000)
* Add support for interface up/down + address add/del events when using
  autoconfigure mode
* Add autoconfig information to show command

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

index 6cfbd7c09017b8e84eff8905dbed29854893feb8..b01bcb939c5791cfb9c16e21969af6ea88b719c6 100644 (file)
 
 #define VRRP_LOGPFX "[CORE] "
 
+/* statics */
+struct hash *vrrp_vrouters_hash;
+bool vrrp_autoconfig_is_on;
+int vrrp_autoconfig_version;
+
 const char *vrrp_state_names[3] = {
        [VRRP_STATE_INITIALIZE] = "Initialize",
        [VRRP_STATE_MASTER] = "Master",
@@ -156,6 +161,10 @@ static bool vrrp_has_ip(struct vrrp_vrouter *vr, struct ipaddr *ip)
 
 int vrrp_add_ip(struct vrrp_router *r, struct ipaddr *ip, bool activate)
 {
+       int af = (ip->ipa_type == IPADDR_V6) ? AF_INET6 : AF_INET;
+
+       assert(r->family == af);
+
        if (vrrp_has_ip(r->vr, ip))
                return 0;
 
@@ -177,8 +186,11 @@ int vrrp_add_ip(struct vrrp_router *r, struct ipaddr *ip, bool activate)
        bool do_activate = (activate && r->fsm.state == VRRP_STATE_INITIALIZE);
        int ret = 0;
 
-       if (do_activate)
+       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) {
                switch (r->family) {
                case AF_INET:
@@ -800,15 +812,6 @@ static int vrrp_socket(struct vrrp_router *r)
        }
 
        /* Configure sockets */
-       if (!listcount(r->vr->ifp->connected)) {
-               zlog_warn(
-                       VRRP_LOGPFX VRRP_LOGPFX_VRID
-                       "No address on interface %s; cannot configure multicast",
-                       r->vr->vrid, r->vr->ifp->name);
-               failed = true;
-               goto done;
-       }
-
        if (r->family == AF_INET) {
                /* Set Tx socket to always Tx with TTL set to 255 */
                int ttl = 255;
@@ -1282,6 +1285,10 @@ static int (*vrrp_event_handlers[])(struct vrrp_router *r) = {
  *
  * event
  *    The event to spawn
+ *
+ * Returns:
+ *    -1 on failure
+ *     0 otherwise
  */
 int vrrp_event(struct vrrp_router *r, int event)
 {
@@ -1291,7 +1298,41 @@ int vrrp_event(struct vrrp_router *r, int event)
 }
 
 
-/* Other ------------------------------------------------------------------- */
+/* Autoconfig -------------------------------------------------------------- */
+
+/*
+ * Set the configured addresses for this VRRP instance to exactly the addresses
+ * present on its macvlan subinterface(s).
+ *
+ * vr
+ *    VRRP router to act on
+ */
+static void vrrp_autoconfig_autoaddrupdate(struct vrrp_vrouter *vr)
+{
+       list_delete_all_node(vr->v4->addrs);
+       list_delete_all_node(vr->v6->addrs);
+
+       struct listnode *ln;
+       struct connected *c = NULL;
+
+       if (vr->v4->mvl_ifp)
+               for (ALL_LIST_ELEMENTS_RO(vr->v4->mvl_ifp->connected, ln, c))
+                       if (c->address->family == AF_INET)
+                               vrrp_add_ipv4(vr, c->address->u.prefix4, true);
+
+       if (vr->v6->mvl_ifp)
+               for (ALL_LIST_ELEMENTS_RO(vr->v6->mvl_ifp->connected, ln, c))
+                       if (c->address->family == AF_INET6
+                           && !IN6_IS_ADDR_LINKLOCAL(&c->address->u.prefix6))
+                               vrrp_add_ipv6(vr, c->address->u.prefix6, true);
+
+       if (vr->v4->addrs->count == 0
+           && vr->v4->fsm.state != VRRP_STATE_INITIALIZE)
+               vrrp_event(vr->v4, VRRP_EVENT_SHUTDOWN);
+       if (vr->v6->addrs->count == 0
+           && vr->v6->fsm.state != VRRP_STATE_INITIALIZE)
+               vrrp_event(vr->v4, VRRP_EVENT_SHUTDOWN);
+}
 
 static struct vrrp_vrouter *
 vrrp_autoconfig_autocreate(struct interface *mvl_ifp)
@@ -1300,47 +1341,32 @@ vrrp_autoconfig_autocreate(struct interface *mvl_ifp)
        struct vrrp_vrouter *vr;
 
        p = if_lookup_by_index(mvl_ifp->link_ifindex, VRF_DEFAULT);
+
+       if (!p)
+               return NULL;
+
        uint8_t vrid = mvl_ifp->hw_addr[5];
 
        zlog_info(VRRP_LOGPFX "Autoconfiguring VRRP on %s", p->name);
 
-       /* If it already exists, skip it */
-       vr = vrrp_lookup(p, vrid);
-       if (vr) {
-               zlog_info(VRRP_LOGPFX "VRRP instance %" PRIu8
-                                     "already configured on %s",
-                         vrid, p->name);
-               return vr;
-       }
-
-       /* create a new one */
        vr = vrrp_vrouter_create(p, vrid, vrrp_autoconfig_version);
 
-       if (!vr)
+       if (!vr) {
+               zlog_warn(VRRP_LOGPFX
+                         "Failed to autoconfigure VRRP instance %" PRIu8
+                         " on %s",
+                         vrid, p->name);
                return NULL;
+       }
 
-       /* add connected addresses as vips */
-       struct listnode *ln;
-       struct connected *c = NULL;
-       for (ALL_LIST_ELEMENTS_RO(mvl_ifp->connected, ln, c))
-               if (c->address->family == AF_INET)
-                       vrrp_add_ipv4(vr, c->address->u.prefix4, false);
-               else if (c->address->family == AF_INET6) {
-                       if (!IN6_IS_ADDR_LINKLOCAL(&c->address->u.prefix6))
-                               vrrp_add_ipv6(vr, c->address->u.prefix6, false);
-               }
-
-       if (vr->v4->addrs->count)
-               vrrp_event(vr->v4, VRRP_EVENT_STARTUP);
-       if (vr->v6->addrs->count)
-               vrrp_event(vr->v6, VRRP_EVENT_STARTUP);
+       vrrp_autoconfig_autoaddrupdate(vr);
 
        vr->autoconf = true;
 
        return vr;
 }
 
-static bool vrrp_ifp_is_mvl(struct interface *ifp)
+static bool vrrp_ifp_has_vrrp_mac(struct interface *ifp)
 {
        struct ethaddr vmac4;
        struct ethaddr vmac6;
@@ -1351,23 +1377,177 @@ static bool vrrp_ifp_is_mvl(struct interface *ifp)
               || !memcmp(ifp->hw_addr, vmac6.octet, sizeof(vmac6.octet) - 1);
 }
 
-int vrrp_autoconfig(struct interface *ifp)
+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)
+{
+       if (!vrrp_autoconfig_is_on)
+               return 0;
+
+       struct vrrp_vrouter *vr;
+
+       if (!ifp || !ifp->link_ifindex || !vrrp_ifp_has_vrrp_mac(ifp))
+               return -1;
+
+       vr = vrrp_lookup_by_mvlif(ifp);
+
+       if (!vr)
+               vr = vrrp_autoconfig_autocreate(ifp);
+
+       if (!vr)
+               return -1;
+
+       if (vr->autoconf == false)
+               return 0;
+       else {
+               vrrp_attach_interface(vr->v4);
+               vrrp_attach_interface(vr->v6);
+               vrrp_autoconfig_autoaddrupdate(vr);
+       }
+
+       return 0;
+}
+
+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;
+
+       if (vr && vr->autoconf == false)
+               return 0;
+
+       if (vr && vr->v4->mvl_ifp == ifp) {
+               if (vr->v4->fsm.state != VRRP_STATE_INITIALIZE)
+                       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)
+                       vrrp_event(vr->v6, VRRP_EVENT_SHUTDOWN);
+               vr->v6->mvl_ifp = NULL;
+       }
+
+       if (vr->v4->mvl_ifp == NULL && vr->v6->mvl_ifp == NULL) {
+               vrrp_vrouter_destroy(vr);
+               vr = NULL;
+       }
+
+       return 0;
+}
+
+int vrrp_autoconfig_if_up(struct interface *ifp)
 {
-       if (ifp && vrrp_ifp_is_mvl(ifp)) {
-               vrrp_autoconfig_autocreate(ifp);
+       if (!vrrp_autoconfig_is_on)
+               return 0;
+
+       struct vrrp_vrouter *vr = vrrp_lookup_by_mvlif(ifp);
+
+       if (vr && !vr->autoconf)
+               return 0;
+
+       if (!vr) {
+               vrrp_autoconfig_if_add(ifp);
                return 0;
        }
 
-       /* Loop through interfaces, looking for compatible macvlan devices. */
+       vrrp_attach_interface(vr->v4);
+       vrrp_attach_interface(vr->v6);
+       vrrp_autoconfig_autoaddrupdate(vr);
+
+       return 0;
+}
+
+int vrrp_autoconfig_if_down(struct interface *ifp)
+{
+       if (!vrrp_autoconfig_is_on)
+               return 0;
+
+       return 0;
+}
+
+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);
+
+       if (vr && vr->autoconf)
+               vrrp_autoconfig_autoaddrupdate(vr);
+
+       return 0;
+}
+
+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);
+
+       if (vr && vr->autoconf)
+               vrrp_autoconfig_autoaddrupdate(vr);
+
+       return 0;
+}
+
+int vrrp_autoconfig(void)
+{
+       if (!vrrp_autoconfig_is_on)
+               return 0;
+
        struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+       struct interface *ifp;
 
        FOR_ALL_INTERFACES (vrf, ifp)
-               if (vrrp_ifp_is_mvl(ifp))
-                       vrrp_autoconfig_autocreate(ifp);
+               vrrp_autoconfig_if_add(ifp);
 
        return 0;
 }
 
+void vrrp_autoconfig_on(int version)
+{
+       vrrp_autoconfig_is_on = true;
+       vrrp_autoconfig_version = version;
+
+       vrrp_autoconfig();
+}
+
+void vrrp_autoconfig_off(void)
+{
+       vrrp_autoconfig_is_on = false;
+
+       struct list *ll = hash_to_list(vrrp_vrouters_hash);
+
+       struct listnode *ln;
+       struct vrrp_vrouter *vr;
+
+       for (ALL_LIST_ELEMENTS_RO(ll, ln, vr))
+               if (vr->autoconf)
+                       vrrp_vrouter_destroy(vr);
+
+       list_delete(&ll);
+}
+
+/* Other ------------------------------------------------------------------- */
+
 static unsigned int vrrp_hash_key(void *arg)
 {
        struct vrrp_vrouter *vr = arg;
index 57ec55eea45e5b060b27b7c03b38cba6527d35e3..ed68b6a812d773ad4ed57f9c7009dc640511719f 100644 (file)
@@ -51,19 +51,15 @@ extern struct thread_master *master;
 extern struct zebra_privs_t vrrp_privs;
 
 /* Global hash of all Virtual Routers */
-struct hash *vrrp_vrouters_hash;
+extern struct hash *vrrp_vrouters_hash;
 
-/* Whether to automatically configure VRRP instances */
-static bool vrrp_autoconfig_on;
-static int vrrp_autoconfig_version;
-
-       /*
-        * VRRP Router.
-        *
-        * This struct contains all state for a particular VRRP Router operating
-        * in a Virtual Router for either IPv4 or IPv6.
-        */
-       struct vrrp_router {
+/*
+ * VRRP Router.
+ *
+ * This struct contains all state for a particular VRRP Router operating
+ * in a Virtual Router for either IPv4 or IPv6.
+ */
+struct vrrp_router {
        /*
         * Whether this VRRP Router is active.
         */
@@ -421,8 +417,7 @@ DECLARE_HOOK(vrrp_change_state_hook, (struct vrrp_router * r, int to), (r, to));
  */
 int vrrp_event(struct vrrp_router *r, int event);
 
-
-/* Other ------------------------------------------------------------------- */
+/* Autoconfig -------------------------------------------------------------- */
 
 /*
  * Search for and automatically configure VRRP instances on interfaces.
@@ -439,7 +434,129 @@ int vrrp_event(struct vrrp_router *r, int event);
  *    -1 on failure
  *     0 otherwise
  */
-int vrrp_autoconfig(struct interface *ifp);
+int vrrp_autoconfig(void);
+
+/*
+ * Enable autoconfiguration.
+ *
+ * Calling this function will cause vrrpd to automatically configure VRRP
+ * instances on existing compatible macvlan interfaces. These instances will
+ * react to interface up/down and address add/delete events to keep themselves
+ * in sync with the available interfaces.
+ *
+ * version
+ *    VRRP version to use for autoconfigured instances. Must be 2 or 3.
+ */
+void vrrp_autoconfig_on(int version);
+
+/*
+ * Disable autoconfiguration.
+ *
+ * Calling this function will delete all existing autoconfigured VRRP instances.
+ */
+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);
+
+/*
+ * 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);
+
+/* Other ------------------------------------------------------------------- */
 
 /*
  * Find VRRP Virtual Router by Virtual Router ID
index c32e5c2c8cfc7da4a0875bd9601b58e93be56b15..0a91026d73179ab6d1b1cb27b9d803e4f76cd124 100644 (file)
@@ -259,22 +259,21 @@ DEFPY(vrrp_preempt,
        return CMD_SUCCESS;
 }
 
-DEFPY(vrrp_autoconf,
-      vrrp_autoconf_cmd,
-      "[no] vrrp autoconfig [version (2-3)]",
+DEFPY(vrrp_autoconfigure,
+      vrrp_autoconfigure_cmd,
+      "[no] vrrp autoconfigure [version (2-3)]",
       NO_STR
       VRRP_STR
       "Automatically set up VRRP instances on VRRP-compatible interfaces\n"
       "Version for automatically configured instances\n"
       VRRP_VERSION_STR)
 {
-       vrrp_autoconfig_on = !no;
        version = version ? version : 3;
 
-       if (vrrp_autoconfig_on)
-               vrrp_autoconfig(NULL);
-
-       vrrp_autoconfig_version = !no ? version : vrrp_autoconfig_version;
+       if (!no)
+               vrrp_autoconfig_on(version);
+       else
+               vrrp_autoconfig_off();
 
        return CMD_SUCCESS;
 }
@@ -293,6 +292,8 @@ static void vrrp_show(struct vty *vty, struct vrrp_vrouter *vr)
 
        ttable_add_row(tt, "%s|%" PRIu32, "Virtual Router ID", vr->vrid);
        ttable_add_row(tt, "%s|%" PRIu8, "Protocol Version", vr->version);
+       ttable_add_row(tt, "%s|%s", "Autoconfigured",
+                      vr->autoconf ? "Yes" : "No");
        ttable_add_row(tt, "%s|%s", "Interface", vr->ifp->name);
        prefix_mac2str(&vr->v4->vmac, ethstr4, sizeof(ethstr4));
        prefix_mac2str(&vr->v6->vmac, ethstr6, sizeof(ethstr6));
@@ -393,7 +394,7 @@ void vrrp_vty_init(void)
        if_cmd_init();
        install_element(VIEW_NODE, &show_debugging_vrrpd_cmd);
        install_element(VIEW_NODE, &vrrp_vrid_show_cmd);
-       install_element(CONFIG_NODE, &vrrp_autoconf_cmd);
+       install_element(CONFIG_NODE, &vrrp_autoconfigure_cmd);
        install_element(INTERFACE_NODE, &vrrp_vrid_cmd);
        install_element(INTERFACE_NODE, &vrrp_priority_cmd);
        install_element(INTERFACE_NODE, &vrrp_advertisement_interval_cmd);
index e7967f93264a953c139555641b175214d8d34ca3..a4e115801035bb86b887b487d601cc0eac004405 100644 (file)
@@ -61,8 +61,7 @@ static int vrrp_zebra_if_add(int command, struct zclient *zclient,
        if (!ifp)
                return 0;
 
-       if (vrrp_autoconfig_on)
-               vrrp_autoconfig(ifp);
+       vrrp_autoconfig_if_add(ifp);
 
        return 0;
 }
@@ -76,6 +75,8 @@ static int vrrp_zebra_if_del(int command, struct zclient *zclient,
        if (!ifp)
                return 0;
 
+       vrrp_autoconfig_if_del(ifp);
+
 #if 0
        if (VRRP_DEBUG_ZEBRA) {
                zlog_debug(
@@ -103,6 +104,8 @@ static int vrrp_zebra_if_state_up(int command, struct zclient *zclient,
        if (!ifp)
                return 0;
 
+       vrrp_autoconfig_if_up(ifp);
+
 #if 0
        if (VRRP_DEBUG_ZEBRA) {
                zlog_debug(
@@ -129,6 +132,8 @@ static int vrrp_zebra_if_state_down(int command, struct zclient *zclient,
        if (!ifp)
                return 0;
 
+       vrrp_autoconfig_if_down(ifp);
+
 #if 0
        if (VRRP_DEBUG_ZEBRA) {
                zlog_debug(
@@ -184,6 +189,8 @@ static int vrrp_zebra_if_address_add(int command, struct zclient *zclient,
        if (!c)
                return 0;
 
+       vrrp_autoconfig_if_address_add(c->ifp);
+
 #if 0
        if (VRRP_DEBUG_ZEBRA) {
                char buf[BUFSIZ];
@@ -218,6 +225,8 @@ static int vrrp_zebra_if_address_del(int command, struct zclient *client,
        if (!c)
                return 0;
 
+       vrrp_autoconfig_if_address_del(c->ifp);
+
        return 0;
 }