diff options
-rw-r--r-- | lib/yang.c | 1 | ||||
-rw-r--r-- | vrrpd/subdir.am | 4 | ||||
-rw-r--r-- | vrrpd/vrrp.c | 12 | ||||
-rw-r--r-- | vrrpd/vrrp.h | 7 | ||||
-rw-r--r-- | vrrpd/vrrp_main.c | 1 | ||||
-rw-r--r-- | vrrpd/vrrp_northbound.c | 814 | ||||
-rw-r--r-- | vrrpd/vrrp_vty.c | 265 | ||||
-rw-r--r-- | vrrpd/vrrp_vty.h | 15 |
8 files changed, 973 insertions, 146 deletions
diff --git a/lib/yang.c b/lib/yang.c index d153f7553..93e6db305 100644 --- a/lib/yang.c +++ b/lib/yang.c @@ -77,6 +77,7 @@ static const char *const frr_native_modules[] = { "frr-ripd", "frr-ripngd", "frr-isisd", + "frr-vrrpd", }; /* Generate the yang_modules tree. */ diff --git a/vrrpd/subdir.am b/vrrpd/subdir.am index 57eec108c..d81594ad9 100644 --- a/vrrpd/subdir.am +++ b/vrrpd/subdir.am @@ -15,6 +15,7 @@ vrrpd_libvrrp_a_SOURCES = \ vrrpd/vrrp_arp.c \ vrrpd/vrrp_debug.c \ vrrpd/vrrp_ndisc.c \ + vrrpd/vrrp_northbound.c \ vrrpd/vrrp_packet.c \ vrrpd/vrrp_vty.c \ vrrpd/vrrp_zebra.c \ @@ -35,3 +36,6 @@ vrrpd/vrrp_vty.$(OBJEXT): vrrpd/vrrp_vty_clippy.c vrrpd_vrrpd_SOURCES = vrrpd/vrrp_main.c vrrpd_vrrpd_LDADD = vrrpd/libvrrp.a lib/libfrr.la @LIBCAP@ +nodist_vrrpd_vrrpd_SOURCES = \ + yang/frr-vrrpd.yang.c \ + # end diff --git a/vrrpd/vrrp.c b/vrrpd/vrrp.c index 7a68b6b82..77bdf79b9 100644 --- a/vrrpd/vrrp.c +++ b/vrrpd/vrrp.c @@ -2337,6 +2337,7 @@ int vrrp_config_write_global(struct vty *vty) vty_out(vty, "vrrp autoconfigure%s\n", vrrp_autoconfig_version == 2 ? " version 2" : ""); + /* FIXME: needs to be udpated for full YANG conversion. */ if (vd.priority != VRRP_DEFAULT_PRIORITY && ++writes) vty_out(vty, "vrrp default priority %" PRIu8 "\n", vd.priority); @@ -2386,10 +2387,13 @@ static bool vrrp_hash_cmp(const void *arg1, const void *arg2) void vrrp_init(void) { /* Set default defaults */ - vd.priority = VRRP_DEFAULT_PRIORITY; - vd.advertisement_interval = VRRP_DEFAULT_ADVINT; - vd.preempt_mode = VRRP_DEFAULT_PREEMPT; - vd.accept_mode = VRRP_DEFAULT_ACCEPT; + vd.version = yang_get_default_uint8("%s/version", VRRP_XPATH_FULL); + vd.priority = yang_get_default_uint8("%s/priority", VRRP_XPATH_FULL); + vd.advertisement_interval = yang_get_default_uint16( + "%s/advertisement-interval", VRRP_XPATH_FULL); + vd.preempt_mode = yang_get_default_bool("%s/preempt", VRRP_XPATH_FULL); + vd.accept_mode = + yang_get_default_bool("%s/accept-mode", VRRP_XPATH_FULL); vd.shutdown = VRRP_DEFAULT_SHUTDOWN; vrrp_autoconfig_version = 3; diff --git a/vrrpd/vrrp.h b/vrrpd/vrrp.h index b1994c23f..7e3e493a2 100644 --- a/vrrpd/vrrp.h +++ b/vrrpd/vrrp.h @@ -28,6 +28,7 @@ #include "lib/hook.h" #include "lib/if.h" #include "lib/linklist.h" +#include "lib/northbound.h" #include "lib/privs.h" #include "lib/stream.h" #include "lib/thread.h" @@ -46,6 +47,8 @@ #define VRRP_LOGPFX_FAM "[%s] " /* Default defaults */ +#define VRRP_XPATH_FULL "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group" +#define VRRP_XPATH "./frr-vrrpd:vrrp/vrrp-group" #define VRRP_DEFAULT_PRIORITY 100 #define VRRP_DEFAULT_ADVINT 100 #define VRRP_DEFAULT_PREEMPT true @@ -57,8 +60,12 @@ DECLARE_MGROUP(VRRPD) +/* Northbound */ +extern const struct frr_yang_module_info frr_vrrpd_info; + /* Configured defaults */ struct vrrp_defaults { + uint8_t version; uint8_t priority; uint16_t advertisement_interval; bool preempt_mode; diff --git a/vrrpd/vrrp_main.c b/vrrpd/vrrp_main.c index fface1718..7bb3f0540 100644 --- a/vrrpd/vrrp_main.c +++ b/vrrpd/vrrp_main.c @@ -107,6 +107,7 @@ struct quagga_signal_t vrrp_signals[] = { static const struct frr_yang_module_info *const vrrp_yang_modules[] = { &frr_interface_info, + &frr_vrrpd_info, }; #define VRRP_VTY_PORT 2619 diff --git a/vrrpd/vrrp_northbound.c b/vrrpd/vrrp_northbound.c new file mode 100644 index 000000000..71fe6f1e4 --- /dev/null +++ b/vrrpd/vrrp_northbound.c @@ -0,0 +1,814 @@ +/* + * VRRP northbound bindings. + * Copyright (C) 2019 Cumulus Networks, Inc. + * Quentin Young + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <zebra.h> + +#include "if.h" +#include "log.h" +#include "prefix.h" +#include "table.h" +#include "command.h" +#include "northbound.h" +#include "libfrr.h" +#include "vrrp.h" +#include "vrrp_vty.h" + +/* + * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group + */ +static int lib_interface_vrrp_vrrp_group_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct interface *ifp; + uint8_t vrid; + uint8_t version = 3; + struct vrrp_vrouter *vr; + + if (event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(dnode, NULL, true); + vrid = yang_dnode_get_uint8(dnode, "./virtual-router-id"); + version = yang_dnode_get_enum(dnode, "./version"); + vr = vrrp_vrouter_create(ifp, vrid, version); + nb_running_set_entry(dnode, vr); + + return NB_OK; +} + +static int lib_interface_vrrp_vrrp_group_destroy(enum nb_event event, + const struct lyd_node *dnode) +{ + struct vrrp_vrouter *vr; + + if (event != NB_EV_APPLY) + return NB_OK; + + vr = nb_running_unset_entry(dnode); + vrrp_vrouter_destroy(vr); + + return NB_OK; +} + +static const void * +lib_interface_vrrp_vrrp_group_get_next(const void *parent_list_entry, + const void *list_entry) +{ + struct list *l = hash_to_list(vrrp_vrouters_hash); + struct listnode *ln; + const struct vrrp_vrouter *vr, *prev, *curr; + const struct interface *ifp = parent_list_entry; + + prev = curr = NULL; + vr = list_entry; + + /* + * If list_entry is null, we return the first vrrp instance with a + * matching interface + */ + bool nextone = list_entry ? false : true; + + for (ALL_LIST_ELEMENTS_RO(l, ln, curr)) { + if (curr == list_entry) { + nextone = true; + continue; + } + + if (nextone && curr->ifp == ifp) + goto done; + + prev = curr; + } + + curr = NULL; + +done: + list_delete(&l); + return curr; +} + +static int lib_interface_vrrp_vrrp_group_get_keys(const void *list_entry, + struct yang_list_keys *keys) +{ + const struct vrrp_vrouter *vr = list_entry; + + keys->num = 1; + snprintf(keys->key[0], sizeof(keys->key[0]), "%" PRIu32, vr->vrid); + + return NB_OK; +} + +static const void * +lib_interface_vrrp_vrrp_group_lookup_entry(const void *parent_list_entry, + const struct yang_list_keys *keys) +{ + uint32_t vrid = strtoul(keys->key[0], NULL, 10); + const struct interface *ifp = parent_list_entry; + + vrrp_lookup(ifp, vrid); + + return NULL; +} + +/* + * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/version + */ +static int +lib_interface_vrrp_vrrp_group_version_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + if (event != NB_EV_APPLY) + return NB_OK; + + struct vrrp_vrouter *vr; + uint8_t version; + + vr = nb_running_get_entry(dnode, NULL, true); + vrrp_event(vr->v4, VRRP_EVENT_SHUTDOWN); + vrrp_event(vr->v6, VRRP_EVENT_SHUTDOWN); + version = yang_dnode_get_enum(dnode, NULL); + vr->version = version; + + vrrp_check_start(vr); + + return NB_OK; +} + +static void vrrp_yang_add_del_virtual_address(const struct lyd_node *dnode, + bool add) +{ + struct vrrp_vrouter *vr; + struct ipaddr ip; + + vr = nb_running_get_entry(dnode, NULL, true); + yang_dnode_get_ip(&ip, dnode, NULL); + if (add) + vrrp_add_ip(vr, &ip); + else + vrrp_del_ip(vr, &ip); + + vrrp_check_start(vr); +} + + +//----------- + +/* + * XPath: + * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/virtual-address + */ +static int lib_interface_vrrp_vrrp_group_v4_virtual_address_create( + enum nb_event event, const struct lyd_node *dnode, + union nb_resource *resource) +{ + if (event != NB_EV_APPLY) + return NB_OK; + + vrrp_yang_add_del_virtual_address(dnode, true); + + return NB_OK; +} + +static int lib_interface_vrrp_vrrp_group_v4_virtual_address_destroy( + enum nb_event event, const struct lyd_node *dnode) +{ + if (event != NB_EV_APPLY) + return NB_OK; + + vrrp_yang_add_del_virtual_address(dnode, false); + + return NB_OK; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/current-priority + */ +static struct yang_data * +lib_interface_vrrp_vrrp_group_v4_current_priority_get_elem( + const char *xpath, const void *list_entry) +{ + const struct vrrp_vrouter *vr = list_entry; + + return yang_data_new_uint8(xpath, vr->v4->priority); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/vrrp-interface + */ +static struct yang_data * +lib_interface_vrrp_vrrp_group_v4_vrrp_interface_get_elem(const char *xpath, + const void *list_entry) +{ + const struct vrrp_vrouter *vr = list_entry; + + struct yang_data *val = NULL; + + if (vr->v4->mvl_ifp) + val = yang_data_new_string(xpath, vr->v4->mvl_ifp->name); + + return val; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/source-address + */ +static struct yang_data * +lib_interface_vrrp_vrrp_group_v4_source_address_get_elem(const char *xpath, + const void *list_entry) +{ + const struct vrrp_vrouter *vr = list_entry; + struct yang_data *val = NULL; + struct ipaddr ip; + + memset(&ip, 0x00, sizeof(ip)); + + if (memcmp(&vr->v4->src.ipaddr_v4, &ip.ipaddr_v4, sizeof(ip.ipaddr_v4))) + val = yang_data_new_ip(xpath, &vr->v4->src); + + return val; +} + +/* + * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/state + */ +static struct yang_data * +lib_interface_vrrp_vrrp_group_v4_state_get_elem(const char *xpath, + const void *list_entry) +{ + const struct vrrp_vrouter *vr = list_entry; + + return yang_data_new_enum(xpath, vr->v4->fsm.state); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/master-advertisement-interval + */ +static struct yang_data * +lib_interface_vrrp_vrrp_group_v4_master_advertisement_interval_get_elem( + const char *xpath, const void *list_entry) +{ + const struct vrrp_vrouter *vr = list_entry; + + return yang_data_new_uint16(xpath, vr->v4->master_adver_interval); +} + +/* + * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/skew-time + */ +static struct yang_data * +lib_interface_vrrp_vrrp_group_v4_skew_time_get_elem(const char *xpath, + const void *list_entry) +{ + const struct vrrp_vrouter *vr = list_entry; + + return yang_data_new_uint16(xpath, vr->v4->skew_time); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/counter/state-transition + */ +static struct yang_data * +lib_interface_vrrp_vrrp_group_v4_counter_state_transition_get_elem( + const char *xpath, const void *list_entry) +{ + const struct vrrp_vrouter *vr = list_entry; + + return yang_data_new_uint32(xpath, vr->v4->stats.trans_cnt); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/counter/tx/advertisement + */ +static struct yang_data * +lib_interface_vrrp_vrrp_group_v4_counter_tx_advertisement_get_elem( + const char *xpath, const void *list_entry) +{ + const struct vrrp_vrouter *vr = list_entry; + + return yang_data_new_uint32(xpath, vr->v4->stats.adver_tx_cnt); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/counter/tx/gratuitous-arp + */ +static struct yang_data * +lib_interface_vrrp_vrrp_group_v4_counter_tx_gratuitous_arp_get_elem( + const char *xpath, const void *list_entry) +{ + const struct vrrp_vrouter *vr = list_entry; + + return yang_data_new_uint32(xpath, vr->v4->stats.garp_tx_cnt); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/counter/rx/advertisement + */ +static struct yang_data * +lib_interface_vrrp_vrrp_group_v4_counter_rx_advertisement_get_elem( + const char *xpath, const void *list_entry) +{ + const struct vrrp_vrouter *vr = list_entry; + + return yang_data_new_uint32(xpath, vr->v4->stats.adver_rx_cnt); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/virtual-address + */ +static int lib_interface_vrrp_vrrp_group_v6_virtual_address_create( + enum nb_event event, const struct lyd_node *dnode, + union nb_resource *resource) +{ + if (event != NB_EV_APPLY) + return NB_OK; + + vrrp_yang_add_del_virtual_address(dnode, true); + + return NB_OK; +} + +static int lib_interface_vrrp_vrrp_group_v6_virtual_address_destroy( + enum nb_event event, const struct lyd_node *dnode) +{ + if (event != NB_EV_APPLY) + return NB_OK; + + vrrp_yang_add_del_virtual_address(dnode, false); + + return NB_OK; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/current-priority + */ +static struct yang_data * +lib_interface_vrrp_vrrp_group_v6_current_priority_get_elem( + const char *xpath, const void *list_entry) +{ + const struct vrrp_vrouter *vr = list_entry; + + return yang_data_new_uint8(xpath, vr->v6->priority); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/vrrp-interface + */ +static struct yang_data * +lib_interface_vrrp_vrrp_group_v6_vrrp_interface_get_elem(const char *xpath, + const void *list_entry) +{ + const struct vrrp_vrouter *vr = list_entry; + struct yang_data *val = NULL; + + if (vr->v6->mvl_ifp) + val = yang_data_new_string(xpath, vr->v6->mvl_ifp->name); + + return val; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/source-address + */ +static struct yang_data * +lib_interface_vrrp_vrrp_group_v6_source_address_get_elem(const char *xpath, + const void *list_entry) +{ + const struct vrrp_vrouter *vr = list_entry; + struct yang_data *val = NULL; + struct ipaddr ip; + + memset(&ip, 0x00, sizeof(ip)); + + if (memcmp(&vr->v6->src.ipaddr_v6, &ip.ipaddr_v6, sizeof(ip.ipaddr_v6))) + val = yang_data_new_ip(xpath, &vr->v6->src); + + return val; +} + +/* + * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/state + */ +static struct yang_data * +lib_interface_vrrp_vrrp_group_v6_state_get_elem(const char *xpath, + const void *list_entry) +{ + const struct vrrp_vrouter *vr = list_entry; + + return yang_data_new_enum(xpath, vr->v6->fsm.state); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/master-advertisement-interval + */ +static struct yang_data * +lib_interface_vrrp_vrrp_group_v6_master_advertisement_interval_get_elem( + const char *xpath, const void *list_entry) +{ + const struct vrrp_vrouter *vr = list_entry; + + return yang_data_new_uint16(xpath, vr->v6->master_adver_interval); +} + +/* + * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/skew-time + */ +static struct yang_data * +lib_interface_vrrp_vrrp_group_v6_skew_time_get_elem(const char *xpath, + const void *list_entry) +{ + const struct vrrp_vrouter *vr = list_entry; + + return yang_data_new_uint16(xpath, vr->v6->skew_time); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/counter/state-transition + */ +static struct yang_data * +lib_interface_vrrp_vrrp_group_v6_counter_state_transition_get_elem( + const char *xpath, const void *list_entry) +{ + const struct vrrp_vrouter *vr = list_entry; + + return yang_data_new_uint32(xpath, vr->v6->stats.trans_cnt); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/counter/tx/advertisement + */ +static struct yang_data * +lib_interface_vrrp_vrrp_group_v6_counter_tx_advertisement_get_elem( + const char *xpath, const void *list_entry) +{ + const struct vrrp_vrouter *vr = list_entry; + + return yang_data_new_uint32(xpath, vr->v6->stats.adver_tx_cnt); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/counter/tx/neighbor-advertisement + */ +static struct yang_data * +lib_interface_vrrp_vrrp_group_v6_counter_tx_neighbor_advertisement_get_elem( + const char *xpath, const void *list_entry) +{ + /* TODO: implement me. */ + return NULL; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/counter/rx/advertisement + */ +static struct yang_data * +lib_interface_vrrp_vrrp_group_v6_counter_rx_advertisement_get_elem( + const char *xpath, const void *list_entry) +{ + /* TODO: implement me. */ + return NULL; +} + +/* + * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/priority + */ +static int +lib_interface_vrrp_vrrp_group_priority_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + if (event != NB_EV_APPLY) + return NB_OK; + + struct vrrp_vrouter *vr; + uint8_t priority; + + vr = nb_running_get_entry(dnode, NULL, true); + priority = yang_dnode_get_uint8(dnode, NULL); + vrrp_set_priority(vr, priority); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/preempt + */ +static int +lib_interface_vrrp_vrrp_group_preempt_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + if (event != NB_EV_APPLY) + return NB_OK; + + struct vrrp_vrouter *vr; + bool preempt; + + vr = nb_running_get_entry(dnode, NULL, true); + preempt = yang_dnode_get_bool(dnode, NULL); + vr->preempt_mode = preempt; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/accept-mode + */ +static int +lib_interface_vrrp_vrrp_group_accept_mode_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + if (event != NB_EV_APPLY) + return NB_OK; + + struct vrrp_vrouter *vr; + bool accept; + + vr = nb_running_get_entry(dnode, NULL, true); + accept = yang_dnode_get_bool(dnode, NULL); + vr->accept_mode = accept; + + return NB_OK; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/advertisement-interval + */ +static int lib_interface_vrrp_vrrp_group_advertisement_interval_modify( + enum nb_event event, const struct lyd_node *dnode, + union nb_resource *resource) +{ + if (event != NB_EV_APPLY) + return NB_OK; + + struct vrrp_vrouter *vr; + uint16_t advert_int; + + vr = nb_running_get_entry(dnode, NULL, true); + advert_int = yang_dnode_get_uint16(dnode, NULL); + vrrp_set_advertisement_interval(vr, advert_int); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/shutdown + */ +static int +lib_interface_vrrp_vrrp_group_shutdown_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + if (event != NB_EV_APPLY) + return NB_OK; + + struct vrrp_vrouter *vr; + bool shutdown; + + vr = nb_running_get_entry(dnode, NULL, true); + shutdown = yang_dnode_get_bool(dnode, NULL); + + vr->shutdown = shutdown; + + if (shutdown) { + vrrp_event(vr->v4, VRRP_EVENT_SHUTDOWN); + vrrp_event(vr->v6, VRRP_EVENT_SHUTDOWN); + } else { + vrrp_check_start(vr); + } + + return NB_OK; +} + +/* clang-format off */ +const struct frr_yang_module_info frr_vrrpd_info = { + .name = "frr-vrrpd", + .nodes = { + { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group", + .cbs = { + .create = lib_interface_vrrp_vrrp_group_create, + .destroy = lib_interface_vrrp_vrrp_group_destroy, + .get_next = lib_interface_vrrp_vrrp_group_get_next, + .get_keys = lib_interface_vrrp_vrrp_group_get_keys, + .lookup_entry = lib_interface_vrrp_vrrp_group_lookup_entry, + .cli_show = cli_show_vrrp, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/version", + .cbs = { + .modify = lib_interface_vrrp_vrrp_group_version_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/priority", + .cbs = { + .modify = lib_interface_vrrp_vrrp_group_priority_modify, + .cli_show = cli_show_priority, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/preempt", + .cbs = { + .modify = lib_interface_vrrp_vrrp_group_preempt_modify, + .cli_show = cli_show_preempt, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/accept-mode", + .cbs = { + .modify = lib_interface_vrrp_vrrp_group_accept_mode_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/advertisement-interval", + .cbs = { + .modify = lib_interface_vrrp_vrrp_group_advertisement_interval_modify, + .cli_show = cli_show_advertisement_interval, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/shutdown", + .cbs = { + .modify = lib_interface_vrrp_vrrp_group_shutdown_modify, + .cli_show = cli_show_shutdown, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/virtual-address", + .cbs = { + .create = lib_interface_vrrp_vrrp_group_v4_virtual_address_create, + .destroy = lib_interface_vrrp_vrrp_group_v4_virtual_address_destroy, + .cli_show = cli_show_ip, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/current-priority", + .cbs = { + .get_elem = lib_interface_vrrp_vrrp_group_v4_current_priority_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/vrrp-interface", + .cbs = { + .get_elem = lib_interface_vrrp_vrrp_group_v4_vrrp_interface_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/source-address", + .cbs = { + .get_elem = lib_interface_vrrp_vrrp_group_v4_source_address_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/state", + .cbs = { + .get_elem = lib_interface_vrrp_vrrp_group_v4_state_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/master-advertisement-interval", + .cbs = { + .get_elem = lib_interface_vrrp_vrrp_group_v4_master_advertisement_interval_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/skew-time", + .cbs = { + .get_elem = lib_interface_vrrp_vrrp_group_v4_skew_time_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/counter/state-transition", + .cbs = { + .get_elem = lib_interface_vrrp_vrrp_group_v4_counter_state_transition_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/counter/tx/advertisement", + .cbs = { + .get_elem = lib_interface_vrrp_vrrp_group_v4_counter_tx_advertisement_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/counter/tx/gratuitous-arp", + .cbs = { + .get_elem = lib_interface_vrrp_vrrp_group_v4_counter_tx_gratuitous_arp_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/counter/rx/advertisement", + .cbs = { + .get_elem = lib_interface_vrrp_vrrp_group_v4_counter_rx_advertisement_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/virtual-address", + .cbs = { + .create = lib_interface_vrrp_vrrp_group_v6_virtual_address_create, + .destroy = lib_interface_vrrp_vrrp_group_v6_virtual_address_destroy, + .cli_show = cli_show_ipv6, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/current-priority", + .cbs = { + .get_elem = lib_interface_vrrp_vrrp_group_v6_current_priority_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/vrrp-interface", + .cbs = { + .get_elem = lib_interface_vrrp_vrrp_group_v6_vrrp_interface_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/source-address", + .cbs = { + .get_elem = lib_interface_vrrp_vrrp_group_v6_source_address_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/state", + .cbs = { + .get_elem = lib_interface_vrrp_vrrp_group_v6_state_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/master-advertisement-interval", + .cbs = { + .get_elem = lib_interface_vrrp_vrrp_group_v6_master_advertisement_interval_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/skew-time", + .cbs = { + .get_elem = lib_interface_vrrp_vrrp_group_v6_skew_time_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/counter/state-transition", + .cbs = { + .get_elem = lib_interface_vrrp_vrrp_group_v6_counter_state_transition_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/counter/tx/advertisement", + .cbs = { + .get_elem = lib_interface_vrrp_vrrp_group_v6_counter_tx_advertisement_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/counter/tx/neighbor-advertisement", + .cbs = { + .get_elem = lib_interface_vrrp_vrrp_group_v6_counter_tx_neighbor_advertisement_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/counter/rx/advertisement", + .cbs = { + .get_elem = lib_interface_vrrp_vrrp_group_v6_counter_rx_advertisement_get_elem, + } + }, + { + .xpath = NULL, + }, + } +}; diff --git a/vrrpd/vrrp_vty.c b/vrrpd/vrrp_vty.c index 239b02ee7..4ccccc43a 100644 --- a/vrrpd/vrrp_vty.c +++ b/vrrpd/vrrp_vty.c @@ -23,6 +23,7 @@ #include "lib/if.h" #include "lib/ipaddr.h" #include "lib/json.h" +#include "lib/northbound_cli.h" #include "lib/prefix.h" #include "lib/termtable.h" #include "lib/vty.h" @@ -54,8 +55,13 @@ } \ } while (0) +#define VRRP_XPATH_ENTRY VRRP_XPATH "[virtual-router-id='%ld']" + /* clang-format off */ +/* + * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group + */ DEFPY(vrrp_vrid, vrrp_vrid_cmd, "[no] vrrp (1-255)$vrid [version (2-3)]", @@ -65,27 +71,42 @@ DEFPY(vrrp_vrid, VRRP_VERSION_STR VRRP_VERSION_STR) { - VTY_DECLVAR_CONTEXT(interface, ifp); + char valbuf[8]; - struct vrrp_vrouter *vr = vrrp_lookup(ifp, vrid); + snprintf(valbuf, sizeof(valbuf), "%ld", version ? version : vd.version); - if (version == 0) - version = 3; + if (no) + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + else { + nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); + nb_cli_enqueue_change(vty, "./version", NB_OP_MODIFY, valbuf); + } - if (no && vr) - vrrp_vrouter_destroy(vr); - else if (no && !vr) - vty_out(vty, "%% VRRP instance %ld does not exist on %s\n", - vrid, ifp->name); - else if (!vr) - vrrp_vrouter_create(ifp, vrid, version); - else if (vr) - vty_out(vty, "%% VRRP instance %ld already exists on %s\n", - vrid, ifp->name); + return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid); +} - return CMD_SUCCESS; +void cli_show_vrrp(struct vty *vty, struct lyd_node *dnode, bool show_defaults) +{ + const char *vrid = yang_dnode_get_string(dnode, "./virtual-router-id"); + const char *ver = yang_dnode_get_string(dnode, "./version"); + const char *dver = + yang_get_default_string("%s/version", VRRP_XPATH_FULL); + + char verstr[16] = {}; + + if (strmatch(dver, ver)) { + if (show_defaults) + snprintf(verstr, sizeof(verstr), "version %s", dver); + } else { + snprintf(verstr, sizeof(verstr), "version %s", ver); + } + + vty_out(vty, " vrrp %s %s\n", vrid, verstr); } +/* + * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/shutdown + */ DEFPY(vrrp_shutdown, vrrp_shutdown_cmd, "[no] vrrp (1-255)$vrid shutdown", @@ -94,26 +115,24 @@ DEFPY(vrrp_shutdown, VRRP_VRID_STR "Force VRRP router into administrative shutdown\n") { - VTY_DECLVAR_CONTEXT(interface, ifp); - - struct vrrp_vrouter *vr; + nb_cli_enqueue_change(vty, "./shutdown", NB_OP_MODIFY, + no ? "false" : "true"); - VROUTER_GET_VTY(vty, ifp, vrid, vr); + return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid); +} - if (!no) { - if (vr->v4->fsm.state != VRRP_STATE_INITIALIZE) - vrrp_event(vr->v4, VRRP_EVENT_SHUTDOWN); - if (vr->v6->fsm.state != VRRP_STATE_INITIALIZE) - vrrp_event(vr->v6, VRRP_EVENT_SHUTDOWN); - vr->shutdown = true; - } else { - vr->shutdown = false; - vrrp_check_start(vr); - } +void cli_show_shutdown(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *vrid = yang_dnode_get_string(dnode, "../virtual-router-id"); + const bool shut = yang_dnode_get_bool(dnode, NULL); - return CMD_SUCCESS; + vty_out(vty, " %svrrp %s shutdown\n", shut ? "" : "no ", vrid); } +/* + * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/priority + */ DEFPY(vrrp_priority, vrrp_priority_cmd, "[no] vrrp (1-255)$vrid priority (1-254)", @@ -123,45 +142,60 @@ DEFPY(vrrp_priority, VRRP_PRIORITY_STR "Priority value") { - VTY_DECLVAR_CONTEXT(interface, ifp); + const char *val = no ? NULL : priority_str; - struct vrrp_vrouter *vr; - uint8_t newprio = no ? vd.priority : priority; + nb_cli_enqueue_change(vty, "./priority", NB_OP_MODIFY, val); - VROUTER_GET_VTY(vty, ifp, vrid, vr); + return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid); +} - vrrp_set_priority(vr, newprio); +void cli_show_priority(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *vrid = yang_dnode_get_string(dnode, "../virtual-router-id"); + const char *prio = yang_dnode_get_string(dnode, NULL); - return CMD_SUCCESS; + vty_out(vty, " vrrp %s priority %s\n", vrid, prio); } +/* + * XPath: + * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/advertisement-interval + */ DEFPY(vrrp_advertisement_interval, vrrp_advertisement_interval_cmd, "[no] vrrp (1-255)$vrid advertisement-interval (10-40950)", NO_STR VRRP_STR VRRP_VRID_STR VRRP_ADVINT_STR "Advertisement interval in milliseconds; must be multiple of 10") { - VTY_DECLVAR_CONTEXT(interface, ifp); + char valbuf[8]; + const char *val; - struct vrrp_vrouter *vr; - uint16_t newadvint = - no ? vd.advertisement_interval * CS2MS : advertisement_interval; + /* all internal computations are in centiseconds */ + advertisement_interval /= CS2MS; + snprintf(valbuf, sizeof(valbuf), "%ld", advertisement_interval); - if (newadvint % CS2MS != 0) { - vty_out(vty, "%% Value must be a multiple of %u\n", - (unsigned int)CS2MS); - return CMD_WARNING_CONFIG_FAILED; - } + val = no ? NULL : valbuf; - /* all internal computations are in centiseconds */ - newadvint /= CS2MS; + nb_cli_enqueue_change(vty, "./advertisement-interval", NB_OP_MODIFY, + val); - VROUTER_GET_VTY(vty, ifp, vrid, vr); - vrrp_set_advertisement_interval(vr, newadvint); + return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid); +} - return CMD_SUCCESS; +void cli_show_advertisement_interval(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *vrid = yang_dnode_get_string(dnode, "../virtual-router-id"); + const char *advi = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " vrrp %s advertisement-interval %s\n", vrid, advi); } +/* + * XPath: + * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v4/virtual-address + */ DEFPY(vrrp_ip, vrrp_ip_cmd, "[no] vrrp (1-255)$vrid ip A.B.C.D", @@ -171,51 +205,25 @@ DEFPY(vrrp_ip, "Add IPv4 address\n" VRRP_IP_STR) { - VTY_DECLVAR_CONTEXT(interface, ifp); + int op = no ? NB_OP_DESTROY : NB_OP_CREATE; + nb_cli_enqueue_change(vty, "./v4/virtual-address", op, ip_str); - struct vrrp_vrouter *vr; - bool deactivated = false; - bool activated = false; - bool failed = false; - int ret = CMD_SUCCESS; - int oldstate; - - VROUTER_GET_VTY(vty, ifp, vrid, vr); - - bool will_activate = (vr->v4->fsm.state == VRRP_STATE_INITIALIZE); - - if (no) { - oldstate = vr->v4->fsm.state; - failed = vrrp_del_ipv4(vr, ip); - vrrp_check_start(vr); - deactivated = (vr->v4->fsm.state == VRRP_STATE_INITIALIZE - && oldstate != VRRP_STATE_INITIALIZE); - } else { - oldstate = vr->v4->fsm.state; - failed = vrrp_add_ipv4(vr, ip); - vrrp_check_start(vr); - activated = (vr->v4->fsm.state != VRRP_STATE_INITIALIZE - && oldstate == VRRP_STATE_INITIALIZE); - } + return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid); +} - if (activated) - vty_out(vty, "%% Activated IPv4 Virtual Router %ld\n", vrid); - if (deactivated) - vty_out(vty, "%% Deactivated IPv4 Virtual Router %ld\n", vrid); - if (failed) { - vty_out(vty, "%% Failed to %s virtual IP\n", - no ? "remove" : "add"); - ret = CMD_WARNING_CONFIG_FAILED; - if (will_activate && !activated) { - vty_out(vty, - "%% Failed to activate IPv4 Virtual Router %ld\n", - vrid); - } - } +void cli_show_ip(struct vty *vty, struct lyd_node *dnode, bool show_defaults) +{ + const char *vrid = + yang_dnode_get_string(dnode, "../../virtual-router-id"); + const char *ipv4 = yang_dnode_get_string(dnode, NULL); - return ret; + vty_out(vty, " vrrp %s ip %s\n", vrid, ipv4); } +/* + * XPath: + * /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/v6/virtual-address + */ DEFPY(vrrp_ip6, vrrp_ip6_cmd, "[no] vrrp (1-255)$vrid ipv6 X:X::X:X", @@ -225,57 +233,24 @@ DEFPY(vrrp_ip6, "Add IPv6 address\n" VRRP_IP_STR) { - VTY_DECLVAR_CONTEXT(interface, ifp); - - struct vrrp_vrouter *vr; - bool deactivated = false; - bool activated = false; - bool failed = false; - int ret = CMD_SUCCESS; - int oldstate; - - VROUTER_GET_VTY(vty, ifp, vrid, vr); - - if (vr->version != 3) { - vty_out(vty, - "%% Cannot add IPv6 address to VRRPv2 virtual router\n"); - return CMD_WARNING_CONFIG_FAILED; - } + int op = no ? NB_OP_DESTROY : NB_OP_CREATE; + nb_cli_enqueue_change(vty, "./v6/virtual-address", op, ipv6_str); - bool will_activate = (vr->v6->fsm.state == VRRP_STATE_INITIALIZE); - - if (no) { - oldstate = vr->v6->fsm.state; - failed = vrrp_del_ipv6(vr, ipv6); - vrrp_check_start(vr); - deactivated = (vr->v6->fsm.state == VRRP_STATE_INITIALIZE - && oldstate != VRRP_STATE_INITIALIZE); - } else { - oldstate = vr->v6->fsm.state; - failed = vrrp_add_ipv6(vr, ipv6); - vrrp_check_start(vr); - activated = (vr->v6->fsm.state != VRRP_STATE_INITIALIZE - && oldstate == VRRP_STATE_INITIALIZE); - } + return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid); +} - if (activated) - vty_out(vty, "%% Activated IPv6 Virtual Router %ld\n", vrid); - if (deactivated) - vty_out(vty, "%% Deactivated IPv6 Virtual Router %ld\n", vrid); - if (failed) { - vty_out(vty, "%% Failed to %s virtual IP\n", - no ? "remove" : "add"); - ret = CMD_WARNING_CONFIG_FAILED; - if (will_activate && !activated) { - vty_out(vty, - "%% Failed to activate IPv6 Virtual Router %ld\n", - vrid); - } - } +void cli_show_ipv6(struct vty *vty, struct lyd_node *dnode, bool show_defaults) +{ + const char *vrid = + yang_dnode_get_string(dnode, "../../virtual-router-id"); + const char *ipv6 = yang_dnode_get_string(dnode, NULL); - return ret; + vty_out(vty, " vrrp %s ipv6 %s\n", vrid, ipv6); } +/* + * XPath: /frr-interface:lib/interface/frr-vrrpd:vrrp/vrrp-group/preempt + */ DEFPY(vrrp_preempt, vrrp_preempt_cmd, "[no] vrrp (1-255)$vrid preempt", @@ -284,17 +259,22 @@ DEFPY(vrrp_preempt, VRRP_VRID_STR "Preempt mode\n") { - VTY_DECLVAR_CONTEXT(interface, ifp); - - struct vrrp_vrouter *vr; + nb_cli_enqueue_change(vty, "./preempt", NB_OP_MODIFY, + no ? "false" : "true"); - VROUTER_GET_VTY(vty, ifp, vrid, vr); + return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid); +} - vr->preempt_mode = !no; +void cli_show_preempt(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *vrid = yang_dnode_get_string(dnode, "../virtual-router-id"); + const bool pre = yang_dnode_get_bool(dnode, NULL); - return CMD_SUCCESS; + vty_out(vty, " %svrrp %s preempt\n", pre ? "" : "no ", vrid); } +/* XXX: yang conversion */ DEFPY(vrrp_autoconfigure, vrrp_autoconfigure_cmd, "[no] vrrp autoconfigure [version (2-3)]", @@ -314,6 +294,7 @@ DEFPY(vrrp_autoconfigure, return CMD_SUCCESS; } +/* XXX: yang conversion */ DEFPY(vrrp_default, vrrp_default_cmd, "[no] vrrp default <advertisement-interval$adv (10-40950)$advint|preempt$p|priority$prio (1-254)$prioval|shutdown$s>", diff --git a/vrrpd/vrrp_vty.h b/vrrpd/vrrp_vty.h index 377321ec4..6c6eef032 100644 --- a/vrrpd/vrrp_vty.h +++ b/vrrpd/vrrp_vty.h @@ -20,6 +20,21 @@ #ifndef __VRRP_VTY_H__ #define __VRRP_VTY_H__ +#include "lib/northbound.h" + void vrrp_vty_init(void); +/* Northbound callbacks */ +void cli_show_vrrp(struct vty *vty, struct lyd_node *dnode, bool show_defaults); +void cli_show_shutdown(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +void cli_show_priority(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +void cli_show_advertisement_interval(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +void cli_show_ip(struct vty *vty, struct lyd_node *dnode, bool show_defaults); +void cli_show_ipv6(struct vty *vty, struct lyd_node *dnode, bool show_defaults); +void cli_show_preempt(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); + #endif /* __VRRP_VTY_H__ */ |