diff options
Diffstat (limited to 'ripngd/ripng_cli.c')
-rw-r--r-- | ripngd/ripng_cli.c | 589 |
1 files changed, 589 insertions, 0 deletions
diff --git a/ripngd/ripng_cli.c b/ripngd/ripng_cli.c new file mode 100644 index 0000000..9a96e29 --- /dev/null +++ b/ripngd/ripng_cli.c @@ -0,0 +1,589 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 1998 Kunihiro Ishiguro + * Copyright (C) 2018 NetDEF, Inc. + * Renato Westphal + */ + +#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_nb.h" +#include "ripngd/ripng_cli_clippy.c" + +/* + * XPath: /frr-ripngd:ripngd/instance + */ +DEFPY_YANG_NOSH (router_ripng, + router_ripng_cmd, + "router ripng [vrf NAME]", + "Enable a routing process\n" + "Make RIPng instance command\n" + VRF_CMD_HELP_STR) +{ + char xpath[XPATH_MAXLEN]; + int ret; + + /* Build RIPng instance XPath. */ + if (!vrf) + vrf = VRF_DEFAULT_NAME; + snprintf(xpath, sizeof(xpath), "/frr-ripngd:ripngd/instance[vrf='%s']", + vrf); + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + ret = nb_cli_apply_changes(vty, NULL); + if (ret == CMD_SUCCESS) + VTY_PUSH_XPATH(RIPNG_NODE, xpath); + + return ret; +} + +DEFPY_YANG (no_router_ripng, + no_router_ripng_cmd, + "no router ripng [vrf NAME]", + NO_STR + "Enable a routing process\n" + "Make RIPng instance command\n" + VRF_CMD_HELP_STR) +{ + char xpath[XPATH_MAXLEN]; + + /* Build RIPng instance XPath. */ + if (!vrf) + vrf = VRF_DEFAULT_NAME; + snprintf(xpath, sizeof(xpath), "/frr-ripngd:ripngd/instance[vrf='%s']", + vrf); + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes_clear_pending(vty, NULL); +} + +void cli_show_router_ripng(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults) +{ + const char *vrf_name; + + vrf_name = yang_dnode_get_string(dnode, "./vrf"); + + vty_out(vty, "!\n"); + vty_out(vty, "router ripng"); + if (!strmatch(vrf_name, VRF_DEFAULT_NAME)) + vty_out(vty, " vrf %s", vrf_name); + vty_out(vty, "\n"); +} + +/* + * XPath: /frr-ripngd:ripngd/instance/allow-ecmp + */ +DEFUN_YANG (ripng_allow_ecmp, + ripng_allow_ecmp_cmd, + "allow-ecmp [" CMD_RANGE_STR(1, MULTIPATH_NUM) "]", + "Allow Equal Cost MultiPath\n" + "Number of paths\n") +{ + int idx_number = 0; + char mpaths[3] = {}; + uint32_t paths = MULTIPATH_NUM; + + if (argv_find(argv, argc, CMD_RANGE_STR(1, MULTIPATH_NUM), &idx_number)) + paths = strtol(argv[idx_number]->arg, NULL, 10); + snprintf(mpaths, sizeof(mpaths), "%u", paths); + + nb_cli_enqueue_change(vty, "./allow-ecmp", NB_OP_MODIFY, mpaths); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFUN_YANG (no_ripng_allow_ecmp, + no_ripng_allow_ecmp_cmd, + "no allow-ecmp [" CMD_RANGE_STR(1, MULTIPATH_NUM) "]", NO_STR + "Allow Equal Cost MultiPath\n" + "Number of paths\n") +{ + nb_cli_enqueue_change(vty, "./allow-ecmp", NB_OP_MODIFY, 0); + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_ripng_allow_ecmp(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults) +{ + uint8_t paths; + + paths = yang_dnode_get_uint8(dnode, NULL); + + if (!paths) + vty_out(vty, " no allow-ecmp\n"); + else + vty_out(vty, " allow-ecmp %d\n", paths); +} + +/* + * XPath: /frr-ripngd:ripngd/instance/default-information-originate + */ +DEFPY_YANG (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, + const 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_YANG (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_YANG (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, + const 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_YANG (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_DESTROY : NB_OP_CREATE, network_str); + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_ripng_network_prefix(struct vty *vty, + const 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_YANG (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_DESTROY : NB_OP_CREATE, network); + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_ripng_network_interface(struct vty *vty, + const 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_YANG (ripng_offset_list, + ripng_offset_list_cmd, + "[no] offset-list ACCESSLIST6_NAME$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_DESTROY, 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, const 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_YANG (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_DESTROY : NB_OP_CREATE, ifname); + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_ripng_passive_interface(struct vty *vty, + const 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_YANG (ripng_redistribute, + ripng_redistribute_cmd, + "[no] redistribute " FRR_REDIST_STR_RIPNGD "$protocol [{metric (0-16)|route-map RMAP_NAME$route_map}]", + 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_DESTROY, + route_map); + nb_cli_enqueue_change(vty, "./metric", + metric_str ? NB_OP_MODIFY : NB_OP_DESTROY, + metric_str); + } else + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, "./redistribute[protocol='%s']", + protocol); +} + +void cli_show_ripng_redistribute(struct vty *vty, const 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_YANG (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_DESTROY : NB_OP_CREATE, route_str); + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_ripng_route(struct vty *vty, const 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_YANG (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_DESTROY : NB_OP_CREATE, + aggregate_address_str); + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_ripng_aggregate_address(struct vty *vty, + const 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_YANG (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_YANG (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, const 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_YANG (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, + const 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_YANG (clear_ipv6_rip, + clear_ipv6_rip_cmd, + "clear ipv6 ripng [vrf WORD]", + CLEAR_STR + IPV6_STR + "Clear IPv6 RIP database\n" + VRF_CMD_HELP_STR) +{ + struct list *input; + int ret; + + input = list_new(); + if (vrf) { + struct yang_data *yang_vrf; + + yang_vrf = yang_data_new( + "/frr-ripngd:clear-ripng-route/input/vrf", vrf); + listnode_add(input, yang_vrf); + } + + ret = nb_cli_rpc(vty, "/frr-ripngd:clear-ripng-route", input, NULL); + + list_delete(&input); + + return ret; +} + +DEFUN (ripng_ipv6_distribute_list, + ripng_ipv6_distribute_list_cmd, + "ipv6 distribute-list [prefix] ACCESSLIST6_NAME <in|out> [WORD]", + "IPv6\n" + "Filter networks in routing updates\n" + "Specify a prefix\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") +{ + const char *ifname = NULL; + int prefix = (argv[2]->type == WORD_TKN) ? 1 : 0; + + if (argv[argc - 1]->type == VARIABLE_TKN) + ifname = argv[argc - 1]->arg; + + return distribute_list_parser(prefix, false, argv[3 + prefix]->text, + argv[2 + prefix]->arg, ifname); +} + +DEFUN (ripng_no_ipv6_distribute_list, + ripng_no_ipv6_distribute_list_cmd, + "no ipv6 distribute-list [prefix] ACCESSLIST6_NAME <in|out> [WORD]", + NO_STR + "IPv6\n" + "Filter networks in routing updates\n" + "Specify a prefix\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") +{ + const char *ifname = NULL; + int prefix = (argv[3]->type == WORD_TKN) ? 1 : 0; + + if (argv[argc - 1]->type == VARIABLE_TKN) + ifname = argv[argc - 1]->arg; + + return distribute_list_no_parser(vty, prefix, false, + argv[4 + prefix]->text, + argv[3 + prefix]->arg, ifname); +} + +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_ipv6_distribute_list_cmd); + install_element(RIPNG_NODE, &ripng_no_ipv6_distribute_list_cmd); + + install_element(RIPNG_NODE, &ripng_allow_ecmp_cmd); + install_element(RIPNG_NODE, &no_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); +} |