From 27fd88271034998b5ae4f333f98062a3f2f5dcdd Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Mon, 11 Feb 2019 20:44:49 +0000 Subject: [PATCH] vrrpd: autoconfig support, continued * 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 --- vrrpd/vrrp.c | 268 +++++++++++++++++++++++++++++++++++++-------- vrrpd/vrrp.h | 147 ++++++++++++++++++++++--- vrrpd/vrrp_vty.c | 19 ++-- vrrpd/vrrp_zebra.c | 13 ++- 4 files changed, 377 insertions(+), 70 deletions(-) diff --git a/vrrpd/vrrp.c b/vrrpd/vrrp.c index 6cfbd7c090..b01bcb939c 100644 --- a/vrrpd/vrrp.c +++ b/vrrpd/vrrp.c @@ -39,6 +39,11 @@ #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; diff --git a/vrrpd/vrrp.h b/vrrpd/vrrp.h index 57ec55eea4..ed68b6a812 100644 --- a/vrrpd/vrrp.h +++ b/vrrpd/vrrp.h @@ -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 diff --git a/vrrpd/vrrp_vty.c b/vrrpd/vrrp_vty.c index c32e5c2c8c..0a91026d73 100644 --- a/vrrpd/vrrp_vty.c +++ b/vrrpd/vrrp_vty.c @@ -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); diff --git a/vrrpd/vrrp_zebra.c b/vrrpd/vrrp_zebra.c index e7967f9326..a4e1158010 100644 --- a/vrrpd/vrrp_zebra.c +++ b/vrrpd/vrrp_zebra.c @@ -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; } -- 2.39.5