diff options
37 files changed, 2179 insertions, 1616 deletions
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index cedca17729..62d3c2350c 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,3 +1,12 @@ +# HOW TO GET YOUR ISSUE ADDRESSED FASTER + +* When reporting a crash provide a backtrace +* When pasting configs, logs, shell output, backtraces, and other large chunks + of text [use Markdown code blocks](https://github.github.com/gfm/#fenced-code-blocks) +* Include the FRR version; if you built from Git, please provide the commit + hash +* Write your issue in English + ### How to submit an issue Please use this text as a template and replace text in the sections or remove the entire section if it does not apply to your issue. For example in case of diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index c69997a41d..b614e87d23 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -418,7 +418,8 @@ static void revalidate_bgp_node(struct bgp_node *bgp_node, afi_t afi, for (ain = bgp_node->adj_in; ain; ain = ain->next) { int ret; - struct bgp_path_info *path = bgp_info_from_node(bgp_node); + struct bgp_path_info *path = + bgp_node_get_bgp_path_info(bgp_node); mpls_label_t *label = NULL; uint32_t num_labels = 0; diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c index e9ba93bbd4..c1321dd7dc 100644 --- a/bgpd/bgp_snmp.c +++ b/bgpd/bgp_snmp.c @@ -715,7 +715,7 @@ static struct bgp_path_info *bgp4PathAttrLookup(struct variable *v, oid name[], if (rn) { bgp_unlock_node(rn); - for (path = bgp_info_from_node(rn); path; + for (path = bgp_node_get_bgp_path_info(rn); path; path = path->next) if (sockunion_same(&path->peer->su, &su)) return path; @@ -763,7 +763,7 @@ static struct bgp_path_info *bgp4PathAttrLookup(struct variable *v, oid name[], do { min = NULL; - for (path = bgp_info_from_node(rn); path; + for (path = bgp_node_get_bgp_path_info(rn); path; path = path->next) { if (path->peer->su.sin.sin_family == AF_INET && ntohl(paddr.s_addr) diff --git a/fpm/subdir.am b/fpm/subdir.am index 05cec5a528..a0fa3d274f 100644 --- a/fpm/subdir.am +++ b/fpm/subdir.am @@ -1,6 +1,8 @@ if FPM +if HAVE_PROTOBUF lib_LTLIBRARIES += fpm/libfrrfpm_pb.la endif +endif fpm_libfrrfpm_pb_la_LDFLAGS = -version-info 0:0:0 fpm_libfrrfpm_pb_la_CPPFLAGS = $(AM_CPPFLAGS) $(PROTOBUF_C_CFLAGS) @@ -10,11 +12,9 @@ fpm_libfrrfpm_pb_la_SOURCES = \ fpm/fpm_pb.c \ # end -if HAVE_PROTOBUF nodist_fpm_libfrrfpm_pb_la_SOURCES = \ fpm/fpm.pb-c.c \ # end -endif CLEANFILES += \ fpm/fpm.pb-c.c \ diff --git a/lib/northbound.c b/lib/northbound.c index 8b96dc4a6c..09aa60b1d2 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -1071,7 +1071,7 @@ static int nb_oper_data_iter_list(const struct nb_node *nb_node, /* Iterate over all list entries. */ do { struct yang_list_keys list_keys; - char xpath[XPATH_MAXLEN]; + char xpath[XPATH_MAXLEN * 2]; int ret; /* Obtain list entry. */ diff --git a/lib/yang.c b/lib/yang.c index 462e693549..780b986103 100644 --- a/lib/yang.c +++ b/lib/yang.c @@ -74,6 +74,7 @@ static const char *yang_module_imp_clb(const char *mod_name, static const char * const frr_native_modules[] = { "frr-interface", "frr-ripd", + "frr-ripngd", }; /* Generate the yang_modules tree. */ diff --git a/lib/zebra.h b/lib/zebra.h index 46721cc1ab..0f3f45f7ba 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -410,18 +410,47 @@ extern const char *zserv_command_string(unsigned int command); #define strmatch(a,b) (!strcmp((a), (b))) /* Zebra message flags */ + +/* + * Cause Zebra to consider this routes nexthops recursively + */ #define ZEBRA_FLAG_ALLOW_RECURSION 0x01 +/* + * This is a route that is read in on startup that was left around + * from a previous run of FRR + */ #define ZEBRA_FLAG_SELFROUTE 0x02 -#define ZEBRA_FLAG_IBGP 0x08 -#define ZEBRA_FLAG_SELECTED 0x10 -#define ZEBRA_FLAG_STATIC 0x40 -#define ZEBRA_FLAG_SCOPE_LINK 0x100 -#define ZEBRA_FLAG_FIB_OVERRIDE 0x200 -#define ZEBRA_FLAG_EVPN_ROUTE 0x400 -#define ZEBRA_FLAG_RR_USE_DISTANCE 0x800 -#define ZEBRA_FLAG_ONLINK 0x1000 -/* ZEBRA_FLAG_BLACKHOLE was 0x04 */ -/* ZEBRA_FLAG_REJECT was 0x80 */ +/* + * This flag is used to tell Zebra that the BGP route being passed + * down is a IBGP route + */ +#define ZEBRA_FLAG_IBGP 0x04 +/* + * This is a route that has been selected for FIB installation. + * This flag is set in zebra and can be passed up to routing daemons + */ +#define ZEBRA_FLAG_SELECTED 0x08 +/* + * This is a route that we are telling Zebra that this route *must* + * win and will be installed even over ZEBRA_FLAG_SELECTED + */ +#define ZEBRA_FLAG_FIB_OVERRIDE 0x10 +/* + * This flag tells Zebra that the route is a EVPN route and should + * be treated specially + */ +#define ZEBRA_FLAG_EVPN_ROUTE 0x20 +/* + * This flag tells Zebra that it should treat the distance passed + * down as an additional discriminator for route selection of the + * route entry. This mainly is used for backup static routes. + */ +#define ZEBRA_FLAG_RR_USE_DISTANCE 0x40 +/* + * This flag tells Zebra that the passed down route is ONLINK and the + * kernel install flag for it should be turned on + */ +#define ZEBRA_FLAG_ONLINK 0x80 /* Zebra FEC flags. */ #define ZEBRA_FEC_REGISTER_LABEL_INDEX 0x1 diff --git a/ripd/rip_cli.c b/ripd/rip_cli.c index e0e5d95895..5bb81ef157 100644 --- a/ripd/rip_cli.c +++ b/ripd/rip_cli.c @@ -210,7 +210,8 @@ DEFPY (rip_distance_source, { if (!no) { nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); - nb_cli_enqueue_change(vty, "./distance", NB_OP_MODIFY, NULL); + nb_cli_enqueue_change(vty, "./distance", NB_OP_MODIFY, + distance_str); nb_cli_enqueue_change(vty, "./access-list", acl ? NB_OP_MODIFY : NB_OP_DELETE, acl); } else diff --git a/ripd/rip_debug.c b/ripd/rip_debug.c index 2ce289e38f..3356d99c2a 100644 --- a/ripd/rip_debug.c +++ b/ripd/rip_debug.c @@ -204,13 +204,6 @@ static int config_write_debug(struct vty *vty) return write; } -void rip_debug_reset(void) -{ - rip_debug_event = 0; - rip_debug_packet = 0; - rip_debug_zebra = 0; -} - void rip_debug_init(void) { rip_debug_event = 0; diff --git a/ripd/rip_debug.h b/ripd/rip_debug.h index c3b15d2e15..3d819ccd0b 100644 --- a/ripd/rip_debug.h +++ b/ripd/rip_debug.h @@ -47,6 +47,5 @@ extern unsigned long rip_debug_packet; extern unsigned long rip_debug_zebra; extern void rip_debug_init(void); -extern void rip_debug_reset(void); #endif /* _ZEBRA_RIP_DEBUG_H */ diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index 3d11ba1464..96b1cd8938 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -531,15 +531,6 @@ static void rip_interface_reset(struct rip_interface *ri) rip_interface_clean(ri); } -void rip_interfaces_reset(void) -{ - struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); - struct interface *ifp; - - FOR_ALL_INTERFACES (vrf, ifp) - rip_interface_reset(ifp->info); -} - int rip_if_down(struct interface *ifp) { struct route_node *rp; diff --git a/ripd/rip_northbound.c b/ripd/rip_northbound.c index 421b0afe38..4e445bd46d 100644 --- a/ripd/rip_northbound.c +++ b/ripd/rip_northbound.c @@ -170,6 +170,7 @@ static int ripd_instance_distance_source_create(enum nb_event event, return NB_OK; yang_dnode_get_ipv4p(&prefix, dnode, "./prefix"); + apply_mask_ipv4(&prefix); /* Get RIP distance node. */ rn = route_node_get(rip_distance_table, (struct prefix *)&prefix); @@ -317,6 +318,7 @@ static int ripd_instance_network_create(enum nb_event event, return NB_OK; yang_dnode_get_ipv4p(&p, dnode, NULL); + apply_mask_ipv4((struct prefix_ipv4 *)&p); return rip_enable_network_add(&p); } @@ -330,6 +332,7 @@ static int ripd_instance_network_delete(enum nb_event event, return NB_OK; yang_dnode_get_ipv4p(&p, dnode, NULL); + apply_mask_ipv4((struct prefix_ipv4 *)&p); return rip_enable_network_delete(&p); } @@ -605,10 +608,9 @@ ripd_instance_redistribute_route_map_delete(enum nb_event event, type = yang_dnode_get_enum(dnode, "../protocol"); - if (rip->route_map[type].name) { - free(rip->route_map[type].name); - rip->route_map[type].name = NULL; - } + free(rip->route_map[type].name); + rip->route_map[type].name = NULL; + rip->route_map[type].map = NULL; return NB_OK; } @@ -667,6 +669,7 @@ static int ripd_instance_static_route_create(enum nb_event event, return NB_OK; yang_dnode_get_ipv4p(&p, dnode, NULL); + apply_mask_ipv4(&p); memset(&nh, 0, sizeof(nh)); nh.type = NEXTHOP_TYPE_IPV4; @@ -685,6 +688,7 @@ static int ripd_instance_static_route_delete(enum nb_event event, return NB_OK; yang_dnode_get_ipv4p(&p, dnode, NULL); + apply_mask_ipv4(&p); rip_redistribute_delete(ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0); diff --git a/ripd/rip_routemap.c b/ripd/rip_routemap.c index b69b2466d5..b34f944c9e 100644 --- a/ripd/rip_routemap.c +++ b/ripd/rip_routemap.c @@ -517,11 +517,6 @@ static struct route_map_rule_cmd route_set_tag_cmd = { #define MATCH_STR "Match values from routing table\n" #define SET_STR "Set values in destination routing protocol\n" -void rip_route_map_reset() -{ - ; -} - /* Route-map init */ void rip_route_map_init() { diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c index 20f543a258..fff8681775 100644 --- a/ripd/rip_zebra.c +++ b/ripd/rip_zebra.c @@ -147,11 +147,6 @@ static int rip_zebra_read_route(int command, struct zclient *zclient, return 0; } -void rip_zclient_reset(void) -{ - zclient_reset(zclient); -} - void rip_redistribute_conf_update(int type) { zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, type, diff --git a/ripd/ripd.h b/ripd/ripd.h index d4fb230a20..91fab2a7a2 100644 --- a/ripd/ripd.h +++ b/ripd/ripd.h @@ -376,17 +376,14 @@ extern void rip_init(void); extern void rip_clean(void); extern void rip_clean_network(void); extern void rip_interfaces_clean(void); -extern void rip_interfaces_reset(void); extern int rip_passive_nondefault_set(const char *ifname); extern int rip_passive_nondefault_unset(const char *ifname); extern void rip_passive_nondefault_clean(void); extern void rip_if_init(void); extern void rip_if_down_all(void); extern void rip_route_map_init(void); -extern void rip_route_map_reset(void); extern void rip_zclient_init(struct thread_master *); extern void rip_zclient_stop(void); -extern void rip_zclient_reset(void); extern int if_check_address(struct in_addr addr); extern int rip_create(int socket); diff --git a/ripd/subdir.am b/ripd/subdir.am index ed74047cce..90cf79178e 100644 --- a/ripd/subdir.am +++ b/ripd/subdir.am @@ -9,9 +9,6 @@ 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 \ - $(top_srcdir)/ripd/rip_zebra.c \ $(top_srcdir)/ripd/ripd.c \ # end diff --git a/ripngd/ripng_cli.c b/ripngd/ripng_cli.c new file mode 100644 index 0000000000..a187e80fd7 --- /dev/null +++ b/ripngd/ripng_cli.c @@ -0,0 +1,489 @@ +/* + * Copyright (C) 1998 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 <zebra.h> + +#include "if.h" +#include "vrf.h" +#include "log.h" +#include "prefix.h" +#include "command.h" +#include "northbound_cli.h" +#include "libfrr.h" + +#include "ripngd/ripngd.h" +#include "ripngd/ripng_cli.h" +#ifndef VTYSH_EXTRACT_PL +#include "ripngd/ripng_cli_clippy.c" +#endif + +/* + * XPath: /frr-ripngd:ripngd/instance + */ +DEFPY_NOSH (router_ripng, + router_ripng_cmd, + "router ripng", + "Enable a routing process\n" + "Make RIPng instance command\n") +{ + int ret; + + nb_cli_enqueue_change(vty, "/frr-ripngd:ripngd/instance", NB_OP_CREATE, + NULL); + + ret = nb_cli_apply_changes(vty, NULL); + if (ret == CMD_SUCCESS) + VTY_PUSH_XPATH(RIPNG_NODE, "/frr-ripngd:ripngd/instance"); + + return ret; +} + +DEFPY (no_router_ripng, + no_router_ripng_cmd, + "no router ripng", + NO_STR + "Enable a routing process\n" + "Make RIPng instance command\n") +{ + nb_cli_enqueue_change(vty, "/frr-ripngd:ripngd/instance", NB_OP_DELETE, + NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_router_ripng(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, "!\n"); + vty_out(vty, "router ripng\n"); +} + +/* + * XPath: /frr-ripngd:ripngd/instance/allow-ecmp + */ +DEFPY (ripng_allow_ecmp, + ripng_allow_ecmp_cmd, + "[no] allow-ecmp", + NO_STR + "Allow Equal Cost MultiPath\n") +{ + nb_cli_enqueue_change(vty, "./allow-ecmp", NB_OP_MODIFY, + no ? "false" : "true"); + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_ripng_allow_ecmp(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + if (!yang_dnode_get_bool(dnode, NULL)) + vty_out(vty, " no"); + + vty_out(vty, " allow-ecmp\n"); +} + +/* + * XPath: /frr-ripngd:ripngd/instance/default-information-originate + */ +DEFPY (ripng_default_information_originate, + ripng_default_information_originate_cmd, + "[no] default-information originate", + NO_STR + "Default route information\n" + "Distribute default route\n") +{ + nb_cli_enqueue_change(vty, "./default-information-originate", + NB_OP_MODIFY, no ? "false" : "true"); + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_ripng_default_information_originate(struct vty *vty, + struct lyd_node *dnode, + bool show_defaults) +{ + if (!yang_dnode_get_bool(dnode, NULL)) + vty_out(vty, " no"); + + vty_out(vty, " default-information originate\n"); +} + +/* + * XPath: /frr-ripngd:ripngd/instance/default-metric + */ +DEFPY (ripng_default_metric, + ripng_default_metric_cmd, + "default-metric (1-16)", + "Set a metric of redistribute routes\n" + "Default metric\n") +{ + nb_cli_enqueue_change(vty, "./default-metric", NB_OP_MODIFY, + default_metric_str); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY (no_ripng_default_metric, + no_ripng_default_metric_cmd, + "no default-metric [(1-16)]", + NO_STR + "Set a metric of redistribute routes\n" + "Default metric\n") +{ + nb_cli_enqueue_change(vty, "./default-metric", NB_OP_MODIFY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_ripng_default_metric(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, " default-metric %s\n", + yang_dnode_get_string(dnode, NULL)); +} + +/* + * XPath: /frr-ripngd:ripngd/instance/network + */ +DEFPY (ripng_network_prefix, + ripng_network_prefix_cmd, + "[no] network X:X::X:X/M", + NO_STR + "RIPng enable on specified interface or network.\n" + "IPv6 network\n") +{ + nb_cli_enqueue_change(vty, "./network", + no ? NB_OP_DELETE : NB_OP_CREATE, network_str); + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_ripng_network_prefix(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, " network %s\n", yang_dnode_get_string(dnode, NULL)); +} + +/* + * XPath: /frr-ripngd:ripngd/instance/interface + */ +DEFPY (ripng_network_if, + ripng_network_if_cmd, + "[no] network WORD", + NO_STR + "RIPng enable on specified interface or network.\n" + "Interface name\n") +{ + nb_cli_enqueue_change(vty, "./interface", + no ? NB_OP_DELETE : NB_OP_CREATE, network); + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_ripng_network_interface(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, " network %s\n", yang_dnode_get_string(dnode, NULL)); +} + +/* + * XPath: /frr-ripngd:ripngd/instance/offset-list + */ +DEFPY (ripng_offset_list, + ripng_offset_list_cmd, + "[no] offset-list WORD$acl <in|out>$direction (0-16)$metric [IFNAME]", + NO_STR + "Modify RIPng metric\n" + "Access-list name\n" + "For incoming updates\n" + "For outgoing updates\n" + "Metric value\n" + "Interface to match\n") +{ + if (!no) { + nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); + nb_cli_enqueue_change(vty, "./access-list", NB_OP_MODIFY, acl); + nb_cli_enqueue_change(vty, "./metric", NB_OP_MODIFY, + metric_str); + } else + nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + + return nb_cli_apply_changes( + vty, "./offset-list[interface='%s'][direction='%s']", + ifname ? ifname : "*", direction); +} + +void cli_show_ripng_offset_list(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + const char *interface; + + interface = yang_dnode_get_string(dnode, "./interface"); + + vty_out(vty, " offset-list %s %s %s", + yang_dnode_get_string(dnode, "./access-list"), + yang_dnode_get_string(dnode, "./direction"), + yang_dnode_get_string(dnode, "./metric")); + if (!strmatch(interface, "*")) + vty_out(vty, " %s", interface); + vty_out(vty, "\n"); +} + +/* + * XPath: /frr-ripngd:ripngd/instance/passive-interface + */ +DEFPY (ripng_passive_interface, + ripng_passive_interface_cmd, + "[no] passive-interface IFNAME", + NO_STR + "Suppress routing updates on an interface\n" + "Interface name\n") +{ + nb_cli_enqueue_change(vty, "./passive-interface", + no ? NB_OP_DELETE : NB_OP_CREATE, ifname); + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_ripng_passive_interface(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, " passive-interface %s\n", + yang_dnode_get_string(dnode, NULL)); +} + +/* + * XPath: /frr-ripngd:ripngd/instance/redistribute + */ +DEFPY (ripng_redistribute, + ripng_redistribute_cmd, + "[no] redistribute " FRR_REDIST_STR_RIPNGD "$protocol [{metric (0-16)|route-map WORD}]", + NO_STR + REDIST_STR + FRR_REDIST_HELP_STR_RIPNGD + "Metric\n" + "Metric value\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + if (!no) { + nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); + nb_cli_enqueue_change(vty, "./route-map", + route_map ? NB_OP_MODIFY : NB_OP_DELETE, + route_map); + nb_cli_enqueue_change(vty, "./metric", + metric_str ? NB_OP_MODIFY : NB_OP_DELETE, + metric_str); + } else + nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); + + return nb_cli_apply_changes(vty, "./redistribute[protocol='%s']", + protocol); +} + +void cli_show_ripng_redistribute(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, " redistribute %s", + yang_dnode_get_string(dnode, "./protocol")); + if (yang_dnode_exists(dnode, "./metric")) + vty_out(vty, " metric %s", + yang_dnode_get_string(dnode, "./metric")); + if (yang_dnode_exists(dnode, "./route-map")) + vty_out(vty, " route-map %s", + yang_dnode_get_string(dnode, "./route-map")); + vty_out(vty, "\n"); +} + +/* + * XPath: /frr-ripngd:ripngd/instance/static-route + */ +DEFPY (ripng_route, + ripng_route_cmd, + "[no] route X:X::X:X/M", + NO_STR + "Static route setup\n" + "Set static RIPng route announcement\n") +{ + nb_cli_enqueue_change(vty, "./static-route", + no ? NB_OP_DELETE : NB_OP_CREATE, route_str); + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_ripng_route(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, " route %s\n", yang_dnode_get_string(dnode, NULL)); +} + +/* + * XPath: /frr-ripngd:ripngd/instance/aggregate-addres + */ +DEFPY (ripng_aggregate_address, + ripng_aggregate_address_cmd, + "[no] aggregate-address X:X::X:X/M", + NO_STR + "Set aggregate RIPng route announcement\n" + "Aggregate network\n") +{ + nb_cli_enqueue_change(vty, "./aggregate-address", + no ? NB_OP_DELETE : NB_OP_CREATE, + aggregate_address_str); + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_ripng_aggregate_address(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, " aggregate-address %s\n", + yang_dnode_get_string(dnode, NULL)); +} + +/* + * XPath: /frr-ripngd:ripngd/instance/timers + */ +DEFPY (ripng_timers, + ripng_timers_cmd, + "timers basic (1-65535)$update (1-65535)$timeout (1-65535)$garbage", + "RIPng timers setup\n" + "Basic timer\n" + "Routing table update timer value in second. Default is 30.\n" + "Routing information timeout timer. Default is 180.\n" + "Garbage collection timer. Default is 120.\n") +{ + nb_cli_enqueue_change(vty, "./update-interval", NB_OP_MODIFY, + update_str); + nb_cli_enqueue_change(vty, "./holddown-interval", NB_OP_MODIFY, + timeout_str); + nb_cli_enqueue_change(vty, "./flush-interval", NB_OP_MODIFY, + garbage_str); + + return nb_cli_apply_changes(vty, "./timers"); +} + +DEFPY (no_ripng_timers, + no_ripng_timers_cmd, + "no timers basic [(1-65535) (1-65535) (1-65535)]", + NO_STR + "RIPng timers setup\n" + "Basic timer\n" + "Routing table update timer value in second. Default is 30.\n" + "Routing information timeout timer. Default is 180.\n" + "Garbage collection timer. Default is 120.\n") +{ + nb_cli_enqueue_change(vty, "./update-interval", NB_OP_MODIFY, NULL); + nb_cli_enqueue_change(vty, "./holddown-interval", NB_OP_MODIFY, NULL); + nb_cli_enqueue_change(vty, "./flush-interval", NB_OP_MODIFY, NULL); + + return nb_cli_apply_changes(vty, "./timers"); +} + +void cli_show_ripng_timers(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, " timers basic %s %s %s\n", + yang_dnode_get_string(dnode, "./update-interval"), + yang_dnode_get_string(dnode, "./holddown-interval"), + yang_dnode_get_string(dnode, "./flush-interval")); +} + +/* + * XPath: /frr-interface:lib/interface/frr-ripngd:ripng/split-horizon + */ +DEFPY (ipv6_ripng_split_horizon, + ipv6_ripng_split_horizon_cmd, + "[no] ipv6 ripng split-horizon [poisoned-reverse$poisoned_reverse]", + NO_STR + IPV6_STR + "Routing Information Protocol\n" + "Perform split horizon\n" + "With poisoned-reverse\n") +{ + const char *value; + + if (no) + value = "disabled"; + else if (poisoned_reverse) + value = "poison-reverse"; + else + value = "simple"; + + nb_cli_enqueue_change(vty, "./split-horizon", NB_OP_MODIFY, value); + + return nb_cli_apply_changes(vty, "./frr-ripngd:ripng"); +} + +void cli_show_ipv6_ripng_split_horizon(struct vty *vty, struct lyd_node *dnode, + bool show_defaults) +{ + int value; + + value = yang_dnode_get_enum(dnode, NULL); + switch (value) { + case RIPNG_NO_SPLIT_HORIZON: + vty_out(vty, " no ipv6 ripng split-horizon\n"); + break; + case RIPNG_SPLIT_HORIZON: + vty_out(vty, " ipv6 ripng split-horizon\n"); + break; + case RIPNG_SPLIT_HORIZON_POISONED_REVERSE: + vty_out(vty, " ipv6 ripng split-horizon poisoned-reverse\n"); + break; + } +} + +/* + * XPath: /frr-ripngd:clear-ripng-route + */ +DEFPY (clear_ipv6_rip, + clear_ipv6_rip_cmd, + "clear ipv6 ripng", + CLEAR_STR + IPV6_STR + "Clear IPv6 RIP database\n") +{ + return nb_cli_rpc("/frr-ripngd:clear-ripng-route", NULL, NULL); +} + +void ripng_cli_init(void) +{ + install_element(CONFIG_NODE, &router_ripng_cmd); + install_element(CONFIG_NODE, &no_router_ripng_cmd); + + install_element(RIPNG_NODE, &ripng_allow_ecmp_cmd); + install_element(RIPNG_NODE, &ripng_default_information_originate_cmd); + install_element(RIPNG_NODE, &ripng_default_metric_cmd); + install_element(RIPNG_NODE, &no_ripng_default_metric_cmd); + install_element(RIPNG_NODE, &ripng_network_prefix_cmd); + install_element(RIPNG_NODE, &ripng_network_if_cmd); + install_element(RIPNG_NODE, &ripng_offset_list_cmd); + install_element(RIPNG_NODE, &ripng_passive_interface_cmd); + install_element(RIPNG_NODE, &ripng_redistribute_cmd); + install_element(RIPNG_NODE, &ripng_route_cmd); + install_element(RIPNG_NODE, &ripng_aggregate_address_cmd); + install_element(RIPNG_NODE, &ripng_timers_cmd); + install_element(RIPNG_NODE, &no_ripng_timers_cmd); + + install_element(INTERFACE_NODE, &ipv6_ripng_split_horizon_cmd); + + install_element(ENABLE_NODE, &clear_ipv6_rip_cmd); +} diff --git a/ripngd/ripng_cli.h b/ripngd/ripng_cli.h new file mode 100644 index 0000000000..d95747e0f8 --- /dev/null +++ b/ripngd/ripng_cli.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 1998 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_RIPNG_CLI_H_ +#define _FRR_RIPNG_CLI_H_ + +extern void cli_show_router_ripng(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void cli_show_ripng_allow_ecmp(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void cli_show_ripng_default_information_originate(struct vty *vty, + struct lyd_node *dnode, + bool show_defaults); +extern void cli_show_ripng_default_metric(struct vty *vty, + struct lyd_node *dnode, + bool show_defaults); +extern void cli_show_ripng_network_prefix(struct vty *vty, + struct lyd_node *dnode, + bool show_defaults); +extern void cli_show_ripng_network_interface(struct vty *vty, + struct lyd_node *dnode, + bool show_defaults); +extern void cli_show_ripng_offset_list(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void cli_show_ripng_passive_interface(struct vty *vty, + struct lyd_node *dnode, + bool show_defaults); +extern void cli_show_ripng_redistribute(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void cli_show_ripng_route(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void cli_show_ripng_aggregate_address(struct vty *vty, + struct lyd_node *dnode, + bool show_defaults); +extern void cli_show_ripng_timers(struct vty *vty, struct lyd_node *dnode, + bool show_defaults); +extern void cli_show_ipv6_ripng_split_horizon(struct vty *vty, + struct lyd_node *dnode, + bool show_defaults); + +#endif /* _FRR_RIPNG_CLI_H_ */ diff --git a/ripngd/ripng_debug.c b/ripngd/ripng_debug.c index c8cad23add..c56ff12627 100644 --- a/ripngd/ripng_debug.c +++ b/ripngd/ripng_debug.c @@ -207,13 +207,6 @@ static int config_write_debug(struct vty *vty) return write; } -void ripng_debug_reset() -{ - ripng_debug_event = 0; - ripng_debug_packet = 0; - ripng_debug_zebra = 0; -} - void ripng_debug_init() { ripng_debug_event = 0; diff --git a/ripngd/ripng_debug.h b/ripngd/ripng_debug.h index 8124a1a0c9..81cb0f9c7e 100644 --- a/ripngd/ripng_debug.h +++ b/ripngd/ripng_debug.h @@ -45,6 +45,5 @@ extern unsigned long ripng_debug_packet; extern unsigned long ripng_debug_zebra; extern void ripng_debug_init(void); -extern void ripng_debug_reset(void); #endif /* _ZEBRA_RIPNG_DEBUG_H */ diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c index a1d25f2961..4d14fbab64 100644 --- a/ripngd/ripng_interface.c +++ b/ripngd/ripng_interface.c @@ -36,6 +36,7 @@ #include "privs.h" #include "vrf.h" #include "lib_errors.h" +#include "northbound_cli.h" #include "ripngd/ripngd.h" #include "ripngd/ripng_debug.h" @@ -323,37 +324,6 @@ void ripng_interface_clean(void) } } -void ripng_interface_reset(void) -{ - struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); - struct interface *ifp; - struct ripng_interface *ri; - - FOR_ALL_INTERFACES (vrf, ifp) { - ri = ifp->info; - - ri->enable_network = 0; - ri->enable_interface = 0; - ri->running = 0; - - ri->split_horizon = RIPNG_NO_SPLIT_HORIZON; - ri->split_horizon_default = RIPNG_NO_SPLIT_HORIZON; - - ri->list[RIPNG_FILTER_IN] = NULL; - ri->list[RIPNG_FILTER_OUT] = NULL; - - ri->prefix[RIPNG_FILTER_IN] = NULL; - ri->prefix[RIPNG_FILTER_OUT] = NULL; - - if (ri->t_wakeup) { - thread_cancel(ri->t_wakeup); - ri->t_wakeup = NULL; - } - - ri->passive = 0; - } -} - static void ripng_apply_address_add(struct connected *ifc) { struct prefix_ipv6 address; @@ -543,7 +513,7 @@ static int ripng_enable_network_lookup2(struct connected *connected) } /* Add RIPng enable network. */ -static int ripng_enable_network_add(struct prefix *p) +int ripng_enable_network_add(struct prefix *p) { struct agg_node *node; @@ -551,18 +521,18 @@ static int ripng_enable_network_add(struct prefix *p) if (node->info) { agg_unlock_node(node); - return -1; + return NB_ERR_INCONSISTENCY; } else node->info = (void *)1; /* XXX: One should find a better solution than a generic one */ ripng_enable_apply_all(); - return 1; + return NB_OK; } /* Delete RIPng enable network. */ -static int ripng_enable_network_delete(struct prefix *p) +int ripng_enable_network_delete(struct prefix *p) { struct agg_node *node; @@ -576,9 +546,10 @@ static int ripng_enable_network_delete(struct prefix *p) /* Unlock lookup lock. */ agg_unlock_node(node); - return 1; + return NB_OK; } - return -1; + + return NB_ERR_INCONSISTENCY; } /* Lookup function. */ @@ -595,30 +566,30 @@ static int ripng_enable_if_lookup(const char *ifname) } /* Add interface to ripng_enable_if. */ -static int ripng_enable_if_add(const char *ifname) +int ripng_enable_if_add(const char *ifname) { int ret; ret = ripng_enable_if_lookup(ifname); if (ret >= 0) - return -1; + return NB_ERR_INCONSISTENCY; vector_set(ripng_enable_if, strdup(ifname)); ripng_enable_apply_all(); - return 1; + return NB_OK; } /* Delete interface from ripng_enable_if. */ -static int ripng_enable_if_delete(const char *ifname) +int ripng_enable_if_delete(const char *ifname) { int index; char *str; index = ripng_enable_if_lookup(ifname); if (index < 0) - return -1; + return NB_ERR_INCONSISTENCY; str = vector_slot(ripng_enable_if, index); free(str); @@ -626,7 +597,7 @@ static int ripng_enable_if_delete(const char *ifname) ripng_enable_apply_all(); - return 1; + return NB_OK; } /* Wake up interface. */ @@ -830,26 +801,26 @@ static void ripng_passive_interface_apply_all(void) } /* Passive interface. */ -static int ripng_passive_interface_set(struct vty *vty, const char *ifname) +int ripng_passive_interface_set(const char *ifname) { if (ripng_passive_interface_lookup(ifname) >= 0) - return CMD_WARNING_CONFIG_FAILED; + return NB_ERR_INCONSISTENCY; vector_set(Vripng_passive_interface, strdup(ifname)); ripng_passive_interface_apply_all(); - return CMD_SUCCESS; + return NB_OK; } -static int ripng_passive_interface_unset(struct vty *vty, const char *ifname) +int ripng_passive_interface_unset(const char *ifname) { int i; char *str; i = ripng_passive_interface_lookup(ifname); if (i < 0) - return CMD_WARNING_CONFIG_FAILED; + return NB_ERR_INCONSISTENCY; str = vector_slot(Vripng_passive_interface, i); free(str); @@ -857,7 +828,7 @@ static int ripng_passive_interface_unset(struct vty *vty, const char *ifname) ripng_passive_interface_apply_all(); - return CMD_SUCCESS; + return NB_OK; } /* Free all configured RIP passive-interface settings. */ @@ -875,7 +846,7 @@ void ripng_passive_interface_clean(void) } /* Write RIPng enable network and interface to the vty. */ -int ripng_network_write(struct vty *vty, int config_mode) +int ripng_network_write(struct vty *vty) { unsigned int i; const char *ifname; @@ -887,8 +858,7 @@ int ripng_network_write(struct vty *vty, int config_mode) node = agg_route_next(node)) if (node->info) { struct prefix *p = &node->p; - vty_out(vty, "%s%s/%d\n", - config_mode ? " network " : " ", + vty_out(vty, " %s/%d\n", inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ), p->prefixlen); } @@ -896,148 +866,11 @@ int ripng_network_write(struct vty *vty, int config_mode) /* Write enable interface. */ for (i = 0; i < vector_active(ripng_enable_if); i++) if ((ifname = vector_slot(ripng_enable_if, i)) != NULL) - vty_out(vty, "%s%s\n", - config_mode ? " network " : " ", ifname); - - /* Write passive interface. */ - if (config_mode) - for (i = 0; i < vector_active(Vripng_passive_interface); i++) - if ((ifname = vector_slot(Vripng_passive_interface, i)) - != NULL) - vty_out(vty, " passive-interface %s\n", ifname); + vty_out(vty, " %s\n", ifname); return 0; } -/* RIPng enable on specified interface or matched network. */ -DEFUN (ripng_network, - ripng_network_cmd, - "network IF_OR_ADDR", - "RIPng enable on specified interface or network.\n" - "Interface or address\n") -{ - int idx_if_or_addr = 1; - int ret; - struct prefix p; - - ret = str2prefix(argv[idx_if_or_addr]->arg, &p); - - /* Given string is IPv6 network or interface name. */ - if (ret) - ret = ripng_enable_network_add(&p); - else - ret = ripng_enable_if_add(argv[idx_if_or_addr]->arg); - - if (ret < 0) { - vty_out(vty, "There is same network configuration %s\n", - argv[idx_if_or_addr]->arg); - return CMD_WARNING_CONFIG_FAILED; - } - - return CMD_SUCCESS; -} - -/* RIPng enable on specified interface or matched network. */ -DEFUN (no_ripng_network, - no_ripng_network_cmd, - "no network IF_OR_ADDR", - NO_STR - "RIPng enable on specified interface or network.\n" - "Interface or address\n") -{ - int idx_if_or_addr = 2; - int ret; - struct prefix p; - - ret = str2prefix(argv[idx_if_or_addr]->arg, &p); - - /* Given string is interface name. */ - if (ret) - ret = ripng_enable_network_delete(&p); - else - ret = ripng_enable_if_delete(argv[idx_if_or_addr]->arg); - - if (ret < 0) { - vty_out(vty, "can't find network %s\n", - argv[idx_if_or_addr]->arg); - return CMD_WARNING_CONFIG_FAILED; - } - - return CMD_SUCCESS; -} - -DEFUN (ipv6_ripng_split_horizon, - ipv6_ripng_split_horizon_cmd, - "ipv6 ripng split-horizon", - IPV6_STR - "Routing Information Protocol\n" - "Perform split horizon\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct ripng_interface *ri; - - ri = ifp->info; - - ri->split_horizon = RIPNG_SPLIT_HORIZON; - return CMD_SUCCESS; -} - -DEFUN (ipv6_ripng_split_horizon_poisoned_reverse, - ipv6_ripng_split_horizon_poisoned_reverse_cmd, - "ipv6 ripng split-horizon poisoned-reverse", - IPV6_STR - "Routing Information Protocol\n" - "Perform split horizon\n" - "With poisoned-reverse\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct ripng_interface *ri; - - ri = ifp->info; - - ri->split_horizon = RIPNG_SPLIT_HORIZON_POISONED_REVERSE; - return CMD_SUCCESS; -} - -DEFUN (no_ipv6_ripng_split_horizon, - no_ipv6_ripng_split_horizon_cmd, - "no ipv6 ripng split-horizon [poisoned-reverse]", - NO_STR - IPV6_STR - "Routing Information Protocol\n" - "Perform split horizon\n" - "With poisoned-reverse\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct ripng_interface *ri; - - ri = ifp->info; - - ri->split_horizon = RIPNG_NO_SPLIT_HORIZON; - return CMD_SUCCESS; -} - -DEFUN (ripng_passive_interface, - ripng_passive_interface_cmd, - "passive-interface IFNAME", - "Suppress routing updates on an interface\n" - "Interface name\n") -{ - int idx_ifname = 1; - return ripng_passive_interface_set(vty, argv[idx_ifname]->arg); -} - -DEFUN (no_ripng_passive_interface, - no_ripng_passive_interface_cmd, - "no passive-interface IFNAME", - NO_STR - "Suppress routing updates on an interface\n" - "Interface name\n") -{ - int idx_ifname = 2; - return ripng_passive_interface_unset(vty, argv[idx_ifname]->arg); -} - static struct ripng_interface *ri_new(void) { struct ripng_interface *ri; @@ -1047,8 +880,8 @@ static struct ripng_interface *ri_new(void) Relay or SMDS is enabled, the default value for split-horizon is off. But currently Zebra does detect Frame Relay or SMDS interface. So all interface is set to split horizon. */ - ri->split_horizon_default = RIPNG_SPLIT_HORIZON; - ri->split_horizon = ri->split_horizon_default; + ri->split_horizon = + yang_get_default_enum("%s/split-horizon", RIPNG_IFACE); return ri; } @@ -1072,44 +905,22 @@ static int interface_config_write(struct vty *vty) { struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); struct interface *ifp; - struct ripng_interface *ri; int write = 0; FOR_ALL_INTERFACES (vrf, ifp) { - ri = ifp->info; + struct lyd_node *dnode; - /* Do not display the interface if there is no - * configuration about it. - **/ - if ((!ifp->desc) - && (ri->split_horizon == ri->split_horizon_default)) + dnode = yang_dnode_get( + running_config->dnode, + "/frr-interface:lib/interface[name='%s'][vrf='%s']", + ifp->name, vrf->name); + if (dnode == NULL) continue; - vty_frame(vty, "interface %s\n", ifp->name); - if (ifp->desc) - vty_out(vty, " description %s\n", ifp->desc); - - /* Split horizon. */ - if (ri->split_horizon != ri->split_horizon_default) { - switch (ri->split_horizon) { - case RIPNG_SPLIT_HORIZON: - vty_out(vty, " ipv6 ripng split-horizon\n"); - break; - case RIPNG_SPLIT_HORIZON_POISONED_REVERSE: - vty_out(vty, - " ipv6 ripng split-horizon poisoned-reverse\n"); - break; - case RIPNG_NO_SPLIT_HORIZON: - default: - vty_out(vty, " no ipv6 ripng split-horizon\n"); - break; - } - } - - vty_endframe(vty, "!\n"); - - write++; + write = 1; + nb_cli_show_dnode_cmds(vty, dnode, false); } + return write; } @@ -1137,14 +948,4 @@ void ripng_if_init() /* Install interface node. */ install_node(&interface_node, interface_config_write); if_cmd_init(); - - install_element(RIPNG_NODE, &ripng_network_cmd); - install_element(RIPNG_NODE, &no_ripng_network_cmd); - install_element(RIPNG_NODE, &ripng_passive_interface_cmd); - install_element(RIPNG_NODE, &no_ripng_passive_interface_cmd); - - install_element(INTERFACE_NODE, &ipv6_ripng_split_horizon_cmd); - install_element(INTERFACE_NODE, - &ipv6_ripng_split_horizon_poisoned_reverse_cmd); - install_element(INTERFACE_NODE, &no_ipv6_ripng_split_horizon_cmd); } diff --git a/ripngd/ripng_main.c b/ripngd/ripng_main.c index 98df7ef12d..10e19efe77 100644 --- a/ripngd/ripng_main.c +++ b/ripngd/ripng_main.c @@ -72,13 +72,9 @@ static struct frr_daemon_info ripngd_di; static void sighup(void) { zlog_info("SIGHUP received"); - ripng_clean(); - ripng_reset(); /* Reload config file. */ vty_read_config(NULL, ripngd_di.config_file, config_default); - - /* Try to return to normal operation. */ } /* SIGINT handler. */ @@ -120,6 +116,7 @@ struct quagga_signal_t ripng_signals[] = { static const struct frr_yang_module_info *ripngd_yang_modules[] = { &frr_interface_info, + &frr_ripngd_info, }; FRR_DAEMON_INFO(ripngd, RIPNG, .vty_port = RIPNG_VTY_PORT, @@ -177,6 +174,7 @@ int main(int argc, char **argv) /* RIPngd inits. */ ripng_init(); + ripng_cli_init(); zebra_init(master); ripng_peer_init(); diff --git a/ripngd/ripng_northbound.c b/ripngd/ripng_northbound.c new file mode 100644 index 0000000000..7993714e8d --- /dev/null +++ b/ripngd/ripng_northbound.c @@ -0,0 +1,1001 @@ +/* + * Copyright (C) 1998 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 <zebra.h> + +#include "if.h" +#include "vrf.h" +#include "log.h" +#include "prefix.h" +#include "table.h" +#include "command.h" +#include "routemap.h" +#include "agg_table.h" +#include "northbound.h" +#include "libfrr.h" + +#include "ripngd/ripngd.h" +#include "ripngd/ripng_route.h" +#include "ripngd/ripng_cli.h" + +/* + * XPath: /frr-ripngd:ripngd/instance + */ +static int ripngd_instance_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + int socket; + + switch (event) { + case NB_EV_VALIDATE: + break; + case NB_EV_PREPARE: + socket = ripng_make_socket(); + if (socket < 0) + return NB_ERR_RESOURCE; + resource->fd = socket; + break; + case NB_EV_ABORT: + socket = resource->fd; + close(socket); + break; + case NB_EV_APPLY: + socket = resource->fd; + ripng_create(socket); + break; + } + + return NB_OK; +} + +static int ripngd_instance_delete(enum nb_event event, + const struct lyd_node *dnode) +{ + if (event != NB_EV_APPLY) + return NB_OK; + + ripng_clean(); + + return NB_OK; +} + +/* + * XPath: /frr-ripngd:ripngd/instance/allow-ecmp + */ +static int ripngd_instance_allow_ecmp_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + if (event != NB_EV_APPLY) + return NB_OK; + + ripng->ecmp = yang_dnode_get_bool(dnode, NULL); + if (!ripng->ecmp) + ripng_ecmp_disable(); + + return NB_OK; +} + +/* + * XPath: /frr-ripngd:ripngd/instance/default-information-originate + */ +static int ripngd_instance_default_information_originate_modify( + enum nb_event event, const struct lyd_node *dnode, + union nb_resource *resource) +{ + bool default_information; + struct prefix_ipv6 p; + + if (event != NB_EV_APPLY) + return NB_OK; + + default_information = yang_dnode_get_bool(dnode, NULL); + str2prefix_ipv6("::/0", &p); + if (default_information) { + ripng_redistribute_add(ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, + &p, 0, NULL, 0); + } else { + ripng_redistribute_delete(ZEBRA_ROUTE_RIPNG, + RIPNG_ROUTE_DEFAULT, &p, 0); + } + + return NB_OK; +} + +/* + * XPath: /frr-ripngd:ripngd/instance/default-metric + */ +static int ripngd_instance_default_metric_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + if (event != NB_EV_APPLY) + return NB_OK; + + ripng->default_metric = yang_dnode_get_uint8(dnode, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-ripngd:ripngd/instance/network + */ +static int ripngd_instance_network_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct prefix p; + + if (event != NB_EV_APPLY) + return NB_OK; + + yang_dnode_get_ipv6p(&p, dnode, NULL); + apply_mask_ipv6((struct prefix_ipv6 *)&p); + + return ripng_enable_network_add(&p); +} + +static int ripngd_instance_network_delete(enum nb_event event, + const struct lyd_node *dnode) +{ + struct prefix p; + + if (event != NB_EV_APPLY) + return NB_OK; + + yang_dnode_get_ipv6p(&p, dnode, NULL); + apply_mask_ipv6((struct prefix_ipv6 *)&p); + + return ripng_enable_network_delete(&p); +} + +/* + * XPath: /frr-ripngd:ripngd/instance/interface + */ +static int ripngd_instance_interface_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + const char *ifname; + + if (event != NB_EV_APPLY) + return NB_OK; + + ifname = yang_dnode_get_string(dnode, NULL); + + return ripng_enable_if_add(ifname); +} + +static int ripngd_instance_interface_delete(enum nb_event event, + const struct lyd_node *dnode) +{ + const char *ifname; + + if (event != NB_EV_APPLY) + return NB_OK; + + ifname = yang_dnode_get_string(dnode, NULL); + + return ripng_enable_if_delete(ifname); +} + +/* + * XPath: /frr-ripngd:ripngd/instance/offset-list + */ +static int ripngd_instance_offset_list_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + const char *ifname; + struct ripng_offset_list *offset; + + if (event != NB_EV_APPLY) + return NB_OK; + + ifname = yang_dnode_get_string(dnode, "./interface"); + + offset = ripng_offset_list_new(ifname); + yang_dnode_set_entry(dnode, offset); + + return NB_OK; +} + +static int ripngd_instance_offset_list_delete(enum nb_event event, + const struct lyd_node *dnode) +{ + int direct; + struct ripng_offset_list *offset; + + if (event != NB_EV_APPLY) + return NB_OK; + + direct = yang_dnode_get_enum(dnode, "./direction"); + + offset = yang_dnode_get_entry(dnode, true); + if (offset->direct[direct].alist_name) { + free(offset->direct[direct].alist_name); + offset->direct[direct].alist_name = NULL; + } + if (offset->direct[RIPNG_OFFSET_LIST_IN].alist_name == NULL + && offset->direct[RIPNG_OFFSET_LIST_OUT].alist_name == NULL) + ripng_offset_list_del(offset); + + return NB_OK; +} + +/* + * XPath: /frr-ripngd:ripngd/instance/offset-list/access-list + */ +static int +ripngd_instance_offset_list_access_list_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + int direct; + struct ripng_offset_list *offset; + const char *alist_name; + + if (event != NB_EV_APPLY) + return NB_OK; + + direct = yang_dnode_get_enum(dnode, "../direction"); + alist_name = yang_dnode_get_string(dnode, NULL); + + offset = yang_dnode_get_entry(dnode, true); + if (offset->direct[direct].alist_name) + free(offset->direct[direct].alist_name); + offset->direct[direct].alist_name = strdup(alist_name); + + return NB_OK; +} + +/* + * XPath: /frr-ripngd:ripngd/instance/offset-list/metric + */ +static int +ripngd_instance_offset_list_metric_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + int direct; + uint8_t metric; + struct ripng_offset_list *offset; + + if (event != NB_EV_APPLY) + return NB_OK; + + direct = yang_dnode_get_enum(dnode, "../direction"); + metric = yang_dnode_get_uint8(dnode, NULL); + + offset = yang_dnode_get_entry(dnode, true); + offset->direct[direct].metric = metric; + + return NB_OK; +} + +/* + * XPath: /frr-ripngd:ripngd/instance/passive-interface + */ +static int +ripngd_instance_passive_interface_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + const char *ifname; + + if (event != NB_EV_APPLY) + return NB_OK; + + ifname = yang_dnode_get_string(dnode, NULL); + + return ripng_passive_interface_set(ifname); +} + +static int +ripngd_instance_passive_interface_delete(enum nb_event event, + const struct lyd_node *dnode) +{ + const char *ifname; + + if (event != NB_EV_APPLY) + return NB_OK; + + ifname = yang_dnode_get_string(dnode, NULL); + + return ripng_passive_interface_unset(ifname); +} + +/* + * XPath: /frr-ripngd:ripngd/instance/redistribute + */ +static int ripngd_instance_redistribute_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + return NB_OK; +} + +static int ripngd_instance_redistribute_delete(enum nb_event event, + const struct lyd_node *dnode) +{ + int type; + + if (event != NB_EV_APPLY) + return NB_OK; + + type = yang_dnode_get_enum(dnode, "./protocol"); + + ripng_redistribute_conf_delete(type); + + return NB_OK; +} + +static void +ripngd_instance_redistribute_apply_finish(const struct lyd_node *dnode) +{ + int type; + + type = yang_dnode_get_enum(dnode, "./protocol"); + ripng_redistribute_conf_update(type); +} + +/* + * XPath: /frr-ripngd:ripngd/instance/redistribute/route-map + */ +static int +ripngd_instance_redistribute_route_map_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + int type; + const char *rmap_name; + + if (event != NB_EV_APPLY) + return NB_OK; + + type = yang_dnode_get_enum(dnode, "../protocol"); + rmap_name = yang_dnode_get_string(dnode, NULL); + + if (ripng->route_map[type].name) + free(ripng->route_map[type].name); + ripng->route_map[type].name = strdup(rmap_name); + ripng->route_map[type].map = route_map_lookup_by_name(rmap_name); + + return NB_OK; +} + +static int +ripngd_instance_redistribute_route_map_delete(enum nb_event event, + const struct lyd_node *dnode) +{ + int type; + + if (event != NB_EV_APPLY) + return NB_OK; + + type = yang_dnode_get_enum(dnode, "../protocol"); + + free(ripng->route_map[type].name); + ripng->route_map[type].name = NULL; + ripng->route_map[type].map = NULL; + + return NB_OK; +} + +/* + * XPath: /frr-ripngd:ripngd/instance/redistribute/metric + */ +static int +ripngd_instance_redistribute_metric_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + int type; + uint8_t metric; + + if (event != NB_EV_APPLY) + return NB_OK; + + type = yang_dnode_get_enum(dnode, "../protocol"); + metric = yang_dnode_get_uint8(dnode, NULL); + + ripng->route_map[type].metric_config = true; + ripng->route_map[type].metric = metric; + + return NB_OK; +} + +static int +ripngd_instance_redistribute_metric_delete(enum nb_event event, + const struct lyd_node *dnode) +{ + int type; + + if (event != NB_EV_APPLY) + return NB_OK; + + type = yang_dnode_get_enum(dnode, "../protocol"); + + ripng->route_map[type].metric_config = false; + ripng->route_map[type].metric = 0; + + return NB_OK; +} + +/* + * XPath: /frr-ripngd:ripngd/instance/static-route + */ +static int ripngd_instance_static_route_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct prefix_ipv6 p; + + if (event != NB_EV_APPLY) + return NB_OK; + + yang_dnode_get_ipv6p(&p, dnode, NULL); + apply_mask_ipv6(&p); + + ripng_redistribute_add(ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0, + NULL, 0); + + return NB_OK; +} + +static int ripngd_instance_static_route_delete(enum nb_event event, + const struct lyd_node *dnode) +{ + struct prefix_ipv6 p; + + if (event != NB_EV_APPLY) + return NB_OK; + + yang_dnode_get_ipv6p(&p, dnode, NULL); + apply_mask_ipv6(&p); + + ripng_redistribute_delete(ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0); + + return NB_OK; +} + +/* + * XPath: /frr-ripngd:ripngd/instance/aggregate-address + */ +static int +ripngd_instance_aggregate_address_create(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct prefix_ipv6 p; + + if (event != NB_EV_APPLY) + return NB_OK; + + yang_dnode_get_ipv6p(&p, dnode, NULL); + apply_mask_ipv6(&p); + + ripng_aggregate_add((struct prefix *)&p); + + return NB_OK; +} + +static int +ripngd_instance_aggregate_address_delete(enum nb_event event, + const struct lyd_node *dnode) +{ + struct prefix_ipv6 p; + + if (event != NB_EV_APPLY) + return NB_OK; + + yang_dnode_get_ipv6p(&p, dnode, NULL); + apply_mask_ipv6(&p); + + ripng_aggregate_delete((struct prefix *)&p); + + return NB_OK; +} + +/* + * XPath: /frr-ripngd:ripngd/instance/timers + */ +static void ripngd_instance_timers_apply_finish(const struct lyd_node *dnode) +{ + /* Reset update timer thread. */ + ripng_event(RIPNG_UPDATE_EVENT, 0); +} + +/* + * XPath: /frr-ripngd:ripngd/instance/timers/flush-interval + */ +static int +ripngd_instance_timers_flush_interval_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + if (event != NB_EV_APPLY) + return NB_OK; + + ripng->garbage_time = yang_dnode_get_uint16(dnode, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-ripngd:ripngd/instance/timers/holddown-interval + */ +static int +ripngd_instance_timers_holddown_interval_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + if (event != NB_EV_APPLY) + return NB_OK; + + ripng->timeout_time = yang_dnode_get_uint16(dnode, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-ripngd:ripngd/instance/timers/update-interval + */ +static int +ripngd_instance_timers_update_interval_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + if (event != NB_EV_APPLY) + return NB_OK; + + ripng->update_time = yang_dnode_get_uint16(dnode, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-ripngd:ripngd/state/neighbors/neighbor + */ +static const void * +ripngd_state_neighbors_neighbor_get_next(const void *parent_list_entry, + const void *list_entry) +{ + struct listnode *node; + + if (list_entry == NULL) + node = listhead(peer_list); + else + node = listnextnode((struct listnode *)list_entry); + + return node; +} + +static int ripngd_state_neighbors_neighbor_get_keys(const void *list_entry, + struct yang_list_keys *keys) +{ + const struct listnode *node = list_entry; + const struct ripng_peer *peer = listgetdata(node); + + keys->num = 1; + (void)inet_ntop(AF_INET6, &peer->addr, keys->key[0], + sizeof(keys->key[0])); + + return NB_OK; +} + +static const void * +ripngd_state_neighbors_neighbor_lookup_entry(const void *parent_list_entry, + const struct yang_list_keys *keys) +{ + struct in6_addr address; + struct ripng_peer *peer; + struct listnode *node; + + yang_str2ipv6(keys->key[0], &address); + + for (ALL_LIST_ELEMENTS_RO(peer_list, node, peer)) { + if (IPV6_ADDR_SAME(&peer->addr, &address)) + return node; + } + + return NULL; +} + +/* + * XPath: /frr-ripngd:ripngd/state/neighbors/neighbor/address + */ +static struct yang_data * +ripngd_state_neighbors_neighbor_address_get_elem(const char *xpath, + const void *list_entry) +{ + const struct listnode *node = list_entry; + const struct ripng_peer *peer = listgetdata(node); + + return yang_data_new_ipv6(xpath, &peer->addr); +} + +/* + * XPath: /frr-ripngd:ripngd/state/neighbors/neighbor/last-update + */ +static struct yang_data * +ripngd_state_neighbors_neighbor_last_update_get_elem(const char *xpath, + const void *list_entry) +{ + /* TODO: yang:date-and-time is tricky */ + return NULL; +} + +/* + * XPath: /frr-ripngd:ripngd/state/neighbors/neighbor/bad-packets-rcvd + */ +static struct yang_data * +ripngd_state_neighbors_neighbor_bad_packets_rcvd_get_elem( + const char *xpath, const void *list_entry) +{ + const struct listnode *node = list_entry; + const struct ripng_peer *peer = listgetdata(node); + + return yang_data_new_uint32(xpath, peer->recv_badpackets); +} + +/* + * XPath: /frr-ripngd:ripngd/state/neighbors/neighbor/bad-routes-rcvd + */ +static struct yang_data * +ripngd_state_neighbors_neighbor_bad_routes_rcvd_get_elem(const char *xpath, + const void *list_entry) +{ + const struct listnode *node = list_entry; + const struct ripng_peer *peer = listgetdata(node); + + return yang_data_new_uint32(xpath, peer->recv_badroutes); +} + +/* + * XPath: /frr-ripngd:ripngd/state/routes/route + */ +static const void * +ripngd_state_routes_route_get_next(const void *parent_list_entry, + const void *list_entry) +{ + struct agg_node *rn; + + if (ripng == NULL) + return NULL; + + if (list_entry == NULL) + rn = agg_route_top(ripng->table); + else + rn = agg_route_next((struct agg_node *)list_entry); + while (rn && rn->info == NULL) + rn = agg_route_next(rn); + + return rn; +} + +static int ripngd_state_routes_route_get_keys(const void *list_entry, + struct yang_list_keys *keys) +{ + const struct agg_node *rn = list_entry; + + keys->num = 1; + (void)prefix2str(&rn->p, keys->key[0], sizeof(keys->key[0])); + + return NB_OK; +} + +static const void * +ripngd_state_routes_route_lookup_entry(const void *parent_list_entry, + const struct yang_list_keys *keys) +{ + struct prefix prefix; + struct agg_node *rn; + + yang_str2ipv6p(keys->key[0], &prefix); + + rn = agg_node_lookup(ripng->table, &prefix); + if (!rn || !rn->info) + return NULL; + + agg_unlock_node(rn); + + return rn; +} + +/* + * XPath: /frr-ripngd:ripngd/state/routes/route/prefix + */ +static struct yang_data * +ripngd_state_routes_route_prefix_get_elem(const char *xpath, + const void *list_entry) +{ + const struct agg_node *rn = list_entry; + const struct ripng_info *rinfo = listnode_head(rn->info); + + return yang_data_new_ipv6p(xpath, &rinfo->rp->p); +} + +/* + * XPath: /frr-ripngd:ripngd/state/routes/route/next-hop + */ +static struct yang_data * +ripngd_state_routes_route_next_hop_get_elem(const char *xpath, + const void *list_entry) +{ + const struct agg_node *rn = list_entry; + const struct ripng_info *rinfo = listnode_head(rn->info); + + return yang_data_new_ipv6(xpath, &rinfo->nexthop); +} + +/* + * XPath: /frr-ripngd:ripngd/state/routes/route/interface + */ +static struct yang_data * +ripngd_state_routes_route_interface_get_elem(const char *xpath, + const void *list_entry) +{ + const struct agg_node *rn = list_entry; + const struct ripng_info *rinfo = listnode_head(rn->info); + + return yang_data_new_string( + xpath, ifindex2ifname(rinfo->ifindex, VRF_DEFAULT)); +} + +/* + * XPath: /frr-ripngd:ripngd/state/routes/route/metric + */ +static struct yang_data * +ripngd_state_routes_route_metric_get_elem(const char *xpath, + const void *list_entry) +{ + const struct agg_node *rn = list_entry; + const struct ripng_info *rinfo = listnode_head(rn->info); + + return yang_data_new_uint8(xpath, rinfo->metric); +} + +/* + * XPath: /frr-ripngd:clear-ripng-route + */ +static int clear_ripng_route_rpc(const char *xpath, const struct list *input, + struct list *output) +{ + struct agg_node *rp; + struct ripng_info *rinfo; + struct list *list; + struct listnode *listnode; + + /* Clear received RIPng routes */ + for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) { + list = rp->info; + if (list == NULL) + continue; + + for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) { + if (!ripng_route_rte(rinfo)) + continue; + + if (CHECK_FLAG(rinfo->flags, RIPNG_RTF_FIB)) + ripng_zebra_ipv6_delete(rp); + break; + } + + if (rinfo) { + RIPNG_TIMER_OFF(rinfo->t_timeout); + RIPNG_TIMER_OFF(rinfo->t_garbage_collect); + listnode_delete(list, rinfo); + ripng_info_free(rinfo); + } + + if (list_isempty(list)) { + list_delete(&list); + rp->info = NULL; + agg_unlock_node(rp); + } + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-ripngd:ripng/split-horizon + */ +static int +lib_interface_ripng_split_horizon_modify(enum nb_event event, + const struct lyd_node *dnode, + union nb_resource *resource) +{ + struct interface *ifp; + struct ripng_interface *ri; + + if (event != NB_EV_APPLY) + return NB_OK; + + ifp = yang_dnode_get_entry(dnode, true); + ri = ifp->info; + ri->split_horizon = yang_dnode_get_enum(dnode, NULL); + + return NB_OK; +} + +/* clang-format off */ +const struct frr_yang_module_info frr_ripngd_info = { + .name = "frr-ripngd", + .nodes = { + { + .xpath = "/frr-ripngd:ripngd/instance", + .cbs.create = ripngd_instance_create, + .cbs.delete = ripngd_instance_delete, + .cbs.cli_show = cli_show_router_ripng, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/allow-ecmp", + .cbs.modify = ripngd_instance_allow_ecmp_modify, + .cbs.cli_show = cli_show_ripng_allow_ecmp, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/default-information-originate", + .cbs.modify = ripngd_instance_default_information_originate_modify, + .cbs.cli_show = cli_show_ripng_default_information_originate, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/default-metric", + .cbs.modify = ripngd_instance_default_metric_modify, + .cbs.cli_show = cli_show_ripng_default_metric, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/network", + .cbs.create = ripngd_instance_network_create, + .cbs.delete = ripngd_instance_network_delete, + .cbs.cli_show = cli_show_ripng_network_prefix, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/interface", + .cbs.create = ripngd_instance_interface_create, + .cbs.delete = ripngd_instance_interface_delete, + .cbs.cli_show = cli_show_ripng_network_interface, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/offset-list", + .cbs.create = ripngd_instance_offset_list_create, + .cbs.delete = ripngd_instance_offset_list_delete, + .cbs.cli_show = cli_show_ripng_offset_list, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/offset-list/access-list", + .cbs.modify = ripngd_instance_offset_list_access_list_modify, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/offset-list/metric", + .cbs.modify = ripngd_instance_offset_list_metric_modify, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/passive-interface", + .cbs.create = ripngd_instance_passive_interface_create, + .cbs.delete = ripngd_instance_passive_interface_delete, + .cbs.cli_show = cli_show_ripng_passive_interface, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/redistribute", + .cbs.create = ripngd_instance_redistribute_create, + .cbs.delete = ripngd_instance_redistribute_delete, + .cbs.apply_finish = ripngd_instance_redistribute_apply_finish, + .cbs.cli_show = cli_show_ripng_redistribute, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/redistribute/route-map", + .cbs.modify = ripngd_instance_redistribute_route_map_modify, + .cbs.delete = ripngd_instance_redistribute_route_map_delete, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/redistribute/metric", + .cbs.modify = ripngd_instance_redistribute_metric_modify, + .cbs.delete = ripngd_instance_redistribute_metric_delete, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/static-route", + .cbs.create = ripngd_instance_static_route_create, + .cbs.delete = ripngd_instance_static_route_delete, + .cbs.cli_show = cli_show_ripng_route, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/aggregate-address", + .cbs.create = ripngd_instance_aggregate_address_create, + .cbs.delete = ripngd_instance_aggregate_address_delete, + .cbs.cli_show = cli_show_ripng_aggregate_address, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/timers", + .cbs.apply_finish = ripngd_instance_timers_apply_finish, + .cbs.cli_show = cli_show_ripng_timers, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/timers/flush-interval", + .cbs.modify = ripngd_instance_timers_flush_interval_modify, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/timers/holddown-interval", + .cbs.modify = ripngd_instance_timers_holddown_interval_modify, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/timers/update-interval", + .cbs.modify = ripngd_instance_timers_update_interval_modify, + }, + { + .xpath = "/frr-ripngd:ripngd/state/neighbors/neighbor", + .cbs.get_next = ripngd_state_neighbors_neighbor_get_next, + .cbs.get_keys = ripngd_state_neighbors_neighbor_get_keys, + .cbs.lookup_entry = ripngd_state_neighbors_neighbor_lookup_entry, + }, + { + .xpath = "/frr-ripngd:ripngd/state/neighbors/neighbor/address", + .cbs.get_elem = ripngd_state_neighbors_neighbor_address_get_elem, + }, + { + .xpath = "/frr-ripngd:ripngd/state/neighbors/neighbor/last-update", + .cbs.get_elem = ripngd_state_neighbors_neighbor_last_update_get_elem, + }, + { + .xpath = "/frr-ripngd:ripngd/state/neighbors/neighbor/bad-packets-rcvd", + .cbs.get_elem = ripngd_state_neighbors_neighbor_bad_packets_rcvd_get_elem, + }, + { + .xpath = "/frr-ripngd:ripngd/state/neighbors/neighbor/bad-routes-rcvd", + .cbs.get_elem = ripngd_state_neighbors_neighbor_bad_routes_rcvd_get_elem, + }, + { + .xpath = "/frr-ripngd:ripngd/state/routes/route", + .cbs.get_next = ripngd_state_routes_route_get_next, + .cbs.get_keys = ripngd_state_routes_route_get_keys, + .cbs.lookup_entry = ripngd_state_routes_route_lookup_entry, + }, + { + .xpath = "/frr-ripngd:ripngd/state/routes/route/prefix", + .cbs.get_elem = ripngd_state_routes_route_prefix_get_elem, + }, + { + .xpath = "/frr-ripngd:ripngd/state/routes/route/next-hop", + .cbs.get_elem = ripngd_state_routes_route_next_hop_get_elem, + }, + { + .xpath = "/frr-ripngd:ripngd/state/routes/route/interface", + .cbs.get_elem = ripngd_state_routes_route_interface_get_elem, + }, + { + .xpath = "/frr-ripngd:ripngd/state/routes/route/metric", + .cbs.get_elem = ripngd_state_routes_route_metric_get_elem, + }, + { + .xpath = "/frr-ripngd:clear-ripng-route", + .cbs.rpc = clear_ripng_route_rpc, + }, + { + .xpath = "/frr-interface:lib/interface/frr-ripngd:ripng/split-horizon", + .cbs.modify = lib_interface_ripng_split_horizon_modify, + .cbs.cli_show = cli_show_ipv6_ripng_split_horizon, + }, + { + .xpath = NULL, + }, + } +}; diff --git a/ripngd/ripng_offset.c b/ripngd/ripng_offset.c index 32b81b5480..278df75892 100644 --- a/ripngd/ripng_offset.c +++ b/ripngd/ripng_offset.c @@ -33,165 +33,49 @@ #include "ripngd/ripngd.h" -#define RIPNG_OFFSET_LIST_IN 0 -#define RIPNG_OFFSET_LIST_OUT 1 -#define RIPNG_OFFSET_LIST_MAX 2 - -struct ripng_offset_list { - char *ifname; - - struct { - char *alist_name; - /* struct access_list *alist; */ - int metric; - } direct[RIPNG_OFFSET_LIST_MAX]; -}; - static struct list *ripng_offset_list_master; -static int strcmp_safe(const char *s1, const char *s2) -{ - if (s1 == NULL && s2 == NULL) - return 0; - if (s1 == NULL) - return -1; - if (s2 == NULL) - return 1; - return strcmp(s1, s2); -} +#define OFFSET_LIST_IN_NAME(O) ((O)->direct[RIPNG_OFFSET_LIST_IN].alist_name) +#define OFFSET_LIST_IN_METRIC(O) ((O)->direct[RIPNG_OFFSET_LIST_IN].metric) + +#define OFFSET_LIST_OUT_NAME(O) ((O)->direct[RIPNG_OFFSET_LIST_OUT].alist_name) +#define OFFSET_LIST_OUT_METRIC(O) ((O)->direct[RIPNG_OFFSET_LIST_OUT].metric) -static struct ripng_offset_list *ripng_offset_list_new(void) +struct ripng_offset_list *ripng_offset_list_new(const char *ifname) { struct ripng_offset_list *new; new = XCALLOC(MTYPE_RIPNG_OFFSET_LIST, sizeof(struct ripng_offset_list)); + new->ifname = strdup(ifname); + listnode_add_sort(ripng_offset_list_master, new); + return new; } -static void ripng_offset_list_free(struct ripng_offset_list *offset) +void ripng_offset_list_del(struct ripng_offset_list *offset) { + listnode_delete(ripng_offset_list_master, offset); + if (OFFSET_LIST_IN_NAME(offset)) + free(OFFSET_LIST_IN_NAME(offset)); + if (OFFSET_LIST_OUT_NAME(offset)) + free(OFFSET_LIST_OUT_NAME(offset)); + free(offset->ifname); XFREE(MTYPE_RIPNG_OFFSET_LIST, offset); } -static struct ripng_offset_list *ripng_offset_list_lookup(const char *ifname) +struct ripng_offset_list *ripng_offset_list_lookup(const char *ifname) { struct ripng_offset_list *offset; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS(ripng_offset_list_master, node, nnode, offset)) { - if (strcmp_safe(offset->ifname, ifname) == 0) + if (strcmp(offset->ifname, ifname) == 0) return offset; } return NULL; } -static struct ripng_offset_list *ripng_offset_list_get(const char *ifname) -{ - struct ripng_offset_list *offset; - - offset = ripng_offset_list_lookup(ifname); - if (offset) - return offset; - - offset = ripng_offset_list_new(); - if (ifname) - offset->ifname = strdup(ifname); - listnode_add_sort(ripng_offset_list_master, offset); - - return offset; -} - -static int ripng_offset_list_set(struct vty *vty, const char *alist, - const char *direct_str, const char *metric_str, - const char *ifname) -{ - int direct; - int metric; - struct ripng_offset_list *offset; - - /* Check direction. */ - if (strncmp(direct_str, "i", 1) == 0) - direct = RIPNG_OFFSET_LIST_IN; - else if (strncmp(direct_str, "o", 1) == 0) - direct = RIPNG_OFFSET_LIST_OUT; - else { - vty_out(vty, "Invalid direction: %s\n", direct_str); - return CMD_WARNING_CONFIG_FAILED; - } - - /* Check metric. */ - metric = atoi(metric_str); - if (metric < 0 || metric > 16) { - vty_out(vty, "Invalid metric: %s\n", metric_str); - return CMD_WARNING_CONFIG_FAILED; - } - - /* Get offset-list structure with interface name. */ - offset = ripng_offset_list_get(ifname); - - if (offset->direct[direct].alist_name) - free(offset->direct[direct].alist_name); - offset->direct[direct].alist_name = strdup(alist); - offset->direct[direct].metric = metric; - - return CMD_SUCCESS; -} - -static int ripng_offset_list_unset(struct vty *vty, const char *alist, - const char *direct_str, - const char *metric_str, const char *ifname) -{ - int direct; - int metric; - struct ripng_offset_list *offset; - - /* Check direction. */ - if (strncmp(direct_str, "i", 1) == 0) - direct = RIPNG_OFFSET_LIST_IN; - else if (strncmp(direct_str, "o", 1) == 0) - direct = RIPNG_OFFSET_LIST_OUT; - else { - vty_out(vty, "Invalid direction: %s\n", direct_str); - return CMD_WARNING_CONFIG_FAILED; - } - - /* Check metric. */ - metric = atoi(metric_str); - if (metric < 0 || metric > 16) { - vty_out(vty, "Invalid metric: %s\n", metric_str); - return CMD_WARNING_CONFIG_FAILED; - } - - /* Get offset-list structure with interface name. */ - offset = ripng_offset_list_lookup(ifname); - - if (offset) { - if (offset->direct[direct].alist_name) - free(offset->direct[direct].alist_name); - offset->direct[direct].alist_name = NULL; - - if (offset->direct[RIPNG_OFFSET_LIST_IN].alist_name == NULL - && offset->direct[RIPNG_OFFSET_LIST_OUT].alist_name - == NULL) { - listnode_delete(ripng_offset_list_master, offset); - if (offset->ifname) - free(offset->ifname); - ripng_offset_list_free(offset); - } - } else { - vty_out(vty, "Can't find offset-list\n"); - return CMD_WARNING_CONFIG_FAILED; - } - return CMD_SUCCESS; -} - -#define OFFSET_LIST_IN_NAME(O) ((O)->direct[RIPNG_OFFSET_LIST_IN].alist_name) -#define OFFSET_LIST_IN_METRIC(O) ((O)->direct[RIPNG_OFFSET_LIST_IN].metric) - -#define OFFSET_LIST_OUT_NAME(O) ((O)->direct[RIPNG_OFFSET_LIST_OUT].alist_name) -#define OFFSET_LIST_OUT_METRIC(O) ((O)->direct[RIPNG_OFFSET_LIST_OUT].metric) - /* If metric is modifed return 1. */ int ripng_offset_list_apply_in(struct prefix_ipv6 *p, struct interface *ifp, uint8_t *metric) @@ -214,7 +98,7 @@ int ripng_offset_list_apply_in(struct prefix_ipv6 *p, struct interface *ifp, return 0; } /* Look up offset-list without interface name. */ - offset = ripng_offset_list_lookup(NULL); + offset = ripng_offset_list_lookup("*"); if (offset && OFFSET_LIST_IN_NAME(offset)) { alist = access_list_lookup(AFI_IP6, OFFSET_LIST_IN_NAME(offset)); @@ -253,7 +137,7 @@ int ripng_offset_list_apply_out(struct prefix_ipv6 *p, struct interface *ifp, } /* Look up offset-list without interface name. */ - offset = ripng_offset_list_lookup(NULL); + offset = ripng_offset_list_lookup("*"); if (offset && OFFSET_LIST_OUT_NAME(offset)) { alist = access_list_lookup(AFI_IP6, OFFSET_LIST_OUT_NAME(offset)); @@ -269,95 +153,10 @@ int ripng_offset_list_apply_out(struct prefix_ipv6 *p, struct interface *ifp, return 0; } -DEFUN (ripng_offset_list, - ripng_offset_list_cmd, - "offset-list WORD <in|out> (0-16)", - "Modify RIPng metric\n" - "Access-list name\n" - "For incoming updates\n" - "For outgoing updates\n" - "Metric value\n") -{ - int idx_word = 1; - int idx_in_out = 2; - int idx_number = 3; - return ripng_offset_list_set(vty, argv[idx_word]->arg, - argv[idx_in_out]->arg, - argv[idx_number]->arg, NULL); -} - -DEFUN (ripng_offset_list_ifname, - ripng_offset_list_ifname_cmd, - "offset-list WORD <in|out> (0-16) IFNAME", - "Modify RIPng metric\n" - "Access-list name\n" - "For incoming updates\n" - "For outgoing updates\n" - "Metric value\n" - "Interface to match\n") -{ - int idx_word = 1; - int idx_in_out = 2; - int idx_number = 3; - int idx_ifname = 4; - return ripng_offset_list_set( - vty, argv[idx_word]->arg, argv[idx_in_out]->arg, - argv[idx_number]->arg, argv[idx_ifname]->arg); -} - -DEFUN (no_ripng_offset_list, - no_ripng_offset_list_cmd, - "no offset-list WORD <in|out> (0-16)", - NO_STR - "Modify RIPng metric\n" - "Access-list name\n" - "For incoming updates\n" - "For outgoing updates\n" - "Metric value\n") -{ - int idx_word = 2; - int idx_in_out = 3; - int idx_number = 4; - return ripng_offset_list_unset(vty, argv[idx_word]->arg, - argv[idx_in_out]->arg, - argv[idx_number]->arg, NULL); -} - -DEFUN (no_ripng_offset_list_ifname, - no_ripng_offset_list_ifname_cmd, - "no offset-list WORD <in|out> (0-16) IFNAME", - NO_STR - "Modify RIPng metric\n" - "Access-list name\n" - "For incoming updates\n" - "For outgoing updates\n" - "Metric value\n" - "Interface to match\n") -{ - int idx_word = 2; - int idx_in_out = 3; - int idx_number = 4; - int idx_ifname = 5; - return ripng_offset_list_unset( - vty, argv[idx_word]->arg, argv[idx_in_out]->arg, - argv[idx_number]->arg, argv[idx_ifname]->arg); -} - static int offset_list_cmp(struct ripng_offset_list *o1, struct ripng_offset_list *o2) { - return strcmp_safe(o1->ifname, o2->ifname); -} - -static void offset_list_del(struct ripng_offset_list *offset) -{ - if (OFFSET_LIST_IN_NAME(offset)) - free(OFFSET_LIST_IN_NAME(offset)); - if (OFFSET_LIST_OUT_NAME(offset)) - free(OFFSET_LIST_OUT_NAME(offset)); - if (offset->ifname) - free(offset->ifname); - ripng_offset_list_free(offset); + return strcmp(o1->ifname, o2->ifname); } void ripng_offset_init(void) @@ -365,12 +164,7 @@ void ripng_offset_init(void) ripng_offset_list_master = list_new(); ripng_offset_list_master->cmp = (int (*)(void *, void *))offset_list_cmp; - ripng_offset_list_master->del = (void (*)(void *))offset_list_del; - - install_element(RIPNG_NODE, &ripng_offset_list_cmd); - install_element(RIPNG_NODE, &ripng_offset_list_ifname_cmd); - install_element(RIPNG_NODE, &no_ripng_offset_list_cmd); - install_element(RIPNG_NODE, &no_ripng_offset_list_ifname_cmd); + ripng_offset_list_master->del = (void (*)(void *))ripng_offset_list_del; } void ripng_offset_clean(void) @@ -380,45 +174,5 @@ void ripng_offset_clean(void) ripng_offset_list_master = list_new(); ripng_offset_list_master->cmp = (int (*)(void *, void *))offset_list_cmp; - ripng_offset_list_master->del = (void (*)(void *))offset_list_del; -} - -int config_write_ripng_offset_list(struct vty *vty) -{ - struct listnode *node, *nnode; - struct ripng_offset_list *offset; - - for (ALL_LIST_ELEMENTS(ripng_offset_list_master, node, nnode, offset)) { - if (!offset->ifname) { - if (offset->direct[RIPNG_OFFSET_LIST_IN].alist_name) - vty_out(vty, " offset-list %s in %d\n", - offset->direct[RIPNG_OFFSET_LIST_IN] - .alist_name, - offset->direct[RIPNG_OFFSET_LIST_IN] - .metric); - if (offset->direct[RIPNG_OFFSET_LIST_OUT].alist_name) - vty_out(vty, " offset-list %s out %d\n", - offset->direct[RIPNG_OFFSET_LIST_OUT] - .alist_name, - offset->direct[RIPNG_OFFSET_LIST_OUT] - .metric); - } else { - if (offset->direct[RIPNG_OFFSET_LIST_IN].alist_name) - vty_out(vty, " offset-list %s in %d %s\n", - offset->direct[RIPNG_OFFSET_LIST_IN] - .alist_name, - offset->direct[RIPNG_OFFSET_LIST_IN] - .metric, - offset->ifname); - if (offset->direct[RIPNG_OFFSET_LIST_OUT].alist_name) - vty_out(vty, " offset-list %s out %d %s\n", - offset->direct[RIPNG_OFFSET_LIST_OUT] - .alist_name, - offset->direct[RIPNG_OFFSET_LIST_OUT] - .metric, - offset->ifname); - } - } - - return 0; + ripng_offset_list_master->del = (void (*)(void *))ripng_offset_list_del; } diff --git a/ripngd/ripng_routemap.c b/ripngd/ripng_routemap.c index a18332516e..9a9e346a59 100644 --- a/ripngd/ripng_routemap.c +++ b/ripngd/ripng_routemap.c @@ -337,12 +337,6 @@ static struct route_map_rule_cmd route_set_tag_cmd = { #define MATCH_STR "Match values from routing table\n" #define SET_STR "Set values in destination routing protocol\n" -void ripng_route_map_reset() -{ - /* XXX ??? */ - ; -} - void ripng_route_map_init() { route_map_init(); diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c index f2b69c85a7..e3f42edf51 100644 --- a/ripngd/ripng_zebra.c +++ b/ripngd/ripng_zebra.c @@ -141,26 +141,19 @@ static int ripng_zebra_read_route(int command, struct zclient *zclient, return 0; } -void ripng_zclient_reset(void) +void ripng_redistribute_conf_update(int type) { - zclient_reset(zclient); + zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6, type, 0, + VRF_DEFAULT); } -static int ripng_redistribute_unset(int type) +void ripng_redistribute_conf_delete(int type) { - - if (!vrf_bitmap_check(zclient->redist[AFI_IP6][type], VRF_DEFAULT)) - return CMD_SUCCESS; - - vrf_bitmap_set(zclient->redist[AFI_IP6][type], VRF_DEFAULT); - if (zclient->sock > 0) zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE, zclient, AFI_IP6, type, 0, VRF_DEFAULT); ripng_redistribute_withdraw(type); - - return CMD_SUCCESS; } int ripng_redistribute_check(int type) @@ -168,206 +161,25 @@ int ripng_redistribute_check(int type) return vrf_bitmap_check(zclient->redist[AFI_IP6][type], VRF_DEFAULT); } -static void ripng_redistribute_metric_set(int type, int metric) -{ - ripng->route_map[type].metric_config = 1; - ripng->route_map[type].metric = metric; -} - -static int ripng_redistribute_metric_unset(int type) -{ - ripng->route_map[type].metric_config = 0; - ripng->route_map[type].metric = 0; - return 0; -} - -static void ripng_redistribute_routemap_set(int type, const char *name) -{ - if (ripng->route_map[type].name) - free(ripng->route_map[type].name); - - ripng->route_map[type].name = strdup(name); - ripng->route_map[type].map = route_map_lookup_by_name(name); -} - -static void ripng_redistribute_routemap_unset(int type) -{ - if (ripng->route_map[type].name) - free(ripng->route_map[type].name); - - ripng->route_map[type].name = NULL; - ripng->route_map[type].map = NULL; -} - -/* Redistribution types */ -static struct { - int type; - int str_min_len; - const char *str; -} redist_type[] = {{ZEBRA_ROUTE_KERNEL, 1, "kernel"}, - {ZEBRA_ROUTE_CONNECT, 1, "connected"}, - {ZEBRA_ROUTE_STATIC, 1, "static"}, - {ZEBRA_ROUTE_OSPF6, 1, "ospf6"}, - {ZEBRA_ROUTE_BGP, 2, "bgp"}, - {ZEBRA_ROUTE_VNC, 1, "vnc"}, - {0, 0, NULL}}; - void ripng_redistribute_clean() { - int i; - - for (i = 0; redist_type[i].str; i++) { - if (vrf_bitmap_check( - zclient->redist[AFI_IP6][redist_type[i].type], - VRF_DEFAULT)) { - if (zclient->sock > 0) - zebra_redistribute_send( - ZEBRA_REDISTRIBUTE_DELETE, zclient, - AFI_IP6, redist_type[i].type, 0, - VRF_DEFAULT); - - vrf_bitmap_unset( - zclient->redist[AFI_IP6][redist_type[i].type], - VRF_DEFAULT); - - /* Remove the routes from RIPng table. */ - ripng_redistribute_withdraw(redist_type[i].type); - } - } -} - -DEFUN (ripng_redistribute_type, - ripng_redistribute_type_cmd, - "redistribute " FRR_REDIST_STR_RIPNGD, - "Redistribute\n" - FRR_REDIST_HELP_STR_RIPNGD) -{ - int type; - - char *proto = argv[argc - 1]->text; - type = proto_redistnum(AFI_IP6, proto); - - if (type < 0) { - vty_out(vty, "Invalid type %s\n", proto); - return CMD_WARNING_CONFIG_FAILED; - } - - zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6, type, 0, - VRF_DEFAULT); - return CMD_SUCCESS; -} - -DEFUN (no_ripng_redistribute_type, - no_ripng_redistribute_type_cmd, - "no redistribute " FRR_REDIST_STR_RIPNGD " [metric (0-16)] [route-map WORD]", - NO_STR - "Redistribute\n" - FRR_REDIST_HELP_STR_RIPNGD - "Metric\n" - "Metric value\n" - "Route map reference\n" - "Pointer to route-map entries\n") -{ - int type; - - char *proto = argv[2]->text; - type = proto_redistnum(AFI_IP6, proto); - - if (type < 0) { - vty_out(vty, "Invalid type %s\n", proto); - return CMD_WARNING_CONFIG_FAILED; - } - - ripng_redistribute_metric_unset(type); - ripng_redistribute_routemap_unset(type); - return ripng_redistribute_unset(type); -} - - -DEFUN (ripng_redistribute_type_metric, - ripng_redistribute_type_metric_cmd, - "redistribute " FRR_REDIST_STR_RIPNGD " metric (0-16)", - "Redistribute\n" - FRR_REDIST_HELP_STR_RIPNGD - "Metric\n" - "Metric value\n") -{ - int idx_protocol = 1; - int idx_number = 3; - int type; - int metric; - - metric = atoi(argv[idx_number]->arg); - type = proto_redistnum(AFI_IP6, argv[idx_protocol]->text); - - if (type < 0) { - vty_out(vty, "Invalid type %s\n", argv[idx_protocol]->text); - return CMD_WARNING_CONFIG_FAILED; - } - - ripng_redistribute_metric_set(type, metric); - zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6, type, 0, - VRF_DEFAULT); - return CMD_SUCCESS; -} - -DEFUN (ripng_redistribute_type_routemap, - ripng_redistribute_type_routemap_cmd, - "redistribute " FRR_REDIST_STR_RIPNGD " route-map WORD", - "Redistribute\n" - FRR_REDIST_HELP_STR_RIPNGD - "Route map reference\n" - "Pointer to route-map entries\n") -{ - int idx_protocol = 1; - int idx_word = 3; - int type; - - type = proto_redistnum(AFI_IP6, argv[idx_protocol]->text); + for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) { + if (!vrf_bitmap_check(zclient->redist[AFI_IP6][i], VRF_DEFAULT)) + continue; - if (type < 0) { - vty_out(vty, "Invalid type %s\n", argv[idx_protocol]->text); - return CMD_WARNING_CONFIG_FAILED; - } + if (zclient->sock > 0) + zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE, + zclient, AFI_IP6, i, 0, + VRF_DEFAULT); - ripng_redistribute_routemap_set(type, argv[idx_word]->text); - zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6, type, 0, - VRF_DEFAULT); - return CMD_SUCCESS; -} + vrf_bitmap_unset(zclient->redist[AFI_IP6][i], VRF_DEFAULT); -DEFUN (ripng_redistribute_type_metric_routemap, - ripng_redistribute_type_metric_routemap_cmd, - "redistribute " FRR_REDIST_STR_RIPNGD " metric (0-16) route-map WORD", - "Redistribute\n" - FRR_REDIST_HELP_STR_RIPNGD - "Metric\n" - "Metric value\n" - "Route map reference\n" - "Pointer to route-map entries\n") -{ - int idx_protocol = 1; - int idx_number = 3; - int idx_word = 5; - int type; - int metric; - - type = proto_redistnum(AFI_IP6, argv[idx_protocol]->text); - metric = atoi(argv[idx_number]->arg); - - if (type < 0) { - vty_out(vty, "Invalid type %s\n", argv[idx_protocol]->text); - return CMD_WARNING_CONFIG_FAILED; + /* Remove the routes from RIP table. */ + ripng_redistribute_withdraw(i); } - - ripng_redistribute_metric_set(type, metric); - ripng_redistribute_routemap_set(type, argv[idx_word]->text); - zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6, type, 0, - VRF_DEFAULT); - return CMD_SUCCESS; } -void ripng_redistribute_write(struct vty *vty, int config_mode) +void ripng_redistribute_write(struct vty *vty) { int i; @@ -377,31 +189,7 @@ void ripng_redistribute_write(struct vty *vty, int config_mode) VRF_DEFAULT)) continue; - if (!config_mode) { - vty_out(vty, " %s", zebra_route_string(i)); - continue; - } - - if (ripng->route_map[i].metric_config) { - if (ripng->route_map[i].name) - vty_out(vty, - " redistribute %s metric %d route-map %s\n", - zebra_route_string(i), - ripng->route_map[i].metric, - ripng->route_map[i].name); - else - vty_out(vty, " redistribute %s metric %d\n", - zebra_route_string(i), - ripng->route_map[i].metric); - } else { - if (ripng->route_map[i].name) - vty_out(vty, " redistribute %s route-map %s\n", - zebra_route_string(i), - ripng->route_map[i].name); - else - vty_out(vty, " redistribute %s\n", - zebra_route_string(i)); - } + vty_out(vty, " %s", zebra_route_string(i)); } } @@ -426,14 +214,6 @@ void zebra_init(struct thread_master *master) zclient->interface_address_delete = ripng_interface_address_delete; zclient->redistribute_route_add = ripng_zebra_read_route; zclient->redistribute_route_del = ripng_zebra_read_route; - - /* Install command elements to ripng node */ - install_element(RIPNG_NODE, &ripng_redistribute_type_cmd); - install_element(RIPNG_NODE, &ripng_redistribute_type_routemap_cmd); - install_element(RIPNG_NODE, &ripng_redistribute_type_metric_cmd); - install_element(RIPNG_NODE, - &ripng_redistribute_type_metric_routemap_cmd); - install_element(RIPNG_NODE, &no_ripng_redistribute_type_cmd); } void ripng_zebra_stop(void) diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index 2cbbbae7f5..58d83febfb 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -36,6 +36,7 @@ #include "if_rmap.h" #include "privs.h" #include "lib_errors.h" +#include "northbound_cli.h" #include "ripngd/ripngd.h" #include "ripngd/ripng_route.h" @@ -65,7 +66,7 @@ struct ripng_nexthop { struct in6_addr address; }; -static int ripng_route_rte(struct ripng_info *rinfo) +int ripng_route_rte(struct ripng_info *rinfo) { return (rinfo->type == ZEBRA_ROUTE_RIPNG && rinfo->sub_type == RIPNG_ROUTE_RTE); @@ -87,7 +88,7 @@ void ripng_info_free(struct ripng_info *rinfo) } /* Create ripng socket. */ -static int ripng_make_socket(void) +int ripng_make_socket(void) { int ret; int sock; @@ -1778,7 +1779,7 @@ void ripng_output_process(struct interface *ifp, struct sockaddr_in6 *to, } /* Create new RIPng instance and set it to global variable. */ -static int ripng_create(void) +int ripng_create(int socket) { /* ripng should be NULL. */ assert(ripng == NULL); @@ -1788,10 +1789,15 @@ static int ripng_create(void) /* Default version and timer values. */ ripng->version = RIPNG_V1; - ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT; - ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT; - ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT; - ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT; + ripng->update_time = yang_get_default_uint32( + "%s/timers/update-interval", RIPNG_INSTANCE); + ripng->timeout_time = yang_get_default_uint32( + "%s/timers/holddown-interval", RIPNG_INSTANCE); + ripng->garbage_time = yang_get_default_uint32( + "%s/timers/flush-interval", RIPNG_INSTANCE); + ripng->default_metric = + yang_get_default_uint8("%s/default-metric", RIPNG_INSTANCE); + ripng->ecmp = yang_get_default_bool("%s/allow-ecmp", RIPNG_INSTANCE); /* Make buffer. */ ripng->ibuf = stream_new(RIPNG_MAX_PACKET_SIZE * 5); @@ -1799,13 +1805,9 @@ static int ripng_create(void) /* Initialize RIPng routig table. */ ripng->table = agg_table_init(); - ripng->route = agg_table_init(); - ripng->aggregate = agg_table_init(); /* Make socket. */ - ripng->sock = ripng_make_socket(); - if (ripng->sock < 0) - return ripng->sock; + ripng->sock = socket; /* Threads. */ ripng_event(RIPNG_READ, ripng->sock); @@ -2060,12 +2062,12 @@ DEFUN (show_ipv6_ripng_status, return CMD_SUCCESS; vty_out(vty, "Routing Protocol is \"RIPng\"\n"); - vty_out(vty, " Sending updates every %ld seconds with +/-50%%,", + vty_out(vty, " Sending updates every %u seconds with +/-50%%,", ripng->update_time); vty_out(vty, " next due in %lu seconds\n", thread_timer_remain_second(ripng->t_update)); - vty_out(vty, " Timeout after %ld seconds,", ripng->timeout_time); - vty_out(vty, " garbage collect after %ld seconds\n", + vty_out(vty, " Timeout after %u seconds,", ripng->timeout_time); + vty_out(vty, " garbage collect after %u seconds\n", ripng->garbage_time); /* Filtering status show. */ @@ -2077,7 +2079,7 @@ DEFUN (show_ipv6_ripng_status, /* Redistribute information. */ vty_out(vty, " Redistributing:"); - ripng_redistribute_write(vty, 0); + ripng_redistribute_write(vty); vty_out(vty, "\n"); vty_out(vty, " Default version control: send version %d,", @@ -2099,7 +2101,7 @@ DEFUN (show_ipv6_ripng_status, } vty_out(vty, " Routing for Networks:\n"); - ripng_network_write(vty, 0); + ripng_network_write(vty); vty_out(vty, " Routing Information Sources:\n"); vty_out(vty, @@ -2109,245 +2111,6 @@ DEFUN (show_ipv6_ripng_status, return CMD_SUCCESS; } -DEFUN (clear_ipv6_rip, - clear_ipv6_rip_cmd, - "clear ipv6 ripng", - CLEAR_STR - IPV6_STR - "Clear IPv6 RIP database\n") -{ - struct agg_node *rp; - struct ripng_info *rinfo; - struct list *list; - struct listnode *listnode; - - /* Clear received RIPng routes */ - for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) { - list = rp->info; - if (list == NULL) - continue; - - for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) { - if (!ripng_route_rte(rinfo)) - continue; - - if (CHECK_FLAG(rinfo->flags, RIPNG_RTF_FIB)) - ripng_zebra_ipv6_delete(rp); - break; - } - - if (rinfo) { - RIPNG_TIMER_OFF(rinfo->t_timeout); - RIPNG_TIMER_OFF(rinfo->t_garbage_collect); - listnode_delete(list, rinfo); - ripng_info_free(rinfo); - } - - if (list_isempty(list)) { - list_delete(&list); - rp->info = NULL; - agg_unlock_node(rp); - } - } - - return CMD_SUCCESS; -} - -DEFUN_NOSH (router_ripng, - router_ripng_cmd, - "router ripng", - "Enable a routing process\n" - "Make RIPng instance command\n") -{ - int ret; - - vty->node = RIPNG_NODE; - - if (!ripng) { - ret = ripng_create(); - - /* Notice to user we couldn't create RIPng. */ - if (ret < 0) { - zlog_warn("can't create RIPng"); - return CMD_WARNING_CONFIG_FAILED; - } - } - - return CMD_SUCCESS; -} - -DEFUN (no_router_ripng, - no_router_ripng_cmd, - "no router ripng", - NO_STR - "Enable a routing process\n" - "Make RIPng instance command\n") -{ - if (ripng) - ripng_clean(); - return CMD_SUCCESS; -} - -DEFUN (ripng_route, - ripng_route_cmd, - "route IPV6ADDR", - "Static route setup\n" - "Set static RIPng route announcement\n") -{ - int idx_ipv6addr = 1; - int ret; - struct prefix_ipv6 p; - struct agg_node *rp; - - ret = str2prefix_ipv6(argv[idx_ipv6addr]->arg, - (struct prefix_ipv6 *)&p); - if (ret <= 0) { - vty_out(vty, "Malformed address\n"); - return CMD_WARNING_CONFIG_FAILED; - } - apply_mask_ipv6(&p); - - rp = agg_node_get(ripng->route, (struct prefix *)&p); - if (rp->info) { - vty_out(vty, "There is already same static route.\n"); - agg_unlock_node(rp); - return CMD_WARNING; - } - rp->info = (void *)1; - - ripng_redistribute_add(ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0, - NULL, 0); - - return CMD_SUCCESS; -} - -DEFUN (no_ripng_route, - no_ripng_route_cmd, - "no route IPV6ADDR", - NO_STR - "Static route setup\n" - "Delete static RIPng route announcement\n") -{ - int idx_ipv6addr = 2; - int ret; - struct prefix_ipv6 p; - struct agg_node *rp; - - ret = str2prefix_ipv6(argv[idx_ipv6addr]->arg, - (struct prefix_ipv6 *)&p); - if (ret <= 0) { - vty_out(vty, "Malformed address\n"); - return CMD_WARNING_CONFIG_FAILED; - } - apply_mask_ipv6(&p); - - rp = agg_node_lookup(ripng->route, (struct prefix *)&p); - if (!rp) { - vty_out(vty, "Can't find static route.\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - ripng_redistribute_delete(ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0); - agg_unlock_node(rp); - - rp->info = NULL; - agg_unlock_node(rp); - - return CMD_SUCCESS; -} - -DEFUN (ripng_aggregate_address, - ripng_aggregate_address_cmd, - "aggregate-address X:X::X:X/M", - "Set aggregate RIPng route announcement\n" - "Aggregate network\n") -{ - int idx_ipv6_prefixlen = 1; - int ret; - struct prefix p; - struct agg_node *node; - - ret = str2prefix_ipv6(argv[idx_ipv6_prefixlen]->arg, - (struct prefix_ipv6 *)&p); - if (ret <= 0) { - vty_out(vty, "Malformed address\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - /* Check aggregate alredy exist or not. */ - node = agg_node_get(ripng->aggregate, &p); - if (node->info) { - vty_out(vty, "There is already same aggregate route.\n"); - agg_unlock_node(node); - return CMD_WARNING; - } - node->info = (void *)1; - - ripng_aggregate_add(&p); - - return CMD_SUCCESS; -} - -DEFUN (no_ripng_aggregate_address, - no_ripng_aggregate_address_cmd, - "no aggregate-address X:X::X:X/M", - NO_STR - "Delete aggregate RIPng route announcement\n" - "Aggregate network\n") -{ - int idx_ipv6_prefixlen = 2; - int ret; - struct prefix p; - struct agg_node *rn; - - ret = str2prefix_ipv6(argv[idx_ipv6_prefixlen]->arg, - (struct prefix_ipv6 *)&p); - if (ret <= 0) { - vty_out(vty, "Malformed address\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - rn = agg_node_lookup(ripng->aggregate, &p); - if (!rn) { - vty_out(vty, "Can't find aggregate route.\n"); - return CMD_WARNING_CONFIG_FAILED; - } - agg_unlock_node(rn); - rn->info = NULL; - agg_unlock_node(rn); - - ripng_aggregate_delete(&p); - - return CMD_SUCCESS; -} - -DEFUN (ripng_default_metric, - ripng_default_metric_cmd, - "default-metric (1-16)", - "Set a metric of redistribute routes\n" - "Default metric\n") -{ - int idx_number = 1; - if (ripng) { - ripng->default_metric = atoi(argv[idx_number]->arg); - } - return CMD_SUCCESS; -} - -DEFUN (no_ripng_default_metric, - no_ripng_default_metric_cmd, - "no default-metric [(1-16)]", - NO_STR - "Set a metric of redistribute routes\n" - "Default metric\n") -{ - if (ripng) { - ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT; - } - return CMD_SUCCESS; -} - - #if 0 /* RIPng update timer setup. */ DEFUN (ripng_update_timer, @@ -2451,58 +2214,6 @@ DEFUN (no_ripng_garbage_timer, } #endif /* 0 */ -DEFUN (ripng_timers, - ripng_timers_cmd, - "timers basic (0-65535) (0-65535) (0-65535)", - "RIPng timers setup\n" - "Basic timer\n" - "Routing table update timer value in second. Default is 30.\n" - "Routing information timeout timer. Default is 180.\n" - "Garbage collection timer. Default is 120.\n") -{ - int idx_number = 2; - int idx_number_2 = 3; - int idx_number_3 = 4; - unsigned long update; - unsigned long timeout; - unsigned long garbage; - - update = strtoul(argv[idx_number]->arg, NULL, 10); - timeout = strtoul(argv[idx_number_2]->arg, NULL, 10); - garbage = strtoul(argv[idx_number_3]->arg, NULL, 10); - - /* Set each timer value. */ - ripng->update_time = update; - ripng->timeout_time = timeout; - ripng->garbage_time = garbage; - - /* Reset update timer thread. */ - ripng_event(RIPNG_UPDATE_EVENT, 0); - - return CMD_SUCCESS; -} - -DEFUN (no_ripng_timers, - no_ripng_timers_cmd, - "no timers basic [(0-65535) (0-65535) (0-65535)]", - NO_STR - "RIPng timers setup\n" - "Basic timer\n" - "Routing table update timer value in second. Default is 30.\n" - "Routing information timeout timer. Default is 180.\n" - "Garbage collection timer. Default is 120.\n") -{ - /* Set each timer value to the default. */ - ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT; - ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT; - ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT; - - /* Reset update timer thread. */ - ripng_event(RIPNG_UPDATE_EVENT, 0); - - return CMD_SUCCESS; -} - #if 0 DEFUN (show_ipv6_protocols, show_ipv6_protocols_cmd, @@ -2530,48 +2241,8 @@ DEFUN (show_ipv6_protocols, } #endif -/* Please be carefull to use this command. */ -DEFUN (ripng_default_information_originate, - ripng_default_information_originate_cmd, - "default-information originate", - "Default route information\n" - "Distribute default route\n") -{ - struct prefix_ipv6 p; - - if (!ripng->default_information) { - ripng->default_information = 1; - - str2prefix_ipv6("::/0", &p); - ripng_redistribute_add(ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, - &p, 0, NULL, 0); - } - - return CMD_SUCCESS; -} - -DEFUN (no_ripng_default_information_originate, - no_ripng_default_information_originate_cmd, - "no default-information originate", - NO_STR - "Default route information\n" - "Distribute default route\n") -{ - struct prefix_ipv6 p; - - if (ripng->default_information) { - ripng->default_information = 0; - - str2prefix_ipv6("::/0", &p); - ripng_redistribute_delete(ZEBRA_ROUTE_RIPNG, - RIPNG_ROUTE_DEFAULT, &p, 0); - } - - return CMD_SUCCESS; -} - /* Update ECMP routes to zebra when ECMP is disabled. */ -static void ripng_ecmp_disable(void) +void ripng_ecmp_disable(void) { struct agg_node *rp; struct ripng_info *rinfo, *tmp_rinfo; @@ -2608,109 +2279,24 @@ static void ripng_ecmp_disable(void) } } -DEFUN (ripng_allow_ecmp, - ripng_allow_ecmp_cmd, - "allow-ecmp", - "Allow Equal Cost MultiPath\n") -{ - if (ripng->ecmp) { - vty_out(vty, "ECMP is already enabled.\n"); - return CMD_WARNING; - } - - ripng->ecmp = 1; - zlog_info("ECMP is enabled."); - return CMD_SUCCESS; -} - -DEFUN (no_ripng_allow_ecmp, - no_ripng_allow_ecmp_cmd, - "no allow-ecmp", - NO_STR - "Allow Equal Cost MultiPath\n") -{ - if (!ripng->ecmp) { - vty_out(vty, "ECMP is already disabled.\n"); - return CMD_WARNING; - } - - ripng->ecmp = 0; - zlog_info("ECMP is disabled."); - ripng_ecmp_disable(); - return CMD_SUCCESS; -} - /* RIPng configuration write function. */ static int ripng_config_write(struct vty *vty) { - int ripng_network_write(struct vty *, int); - void ripng_redistribute_write(struct vty *, int); + struct lyd_node *dnode; int write = 0; - struct agg_node *rp; - - if (ripng) { - /* RIPng router. */ - vty_out(vty, "router ripng\n"); - - if (ripng->default_information) - vty_out(vty, " default-information originate\n"); - - ripng_network_write(vty, 1); - - /* RIPng default metric configuration */ - if (ripng->default_metric != RIPNG_DEFAULT_METRIC_DEFAULT) - vty_out(vty, " default-metric %d\n", - ripng->default_metric); - - ripng_redistribute_write(vty, 1); - - /* RIP offset-list configuration. */ - config_write_ripng_offset_list(vty); - - /* RIPng aggregate routes. */ - for (rp = agg_route_top(ripng->aggregate); rp; - rp = agg_route_next(rp)) - if (rp->info != NULL) - vty_out(vty, " aggregate-address %s/%d\n", - inet6_ntoa(rp->p.u.prefix6), - rp->p.prefixlen); - - /* ECMP configuration. */ - if (ripng->ecmp) - vty_out(vty, " allow-ecmp\n"); - - /* RIPng static routes. */ - for (rp = agg_route_top(ripng->route); rp; - rp = agg_route_next(rp)) - if (rp->info != NULL) - vty_out(vty, " route %s/%d\n", - inet6_ntoa(rp->p.u.prefix6), - rp->p.prefixlen); - - /* RIPng timers configuration. */ - if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT - || ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT - || ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT) { - vty_out(vty, " timers basic %ld %ld %ld\n", - ripng->update_time, ripng->timeout_time, - ripng->garbage_time); - } -#if 0 - if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT) - vty_out (vty, " update-timer %d\n", ripng->update_time); - if (ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT) - vty_out (vty, " timeout-timer %d\n", ripng->timeout_time); - if (ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT) - vty_out (vty, " garbage-timer %d\n", ripng->garbage_time); -#endif /* 0 */ + dnode = yang_dnode_get(running_config->dnode, + "/frr-ripngd:ripngd/instance"); + if (dnode) { + nb_cli_show_dnode_cmds(vty, dnode, false); - write += config_write_distribute(vty); + config_write_distribute(vty); - write += config_write_if_rmap(vty); + config_write_if_rmap(vty); - write++; + write = 1; } + return write; } @@ -2855,29 +2441,11 @@ void ripng_clean() ripng->sock = -1; } - /* Static RIPng route configuration. */ - for (rp = agg_route_top(ripng->route); rp; - rp = agg_route_next(rp)) - if (rp->info) { - rp->info = NULL; - agg_unlock_node(rp); - } - - /* RIPng aggregated prefixes */ - for (rp = agg_route_top(ripng->aggregate); rp; - rp = agg_route_next(rp)) - if (rp->info) { - rp->info = NULL; - agg_unlock_node(rp); - } - for (i = 0; i < ZEBRA_ROUTE_MAX; i++) if (ripng->route_map[i].name) free(ripng->route_map[i].name); XFREE(MTYPE_ROUTE_TABLE, ripng->table); - XFREE(MTYPE_ROUTE_TABLE, ripng->route); - XFREE(MTYPE_ROUTE_TABLE, ripng->aggregate); stream_free(ripng->ibuf); stream_free(ripng->obuf); @@ -2893,25 +2461,6 @@ void ripng_clean() ripng_redistribute_clean(); } -/* Reset all values to the default settings. */ -void ripng_reset() -{ - /* Call ripd related reset functions. */ - ripng_debug_reset(); - ripng_route_map_reset(); - - /* Call library reset functions. */ - vty_reset(); - access_list_reset(); - prefix_list_reset(); - - distribute_list_reset(); - - ripng_interface_reset(); - - ripng_zclient_reset(); -} - static void ripng_if_rmap_update(struct if_rmap *if_rmap) { struct interface *ifp; @@ -2987,22 +2536,8 @@ void ripng_init() install_element(VIEW_NODE, &show_ipv6_ripng_cmd); install_element(VIEW_NODE, &show_ipv6_ripng_status_cmd); - install_element(ENABLE_NODE, &clear_ipv6_rip_cmd); - - install_element(CONFIG_NODE, &router_ripng_cmd); - install_element(CONFIG_NODE, &no_router_ripng_cmd); - install_default(RIPNG_NODE); - install_element(RIPNG_NODE, &ripng_route_cmd); - install_element(RIPNG_NODE, &no_ripng_route_cmd); - install_element(RIPNG_NODE, &ripng_aggregate_address_cmd); - install_element(RIPNG_NODE, &no_ripng_aggregate_address_cmd); - - install_element(RIPNG_NODE, &ripng_default_metric_cmd); - install_element(RIPNG_NODE, &no_ripng_default_metric_cmd); - install_element(RIPNG_NODE, &ripng_timers_cmd); - install_element(RIPNG_NODE, &no_ripng_timers_cmd); #if 0 install_element (VIEW_NODE, &show_ipv6_protocols_cmd); install_element (RIPNG_NODE, &ripng_update_timer_cmd); @@ -3013,13 +2548,6 @@ void ripng_init() install_element (RIPNG_NODE, &no_ripng_garbage_timer_cmd); #endif /* 0 */ - install_element(RIPNG_NODE, &ripng_default_information_originate_cmd); - install_element(RIPNG_NODE, - &no_ripng_default_information_originate_cmd); - - install_element(RIPNG_NODE, &ripng_allow_ecmp_cmd); - install_element(RIPNG_NODE, &no_ripng_allow_ecmp_cmd); - ripng_if_init(); ripng_debug_init(); diff --git a/ripngd/ripngd.h b/ripngd/ripngd.h index 1095a33494..5b32374ace 100644 --- a/ripngd/ripngd.h +++ b/ripngd/ripngd.h @@ -43,11 +43,6 @@ #define RIPNG_METRIC_NEXTHOP 0xff #define RIPNG_GROUP "ff02::9" -/* RIPng timers. */ -#define RIPNG_UPDATE_TIMER_DEFAULT 30 -#define RIPNG_TIMEOUT_TIMER_DEFAULT 180 -#define RIPNG_GARBAGE_TIMER_DEFAULT 120 - /* RIPng peer timeout value. */ #define RIPNG_PEER_TIMER_DEFAULT 180 @@ -77,9 +72,6 @@ #define RIPNG_DEFAULT_ACCEPT_NONE 1 #define RIPNG_DEFAULT_ACCEPT 2 -/* Default value for "default-metric" command. */ -#define RIPNG_DEFAULT_METRIC_DEFAULT 1 - /* For max RTE calculation. */ #ifndef IPV6_HDRLEN #define IPV6_HDRLEN 40 @@ -89,6 +81,10 @@ #define IFMINMTU 576 #endif /* IFMINMTU */ +/* YANG paths */ +#define RIPNG_INSTANCE "/frr-ripngd:ripngd/instance" +#define RIPNG_IFACE "/frr-interface:lib/interface/frr-ripngd:ripng" + /* RIPng structure. */ struct ripng { /* RIPng socket. */ @@ -97,12 +93,11 @@ struct ripng { /* RIPng Parameters.*/ uint8_t command; uint8_t version; - unsigned long update_time; - unsigned long timeout_time; - unsigned long garbage_time; + uint16_t update_time; + uint16_t timeout_time; + uint16_t garbage_time; int max_mtu; - int default_metric; - int default_information; + uint8_t default_metric; /* Input/output buffer of RIPng. */ struct stream *ibuf; @@ -111,12 +106,6 @@ struct ripng { /* RIPng routing information base. */ struct agg_table *table; - /* RIPng only static route information. */ - struct agg_table *route; - - /* RIPng aggregate route information. */ - struct agg_table *aggregate; - /* RIPng threads. */ struct thread *t_read; struct thread *t_write; @@ -130,14 +119,14 @@ struct ripng { struct thread *t_triggered_interval; /* RIPng ECMP flag */ - unsigned int ecmp; + bool ecmp; /* For redistribute route map. */ struct { char *name; struct route_map *map; - int metric_config; - uint32_t metric; + bool metric_config; + uint8_t metric; } route_map[ZEBRA_ROUTE_MAX]; }; @@ -247,7 +236,6 @@ struct ripng_interface { /* Split horizon flag. */ split_horizon_policy_t split_horizon; - split_horizon_policy_t split_horizon_default; /* For filter type slot. */ #define RIPNG_FILTER_IN 0 @@ -325,30 +313,46 @@ enum ripng_event { } \ } while (0) +#define RIPNG_OFFSET_LIST_IN 0 +#define RIPNG_OFFSET_LIST_OUT 1 +#define RIPNG_OFFSET_LIST_MAX 2 + +struct ripng_offset_list { + char *ifname; + + struct { + char *alist_name; + /* struct access_list *alist; */ + uint8_t metric; + } direct[RIPNG_OFFSET_LIST_MAX]; +}; + /* Extern variables. */ extern struct ripng *ripng; +extern struct list *peer_list; extern struct zebra_privs_t ripngd_privs; extern struct thread_master *master; /* Prototypes. */ extern void ripng_init(void); -extern void ripng_reset(void); extern void ripng_clean(void); extern void ripng_clean_network(void); extern void ripng_interface_clean(void); -extern void ripng_interface_reset(void); +extern int ripng_enable_network_add(struct prefix *p); +extern int ripng_enable_network_delete(struct prefix *p); +extern int ripng_enable_if_add(const char *ifname); +extern int ripng_enable_if_delete(const char *ifname); +extern int ripng_passive_interface_set(const char *ifname); +extern int ripng_passive_interface_unset(const char *ifname); extern void ripng_passive_interface_clean(void); extern void ripng_if_init(void); extern void ripng_route_map_init(void); -extern void ripng_route_map_reset(void); extern void ripng_terminate(void); /* zclient_init() is done by ripng_zebra.c:zebra_init() */ extern void zebra_init(struct thread_master *); extern void ripng_zebra_stop(void); -extern void ripng_zclient_reset(void); -extern void ripng_offset_init(void); - -extern int config_write_ripng_offset_list(struct vty *); +extern void ripng_redistribute_conf_update(int type); +extern void ripng_redistribute_conf_delete(int type); extern void ripng_peer_init(void); extern void ripng_peer_update(struct sockaddr_in6 *, uint8_t); @@ -358,12 +362,18 @@ extern void ripng_peer_display(struct vty *); extern struct ripng_peer *ripng_peer_lookup(struct in6_addr *); extern struct ripng_peer *ripng_peer_lookup_next(struct in6_addr *); +extern struct ripng_offset_list *ripng_offset_list_new(const char *ifname); +extern void ripng_offset_list_del(struct ripng_offset_list *offset); +extern struct ripng_offset_list *ripng_offset_list_lookup(const char *ifname); +extern struct ripng_offset_list *ripng_offset_list_lookup(const char *ifname); extern int ripng_offset_list_apply_in(struct prefix_ipv6 *, struct interface *, uint8_t *); extern int ripng_offset_list_apply_out(struct prefix_ipv6 *, struct interface *, uint8_t *); +extern void ripng_offset_init(void); extern void ripng_offset_clean(void); +extern int ripng_route_rte(struct ripng_info *rinfo); extern struct ripng_info *ripng_info_new(void); extern void ripng_info_free(struct ripng_info *rinfo); extern void ripng_event(enum ripng_event, int); @@ -374,6 +384,7 @@ extern void ripng_redistribute_delete(int, int, struct prefix_ipv6 *, ifindex_t); extern void ripng_redistribute_withdraw(int type); +extern void ripng_ecmp_disable(void); extern void ripng_distribute_update_interface(struct interface *); extern void ripng_if_rmap_update_interface(struct interface *); @@ -382,7 +393,7 @@ extern void ripng_zebra_ipv6_delete(struct agg_node *node); extern void ripng_redistribute_clean(void); extern int ripng_redistribute_check(int); -extern void ripng_redistribute_write(struct vty *, int); +extern void ripng_redistribute_write(struct vty *); extern int ripng_write_rte(int num, struct stream *s, struct prefix_ipv6 *p, struct in6_addr *nexthop, uint16_t tag, @@ -406,10 +417,16 @@ extern int ripng_interface_address_add(int command, struct zclient *, extern int ripng_interface_address_delete(int command, struct zclient *, zebra_size_t, vrf_id_t); -extern int ripng_network_write(struct vty *, int); +extern int ripng_create(int socket); +extern int ripng_make_socket(void); +extern int ripng_network_write(struct vty *); extern struct ripng_info *ripng_ecmp_add(struct ripng_info *); extern struct ripng_info *ripng_ecmp_replace(struct ripng_info *); extern struct ripng_info *ripng_ecmp_delete(struct ripng_info *); +/* Northbound. */ +extern void ripng_cli_init(void); +extern const struct frr_yang_module_info frr_ripngd_info; + #endif /* _ZEBRA_RIPNG_RIPNGD_H */ diff --git a/ripngd/subdir.am b/ripngd/subdir.am index 8f834a1d29..d401e9bbf6 100644 --- a/ripngd/subdir.am +++ b/ripngd/subdir.am @@ -6,21 +6,21 @@ if RIPNGD noinst_LIBRARIES += ripngd/libripng.a sbin_PROGRAMS += ripngd/ripngd vtysh_scan += \ + $(top_srcdir)/ripngd/ripng_cli.c \ $(top_srcdir)/ripngd/ripng_debug.c \ - $(top_srcdir)/ripngd/ripng_interface.c \ - $(top_srcdir)/ripngd/ripng_offset.c \ - $(top_srcdir)/ripngd/ripng_zebra.c \ $(top_srcdir)/ripngd/ripngd.c \ # end man8 += $(MANBUILD)/ripngd.8 endif ripngd_libripng_a_SOURCES = \ + ripngd/ripng_cli.c \ ripngd/ripng_debug.c \ ripngd/ripng_interface.c \ ripngd/ripng_memory.c \ ripngd/ripng_nexthop.c \ ripngd/ripng_offset.c \ + ripngd/ripng_northbound.c \ ripngd/ripng_peer.c \ ripngd/ripng_route.c \ ripngd/ripng_routemap.c \ @@ -28,7 +28,11 @@ ripngd_libripng_a_SOURCES = \ ripngd/ripngd.c \ # end +ripngd/ripng_cli_clippy.c: $(CLIPPY_DEPS) +ripngd/ripng_cli.$(OBJEXT): ripngd/ripng_cli_clippy.c + noinst_HEADERS += \ + ripngd/ripng_cli.h \ ripngd/ripng_debug.h \ ripngd/ripng_memory.h \ ripngd/ripng_nexthop.h \ @@ -40,5 +44,8 @@ ripngd_ripngd_LDADD = ripngd/libripng.a lib/libfrr.la @LIBCAP@ ripngd_ripngd_SOURCES = \ ripngd/ripng_main.c \ # end +nodist_ripngd_ripngd_SOURCES = \ + yang/frr-ripngd.yang.c \ + # end dist_examples_DATA += ripngd/ripngd.conf.sample diff --git a/yang/confd/confd.frr-ripngd.yang b/yang/confd/confd.frr-ripngd.yang new file mode 100644 index 0000000000..5d876ff4d3 --- /dev/null +++ b/yang/confd/confd.frr-ripngd.yang @@ -0,0 +1,22 @@ +module confd.frr-ripngd { + namespace "urn:dummy"; + prefix "dummy"; + + import tailf-common { + prefix tailf; + } + import frr-ripngd { + prefix frr-ripngd; + } + + tailf:annotate-module "frr-ripngd" { + tailf:annotate-statement "container[name='ripngd']" { + tailf:annotate-statement "container[name='state']" { + tailf:callpoint "state"; + } + } + tailf:annotate-statement "rpc[name='clear-ripng-route']" { + tailf:actionpoint "actionpoint"; + } + } +} diff --git a/yang/frr-ripngd.yang b/yang/frr-ripngd.yang new file mode 100644 index 0000000000..0cc5f18a5f --- /dev/null +++ b/yang/frr-ripngd.yang @@ -0,0 +1,321 @@ +module frr-ripngd { + yang-version 1.1; + namespace "http://frrouting.org/yang/ripngd"; + prefix frr-ripngd; + + 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: <mailto:frog@lists.frrouting.org> + FRR Development List: <mailto:dev@lists.frrouting.org>"; + description + "This module defines a model for managing FRR ripngd daemon."; + + revision 2018-11-27 { + description + "Initial revision."; + reference + "RFC 2080: RIPng for IPv6."; + } + + container ripngd { + /* + * Global configuration data + */ + container instance { + presence "Present if the RIPng protocol is enabled."; + description + "RIPng 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."; + } + leaf-list network { + type inet:ipv6-prefix; + description + "Enable RIPng on the specified IPv6 network."; + } + leaf-list interface { + type string { + length "1..16"; + } + description + "Enable RIPng 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-list passive-interface { + type string { + length "1..16"; + } + description + "A list of interfaces where the sending of RIPng packets + is disabled."; + } + list redistribute { + key "protocol"; + description + "Redistributes routes learned from other routing protocols."; + leaf protocol { + type frr-route-types:frr-route-types-v6; + description + "Routing protocol."; + must '. != "ripng"'; + } + leaf route-map { + type string { + length "1..max"; + } + description + "Applies the conditions of the specified route-map to + routes that are redistributed into the RIPng 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 RIPng 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:ipv6-prefix; + description + "RIPng static routes."; + } + leaf-list aggregate-address { + type inet:ipv6-prefix; + description + "RIPng aggregate route announcement."; + } + container timers { + description + "Settings of basic timers"; + leaf flush-interval { + type uint16 { + range "1..65535"; + } + units "seconds"; + default "120"; + description + "Interval before a route is flushed from the routing + table."; + } + leaf holddown-interval { + type uint16 { + range "1..65535"; + } + units "seconds"; + default "180"; + description + "Interval before better routes are released."; + } + leaf update-interval { + type uint16 { + range "1..65535"; + } + units "seconds"; + default "30"; + description + "Interval at which RIPng updates are sent."; + } + } + } + + /* + * Operational data. + */ + container state { + config false; + description + "Operational data."; + + container neighbors { + description + "Neighbor information."; + list neighbor { + key "address"; + description + "A RIPng neighbor."; + leaf address { + type inet:ipv6-address; + description + "IPv6 address that a RIPng neighbor is using as its + source address."; + } + leaf last-update { + type yang:date-and-time; + description + "The time when the most recent RIPng update was + received from this neighbor."; + } + leaf bad-packets-rcvd { + type yang:counter32; + description + "The number of RIPng 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 RIPng 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 RIPng IPv6 route."; + leaf prefix { + type inet:ipv6-prefix; + description + "IPv6 address and prefix length, in the format + specified in RFC6991."; + } + leaf next-hop { + type inet:ipv6-address; + description + "Next hop IPv6 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 ripng { + description + "RIPng 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 RIPng split-horizon processing on the specified + interface."; + } + } + } + + /* + * RPCs + */ + rpc clear-ripng-route { + description + "Clears RIPng routes from the IPv6 routing table and routes + redistributed into the RIPng protocol."; + } +} diff --git a/yang/subdir.am b/yang/subdir.am index 07bd225780..6484e1181f 100644 --- a/yang/subdir.am +++ b/yang/subdir.am @@ -27,3 +27,7 @@ dist_yangmodels_DATA += yang/frr-route-types.yang if RIPD dist_yangmodels_DATA += yang/frr-ripd.yang endif + +if RIPNGD +dist_yangmodels_DATA += yang/frr-ripngd.yang +endif diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 8a7cb0e528..4f89d53e39 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -918,6 +918,9 @@ void rtm_read(struct rt_msghdr *rtm) char ifname[INTERFACE_NAMSIZ + 1]; short ifnlen = 0; struct nexthop nh; + struct prefix p; + ifindex_t ifindex = 0; + afi_t afi; zebra_flags = 0; @@ -951,10 +954,6 @@ void rtm_read(struct rt_msghdr *rtm) if (flags & RTF_PROTO1) SET_FLAG(zebra_flags, ZEBRA_FLAG_SELFROUTE); - /* This is persistent route. */ - if (flags & RTF_STATIC) - SET_FLAG(zebra_flags, ZEBRA_FLAG_STATIC); - memset(&nh, 0, sizeof(nh)); nh.vrf_id = VRF_DEFAULT; @@ -967,9 +966,14 @@ void rtm_read(struct rt_msghdr *rtm) nh.bh_type = BLACKHOLE_NULL; } - if (dest.sa.sa_family == AF_INET) { - struct prefix p; + /* + * Ignore our own messages. + */ + if (rtm->rtm_type != RTM_GET && rtm->rtm_pid == pid) + return; + if (dest.sa.sa_family == AF_INET) { + afi = AFI_IP; p.family = AF_INET; p.u.prefix4 = dest.sin.sin_addr; if (flags & RTF_HOST) @@ -977,146 +981,12 @@ void rtm_read(struct rt_msghdr *rtm) else p.prefixlen = ip_masklen(mask.sin.sin_addr); - /* Catch self originated messages and match them against our - * current RIB. - * At the same time, ignore unconfirmed messages, they should be - * tracked - * by rtm_write() and kernel_rtm_ipv4(). - */ - if (rtm->rtm_type != RTM_GET && rtm->rtm_pid == pid) { - char buf[PREFIX_STRLEN], gate_buf[INET_ADDRSTRLEN]; - int ret; - if (!IS_ZEBRA_DEBUG_RIB) - return; - ret = rib_lookup_ipv4_route((struct prefix_ipv4 *)&p, - &gate, VRF_DEFAULT); - prefix2str(&p, buf, sizeof(buf)); - switch (rtm->rtm_type) { - case RTM_ADD: - case RTM_GET: - case RTM_CHANGE: - /* The kernel notifies us about a new route in - FIB created by us. - Do we have a correspondent entry in our RIB? - */ - switch (ret) { - case ZEBRA_RIB_NOTFOUND: - zlog_debug( - "%s: %s %s: desync: RR isn't yet in RIB, while already in FIB", - __func__, - lookup_msg(rtm_type_str, - rtm->rtm_type, NULL), - buf); - break; - case ZEBRA_RIB_FOUND_CONNECTED: - case ZEBRA_RIB_FOUND_NOGATE: - inet_ntop(AF_INET, &gate.sin.sin_addr, - gate_buf, INET_ADDRSTRLEN); - zlog_debug( - "%s: %s %s: desync: RR is in RIB, but gate differs (ours is %s)", - __func__, - lookup_msg(rtm_type_str, - rtm->rtm_type, NULL), - buf, gate_buf); - break; - case ZEBRA_RIB_FOUND_EXACT: /* RIB RR == FIB RR - */ - zlog_debug( - "%s: %s %s: done Ok", __func__, - lookup_msg(rtm_type_str, - rtm->rtm_type, NULL), - buf); - rib_lookup_and_dump( - (struct prefix_ipv4 *)&p, - VRF_DEFAULT); - return; - break; - } - break; - case RTM_DELETE: - /* The kernel notifies us about a route deleted - by us. Do we still - have it in the RIB? Do we have anything - instead? */ - switch (ret) { - case ZEBRA_RIB_FOUND_EXACT: - zlog_debug( - "%s: %s %s: desync: RR is still in RIB, while already not in FIB", - __func__, - lookup_msg(rtm_type_str, - rtm->rtm_type, NULL), - buf); - rib_lookup_and_dump( - (struct prefix_ipv4 *)&p, - VRF_DEFAULT); - break; - case ZEBRA_RIB_FOUND_CONNECTED: - case ZEBRA_RIB_FOUND_NOGATE: - zlog_debug( - "%s: %s %s: desync: RR is still in RIB, plus gate differs", - __func__, - lookup_msg(rtm_type_str, - rtm->rtm_type, NULL), - buf); - rib_lookup_and_dump( - (struct prefix_ipv4 *)&p, - VRF_DEFAULT); - break; - case ZEBRA_RIB_NOTFOUND: /* RIB RR == FIB RR */ - zlog_debug( - "%s: %s %s: done Ok", __func__, - lookup_msg(rtm_type_str, - rtm->rtm_type, NULL), - buf); - rib_lookup_and_dump( - (struct prefix_ipv4 *)&p, - VRF_DEFAULT); - return; - break; - } - break; - default: - zlog_debug( - "%s: %s: warning: loopback RTM of type %s received", - __func__, buf, - lookup_msg(rtm_type_str, rtm->rtm_type, - NULL)); - } - return; - } - - /* Change, delete the old prefix, we have no further information - * to specify the route really - */ - if (rtm->rtm_type == RTM_CHANGE) - rib_delete(AFI_IP, SAFI_UNICAST, VRF_DEFAULT, - ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL, - NULL, 0, 0, 0, true); - if (!nh.type) { nh.type = NEXTHOP_TYPE_IPV4; nh.gate.ipv4 = gate.sin.sin_addr; } - - if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD - || rtm->rtm_type == RTM_CHANGE) - rib_add(AFI_IP, SAFI_UNICAST, VRF_DEFAULT, - ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL, - &nh, 0, 0, 0, 0, 0); - else - rib_delete(AFI_IP, SAFI_UNICAST, VRF_DEFAULT, - ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL, - &nh, 0, 0, 0, true); - } - if (dest.sa.sa_family == AF_INET6) { - /* One day we might have a debug section here like one in the - * IPv4 case above. Just ignore own messages at the moment. - */ - if (rtm->rtm_type != RTM_GET && rtm->rtm_pid == pid) - return; - struct prefix p; - ifindex_t ifindex = 0; - + } else if (dest.sa.sa_family == AF_INET6) { + afi = AFI_IP6; p.family = AF_INET6; p.u.prefix6 = dest.sin6.sin6_addr; if (flags & RTF_HOST) @@ -1131,31 +1001,29 @@ void rtm_read(struct rt_msghdr *rtm) } #endif /* KAME */ - /* CHANGE: delete the old prefix, we have no further information - * to specify the route really - */ - if (rtm->rtm_type == RTM_CHANGE) - rib_delete(AFI_IP6, SAFI_UNICAST, VRF_DEFAULT, - ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL, - NULL, 0, 0, 0, true); - if (!nh.type) { nh.type = ifindex ? NEXTHOP_TYPE_IPV6_IFINDEX : NEXTHOP_TYPE_IPV6; nh.gate.ipv6 = gate.sin6.sin6_addr; nh.ifindex = ifindex; } + } else + return; - if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD - || rtm->rtm_type == RTM_CHANGE) - rib_add(AFI_IP6, SAFI_UNICAST, VRF_DEFAULT, - ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL, - &nh, 0, 0, 0, 0, 0); - else - rib_delete(AFI_IP6, SAFI_UNICAST, VRF_DEFAULT, - ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL, - &nh, 0, 0, 0, true); - } + /* + * CHANGE: delete the old prefix, we have no further information + * to specify the route really + */ + if (rtm->rtm_type == RTM_CHANGE) + rib_delete(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, + 0, zebra_flags, &p, NULL, NULL, 0, 0, 0, true); + if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD + || rtm->rtm_type == RTM_CHANGE) + rib_add(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, + zebra_flags, &p, NULL, &nh, 0, 0, 0, 0, 0); + else + rib_delete(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, + 0, zebra_flags, &p, NULL, &nh, 0, 0, 0, true); } /* Interface function for the kernel routing table updates. Support diff --git a/zebra/rib.h b/zebra/rib.h index 97eae79f03..ae25a0e679 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -282,8 +282,6 @@ extern enum multicast_mode multicast_mode_ipv4_get(void); extern void rib_lookup_and_dump(struct prefix_ipv4 *p, vrf_id_t vrf_id); extern void rib_lookup_and_pushup(struct prefix_ipv4 *p, vrf_id_t vrf_id); -extern int rib_lookup_ipv4_route(struct prefix_ipv4 *p, union sockunion *qgate, - vrf_id_t vrf_id); #define ZEBRA_RIB_LOOKUP_ERROR -1 #define ZEBRA_RIB_FOUND_EXACT 0 #define ZEBRA_RIB_FOUND_NOGATE 1 diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index cb9ef8e36f..8ce963b37b 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1584,7 +1584,7 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) } /* Singlepath case. */ - if (nexthop_num == 1 || multipath_num == 1) { + if (nexthop_num == 1) { nexthop_num = 0; for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) { /* @@ -1676,9 +1676,6 @@ static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) nexthop_num = 0; for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) { - if (nexthop_num >= multipath_num) - break; - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) { /* This only works for IPv4 now */ @@ -1876,12 +1873,6 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) { SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); - - /* If we're only allowed a single nh, don't - * continue. - */ - if (multipath_num == 1) - break; } } } @@ -2698,7 +2689,7 @@ int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp) /* Fill nexthops (paths) based on single-path or multipath. The paths * chosen depend on the operation. */ - if (nexthop_num == 1 || multipath_num == 1) { + if (nexthop_num == 1) { routedesc = "single-path"; _netlink_mpls_debug(cmd, lsp->ile.in_label, routedesc); @@ -2745,9 +2736,6 @@ int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp) if (!nexthop) continue; - if (nexthop_num >= multipath_num) - break; - if ((cmd == RTM_NEWROUTE && (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED) && CHECK_FLAG(nexthop->flags, diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 9f1374af57..5d6eac7533 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -412,7 +412,7 @@ static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop, /* If force flag is not set, do not modify falgs at all for uninstall the route from FIB. */ static int nexthop_active(afi_t afi, struct route_entry *re, - struct nexthop *nexthop, int set, + struct nexthop *nexthop, bool set, struct route_node *top) { struct prefix p; @@ -808,84 +808,6 @@ struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, vrf_id_t vrf_id) return NULL; } -/* - * This clone function, unlike its original rib_lookup_ipv4(), checks - * if specified IPv4 route record (prefix/mask -> gate) exists in - * the whole RIB and has ROUTE_ENTRY_SELECTED_FIB set. - * - * Return values: - * -1: error - * 0: exact match found - * 1: a match was found with a different gate - * 2: connected route found - * 3: no matches found - */ -int rib_lookup_ipv4_route(struct prefix_ipv4 *p, union sockunion *qgate, - vrf_id_t vrf_id) -{ - struct route_table *table; - struct route_node *rn; - struct route_entry *match = NULL; - struct nexthop *nexthop; - int nexthops_active; - rib_dest_t *dest; - - /* Lookup table. */ - table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, vrf_id); - if (!table) - return ZEBRA_RIB_LOOKUP_ERROR; - - /* Scan the RIB table for exactly matching RIB entry. */ - rn = route_node_lookup(table, (struct prefix *)p); - - /* No route for this prefix. */ - if (!rn) - return ZEBRA_RIB_NOTFOUND; - - /* Unlock node. */ - route_unlock_node(rn); - dest = rib_dest_from_rnode(rn); - - /* Find out if a "selected" RR for the discovered RIB entry exists ever. - */ - if (dest && dest->selected_fib - && !CHECK_FLAG(dest->selected_fib->status, ROUTE_ENTRY_REMOVED)) - match = dest->selected_fib; - - /* None such found :( */ - if (!match) - return ZEBRA_RIB_NOTFOUND; - - if (match->type == ZEBRA_ROUTE_CONNECT) - return ZEBRA_RIB_FOUND_CONNECTED; - - /* Ok, we have a cood candidate, let's check it's nexthop list... */ - nexthops_active = 0; - for (ALL_NEXTHOPS(match->ng, nexthop)) - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) { - nexthops_active = 1; - if (nexthop->gate.ipv4.s_addr == sockunion2ip(qgate)) - return ZEBRA_RIB_FOUND_EXACT; - if (IS_ZEBRA_DEBUG_RIB) { - char gate_buf[INET_ADDRSTRLEN], - qgate_buf[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &nexthop->gate.ipv4.s_addr, - gate_buf, INET_ADDRSTRLEN); - inet_ntop(AF_INET, &sockunion2ip(qgate), - qgate_buf, INET_ADDRSTRLEN); - zlog_debug("%s: qgate == %s, %s == %s", - __func__, qgate_buf, - nexthop->rparent ? "rgate" : "gate", - gate_buf); - } - } - - if (nexthops_active) - return ZEBRA_RIB_FOUND_NOGATE; - - return ZEBRA_RIB_NOTFOUND; -} - #define RIB_SYSTEM_ROUTE(R) \ ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT) @@ -904,7 +826,7 @@ int rib_lookup_ipv4_route(struct prefix_ipv4 *p, union sockunion *qgate, static unsigned nexthop_active_check(struct route_node *rn, struct route_entry *re, - struct nexthop *nexthop, int set) + struct nexthop *nexthop, bool set) { struct interface *ifp; route_map_result_t ret = RMAP_MATCH; @@ -1031,7 +953,7 @@ static unsigned nexthop_active_check(struct route_node *rn, */ static int nexthop_active_update(struct route_node *rn, struct route_entry *re, - int set) + bool set) { struct nexthop *nexthop; union g_addr prev_src; @@ -1049,7 +971,18 @@ static int nexthop_active_update(struct route_node *rn, struct route_entry *re, prev_src = nexthop->rmap_src; prev_active = CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); prev_index = nexthop->ifindex; - if ((new_active = nexthop_active_check(rn, re, nexthop, set))) + /* + * We need to respect the multipath_num here + * as that what we should be able to install from + * a multipath perpsective should not be a data plane + * decision point. + */ + new_active = nexthop_active_check(rn, re, nexthop, set); + if (new_active && re->nexthop_active_num >= multipath_num) { + UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); + new_active = 0; + } + if (new_active) re->nexthop_active_num++; /* Don't allow src setting on IPv6 addr for now */ if (prev_active != new_active || prev_index != nexthop->ifindex @@ -1322,7 +1255,7 @@ static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn, /* Update real nexthop. This may actually determine if nexthop is active * or not. */ - if (!nexthop_active_update(rn, new, 1)) { + if (!nexthop_active_update(rn, new, true)) { UNSET_FLAG(new->status, ROUTE_ENTRY_CHANGED); return; } @@ -1383,7 +1316,7 @@ static void rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn, * down, causing the kernel to delete routes without sending DELROUTE * notifications */ - if (!nexthop_active_update(rn, old, 1) && + if (!nexthop_active_update(rn, old, true) && (RIB_KERNEL_ROUTE(old))) SET_FLAG(old->status, ROUTE_ENTRY_REMOVED); else @@ -1408,7 +1341,7 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, /* Update the nexthop; we could determine here that nexthop is * inactive. */ - if (nexthop_active_update(rn, new, 1)) + if (nexthop_active_update(rn, new, true)) nh_active = 1; /* If nexthop is active, install the selected route, if @@ -1533,7 +1466,7 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, /* Update prior route. */ if (new != old) { /* Set real nexthop. */ - nexthop_active_update(rn, old, 1); + nexthop_active_update(rn, old, true); UNSET_FLAG(old->status, ROUTE_ENTRY_CHANGED); } @@ -1682,7 +1615,7 @@ static void rib_process(struct route_node *rn) * recursive NHs. */ if (!CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED) - && !nexthop_active_update(rn, re, 0)) { + && !nexthop_active_update(rn, re, false)) { if (re->type == ZEBRA_ROUTE_TABLE) { /* XXX: HERE BE DRAGONS!!!!! * In all honesty, I have not yet figured out @@ -1774,7 +1707,7 @@ static void rib_process(struct route_node *rn) if (old_selected != new_selected || selected_changed) { if (new_selected && new_selected != new_fib) { - nexthop_active_update(rn, new_selected, 1); + nexthop_active_update(rn, new_selected, true); UNSET_FLAG(new_selected->status, ROUTE_ENTRY_CHANGED); } @@ -1950,7 +1883,7 @@ static void rib_process_after(struct zebra_dplane_ctx *ctx) zvrf->removals++; } else { zsend_route_notify_owner_ctx(ctx, - ZAPI_ROUTE_FAIL_INSTALL); + ZAPI_ROUTE_REMOVE_FAIL); zlog_warn("%u:%s: Route Deletion failure", dplane_ctx_get_vrf(ctx), diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index e92cd8bb8a..b1fbe8a653 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -528,8 +528,7 @@ static void zebra_rnh_process_pbr_tables(int family, */ static bool rnh_nexthop_valid(const struct nexthop *nh) { - return ((CHECK_FLAG(nh->flags, NEXTHOP_FLAG_FIB) - || CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) + return (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_FIB) && CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE)); } @@ -581,8 +580,7 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, int family, /* Just being SELECTED isn't quite enough - must * have an installed nexthop to be useful. */ - for (nexthop = re->ng.nexthop; nexthop; - nexthop = nexthop->next) { + for (ALL_NEXTHOPS(re->ng, nexthop)) { if (rnh_nexthop_valid(nexthop)) break; } @@ -915,7 +913,7 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type, num = 0; nump = stream_get_endp(s); stream_putc(s, 0); - for (nh = re->ng.nexthop; nh; nh = nh->next) + for (ALL_NEXTHOPS(re->ng, nh)) if (rnh_nexthop_valid(nh)) { stream_putl(s, nh->vrf_id); stream_putc(s, nh->type); |
