From 707656ec85360602d849fbbe7fe54c717194f4d5 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Wed, 9 May 2018 01:34:57 -0300 Subject: [PATCH] yang, ripd: add 'frr-ripd.yang' and associated stub callbacks Introduce frr-ripd.yang, which defines a model for managing the FRR ripd daemon. Also add frr-route-types.yang which defines typedefs for FRR route types. Update the 'frr_yang_module_info' array of ripd with the new 'frr-ripd' module. Add two new files (rip_cli.[ch]) which should contain all ripd commands converted to the new northbound model. Centralizing all commands in a single place will facilitate the process of moving the CLI to a separate program in the future. Add automatically generated stub callbacks in rip_northbound.c. These callbacks will be implemented gradually in the following commits. Add example JSON/XML ripd configurations in yang/examples/. Add the confd.frr-ripd.yang YANG module with annotations specific to the ConfD daemon. Signed-off-by: Renato Westphal --- ripd/rip_cli.c | 39 ++ ripd/rip_cli.h | 24 + ripd/rip_main.c | 2 + ripd/rip_northbound.c | 896 +++++++++++++++++++++++++++++++++ ripd/ripd.h | 8 + ripd/subdir.am | 7 + yang/confd/confd.frr-ripd.yang | 22 + yang/example/ripd.json | 44 ++ yang/example/ripd.xml | 34 ++ yang/frr-ripd.yang | 587 +++++++++++++++++++++ yang/frr-route-types.yang | 109 ++++ yang/subdir.am | 5 + 12 files changed, 1777 insertions(+) create mode 100644 ripd/rip_cli.c create mode 100644 ripd/rip_cli.h create mode 100644 ripd/rip_northbound.c create mode 100644 yang/confd/confd.frr-ripd.yang create mode 100644 yang/example/ripd.json create mode 100644 yang/example/ripd.xml create mode 100644 yang/frr-ripd.yang create mode 100644 yang/frr-route-types.yang diff --git a/ripd/rip_cli.c b/ripd/rip_cli.c new file mode 100644 index 000000000..0923af579 --- /dev/null +++ b/ripd/rip_cli.c @@ -0,0 +1,39 @@ +/* + * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro + * Copyright (C) 2018 NetDEF, Inc. + * Renato Westphal + * + * 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 + +#include "if.h" +#include "vrf.h" +#include "log.h" +#include "prefix.h" +#include "command.h" +#include "northbound_cli.h" +#include "libfrr.h" + +#include "ripd/ripd.h" +#include "ripd/rip_cli.h" +#ifndef VTYSH_EXTRACT_PL +#include "ripd/rip_cli_clippy.c" +#endif + +void rip_cli_init(void) +{ +} diff --git a/ripd/rip_cli.h b/ripd/rip_cli.h new file mode 100644 index 000000000..2af54e359 --- /dev/null +++ b/ripd/rip_cli.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro + * Copyright (C) 2018 NetDEF, Inc. + * Renato Westphal + * + * 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 + */ + +#ifndef _FRR_RIP_CLI_H_ +#define _FRR_RIP_CLI_H_ + +#endif /* _FRR_RIP_CLI_H_ */ diff --git a/ripd/rip_main.c b/ripd/rip_main.c index b47b111bc..23981d6d6 100644 --- a/ripd/rip_main.c +++ b/ripd/rip_main.c @@ -121,6 +121,7 @@ static struct quagga_signal_t ripd_signals[] = { static const struct frr_yang_module_info *ripd_yang_modules[] = { &frr_interface_info, + &frr_ripd_info, }; FRR_DAEMON_INFO(ripd, RIP, .vty_port = RIP_VTY_PORT, @@ -180,6 +181,7 @@ int main(int argc, char **argv) /* RIP related initialization. */ rip_init(); rip_if_init(); + rip_cli_init(); rip_zclient_init(master); rip_peer_init(); diff --git a/ripd/rip_northbound.c b/ripd/rip_northbound.c new file mode 100644 index 000000000..c2a73bfa8 --- /dev/null +++ b/ripd/rip_northbound.c @@ -0,0 +1,896 @@ +/* + * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro + * Copyright (C) 2018 NetDEF, Inc. + * Renato Westphal + * + * 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 + +#include "if.h" +#include "vrf.h" +#include "log.h" +#include "prefix.h" +#include "table.h" +#include "command.h" +#include "northbound.h" +#include "libfrr.h" + +#include "ripd/ripd.h" +#include "ripd/rip_cli.h" + +/* + * XPath: /frr-ripd:ripd/instance + */ +static int ripd_instance_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +static int ripd_instance_delete(enum nb_event event, + const struct lyd_node *dnode) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-ripd:ripd/instance/allow-ecmp + */ +static int ripd_instance_allow_ecmp_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-ripd:ripd/instance/default-information-originate + */ +static int +ripd_instance_default_information_originate_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-ripd:ripd/instance/default-metric + */ +static int ripd_instance_default_metric_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-ripd:ripd/instance/distance/default + */ +static int ripd_instance_distance_default_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-ripd:ripd/instance/distance/source + */ +static int ripd_instance_distance_source_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +static int ripd_instance_distance_source_delete(enum nb_event event, + const struct lyd_node *dnode) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-ripd:ripd/instance/distance/source/distance + */ +static int +ripd_instance_distance_source_distance_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-ripd:ripd/instance/distance/source/access-list + */ +static int +ripd_instance_distance_source_access_list_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +static int +ripd_instance_distance_source_access_list_delete(enum nb_event event, + const struct lyd_node *dnode) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-ripd:ripd/instance/explicit-neighbor + */ +static int ripd_instance_explicit_neighbor_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +static int ripd_instance_explicit_neighbor_delete(enum nb_event event, + const struct lyd_node *dnode) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-ripd:ripd/instance/network + */ +static int ripd_instance_network_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +static int ripd_instance_network_delete(enum nb_event event, + const struct lyd_node *dnode) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-ripd:ripd/instance/interface + */ +static int ripd_instance_interface_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +static int ripd_instance_interface_delete(enum nb_event event, + const struct lyd_node *dnode) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-ripd:ripd/instance/offset-list + */ +static int ripd_instance_offset_list_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +static int ripd_instance_offset_list_delete(enum nb_event event, + const struct lyd_node *dnode) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-ripd:ripd/instance/offset-list/access-list + */ +static int +ripd_instance_offset_list_access_list_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-ripd:ripd/instance/offset-list/metric + */ +static int ripd_instance_offset_list_metric_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-ripd:ripd/instance/passive-default + */ +static int ripd_instance_passive_default_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-ripd:ripd/instance/passive-interface + */ +static int ripd_instance_passive_interface_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +static int ripd_instance_passive_interface_delete(enum nb_event event, + const struct lyd_node *dnode) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-ripd:ripd/instance/non-passive-interface + */ +static int +ripd_instance_non_passive_interface_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +static int +ripd_instance_non_passive_interface_delete(enum nb_event event, + const struct lyd_node *dnode) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-ripd:ripd/instance/redistribute + */ +static int ripd_instance_redistribute_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +static int ripd_instance_redistribute_delete(enum nb_event event, + const struct lyd_node *dnode) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-ripd:ripd/instance/redistribute/route-map + */ +static int +ripd_instance_redistribute_route_map_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +static int +ripd_instance_redistribute_route_map_delete(enum nb_event event, + const struct lyd_node *dnode) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-ripd:ripd/instance/redistribute/metric + */ +static int +ripd_instance_redistribute_metric_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +static int +ripd_instance_redistribute_metric_delete(enum nb_event event, + const struct lyd_node *dnode) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-ripd:ripd/instance/static-route + */ +static int ripd_instance_static_route_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +static int ripd_instance_static_route_delete(enum nb_event event, + const struct lyd_node *dnode) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-ripd:ripd/instance/timers/flush-interval + */ +static int +ripd_instance_timers_flush_interval_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-ripd:ripd/instance/timers/holddown-interval + */ +static int +ripd_instance_timers_holddown_interval_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-ripd:ripd/instance/timers/update-interval + */ +static int +ripd_instance_timers_update_interval_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-ripd:ripd/instance/version/receive + */ +static int ripd_instance_version_receive_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-ripd:ripd/instance/version/send + */ +static int ripd_instance_version_send_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-ripd:rip/split-horizon + */ +static int lib_interface_rip_split_horizon_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-ripd:rip/v2-broadcast + */ +static int lib_interface_rip_v2_broadcast_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-ripd:rip/version-receive + */ +static int +lib_interface_rip_version_receive_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-ripd:rip/version-send + */ +static int lib_interface_rip_version_send_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-ripd:rip/authentication-scheme/mode + */ +static int lib_interface_rip_authentication_scheme_mode_modify( + enum nb_event event, const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-ripd:rip/authentication-scheme/md5-auth-length + */ +static int lib_interface_rip_authentication_scheme_md5_auth_length_modify( + enum nb_event event, const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +static int lib_interface_rip_authentication_scheme_md5_auth_length_delete( + enum nb_event event, const struct lyd_node *dnode) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-ripd:rip/authentication-password + */ +static int +lib_interface_rip_authentication_password_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +static int +lib_interface_rip_authentication_password_delete(enum nb_event event, + const struct lyd_node *dnode) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-ripd:rip/authentication-key-chain + */ +static int +lib_interface_rip_authentication_key_chain_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + /* TODO: implement me. */ + return NB_OK; +} + +static int +lib_interface_rip_authentication_key_chain_delete(enum nb_event event, + const struct lyd_node *dnode) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* + * XPath: /frr-ripd:ripd/state/neighbors/neighbor + */ +static const void * +ripd_state_neighbors_neighbor_get_next(const char *xpath, + const void *list_entry) +{ + /* TODO: implement me. */ + return NULL; +} + +static int ripd_state_neighbors_neighbor_get_keys(const void *list_entry, + struct yang_list_keys *keys) +{ + /* TODO: implement me. */ + return NB_OK; +} + +static const void * +ripd_state_neighbors_neighbor_lookup_entry(const struct yang_list_keys *keys) +{ + /* TODO: implement me. */ + return NULL; +} + +/* + * XPath: /frr-ripd:ripd/state/neighbors/neighbor/address + */ +static struct yang_data * +ripd_state_neighbors_neighbor_address_get_elem(const char *xpath, + const void *list_entry) +{ + /* TODO: implement me. */ + return NULL; +} + +/* + * XPath: /frr-ripd:ripd/state/neighbors/neighbor/last-update + */ +static struct yang_data * +ripd_state_neighbors_neighbor_last_update_get_elem(const char *xpath, + const void *list_entry) +{ + /* TODO: implement me. */ + return NULL; +} + +/* + * XPath: /frr-ripd:ripd/state/neighbors/neighbor/bad-packets-rcvd + */ +static struct yang_data * +ripd_state_neighbors_neighbor_bad_packets_rcvd_get_elem(const char *xpath, + const void *list_entry) +{ + /* TODO: implement me. */ + return NULL; +} + +/* + * XPath: /frr-ripd:ripd/state/neighbors/neighbor/bad-routes-rcvd + */ +static struct yang_data * +ripd_state_neighbors_neighbor_bad_routes_rcvd_get_elem(const char *xpath, + const void *list_entry) +{ + /* TODO: implement me. */ + return NULL; +} + +/* + * XPath: /frr-ripd:ripd/state/routes/route + */ +static const void *ripd_state_routes_route_get_next(const char *xpath, + const void *list_entry) +{ + /* TODO: implement me. */ + return NULL; +} + +static int ripd_state_routes_route_get_keys(const void *list_entry, + struct yang_list_keys *keys) +{ + /* TODO: implement me. */ + return NB_OK; +} + +static const void * +ripd_state_routes_route_lookup_entry(const struct yang_list_keys *keys) +{ + /* TODO: implement me. */ + return NULL; +} + +/* + * XPath: /frr-ripd:ripd/state/routes/route/prefix + */ +static struct yang_data * +ripd_state_routes_route_prefix_get_elem(const char *xpath, + const void *list_entry) +{ + /* TODO: implement me. */ + return NULL; +} + +/* + * XPath: /frr-ripd:ripd/state/routes/route/next-hop + */ +static struct yang_data * +ripd_state_routes_route_next_hop_get_elem(const char *xpath, + const void *list_entry) +{ + /* TODO: implement me. */ + return NULL; +} + +/* + * XPath: /frr-ripd:ripd/state/routes/route/interface + */ +static struct yang_data * +ripd_state_routes_route_interface_get_elem(const char *xpath, + const void *list_entry) +{ + /* TODO: implement me. */ + return NULL; +} + +/* + * XPath: /frr-ripd:ripd/state/routes/route/metric + */ +static struct yang_data * +ripd_state_routes_route_metric_get_elem(const char *xpath, + const void *list_entry) +{ + /* TODO: implement me. */ + return NULL; +} + +/* + * XPath: /frr-ripd:clear-rip-route + */ +static int clear_rip_route_rpc(const char *xpath, const struct list *input, + struct list *output) +{ + /* TODO: implement me. */ + return NB_OK; +} + +/* clang-format off */ +const struct frr_yang_module_info frr_ripd_info = { + .name = "frr-ripd", + .nodes = { + { + .xpath = "/frr-ripd:ripd/instance", + .cbs.create = ripd_instance_create, + .cbs.delete = ripd_instance_delete, + }, + { + .xpath = "/frr-ripd:ripd/instance/allow-ecmp", + .cbs.modify = ripd_instance_allow_ecmp_modify, + }, + { + .xpath = "/frr-ripd:ripd/instance/default-information-originate", + .cbs.modify = ripd_instance_default_information_originate_modify, + }, + { + .xpath = "/frr-ripd:ripd/instance/default-metric", + .cbs.modify = ripd_instance_default_metric_modify, + }, + { + .xpath = "/frr-ripd:ripd/instance/distance/default", + .cbs.modify = ripd_instance_distance_default_modify, + }, + { + .xpath = "/frr-ripd:ripd/instance/distance/source", + .cbs.create = ripd_instance_distance_source_create, + .cbs.delete = ripd_instance_distance_source_delete, + }, + { + .xpath = "/frr-ripd:ripd/instance/distance/source/distance", + .cbs.modify = ripd_instance_distance_source_distance_modify, + }, + { + .xpath = "/frr-ripd:ripd/instance/distance/source/access-list", + .cbs.modify = ripd_instance_distance_source_access_list_modify, + .cbs.delete = ripd_instance_distance_source_access_list_delete, + }, + { + .xpath = "/frr-ripd:ripd/instance/explicit-neighbor", + .cbs.create = ripd_instance_explicit_neighbor_create, + .cbs.delete = ripd_instance_explicit_neighbor_delete, + }, + { + .xpath = "/frr-ripd:ripd/instance/network", + .cbs.create = ripd_instance_network_create, + .cbs.delete = ripd_instance_network_delete, + }, + { + .xpath = "/frr-ripd:ripd/instance/interface", + .cbs.create = ripd_instance_interface_create, + .cbs.delete = ripd_instance_interface_delete, + }, + { + .xpath = "/frr-ripd:ripd/instance/offset-list", + .cbs.create = ripd_instance_offset_list_create, + .cbs.delete = ripd_instance_offset_list_delete, + }, + { + .xpath = "/frr-ripd:ripd/instance/offset-list/access-list", + .cbs.modify = ripd_instance_offset_list_access_list_modify, + }, + { + .xpath = "/frr-ripd:ripd/instance/offset-list/metric", + .cbs.modify = ripd_instance_offset_list_metric_modify, + }, + { + .xpath = "/frr-ripd:ripd/instance/passive-default", + .cbs.modify = ripd_instance_passive_default_modify, + }, + { + .xpath = "/frr-ripd:ripd/instance/passive-interface", + .cbs.create = ripd_instance_passive_interface_create, + .cbs.delete = ripd_instance_passive_interface_delete, + }, + { + .xpath = "/frr-ripd:ripd/instance/non-passive-interface", + .cbs.create = ripd_instance_non_passive_interface_create, + .cbs.delete = ripd_instance_non_passive_interface_delete, + }, + { + .xpath = "/frr-ripd:ripd/instance/redistribute", + .cbs.create = ripd_instance_redistribute_create, + .cbs.delete = ripd_instance_redistribute_delete, + }, + { + .xpath = "/frr-ripd:ripd/instance/redistribute/route-map", + .cbs.modify = ripd_instance_redistribute_route_map_modify, + .cbs.delete = ripd_instance_redistribute_route_map_delete, + }, + { + .xpath = "/frr-ripd:ripd/instance/redistribute/metric", + .cbs.modify = ripd_instance_redistribute_metric_modify, + .cbs.delete = ripd_instance_redistribute_metric_delete, + }, + { + .xpath = "/frr-ripd:ripd/instance/static-route", + .cbs.create = ripd_instance_static_route_create, + .cbs.delete = ripd_instance_static_route_delete, + }, + { + .xpath = "/frr-ripd:ripd/instance/timers/flush-interval", + .cbs.modify = ripd_instance_timers_flush_interval_modify, + }, + { + .xpath = "/frr-ripd:ripd/instance/timers/holddown-interval", + .cbs.modify = ripd_instance_timers_holddown_interval_modify, + }, + { + .xpath = "/frr-ripd:ripd/instance/timers/update-interval", + .cbs.modify = ripd_instance_timers_update_interval_modify, + }, + { + .xpath = "/frr-ripd:ripd/instance/version/receive", + .cbs.modify = ripd_instance_version_receive_modify, + }, + { + .xpath = "/frr-ripd:ripd/instance/version/send", + .cbs.modify = ripd_instance_version_send_modify, + }, + { + .xpath = "/frr-interface:lib/interface/frr-ripd:rip/split-horizon", + .cbs.modify = lib_interface_rip_split_horizon_modify, + }, + { + .xpath = "/frr-interface:lib/interface/frr-ripd:rip/v2-broadcast", + .cbs.modify = lib_interface_rip_v2_broadcast_modify, + }, + { + .xpath = "/frr-interface:lib/interface/frr-ripd:rip/version-receive", + .cbs.modify = lib_interface_rip_version_receive_modify, + }, + { + .xpath = "/frr-interface:lib/interface/frr-ripd:rip/version-send", + .cbs.modify = lib_interface_rip_version_send_modify, + }, + { + .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-scheme/mode", + .cbs.modify = lib_interface_rip_authentication_scheme_mode_modify, + }, + { + .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-scheme/md5-auth-length", + .cbs.modify = lib_interface_rip_authentication_scheme_md5_auth_length_modify, + .cbs.delete = lib_interface_rip_authentication_scheme_md5_auth_length_delete, + }, + { + .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-password", + .cbs.modify = lib_interface_rip_authentication_password_modify, + .cbs.delete = lib_interface_rip_authentication_password_delete, + }, + { + .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-key-chain", + .cbs.modify = lib_interface_rip_authentication_key_chain_modify, + .cbs.delete = lib_interface_rip_authentication_key_chain_delete, + }, + { + .xpath = "/frr-ripd:ripd/state/neighbors/neighbor", + .cbs.get_next = ripd_state_neighbors_neighbor_get_next, + .cbs.get_keys = ripd_state_neighbors_neighbor_get_keys, + .cbs.lookup_entry = ripd_state_neighbors_neighbor_lookup_entry, + }, + { + .xpath = "/frr-ripd:ripd/state/neighbors/neighbor/address", + .cbs.get_elem = ripd_state_neighbors_neighbor_address_get_elem, + }, + { + .xpath = "/frr-ripd:ripd/state/neighbors/neighbor/last-update", + .cbs.get_elem = ripd_state_neighbors_neighbor_last_update_get_elem, + }, + { + .xpath = "/frr-ripd:ripd/state/neighbors/neighbor/bad-packets-rcvd", + .cbs.get_elem = ripd_state_neighbors_neighbor_bad_packets_rcvd_get_elem, + }, + { + .xpath = "/frr-ripd:ripd/state/neighbors/neighbor/bad-routes-rcvd", + .cbs.get_elem = ripd_state_neighbors_neighbor_bad_routes_rcvd_get_elem, + }, + { + .xpath = "/frr-ripd:ripd/state/routes/route", + .cbs.get_next = ripd_state_routes_route_get_next, + .cbs.get_keys = ripd_state_routes_route_get_keys, + .cbs.lookup_entry = ripd_state_routes_route_lookup_entry, + }, + { + .xpath = "/frr-ripd:ripd/state/routes/route/prefix", + .cbs.get_elem = ripd_state_routes_route_prefix_get_elem, + }, + { + .xpath = "/frr-ripd:ripd/state/routes/route/next-hop", + .cbs.get_elem = ripd_state_routes_route_next_hop_get_elem, + }, + { + .xpath = "/frr-ripd:ripd/state/routes/route/interface", + .cbs.get_elem = ripd_state_routes_route_interface_get_elem, + }, + { + .xpath = "/frr-ripd:ripd/state/routes/route/metric", + .cbs.get_elem = ripd_state_routes_route_metric_get_elem, + }, + { + .xpath = "/frr-ripd:clear-rip-route", + .cbs.rpc = clear_rip_route_rpc, + }, + { + .xpath = NULL, + }, + } +}; diff --git a/ripd/ripd.h b/ripd/ripd.h index 784b06460..78a204eb7 100644 --- a/ripd/ripd.h +++ b/ripd/ripd.h @@ -98,6 +98,10 @@ #define RIP_AUTH_MD5_SIZE 16 #define RIP_AUTH_MD5_COMPAT_SIZE RIP_RTE_SIZE +/* YANG paths */ +#define RIP_INSTANCE "/frr-ripd:ripd/instance" +#define RIP_IFACE "/frr-interface:lib/interface/frr-ripd:rip" + /* RIP structure. */ struct rip { /* RIP socket. */ @@ -437,4 +441,8 @@ extern long rip_global_queries; DECLARE_HOOK(rip_ifaddr_add, (struct connected * ifc), (ifc)) DECLARE_HOOK(rip_ifaddr_del, (struct connected * ifc), (ifc)) +/* Northbound. */ +extern void rip_cli_init(void); +extern const struct frr_yang_module_info frr_ripd_info; + #endif /* _ZEBRA_RIP_H */ diff --git a/ripd/subdir.am b/ripd/subdir.am index 0d06e7e65..480fa1e47 100644 --- a/ripd/subdir.am +++ b/ripd/subdir.am @@ -7,6 +7,7 @@ noinst_LIBRARIES += ripd/librip.a sbin_PROGRAMS += ripd/ripd dist_examples_DATA += ripd/ripd.conf.sample vtysh_scan += \ + $(top_srcdir)/ripd/rip_cli.c \ $(top_srcdir)/ripd/rip_debug.c \ $(top_srcdir)/ripd/rip_interface.c \ $(top_srcdir)/ripd/rip_offset.c \ @@ -21,18 +22,24 @@ man8 += $(MANBUILD)/ripd.8 endif ripd_librip_a_SOURCES = \ + ripd/rip_cli.c \ ripd/rip_debug.c \ ripd/rip_errors.c \ ripd/rip_interface.c \ ripd/rip_memory.c \ ripd/rip_offset.c \ + ripd/rip_northbound.c \ ripd/rip_peer.c \ ripd/rip_routemap.c \ ripd/rip_zebra.c \ ripd/ripd.c \ # end +ripd/rip_cli_clippy.c: $(CLIPPY_DEPS) +ripd/rip_cli.$(OBJEXT): ripd/rip_cli_clippy.c + noinst_HEADERS += \ + ripd/rip_cli.h \ ripd/rip_debug.h \ ripd/rip_errors.h \ ripd/rip_interface.h \ diff --git a/yang/confd/confd.frr-ripd.yang b/yang/confd/confd.frr-ripd.yang new file mode 100644 index 000000000..9b21c0756 --- /dev/null +++ b/yang/confd/confd.frr-ripd.yang @@ -0,0 +1,22 @@ +module confd.frr-ripd { + namespace "urn:dummy"; + prefix "dummy"; + + import tailf-common { + prefix tailf; + } + import frr-ripd { + prefix frr-ripd; + } + + tailf:annotate-module "frr-ripd" { + tailf:annotate-statement "container[name='ripd']" { + tailf:annotate-statement "container[name='state']" { + tailf:callpoint "state"; + } + } + tailf:annotate-statement "rpc[name='clear-rip-route']" { + tailf:actionpoint "actionpoint"; + } + } +} diff --git a/yang/example/ripd.json b/yang/example/ripd.json new file mode 100644 index 000000000..888c52b93 --- /dev/null +++ b/yang/example/ripd.json @@ -0,0 +1,44 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth0", + "vrf": "default", + "description": "engineering", + "frr-ripd:rip": { + "split-horizon": "poison-reverse", + "v2-broadcast": "true", + "version-receive": "1", + "version-send": "1" + } + }, + { + "name": "eth1", + "vrf": "default", + "description": "marketing" + } + ] + }, + "frr-ripd:ripd": { + "instance": { + "allow-ecmp": "true", + "distance": { + "source": [ + { + "prefix": "172.16.1.0/24", + "distance": "25" + } + ] + }, + "redistribute": [ + { + "protocol": "ospf", + "metric": "3" + } + ], + "static-route": [ + "10.0.1.0/24" + ] + } + } +} diff --git a/yang/example/ripd.xml b/yang/example/ripd.xml new file mode 100644 index 000000000..756e382bd --- /dev/null +++ b/yang/example/ripd.xml @@ -0,0 +1,34 @@ + + + eth0 + default + engineering + + poison-reverse + 1 + 1 + true + + + + eth1 + default + marketing + + + + + true + 10.0.1.0/24 + + + 172.16.1.0/24 + 25 + + + + ospf + 3 + + + diff --git a/yang/frr-ripd.yang b/yang/frr-ripd.yang new file mode 100644 index 000000000..8073fba77 --- /dev/null +++ b/yang/frr-ripd.yang @@ -0,0 +1,587 @@ +module frr-ripd { + yang-version 1.1; + namespace "http://frrouting.org/yang/ripd"; + prefix frr-ripd; + + import ietf-inet-types { + prefix inet; + } + import ietf-yang-types { + prefix yang; + } + import frr-interface { + prefix frr-interface; + } + import frr-route-types { + prefix frr-route-types; + } + + organization + "Free Range Routing"; + contact + "FRR Users List: + FRR Development List: "; + description + "This module defines a model for managing FRR ripd daemon."; + + revision 2017-12-06 { + description + "Initial revision."; + reference + "RFC 1058: Routing Information Protocol. + RFC 2453: RIP Version 2."; + } + + container ripd { + /* + * Global configuration data + */ + container instance { + presence "Present if the RIP protocol is enabled."; + description + "RIP routing instance."; + + leaf allow-ecmp { + type boolean; + default "false"; + description + "Allow equal-cost multi-path."; + } + leaf default-information-originate { + type boolean; + default "false"; + description + "Control distribution of default route."; + } + leaf default-metric { + type uint8 { + range "1..16"; + } + default "1"; + description + "Default metric of redistributed routes."; + } + container distance { + description + "Administrative distance."; + leaf default { + type uint8 { + range "0..255"; + } + default "0"; + description + "Default administrative distance."; + } + list source { + key "prefix"; + description + "Custom administrative distance per IP prefix."; + leaf prefix { + type inet:ipv4-prefix; + description + "Prefix."; + } + leaf distance { + type uint8 { + range "1..255"; + } + mandatory true; + description + "Administrative distance."; + } + leaf access-list { + type string; + description + "Access-list name."; + } + } + } + leaf-list explicit-neighbor { + type inet:ipv4-address; + description + "Specifies the RIP neighbors. Useful for a + non-broadcast multiple access (NBMA) network."; + } + leaf-list network { + type inet:ipv4-prefix; + description + "Enable RIP on the specified IP network."; + } + leaf-list interface { + type string { + length "1..16"; + } + description + "Enable RIP on the specified interface."; + } + list offset-list { + key "interface direction"; + description + "Offset-list to modify route metric."; + leaf interface { + type string; + description + "Interface to match. Use '*' to match all interfaces."; + } + leaf direction { + type enumeration { + enum in { + value 0; + description + "Incoming updates."; + } + enum out { + value 1; + description + "Outgoing updates."; + } + } + description + "Incoming or outgoing updates."; + } + leaf access-list { + type string; + mandatory true; + description + "Access-list name."; + } + leaf metric { + type uint8 { + range "0..16"; + } + mandatory true; + description + "Route metric."; + } + } + leaf passive-default { + type boolean; + default "false"; + description + "Control whether interfaces are in the passive mode + by default or not."; + } + leaf-list passive-interface { + when "../passive-default = 'false'"; + type string { + length "1..16"; + } + description + "A list of interfaces where the sending of RIP packets + is disabled."; + } + leaf-list non-passive-interface { + when "../passive-default = 'true'"; + type string { + length "1..16"; + } + description + "A list of interfaces where the sending of RIP packets + is enabled."; + } + list redistribute { + key "protocol"; + description + "Redistributes routes learned from other routing protocols."; + leaf protocol { + type frr-route-types:frr-route-types-v4; + description + "Routing protocol."; + must '. != "rip"'; + } + leaf route-map { + type string { + length "1..max"; + } + description + "Applies the conditions of the specified route-map to + routes that are redistributed into the RIP routing + instance."; + } + leaf metric { + type uint8 { + range "0..16"; + } + description + "Metric used for the redistributed route. If a metric is + not specified, the metric configured with the + default-metric attribute in RIP router configuration is + used. If the default-metric attribute has not been + configured, the default metric for redistributed routes + is 0."; + } + } + leaf-list static-route { + type inet:ipv4-prefix; + description + "RIP static routes."; + } + container timers { + description + "Settings of basic timers"; + leaf flush-interval { + type uint32 { + range "5..2147483647"; + } + units "seconds"; + default "120"; + description + "Interval before a route is flushed from the routing + table."; + } + leaf holddown-interval { + type uint32 { + range "5..2147483647"; + } + units "seconds"; + default "180"; + description + "Interval before better routes are released."; + } + leaf update-interval { + type uint32 { + range "5..2147483647"; + } + units "seconds"; + default "30"; + description + "Interval at which RIP updates are sent."; + } + } + container version { + leaf receive { + type enumeration { + enum "1" { + value 1; + description + "Accept RIPv1 updates only."; + } + enum "2" { + value 2; + description + "Accept RIPv2 updates only."; + } + enum "1-2" { + value 3; + description + "Accept both RIPv1 and RIPv2 updates."; + } + } + default "1-2"; + description + "Advertisement reception - Version control."; + } + leaf send { + type enumeration { + enum "1" { + value 1; + description + "Send RIPv1 updates only."; + } + enum "2" { + value 2; + description + "Send RIPv2 updates only."; + } + } + default "2"; + description + "Advertisement transmission - Version control."; + } + must + '(./receive = "1" and ./send = "1") or ' + + '(./receive = "2" and ./send = "2") or ' + + '(./receive = "1-2" and ./send = "2")'; + } + } + + /* + * Operational data. + */ + container state { + config false; + description + "Operational data."; + + container neighbors { + description + "Neighbor information."; + list neighbor { + key "address"; + description + "A RIP neighbor."; + leaf address { + type inet:ipv4-address; + description + "IP address that a RIP neighbor is using as its + source address."; + } + leaf last-update { + type yang:date-and-time; + description + "The time when the most recent RIP update was + received from this neighbor."; + } + leaf bad-packets-rcvd { + type yang:counter32; + description + "The number of RIP invalid packets received from + this neighbor which were subsequently discarded + for any reason (e.g. a version 0 packet, or an + unknown command type)."; + } + leaf bad-routes-rcvd { + type yang:counter32; + description + "The number of routes received from this neighbor, + in valid RIP packets, which were ignored for any + reason (e.g. unknown address family, or invalid + metric)."; + } + } + } + container routes { + description + "Route information."; + list route { + key "prefix"; + description + "A RIP IPv4 route."; + leaf prefix { + type inet:ipv4-prefix; + description + "IP address (in the form A.B.C.D) and prefix length, + separated by the slash (/) character. The range of + values for the prefix-length is 0 to 32."; + } + leaf next-hop { + type inet:ipv4-address; + description + "Next hop IPv4 address."; + } + leaf interface { + type string; + description + "The interface that the route uses."; + } + leaf metric { + type uint8 { + range "0..16"; + } + description + "Route metric."; + } + } + } + } + } + + /* + * Per-interface configuration data + */ + augment "/frr-interface:lib/frr-interface:interface" { + container rip { + description + "RIP interface parameters."; + leaf split-horizon { + type enumeration { + enum "disabled" { + value 0; + description + "Disables split-horizon processing."; + } + enum "simple" { + value 1; + description + "Enables simple split-horizon processing."; + } + enum "poison-reverse" { + value 2; + description + "Enables split-horizon processing with poison + reverse."; + } + } + default "simple"; + description + "Controls RIP split-horizon processing on the specified + interface."; + } + leaf v2-broadcast { + type boolean; + default "false"; + description + "Send IP broadcast v2 update."; + } + leaf version-receive { + type enumeration { + enum "unspecified" { + value 0; + description + "Inherit configuration from the routing instance."; + } + enum "1" { + value 1; + description + "Accept RIPv1 updates only."; + } + enum "2" { + value 2; + description + "Accept RIPv2 updates only."; + } + enum "both" { + value 3; + description + "Accept both RIPv1 and RIPv2 updates."; + } + enum "none" { + value 4; + description + "Do not accept neither RIPv1 nor RIPv2 updates."; + } + } + default "unspecified"; + description + "Advertisement reception - Version control."; + } + leaf version-send { + type enumeration { + enum "unspecified" { + value 0; + description + "Inherit configuration from the routing instance."; + } + enum "1" { + value 1; + description + "Send RIPv1 updates only."; + } + enum "2" { + value 2; + description + "Send RIPv2 updates only."; + } + enum "both" { + value 3; + description + "Send both RIPv1 and RIPv2 updates."; + } + enum "none" { + value 4; + description + "Do not send neither RIPv1 nor RIPv2 updates."; + } + } + default "unspecified"; + description + "Advertisement transmission - Version control."; + } + container authentication-scheme { + description + "Specify the authentication scheme for the RIP interface"; + leaf mode { + type enumeration { + enum "none" { + value 0; + description + "No authentication."; + } + enum "plain-text" { + value 2; + description + "Plain-text authentication."; + } + enum "md5" { + value 3; + description + "MD5 authentication."; + } + } + default "none"; + description + "Specify the authentication mode."; + } + leaf md5-auth-length { + when "../mode = 'md5'"; + type enumeration { + enum "16" { + value 16; + description + "RFC compatible."; + } + enum "20" { + value 20; + description + "Old ripd compatible."; + } + } + default "20"; + description + "MD5 authentication data length."; + } + } + choice authentication-data { + description + "Choose whether to use a simple password or a key-chain."; + leaf authentication-password { + type string { + length "1..16"; + } + description + "Authentication string."; + } + leaf authentication-key-chain { + type string; + description + "Key-chain name."; + } + } + } + } + + /* + * RPCs + */ + rpc clear-rip-route { + description + "Clears RIP routes from the IP routing table and routes + redistributed into the RIP protocol."; + } + + /* + * Notifications + */ + notification authentication-type-failure { + description + "This notification is sent when the system + receives a PDU with the wrong authentication type + field."; + leaf interface-name { + type string; + description + "Describes the name of the RIP interface."; + } + leaf raw-pdu { + type binary; + description + "Received raw PDU."; + } + } + notification authentication-failure { + description + "This notification is sent when the system + receives a PDU with the wrong authentication + information."; + leaf interface-name { + type string; + description + "Describes the name of the RIP interface."; + } + leaf raw-pdu { + type binary; + description + "Received raw PDU."; + } + } +} diff --git a/yang/frr-route-types.yang b/yang/frr-route-types.yang new file mode 100644 index 000000000..f22c5ef89 --- /dev/null +++ b/yang/frr-route-types.yang @@ -0,0 +1,109 @@ +module frr-route-types { + yang-version 1.1; + namespace "http://frrouting.org/yang/route-types"; + prefix frr-route-types; + + organization + "Free Range Routing"; + contact + "FRR Users List: + FRR Development List: "; + description + "This module defines typedefs for route types."; + + revision 2018-03-28 { + description + "Initial revision."; + } + + typedef frr-route-types-v4 { + type enumeration { + enum kernel { + value 1; + } + enum connected { + value 2; + } + enum static { + value 3; + } + enum rip { + value 4; + } + enum ospf { + value 6; + } + enum isis { + value 8; + } + enum bgp { + value 9; + } + enum eigrp { + value 11; + } + enum nhrp { + value 12; + } + enum table { + value 15; + } + enum vnc { + value 17; + } + enum babel { + value 22; + } + enum sharp { + value 23; + } + enum openfabric { + value 26; + } + } + } + + typedef frr-route-types-v6 { + type enumeration { + enum kernel { + value 1; + } + enum connected { + value 2; + } + enum static { + value 3; + } + enum ripng { + value 5; + } + enum ospf6 { + value 7; + } + enum isis { + value 8; + } + enum bgp { + value 9; + } + enum nhrp { + value 12; + } + enum table { + value 15; + } + enum vnc { + value 17; + } + enum babel { + value 22; + } + enum sharp { + value 23; + } + enum openfabric { + value 26; + } + } + } +} diff --git a/yang/subdir.am b/yang/subdir.am index 8e9f83c3e..d68a341a9 100644 --- a/yang/subdir.am +++ b/yang/subdir.am @@ -1,2 +1,7 @@ dist_yangmodels_DATA += yang/frr-module-translator.yang dist_yangmodels_DATA += yang/frr-interface.yang +dist_yangmodels_DATA += yang/frr-route-types.yang + +if RIPD +dist_yangmodels_DATA += yang/frr-ripd.yang +endif -- 2.39.5