summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQuentin Young <qlyoung@cumulusnetworks.com>2019-02-08 00:48:49 +0100
committerQuentin Young <qlyoung@cumulusnetworks.com>2019-05-17 02:27:08 +0200
commit53e60e5c5819ea3a602d1bd60b50b0b30caf7702 (patch)
treebcbf644e60899329c024416485d8b165c150795a
parentvrrpd: add cli for preempt mode (diff)
downloadfrr-53e60e5c5819ea3a602d1bd60b50b0b30caf7702.tar.xz
frr-53e60e5c5819ea3a602d1bd60b50b0b30caf7702.zip
vrrpd: autoconfig support
Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
-rw-r--r--lib/if.h4
-rw-r--r--lib/zclient.c3
-rw-r--r--vrrpd/vrrp.c76
-rw-r--r--vrrpd/vrrp.h38
-rw-r--r--vrrpd/vrrp_vty.c21
-rw-r--r--vrrpd/vrrp_zebra.c3
-rw-r--r--zebra/zapi_msg.c2
7 files changed, 139 insertions, 8 deletions
diff --git a/lib/if.h b/lib/if.h
index ef596d45d..2dc1a7b2d 100644
--- a/lib/if.h
+++ b/lib/if.h
@@ -225,6 +225,10 @@ struct interface {
not work as expected.
*/
ifindex_t ifindex;
+ /*
+ * ifindex of parent interface, if any
+ */
+ ifindex_t link_ifindex;
#define IFINDEX_INTERNAL 0
/* Zebra internal interface status */
diff --git a/lib/zclient.c b/lib/zclient.c
index 6647a1ab1..0972590ca 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -1400,6 +1400,8 @@ stream_failure:
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | bandwidth |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | parent ifindex |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Link Layer Type |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Harware Address Length |
@@ -1580,6 +1582,7 @@ void zebra_interface_if_set_value(struct stream *s, struct interface *ifp)
ifp->mtu = stream_getl(s);
ifp->mtu6 = stream_getl(s);
ifp->bandwidth = stream_getl(s);
+ ifp->link_ifindex = stream_getl(s);
ifp->ll_type = stream_getl(s);
ifp->hw_addr_len = stream_getl(s);
if (ifp->hw_addr_len)
diff --git a/vrrpd/vrrp.c b/vrrpd/vrrp.c
index 265cce33f..bf804abb3 100644
--- a/vrrpd/vrrp.c
+++ b/vrrpd/vrrp.c
@@ -1297,6 +1297,81 @@ int vrrp_event(struct vrrp_router *r, int event)
/* Other ------------------------------------------------------------------- */
+static struct vrrp_vrouter *
+vrrp_autoconfig_autocreate(struct interface *mvl_ifp)
+{
+ struct interface *p;
+ struct vrrp_vrouter *vr;
+
+ p = if_lookup_by_index(mvl_ifp->link_ifindex, VRF_DEFAULT);
+ 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)
+ 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);
+
+ vr->autoconf = true;
+
+ return vr;
+}
+
+static bool vrrp_ifp_is_mvl(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);
+}
+
+int vrrp_autoconfig(struct interface *ifp)
+{
+ if (ifp && vrrp_ifp_is_mvl(ifp)) {
+ vrrp_autoconfig_autocreate(ifp);
+ return 0;
+ }
+
+ /* Loop through interfaces, looking for compatible macvlan devices. */
+ struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+
+ FOR_ALL_INTERFACES (vrf, ifp)
+ if (vrrp_ifp_is_mvl(ifp))
+ vrrp_autoconfig_autocreate(ifp);
+
+ return 0;
+}
+
static unsigned int vrrp_hash_key(void *arg)
{
struct vrrp_vrouter *vr = arg;
@@ -1323,6 +1398,7 @@ static bool vrrp_hash_cmp(const void *arg1, const void *arg2)
void vrrp_init(void)
{
+ vrrp_autoconfig_version = 3;
vrrp_vrouters_hash = hash_create(&vrrp_hash_key, vrrp_hash_cmp,
"VRRP virtual router hash");
vrf_init(NULL, NULL, NULL, NULL, NULL);
diff --git a/vrrpd/vrrp.h b/vrrpd/vrrp.h
index 0df588b22..57ec55eea 100644
--- a/vrrpd/vrrp.h
+++ b/vrrpd/vrrp.h
@@ -53,13 +53,17 @@ extern struct zebra_privs_t vrrp_privs;
/* Global hash of all Virtual Routers */
struct hash *vrrp_vrouters_hash;
-/*
- * 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 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 {
/*
* Whether this VRRP Router is active.
*/
@@ -164,6 +168,9 @@ struct vrrp_router {
* implementations.
*/
struct vrrp_vrouter {
+ /* Whether this instance was automatically configured */
+ bool autoconf;
+
/* Interface */
struct interface *ifp;
@@ -418,6 +425,23 @@ int vrrp_event(struct vrrp_router *r, int event);
/* Other ------------------------------------------------------------------- */
/*
+ * Search for and automatically configure VRRP instances on interfaces.
+ *
+ * ifp
+ * Interface to autoconfig. If it is a macvlan interface and has a VRRP MAC,
+ * a VRRP instance corresponding to VMAC assigned to macvlan will be created
+ * on the parent interface and all addresses on the macvlan interface except
+ * the v6 link local will be configured as VRRP addresses. If NULL, this
+ * treatment will be applied to all existing interfaces matching the above
+ * criterion.
+ *
+ * Returns:
+ * -1 on failure
+ * 0 otherwise
+ */
+int vrrp_autoconfig(struct interface *ifp);
+
+/*
* Find VRRP Virtual Router by Virtual Router ID
*/
struct vrrp_vrouter *vrrp_lookup(struct interface *ifp, uint8_t vrid);
diff --git a/vrrpd/vrrp_vty.c b/vrrpd/vrrp_vty.c
index 70711d12a..c73e5cb55 100644
--- a/vrrpd/vrrp_vty.c
+++ b/vrrpd/vrrp_vty.c
@@ -287,6 +287,26 @@ DEFPY(vrrp_preempt,
return CMD_SUCCESS;
}
+DEFPY(vrrp_autoconf,
+ vrrp_autoconf_cmd,
+ "[no] vrrp autoconfig [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;
+
+ return CMD_SUCCESS;
+}
+
static void vrrp_show(struct vty *vty, struct vrrp_vrouter *vr)
{
char ethstr4[ETHER_ADDR_STRLEN];
@@ -401,6 +421,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(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 c41915cbd..e7967f932 100644
--- a/vrrpd/vrrp_zebra.c
+++ b/vrrpd/vrrp_zebra.c
@@ -61,7 +61,8 @@ static int vrrp_zebra_if_add(int command, struct zclient *zclient,
if (!ifp)
return 0;
- /* FIXME: handle subinterface creation here */
+ if (vrrp_autoconfig_on)
+ vrrp_autoconfig(ifp);
return 0;
}
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index a49733170..ca371186b 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -71,6 +71,7 @@
static void zserv_encode_interface(struct stream *s, struct interface *ifp)
{
/* Interface information. */
+ struct zebra_if *zif = ifp->info;
stream_put(s, ifp->name, INTERFACE_NAMSIZ);
stream_putl(s, ifp->ifindex);
stream_putc(s, ifp->status);
@@ -82,6 +83,7 @@ static void zserv_encode_interface(struct stream *s, struct interface *ifp)
stream_putl(s, ifp->mtu);
stream_putl(s, ifp->mtu6);
stream_putl(s, ifp->bandwidth);
+ stream_putl(s, zif->link_ifindex);
stream_putl(s, ifp->ll_type);
stream_putl(s, ifp->hw_addr_len);
if (ifp->hw_addr_len)