From 7e24fdf333e8ffe78403788d824eae110c6e65bf Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 8 May 2018 07:58:32 -0400 Subject: [PATCH] staticd: Start the addition of a staticd This is the start of separating out the static handling code from zebra -> staticd. This will help simplify the zebra code and isolate static route handling to it's own code base. Signed-off-by: Donald Sharp --- Makefile.am | 1 + configure.ac | 1 + staticd/.gitignore | 2 + staticd/Makefile | 10 + staticd/static_main.c | 145 ++++ staticd/static_memory.c | 28 + staticd/static_memory.h | 28 + staticd/static_nht.c | 75 ++ staticd/static_nht.h | 25 + staticd/static_routes.c | 513 +++++++++++++ staticd/static_routes.h | 110 +++ staticd/static_vrf.c | 196 +++++ staticd/static_vrf.h | 38 + staticd/static_vty.c | 1414 +++++++++++++++++++++++++++++++++++ staticd/static_vty.h | 29 + staticd/static_zebra.c | 377 ++++++++++ staticd/static_zebra.h | 30 + staticd/staticd.conf.sample | 3 + staticd/subdir.am | 33 + vtysh/Makefile.am | 4 + vtysh/vtysh.c | 1 + vtysh/vtysh.h | 3 +- zebra/interface.c | 13 - zebra/rib.h | 5 - zebra/zebra_rib.c | 7 +- zebra/zebra_rnh.c | 192 ----- zebra/zebra_rnh.h | 23 +- zebra/zebra_static.c | 830 -------------------- zebra/zebra_static.h | 89 --- zebra/zebra_vrf.c | 67 -- zebra/zebra_vrf.h | 6 +- zebra/zebra_vty.c | 1368 +-------------------------------- 32 files changed, 3079 insertions(+), 2587 deletions(-) create mode 100644 staticd/.gitignore create mode 100644 staticd/Makefile create mode 100644 staticd/static_main.c create mode 100644 staticd/static_memory.c create mode 100644 staticd/static_memory.h create mode 100644 staticd/static_nht.c create mode 100644 staticd/static_nht.h create mode 100644 staticd/static_routes.c create mode 100644 staticd/static_routes.h create mode 100644 staticd/static_vrf.c create mode 100644 staticd/static_vrf.h create mode 100644 staticd/static_vty.c create mode 100644 staticd/static_vty.h create mode 100644 staticd/static_zebra.c create mode 100644 staticd/static_zebra.h create mode 100644 staticd/staticd.conf.sample create mode 100644 staticd/subdir.am diff --git a/Makefile.am b/Makefile.am index f9fb23196..8c96f39f3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -55,6 +55,7 @@ include eigrpd/subdir.am include sharpd/subdir.am include pimd/subdir.am include pbrd/subdir.am +include staticd/subdir.am SUBDIRS = . @LIBRFP@ @RFPTEST@ \ @BGPD@ \ diff --git a/configure.ac b/configure.ac index a155a12ba..f65b1640d 100755 --- a/configure.ac +++ b/configure.ac @@ -1409,6 +1409,7 @@ AM_CONDITIONAL(ISISD, test "${enable_isisd}" != "no") AM_CONDITIONAL(PIMD, test "${enable_pimd}" != "no") AM_CONDITIONAL(PBRD, test "${enable_pbrd}" != "no") AM_CONDITIONAL(SHARPD, test "${enable_sharpd}" = "yes") +AM_CONDITIONAL(STATICD, test "${enable_staticd}" != "no") if test "${enable_bgp_announce}" = "no";then AC_DEFINE(DISABLE_BGP_ANNOUNCE,1,Disable BGP installation to zebra) diff --git a/staticd/.gitignore b/staticd/.gitignore new file mode 100644 index 000000000..af895301a --- /dev/null +++ b/staticd/.gitignore @@ -0,0 +1,2 @@ +libstatic.a +staticd diff --git a/staticd/Makefile b/staticd/Makefile new file mode 100644 index 000000000..ecd33df68 --- /dev/null +++ b/staticd/Makefile @@ -0,0 +1,10 @@ +all: ALWAYS + @$(MAKE) -s -C .. staticd/staticd +%: ALWAYS + @$(MAKE) -s -C .. staticd/$@ + +Makefile: + #nothing +ALWAYS: +.PHONY: ALWAYS makefiles +.SUFFIXES: diff --git a/staticd/static_main.c b/staticd/static_main.c new file mode 100644 index 000000000..7da526cef --- /dev/null +++ b/staticd/static_main.c @@ -0,0 +1,145 @@ +/* + * STATICd - main code + * Copyright (C) 2018 Cumulus Networks, Inc. + * Donald Sharp + * + * FRR 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, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include + +#include +#include "getopt.h" +#include "thread.h" +#include "command.h" +#include "log.h" +#include "memory.h" +#include "privs.h" +#include "sigevent.h" +#include "libfrr.h" +#include "vrf.h" +#include "nexthop.h" + +#include "static_vrf.h" +#include "static_vty.h" +#include "static_routes.h" +#include "static_zebra.h" + +bool mpls_enabled; + +zebra_capabilities_t _caps_p[] = { +}; + +struct zebra_privs_t static_privs = { +#if defined(FRR_USER) && defined(FRR_GROUP) + .user = FRR_USER, + .group = FRR_GROUP, +#endif +#if defined(VTY_GROUP) + .vty_group = VTY_GROUP, +#endif + .caps_p = _caps_p, + .cap_num_p = array_size(_caps_p), + .cap_num_i = 0}; + +struct option longopts[] = { { 0 } }; + +/* Master of threads. */ +struct thread_master *master; + +/* SIGHUP handler. */ +static void sighup(void) +{ + zlog_info("SIGHUP received"); +} + +/* SIGINT / SIGTERM handler. */ +static void sigint(void) +{ + zlog_notice("Terminating on signal"); + + exit(0); +} + +/* SIGUSR1 handler. */ +static void sigusr1(void) +{ + zlog_rotate(); +} + +struct quagga_signal_t static_signals[] = { + { + .signal = SIGHUP, + .handler = &sighup, + }, + { + .signal = SIGUSR1, + .handler = &sigusr1, + }, + { + .signal = SIGINT, + .handler = &sigint, + }, + { + .signal = SIGTERM, + .handler = &sigint, + }, +}; + +#define STATIC_VTY_PORT 2616 + +FRR_DAEMON_INFO(staticd, STATIC, .vty_port = STATIC_VTY_PORT, + + .proghelp = "Implementation of STATIC.", + + .signals = static_signals, + .n_signals = array_size(static_signals), + + .privs = &static_privs, ) + +int main(int argc, char **argv, char **envp) +{ + frr_preinit(&staticd_di, argc, argv); + frr_opt_add("", longopts, ""); + + while (1) { + int opt; + + opt = frr_getopt(argc, argv, NULL); + + if (opt == EOF) + break; + + switch (opt) { + case 0: + break; + default: + frr_help_exit(1); + break; + } + } + + master = frr_init(); + + static_vrf_init(); + + static_zebra_init(); + static_vty_init(); + + frr_config_fork(); + frr_run(master); + + /* Not reached. */ + return 0; +} diff --git a/staticd/static_memory.c b/staticd/static_memory.c new file mode 100644 index 000000000..9eb5a6ffb --- /dev/null +++ b/staticd/static_memory.c @@ -0,0 +1,28 @@ +/* + * static memory code. + * Copyright (C) 2018 Cumulus Networks, Inc. + * Donald Sharp + * + * FRR 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, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include + +#include + +#include "staticd/static_memory.h" + +DEFINE_MGROUP(STATIC, "staticd") + +DEFINE_MTYPE(STATIC, STATIC_ROUTE, "Static Route"); diff --git a/staticd/static_memory.h b/staticd/static_memory.h new file mode 100644 index 000000000..60d2d9b5c --- /dev/null +++ b/staticd/static_memory.h @@ -0,0 +1,28 @@ +/* + * static memory code. + * Copyright (C) 2018 Cumulus Networks, Inc. + * Donald Sharp + * + * FRR 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, or (at your option) any + * later version. + * + * FRR 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 __STATIC_MEMORY_H__ + +#include "memory.h" + +DECLARE_MGROUP(STATIC) + +DECLARE_MTYPE(STATIC_ROUTE); + +#endif diff --git a/staticd/static_nht.c b/staticd/static_nht.c new file mode 100644 index 000000000..e6592c9c9 --- /dev/null +++ b/staticd/static_nht.c @@ -0,0 +1,75 @@ +/* + * Static NHT code. + * Copyright (C) 2018 Cumulus Networks, Inc. + * Donald Sharp + * + * FRR 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, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include + +#include "prefix.h" +#include "table.h" +#include "vrf.h" +#include "nexthop.h" + +#include "static_vrf.h" +#include "static_routes.h" +#include "static_zebra.h" +#include "static_nht.h" + +void static_nht_update(struct prefix *p, uint32_t nh_num, + afi_t afi, vrf_id_t vrf_id) +{ + struct route_table *stable; + struct static_route *si; + struct static_vrf *svrf; + struct route_node *rn; + struct vrf *vrf; + bool orig; + bool reinstall; + + vrf = vrf_lookup_by_id(vrf_id); + + if (!vrf->info) + return; + + svrf = vrf->info; + stable = static_vrf_static_table(afi, SAFI_UNICAST, svrf); + if (!stable) + return; + + for (rn = route_top(stable); rn; rn = route_next(rn)) { + reinstall = false; + for (si = rn->info; si; si = si->next) { + if (si->type != STATIC_IPV4_GATEWAY && + si->type != STATIC_IPV6_GATEWAY) + continue; + + orig = si->nh_valid; + if (p->family == AF_INET && + p->u.prefix4.s_addr == si->addr.ipv4.s_addr) + si->nh_valid = !!nh_num; + + if (p->family == AF_INET6 && + memcmp(&p->u.prefix6, &si->addr.ipv6, 16) == 0) + si->nh_valid = !!nh_num; + + if (orig != si->nh_valid) + reinstall = true; + } + if (reinstall) + static_zebra_route_add(rn, vrf_id, SAFI_UNICAST, true); + } +} diff --git a/staticd/static_nht.h b/staticd/static_nht.h new file mode 100644 index 000000000..27d5e74a7 --- /dev/null +++ b/staticd/static_nht.h @@ -0,0 +1,25 @@ +/* + * Static NHT header. + * Copyright (C) 2018 Cumulus Networks, Inc. + * Donald Sharp + * + * FRR 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, or (at your option) any + * later version. + * + * FRR 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 __STATIC_NHT_H__ +#define __STATIC_NHT_H__ + +extern void static_nht_update(struct prefix *p, uint32_t nh_num, + afi_t afi, vrf_id_t vrf_id); +#endif diff --git a/staticd/static_routes.c b/staticd/static_routes.c new file mode 100644 index 000000000..3eb4c8cc6 --- /dev/null +++ b/staticd/static_routes.c @@ -0,0 +1,513 @@ +/* + * STATICd - vrf code + * Copyright (C) 2018 Cumulus Networks, Inc. + * Donald Sharp + * + * FRR 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, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "static_vrf.h" +#include "static_routes.h" +#include "static_memory.h" +#include "static_zebra.h" + +/* Install static route into rib. */ +static void static_install_route(struct route_node *rn, safi_t safi) +{ + struct static_route *si; + + for (si = rn->info; si; si = si->next) + static_zebra_nht_register(si, true); + + si = rn->info; + if (si) + static_zebra_route_add(rn, si->vrf_id, safi, true); + +} + +/* Uninstall static route from RIB. */ +static void static_uninstall_route(vrf_id_t vrf_id, safi_t safi, + struct route_node *rn) +{ + + if (rn->info) + static_zebra_route_add(rn, vrf_id, safi, true); + else + static_zebra_route_add(rn, vrf_id, safi, false); +} + +int static_add_route(afi_t afi, safi_t safi, uint8_t type, struct prefix *p, + struct prefix_ipv6 *src_p, union g_addr *gate, + const char *ifname, enum static_blackhole_type bh_type, + route_tag_t tag, uint8_t distance, struct static_vrf *svrf, + struct static_vrf *nh_svrf, + struct static_nh_label *snh_label, + uint32_t table_id) +{ + struct route_node *rn; + struct static_route *si; + struct static_route *pp; + struct static_route *cp; + struct static_route *update = NULL; + struct route_table *stable = svrf->stable[afi][safi]; + + if (!stable) + return -1; + + if (!gate && (type == STATIC_IPV4_GATEWAY + || type == STATIC_IPV4_GATEWAY_IFNAME + || type == STATIC_IPV6_GATEWAY + || type == STATIC_IPV6_GATEWAY_IFNAME)) + return -1; + + if (!ifname + && (type == STATIC_IFNAME || type == STATIC_IPV4_GATEWAY_IFNAME + || type == STATIC_IPV6_GATEWAY_IFNAME)) + return -1; + + /* Lookup static route prefix. */ + rn = srcdest_rnode_get(stable, p, src_p); + + /* Do nothing if there is a same static route. */ + for (si = rn->info; si; si = si->next) { + if (type == si->type + && (!gate + || ((afi == AFI_IP + && IPV4_ADDR_SAME(&gate->ipv4, &si->addr.ipv4)) + || (afi == AFI_IP6 + && IPV6_ADDR_SAME(gate, &si->addr.ipv6)))) + && (!strcmp(ifname ? ifname : "", si->ifname))) { + if ((distance == si->distance) && (tag == si->tag) + && (table_id == si->table_id) + && !memcmp(&si->snh_label, snh_label, + sizeof(struct static_nh_label)) + && si->bh_type == bh_type) { + route_unlock_node(rn); + return 0; + } + update = si; + } + } + + /* Distance or tag or label changed, delete existing first. */ + if (update) + static_delete_route(afi, safi, type, p, src_p, gate, ifname, + update->tag, update->distance, svrf, + &update->snh_label, table_id); + + /* Make new static route structure. */ + si = XCALLOC(MTYPE_STATIC_ROUTE, sizeof(struct static_route)); + + si->type = type; + si->distance = distance; + si->bh_type = bh_type; + si->tag = tag; + si->vrf_id = svrf->vrf->vrf_id; + si->nh_vrf_id = nh_svrf->vrf->vrf_id; + strcpy(si->nh_vrfname, nh_svrf->vrf->name); + si->table_id = table_id; + + if (ifname) + strlcpy(si->ifname, ifname, sizeof(si->ifname)); + si->ifindex = IFINDEX_INTERNAL; + + switch (type) { + case STATIC_IPV4_GATEWAY: + case STATIC_IPV4_GATEWAY_IFNAME: + si->addr.ipv4 = gate->ipv4; + break; + case STATIC_IPV6_GATEWAY: + case STATIC_IPV6_GATEWAY_IFNAME: + si->addr.ipv6 = gate->ipv6; + break; + case STATIC_IFNAME: + break; + } + + /* Save labels, if any. */ + memcpy(&si->snh_label, snh_label, sizeof(struct static_nh_label)); + + /* + * Add new static route information to the tree with sort by + * distance value and gateway address. + */ + for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next) { + if (si->distance < cp->distance) + break; + if (si->distance > cp->distance) + continue; + if (si->type == STATIC_IPV4_GATEWAY + && cp->type == STATIC_IPV4_GATEWAY) { + if (ntohl(si->addr.ipv4.s_addr) + < ntohl(cp->addr.ipv4.s_addr)) + break; + if (ntohl(si->addr.ipv4.s_addr) + > ntohl(cp->addr.ipv4.s_addr)) + continue; + } + } + + /* Make linked list. */ + if (pp) + pp->next = si; + else + rn->info = si; + if (cp) + cp->prev = si; + si->prev = pp; + si->next = cp; + + /* check whether interface exists in system & install if it does */ + if (!ifname) + static_install_route(rn, safi); + else { + struct interface *ifp; + + ifp = if_lookup_by_name(ifname, nh_svrf->vrf->vrf_id); + if (ifp && ifp->ifindex != IFINDEX_INTERNAL) { + si->ifindex = ifp->ifindex; + static_install_route(rn, safi); + } else + zlog_warn("Static Route using %s interface not installed because the interface does not exist in specified vrf", + ifname); + } + + return 1; +} + +int static_delete_route(afi_t afi, safi_t safi, uint8_t type, struct prefix *p, + struct prefix_ipv6 *src_p, union g_addr *gate, + const char *ifname, route_tag_t tag, uint8_t distance, + struct static_vrf *svrf, + struct static_nh_label *snh_label, + uint32_t table_id) +{ + struct route_node *rn; + struct static_route *si; + struct route_table *stable; + + /* Lookup table. */ + stable = static_vrf_static_table(afi, safi, svrf); + if (!stable) + return -1; + + /* Lookup static route prefix. */ + rn = srcdest_rnode_lookup(stable, p, src_p); + if (!rn) + return 0; + + /* Find same static route is the tree */ + for (si = rn->info; si; si = si->next) + if (type == si->type + && (!gate + || ((afi == AFI_IP + && IPV4_ADDR_SAME(&gate->ipv4, &si->addr.ipv4)) + || (afi == AFI_IP6 + && IPV6_ADDR_SAME(gate, &si->addr.ipv6)))) + && (!strcmp(ifname ? ifname : "", si->ifname)) + && (!tag || (tag == si->tag)) + && (table_id == si->table_id) + && (!snh_label->num_labels + || !memcmp(&si->snh_label, snh_label, + sizeof(struct static_nh_label)))) + break; + + /* Can't find static route. */ + if (!si) { + route_unlock_node(rn); + return 0; + } + + static_zebra_nht_register(si, false); + + /* Unlink static route from linked list. */ + if (si->prev) + si->prev->next = si->next; + else + rn->info = si->next; + if (si->next) + si->next->prev = si->prev; + + /* + * If we have other si nodes then route replace + * else delete the route + */ + static_uninstall_route(si->vrf_id, safi, rn); + route_unlock_node(rn); + + /* Free static route configuration. */ + XFREE(MTYPE_STATIC_ROUTE, si); + + route_unlock_node(rn); + + return 1; +} + +static void static_ifindex_update_af(struct interface *ifp, bool up, afi_t afi, + safi_t safi) +{ + struct route_table *stable; + struct route_node *rn; + struct static_route *si; + struct vrf *vrf; + + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + struct static_vrf *svrf; + + svrf = vrf->info; + + stable = static_vrf_static_table(afi, safi, svrf); + if (!stable) + continue; + + for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) { + for (si = rn->info; si; si = si->next) { + if (!si->ifname[0]) + continue; + if (up) { + if (strcmp(si->ifname, ifp->name)) + continue; + si->ifindex = ifp->ifindex; + } else { + if (si->ifindex != ifp->ifindex) + continue; + si->ifindex = IFINDEX_INTERNAL; + } + } + + static_install_route(rn, safi); + } + } +} + +/* + * This function looks at a svrf's stable and notices if any of the + * nexthops we are using are part of the vrf coming up. + * If we are using them then cleanup the nexthop vrf id + * to be the new value and then re-installs them + * + * + * stable -> The table we are looking at. + * svrf -> The newly changed vrf. + * afi -> The afi to look at + * safi -> the safi to look at + */ +static void static_fixup_vrf(struct static_vrf *svrf, + struct route_table *stable, afi_t afi, safi_t safi) +{ + struct route_node *rn; + struct static_route *si; + struct interface *ifp; + bool install; + + for (rn = route_top(stable); rn; rn = route_next(rn)) { + install = false; + for (si = rn->info; si; si = si->next) { + if (strcmp(svrf->vrf->name, si->nh_vrfname) != 0) + continue; + + si->nh_vrf_id = svrf->vrf->vrf_id; + install = true; + if (si->ifindex) { + ifp = if_lookup_by_name(si->ifname, + si->nh_vrf_id); + if (ifp) + si->ifindex = ifp->ifindex; + else + continue; + } + } + + if (install) + static_install_route(rn, safi); + } +} + +/* + * This function enables static routes in a svrf as it + * is coming up. It sets the new vrf_id as appropriate. + * + * svrf -> The svrf that is being brought up and enabled by the kernel + * stable -> The stable we are looking at. + * afi -> the afi in question + * safi -> the safi in question + */ +static void static_enable_vrf(struct static_vrf *svrf, + struct route_table *stable, + afi_t afi, safi_t safi) +{ + struct route_node *rn; + struct static_route *si; + struct interface *ifp; + struct vrf *vrf = svrf->vrf; + bool install; + + for (rn = route_top(stable); rn; rn = route_next(rn)) { + install = false; + for (si = rn->info; si; si = si->next) { + si->vrf_id = vrf->vrf_id; + if (si->ifindex) { + ifp = if_lookup_by_name(si->ifname, + si->nh_vrf_id); + if (ifp) + si->ifindex = ifp->ifindex; + else + continue; + } + install = true; + } + + if (install) + static_install_route(rn, safi); + } +} + +/* + * When a vrf is being enabled by the kernel, go through all the + * static routes in the system that use this vrf (both nexthops vrfs + * and the routes vrf ) + * + * enable_svrf -> the vrf being enabled + */ +void static_fixup_vrf_ids(struct static_vrf *enable_svrf) +{ + struct route_table *stable; + struct vrf *vrf; + afi_t afi; + safi_t safi; + + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + struct static_vrf *svrf; + + svrf = vrf->info; + /* Install any static routes configured for this VRF. */ + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { + stable = svrf->stable[afi][safi]; + if (!stable) + continue; + + static_fixup_vrf(enable_svrf, stable, + afi, safi); + + if (enable_svrf == svrf) + static_enable_vrf(svrf, stable, + afi, safi); + } + } + } +} + +/* + * Look at the specified stable and if any of the routes in + * this table are using the svrf as the nexthop, uninstall + * those routes. + * + * svrf -> the vrf being disabled + * stable -> the table we need to look at. + * afi -> the afi in question + * safi -> the safi in question + */ +static void static_cleanup_vrf(struct static_vrf *svrf, + struct route_table *stable, + afi_t afi, safi_t safi) +{ + struct route_node *rn; + struct static_route *si; + + for (rn = route_top(stable); rn; rn = route_next(rn)) { + for (si = rn->info; si; si = si->next) { + if (strcmp(svrf->vrf->name, si->nh_vrfname) != 0) + continue; + + static_uninstall_route(si->vrf_id, safi, rn); + } + } +} + +/* + * Look at all static routes in this table and uninstall + * them. + * + * stable -> The table to uninstall from + * afi -> The afi in question + * safi -> the safi in question + */ +static void static_disable_vrf(struct route_table *stable, + afi_t afi, safi_t safi) +{ + struct route_node *rn; + struct static_route *si; + + for (rn = route_top(stable); rn; rn = route_next(rn)) + for (si = rn->info; si; si = si->next) + static_uninstall_route(si->vrf_id, safi, rn); +} + +/* + * When the disable_svrf is shutdown by the kernel, we call + * this function and it cleans up all static routes using + * this vrf as a nexthop as well as all static routes + * in it's stables. + * + * disable_svrf - The vrf being disabled + */ +void static_cleanup_vrf_ids(struct static_vrf *disable_svrf) +{ + struct vrf *vrf; + afi_t afi; + safi_t safi; + + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + struct static_vrf *svrf; + + svrf = vrf->info; + + /* Uninstall any static routes configured for this VRF. */ + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { + struct route_table *stable; + + stable = svrf->stable[afi][safi]; + if (!stable) + continue; + + static_cleanup_vrf(disable_svrf, stable, + afi, safi); + + if (disable_svrf == svrf) + static_disable_vrf(stable, afi, safi); + } + } + } +} + +/* called from if_{add,delete}_update, i.e. when ifindex becomes [in]valid */ +void static_ifindex_update(struct interface *ifp, bool up) +{ + static_ifindex_update_af(ifp, up, AFI_IP, SAFI_UNICAST); + static_ifindex_update_af(ifp, up, AFI_IP, SAFI_MULTICAST); + static_ifindex_update_af(ifp, up, AFI_IP6, SAFI_UNICAST); + static_ifindex_update_af(ifp, up, AFI_IP6, SAFI_MULTICAST); +} diff --git a/staticd/static_routes.h b/staticd/static_routes.h new file mode 100644 index 000000000..ec4ca1861 --- /dev/null +++ b/staticd/static_routes.h @@ -0,0 +1,110 @@ +/* + * STATICd - static routes header + * Copyright (C) 2018 Cumulus Networks, Inc. + * Donald Sharp + * + * FRR 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, or (at your option) any + * later version. + * + * FRR 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 __STATIC_ROUTES_H__ +#define __STATIC_ROUTES_H__ + +#include "lib/mpls.h" + +/* Static route label information */ +struct static_nh_label { + uint8_t num_labels; + uint8_t reserved[3]; + mpls_label_t label[MPLS_MAX_LABELS]; +}; + +enum static_blackhole_type { + STATIC_BLACKHOLE_DROP = 0, + STATIC_BLACKHOLE_NULL, + STATIC_BLACKHOLE_REJECT +}; + +typedef enum { + STATIC_IFNAME, + STATIC_IPV4_GATEWAY, + STATIC_IPV4_GATEWAY_IFNAME, + STATIC_BLACKHOLE, + STATIC_IPV6_GATEWAY, + STATIC_IPV6_GATEWAY_IFNAME, +} static_types; + +/* Static route information. */ +struct static_route { + /* For linked list. */ + struct static_route *prev; + struct static_route *next; + + /* VRF identifier. */ + vrf_id_t vrf_id; + vrf_id_t nh_vrf_id; + char nh_vrfname[VRF_NAMSIZ + 1]; + + /* Administrative distance. */ + uint8_t distance; + + /* Tag */ + route_tag_t tag; + + /* Flag for this static route's type. */ + static_types type; + + /* + * Nexthop value. + */ + enum static_blackhole_type bh_type; + union g_addr addr; + ifindex_t ifindex; + bool nh_registered; + bool nh_valid; + + char ifname[INTERFACE_NAMSIZ + 1]; + + /* Label information */ + struct static_nh_label snh_label; + + uint32_t table_id; +}; + +extern bool mpls_enabled; + +extern struct zebra_privs_t static_privs; + +void static_fixup_vrf_ids(struct static_vrf *svrf); + +extern int static_add_route(afi_t afi, safi_t safi, uint8_t type, + struct prefix *p, struct prefix_ipv6 *src_p, + union g_addr *gate, const char *ifname, + enum static_blackhole_type bh_type, route_tag_t tag, + uint8_t distance, struct static_vrf *svrf, + struct static_vrf *nh_svrf, + struct static_nh_label *snh_label, + uint32_t table_id); + +extern int static_delete_route(afi_t afi, safi_t safi, uint8_t type, + struct prefix *p, struct prefix_ipv6 *src_p, + union g_addr *gate, const char *ifname, + route_tag_t tag, uint8_t distance, + struct static_vrf *svrf, + struct static_nh_label *snh_label, + uint32_t table_id); + +extern void static_cleanup_vrf_ids(struct static_vrf *disable_svrf); + +extern void static_ifindex_update(struct interface *ifp, bool up); +#endif diff --git a/staticd/static_vrf.c b/staticd/static_vrf.c new file mode 100644 index 000000000..45225bf8f --- /dev/null +++ b/staticd/static_vrf.c @@ -0,0 +1,196 @@ +/* + * STATICd - vrf code + * Copyright (C) 2018 Cumulus Networks, Inc. + * Donald Sharp + * + * FRR 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, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include + +#include "vrf.h" +#include "nexthop.h" +#include "table.h" +#include "srcdest_table.h" + +#include "static_memory.h" +#include "static_vrf.h" +#include "static_routes.h" +#include "static_vty.h" + +static void zebra_stable_node_cleanup(struct route_table *table, + struct route_node *node) +{ + struct static_route *si, *next; + + if (node->info) + for (si = node->info; si; si = next) { + next = si->next; + XFREE(MTYPE_STATIC_ROUTE, si); + } +} + +static struct static_vrf *static_vrf_alloc(void) +{ + struct route_table *table; + struct static_vrf *svrf; + safi_t safi; + afi_t afi; + + svrf = XCALLOC(MTYPE_TMP, sizeof(struct static_vrf)); + + for (afi = AFI_IP; afi <= AFI_IP6; afi++) { + for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) { + if (afi == AFI_IP6) + table = srcdest_table_init(); + else + table = route_table_init(); + table->cleanup = zebra_stable_node_cleanup; + svrf->stable[afi][safi] = table; + } + } + return svrf; +} + +static int static_vrf_new(struct vrf *vrf) +{ + struct static_vrf *svrf; + + svrf = static_vrf_alloc(); + vrf->info = svrf; + svrf->vrf = vrf; + + return 0; +} + +static int static_vrf_enable(struct vrf *vrf) +{ + static_fixup_vrf_ids(vrf->info); + + /* + * We may have static routes that are now possible to + * insert into the appropriate tables + */ + static_config_install_delayed_routes(vrf->info); + + return 0; +} + +static int static_vrf_disable(struct vrf *vrf) +{ + return 0; +} + +static int static_vrf_delete(struct vrf *vrf) +{ + struct route_table *table; + struct static_vrf *svrf; + safi_t safi; + afi_t afi; + + svrf = vrf->info; + for (afi = AFI_IP; afi <= AFI_IP6; afi++) { + for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) { + table = svrf->stable[afi][safi]; + route_table_finish(table); + svrf->stable[afi][safi] = NULL; + } + } + return 0; +} + +/* Lookup the static routing table in a VRF. */ +struct route_table *static_vrf_static_table(afi_t afi, safi_t safi, + struct static_vrf *svrf) +{ + if (!svrf) + return NULL; + + if (afi >= AFI_MAX || safi >= SAFI_MAX) + return NULL; + + return svrf->stable[afi][safi]; +} + +struct static_vrf *static_vrf_lookup_by_id(vrf_id_t vrf_id) +{ + struct vrf *vrf; + + vrf = vrf_lookup_by_id(vrf_id); + if (vrf) + return ((struct static_vrf *)vrf->info); + + return NULL; +} + +struct static_vrf *static_vrf_lookup_by_name(const char *name) +{ + struct vrf *vrf; + + if (!name) + name = VRF_DEFAULT_NAME; + + vrf = vrf_lookup_by_name(name); + if (vrf) + return ((struct static_vrf *)vrf->info); + + return NULL; +} + +static int static_vrf_config_write(struct vty *vty) +{ + struct vrf *vrf; + + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + static_config(vty, vrf->info, AFI_IP, + SAFI_UNICAST, "ip route"); + static_config(vty, vrf->info, AFI_IP, + SAFI_MULTICAST, "ip mroute"); + static_config(vty, vrf->info, AFI_IP6, + SAFI_UNICAST, "ipv6 route"); + } + + return 0; +} + +int static_vrf_has_config(struct static_vrf *svrf) +{ + struct route_table *table; + safi_t safi; + afi_t afi; + + /* + * NOTE: This is a don't care for the default VRF, but we go through + * the motions to keep things consistent. + */ + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { + table = svrf->stable[afi][safi]; + if (!table) + continue; + if (route_table_count(table)) + return 1; + } + } + + return 0; +} + +void static_vrf_init(void) +{ + vrf_init(static_vrf_new, static_vrf_enable, + static_vrf_disable, static_vrf_delete); + + vrf_cmd_init(static_vrf_config_write, &static_privs); +} diff --git a/staticd/static_vrf.h b/staticd/static_vrf.h new file mode 100644 index 000000000..40d56979b --- /dev/null +++ b/staticd/static_vrf.h @@ -0,0 +1,38 @@ +/* + * STATICd - vrf header + * Copyright (C) 2018 Cumulus Networks, Inc. + * Donald Sharp + * + * FRR 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, or (at your option) any + * later version. + * + * FRR 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 __STATIC_VRF_H__ +#define __STATIC_VRF_H__ + +struct static_vrf { + struct vrf *vrf; + + struct route_table *stable[AFI_MAX][SAFI_MAX]; +}; + +struct static_vrf *static_vrf_lookup_by_name(const char *vrf_name); +struct static_vrf *static_vrf_lookup_by_id(vrf_id_t vrf_id); + +int static_vrf_has_config(struct static_vrf *svrf); + +void static_vrf_init(void); + +struct route_table *static_vrf_static_table(afi_t afi, safi_t safi, + struct static_vrf *svrf); +#endif diff --git a/staticd/static_vty.c b/staticd/static_vty.c new file mode 100644 index 000000000..1f54e9bff --- /dev/null +++ b/staticd/static_vty.c @@ -0,0 +1,1414 @@ +/* + * STATICd - vty code + * Copyright (C) 2018 Cumulus Networks, Inc. + * Donald Sharp + * + * FRR 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, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include + +#include "command.h" +#include "vty.h" +#include "vrf.h" +#include "prefix.h" +#include "nexthop.h" +#include "table.h" +#include "srcdest_table.h" +#include "mpls.h" + +#include "static_vrf.h" +#include "static_memory.h" +#include "static_vty.h" +#include "static_routes.h" +#ifndef VTYSH_EXTRACT_PL +#include "staticd/static_vty_clippy.c" +#endif + +static struct static_vrf *static_vty_get_unknown_vrf(struct vty *vty, + const char *vrf_name) +{ + struct static_vrf *svrf; + struct vrf *vrf; + + svrf = static_vrf_lookup_by_name(vrf_name); + + if (svrf) + return svrf; + + vrf = vrf_get(VRF_UNKNOWN, vrf_name); + if (!vrf) { + vty_out(vty, "%% Could not create vrf %s\n", vrf_name); + return NULL; + } + svrf = vrf->info; + if (!svrf) { + vty_out(vty, "%% Could not create vrf-info %s\n", + vrf_name); + return NULL; + } + /* Mark as having FRR configuration */ + vrf_set_user_cfged(vrf); + + return svrf; +} + +struct static_hold_route { + char *vrf_name; + char *nhvrf_name; + afi_t afi; + safi_t safi; + char *dest_str; + char *mask_str; + char *src_str; + char *gate_str; + char *ifname; + char *flag_str; + char *tag_str; + char *distance_str; + char *label_str; + char *table_str; + + /* processed & masked destination, used for config display */ + struct prefix dest; +}; + +static struct list *static_list; + +static int static_list_compare_helper(const char *s1, const char *s2) +{ + /* Are Both NULL */ + if (s1 == s2) + return 0; + + if (!s1 && s2) + return -1; + + if (s1 && !s2) + return 1; + + return strcmp(s1, s2); +} + +static void static_list_delete(struct static_hold_route *shr) +{ + if (shr->vrf_name) + XFREE(MTYPE_STATIC_ROUTE, shr->vrf_name); + if (shr->nhvrf_name) + XFREE(MTYPE_STATIC_ROUTE, shr->nhvrf_name); + if (shr->dest_str) + XFREE(MTYPE_STATIC_ROUTE, shr->dest_str); + if (shr->mask_str) + XFREE(MTYPE_STATIC_ROUTE, shr->mask_str); + if (shr->src_str) + XFREE(MTYPE_STATIC_ROUTE, shr->src_str); + if (shr->gate_str) + XFREE(MTYPE_STATIC_ROUTE, shr->gate_str); + if (shr->ifname) + XFREE(MTYPE_STATIC_ROUTE, shr->ifname); + if (shr->flag_str) + XFREE(MTYPE_STATIC_ROUTE, shr->flag_str); + if (shr->tag_str) + XFREE(MTYPE_STATIC_ROUTE, shr->tag_str); + if (shr->distance_str) + XFREE(MTYPE_STATIC_ROUTE, shr->distance_str); + if (shr->label_str) + XFREE(MTYPE_STATIC_ROUTE, shr->label_str); + if (shr->table_str) + XFREE(MTYPE_STATIC_ROUTE, shr->table_str); + + XFREE(MTYPE_STATIC_ROUTE, shr); +} + +static int static_list_compare(void *arg1, void *arg2) +{ + struct static_hold_route *shr1 = arg1; + struct static_hold_route *shr2 = arg2; + int ret; + + ret = strcmp(shr1->vrf_name, shr2->vrf_name); + if (ret) + return ret; + + ret = strcmp(shr1->nhvrf_name, shr2->nhvrf_name); + if (ret) + return ret; + + ret = shr1->afi - shr2->afi; + if (ret) + return ret; + + ret = shr1->safi - shr2->safi; + if (ret) + return ret; + + ret = prefix_cmp(&shr1->dest, &shr2->dest); + if (ret) + return ret; + + ret = static_list_compare_helper(shr1->src_str, shr2->src_str); + if (ret) + return ret; + + ret = static_list_compare_helper(shr1->gate_str, shr2->gate_str); + if (ret) + return ret; + + ret = static_list_compare_helper(shr1->ifname, shr2->ifname); + if (ret) + return ret; + + ret = static_list_compare_helper(shr1->flag_str, shr2->flag_str); + if (ret) + return ret; + + ret = static_list_compare_helper(shr1->tag_str, shr2->tag_str); + if (ret) + return ret; + + ret = static_list_compare_helper(shr1->distance_str, + shr2->distance_str); + if (ret) + return ret; + + ret = static_list_compare_helper(shr1->table_str, + shr2->table_str); + if (ret) + return ret; + + return static_list_compare_helper(shr1->label_str, shr2->label_str); +} + + +/* General function for static route. */ +static int zebra_static_route_holdem( + struct static_vrf *svrf, struct static_vrf *nh_svrf, afi_t afi, + safi_t safi, const char *negate, struct prefix *dest, + const char *dest_str, const char *mask_str, const char *src_str, + const char *gate_str, const char *ifname, const char *flag_str, + const char *tag_str, const char *distance_str, const char *label_str, + const char *table_str) +{ + struct static_hold_route *shr, *lookup; + struct listnode *node; + + zlog_warn("Static Route to %s not installed currently because dependent config not fully available", + dest_str); + + shr = XCALLOC(MTYPE_STATIC_ROUTE, sizeof(*shr)); + shr->vrf_name = XSTRDUP(MTYPE_STATIC_ROUTE, svrf->vrf->name); + shr->nhvrf_name = XSTRDUP(MTYPE_STATIC_ROUTE, nh_svrf->vrf->name); + shr->afi = afi; + shr->safi = safi; + if (dest) + prefix_copy(&shr->dest, dest); + if (dest_str) + shr->dest_str = XSTRDUP(MTYPE_STATIC_ROUTE, dest_str); + if (mask_str) + shr->mask_str = XSTRDUP(MTYPE_STATIC_ROUTE, mask_str); + if (src_str) + shr->src_str = XSTRDUP(MTYPE_STATIC_ROUTE, src_str); + if (gate_str) + shr->gate_str = XSTRDUP(MTYPE_STATIC_ROUTE, gate_str); + if (ifname) + shr->ifname = XSTRDUP(MTYPE_STATIC_ROUTE, ifname); + if (flag_str) + shr->flag_str = XSTRDUP(MTYPE_STATIC_ROUTE, flag_str); + if (tag_str) + shr->tag_str = XSTRDUP(MTYPE_STATIC_ROUTE, tag_str); + if (distance_str) + shr->distance_str = XSTRDUP(MTYPE_STATIC_ROUTE, distance_str); + if (label_str) + shr->label_str = XSTRDUP(MTYPE_STATIC_ROUTE, label_str); + if (table_str) + shr->table_str = XSTRDUP(MTYPE_STATIC_ROUTE, table_str); + + for (ALL_LIST_ELEMENTS_RO(static_list, node, lookup)) { + if (static_list_compare(shr, lookup) == 0) + break; + } + + if (lookup) { + if (negate) { + listnode_delete(static_list, lookup); + static_list_delete(shr); + static_list_delete(lookup); + + return CMD_SUCCESS; + } + + /* + * If a person enters the same line again + * we need to silently accept it + */ + goto shr_cleanup; + } + + if (!negate) { + listnode_add_sort(static_list, shr); + return CMD_SUCCESS; + } + + shr_cleanup: + XFREE(MTYPE_STATIC_ROUTE, shr->nhvrf_name); + XFREE(MTYPE_STATIC_ROUTE, shr->vrf_name); + XFREE(MTYPE_STATIC_ROUTE, shr); + + return CMD_SUCCESS; +} + +static int static_route_leak( + struct vty *vty, struct static_vrf *svrf, struct static_vrf *nh_svrf, + afi_t afi, safi_t safi, const char *negate, const char *dest_str, + const char *mask_str, const char *src_str, const char *gate_str, + const char *ifname, const char *flag_str, const char *tag_str, + const char *distance_str, const char *label_str, const char *table_str) +{ + int ret; + uint8_t distance; + struct prefix p, src; + struct prefix_ipv6 *src_p = NULL; + union g_addr gate; + union g_addr *gatep = NULL; + struct in_addr mask; + enum static_blackhole_type bh_type = 0; + route_tag_t tag = 0; + uint8_t type; + struct static_nh_label snh_label; + uint32_t table_id = 0; + + ret = str2prefix(dest_str, &p); + if (ret <= 0) { + if (vty) + vty_out(vty, "%% Malformed address\n"); + else + zlog_warn("%s: Malformed address: %s", + __PRETTY_FUNCTION__, dest_str); + return CMD_WARNING_CONFIG_FAILED; + } + + switch (afi) { + case AFI_IP: + /* Cisco like mask notation. */ + if (mask_str) { + ret = inet_aton(mask_str, &mask); + if (ret == 0) { + if (vty) + vty_out(vty, "%% Malformed address\n"); + else + zlog_warn("%s: Malformed address: %s", + __PRETTY_FUNCTION__, + mask_str); + return CMD_WARNING_CONFIG_FAILED; + } + p.prefixlen = ip_masklen(mask); + } + break; + case AFI_IP6: + /* srcdest routing */ + if (src_str) { + ret = str2prefix(src_str, &src); + if (ret <= 0 || src.family != AF_INET6) { + if (vty) + vty_out(vty, + "%% Malformed source address\n"); + else + zlog_warn( + "%s: Malformed Source address: %s", + __PRETTY_FUNCTION__, src_str); + return CMD_WARNING_CONFIG_FAILED; + } + src_p = (struct prefix_ipv6 *)&src; + } + break; + default: + break; + } + + /* Apply mask for given prefix. */ + apply_mask(&p); + + if (svrf->vrf->vrf_id == VRF_UNKNOWN + || nh_svrf->vrf->vrf_id == VRF_UNKNOWN) { + vrf_set_user_cfged(svrf->vrf); + return zebra_static_route_holdem( + svrf, nh_svrf, afi, safi, negate, &p, dest_str, + mask_str, src_str, gate_str, ifname, flag_str, tag_str, + distance_str, label_str, table_str); + } + + if (table_str) { + /* table configured. check consistent with vrf config + */ + if (svrf->vrf->data.l.table_id != RT_TABLE_MAIN) { + if (vty) + vty_out(vty, + "%% Table %s overlaps vrf table %u\n", + table_str, svrf->vrf->data.l.table_id); + else + zlog_warn( + "%s: Table %s overlaps vrf table %u", + __PRETTY_FUNCTION__, + table_str, svrf->vrf->data.l.table_id); + return CMD_WARNING_CONFIG_FAILED; + } + } + + /* Administrative distance. */ + if (distance_str) + distance = atoi(distance_str); + else + distance = ZEBRA_STATIC_DISTANCE_DEFAULT; + + /* tag */ + if (tag_str) + tag = strtoul(tag_str, NULL, 10); + + /* Labels */ + memset(&snh_label, 0, sizeof(struct static_nh_label)); + if (label_str) { + if (!mpls_enabled) { + if (vty) + vty_out(vty, + "%% MPLS not turned on in kernel, ignoring command\n"); + else + zlog_warn( + "%s: MPLS not turned on in kernel ignoring static route to %s", + __PRETTY_FUNCTION__, dest_str); + return CMD_WARNING_CONFIG_FAILED; + } + int rc = mpls_str2label(label_str, &snh_label.num_labels, + snh_label.label); + if (rc < 0) { + switch (rc) { + case -1: + if (vty) + vty_out(vty, "%% Malformed label(s)\n"); + else + zlog_warn( + "%s: Malformed labels specified for route %s", + __PRETTY_FUNCTION__, dest_str); + break; + case -2: + if (vty) + vty_out(vty, + "%% Cannot use reserved label(s) (%d-%d)\n", + MPLS_LABEL_RESERVED_MIN, + MPLS_LABEL_RESERVED_MAX); + else + zlog_warn( + "%s: Cannot use reserved labels (%d-%d) for %s", + __PRETTY_FUNCTION__, + MPLS_LABEL_RESERVED_MIN, + MPLS_LABEL_RESERVED_MAX, + dest_str); + break; + case -3: + if (vty) + vty_out(vty, + "%% Too many labels. Enter %d or fewer\n", + MPLS_MAX_LABELS); + else + zlog_warn( + "%s: Too many labels, Enter %d or fewer for %s", + __PRETTY_FUNCTION__, + MPLS_MAX_LABELS, dest_str); + break; + } + return CMD_WARNING_CONFIG_FAILED; + } + } + + /* TableID */ + if (table_str) + table_id = atol(table_str); + + /* Null0 static route. */ + if (ifname != NULL) { + if (strncasecmp(ifname, "Null0", strlen(ifname)) == 0 + || strncasecmp(ifname, "reject", strlen(ifname)) == 0 + || strncasecmp(ifname, "blackhole", strlen(ifname)) == 0) { + if (vty) + vty_out(vty, + "%% Nexthop interface cannot be Null0, reject or blackhole\n"); + else + zlog_warn( + "%s: Nexthop interface cannot be Null0, reject or blackhole for %s", + __PRETTY_FUNCTION__, dest_str); + return CMD_WARNING_CONFIG_FAILED; + } + } + + /* Route flags */ + if (flag_str) { + switch (flag_str[0]) { + case 'r': + bh_type = STATIC_BLACKHOLE_REJECT; + break; + case 'b': + bh_type = STATIC_BLACKHOLE_DROP; + break; + case 'N': + bh_type = STATIC_BLACKHOLE_NULL; + break; + default: + if (vty) + vty_out(vty, "%% Malformed flag %s \n", + flag_str); + else + zlog_warn("%s: Malformed flag %s for %s", + __PRETTY_FUNCTION__, flag_str, + dest_str); + return CMD_WARNING_CONFIG_FAILED; + } + } + + if (gate_str) { + if (inet_pton(afi2family(afi), gate_str, &gate) != 1) { + if (vty) + vty_out(vty, + "%% Malformed nexthop address %s\n", + gate_str); + else + zlog_warn( + "%s: Malformed nexthop address %s for %s", + __PRETTY_FUNCTION__, gate_str, + dest_str); + return CMD_WARNING_CONFIG_FAILED; + } + gatep = &gate; + } + + if (gate_str == NULL && ifname == NULL) + type = STATIC_BLACKHOLE; + else if (gate_str && ifname) { + if (afi == AFI_IP) + type = STATIC_IPV4_GATEWAY_IFNAME; + else + type = STATIC_IPV6_GATEWAY_IFNAME; + } else if (ifname) + type = STATIC_IFNAME; + else { + if (afi == AFI_IP) + type = STATIC_IPV4_GATEWAY; + else + type = STATIC_IPV6_GATEWAY; + } + + if (!negate) { + static_add_route(afi, safi, type, &p, src_p, gatep, ifname, + bh_type, tag, distance, svrf, nh_svrf, + &snh_label, table_id); + /* Mark as having FRR configuration */ + vrf_set_user_cfged(svrf->vrf); + } else { + static_delete_route(afi, safi, type, &p, src_p, gatep, ifname, + tag, distance, svrf, &snh_label, table_id); + /* If no other FRR config for this VRF, mark accordingly. */ + if (!static_vrf_has_config(svrf)) + vrf_reset_user_cfged(svrf->vrf); + } + + return CMD_SUCCESS; +} + +static int static_route(struct vty *vty, afi_t afi, safi_t safi, + const char *negate, const char *dest_str, + const char *mask_str, const char *src_str, + const char *gate_str, const char *ifname, + const char *flag_str, const char *tag_str, + const char *distance_str, const char *vrf_name, + const char *label_str, const char *table_str) +{ + struct static_vrf *svrf; + + /* VRF id */ + svrf = static_vrf_lookup_by_name(vrf_name); + + /* When trying to delete, the VRF must exist. */ + if (negate && !svrf) { + vty_out(vty, "%% vrf %s is not defined\n", vrf_name); + return CMD_WARNING_CONFIG_FAILED; + } + + /* When trying to create, create the VRF if it doesn't exist. + * Note: The VRF isn't active until we hear about it from the kernel. + */ + if (!svrf) { + svrf = static_vty_get_unknown_vrf(vty, vrf_name); + if (!svrf) + return CMD_WARNING_CONFIG_FAILED; + } + return static_route_leak( + vty, svrf, svrf, afi, safi, negate, dest_str, mask_str, src_str, + gate_str, ifname, flag_str, tag_str, distance_str, label_str, + table_str); +} + +void static_config_install_delayed_routes(struct static_vrf *svrf) +{ + struct listnode *node, *nnode; + struct static_hold_route *shr; + struct static_vrf *osvrf, *nh_svrf; + int installed; + + for (ALL_LIST_ELEMENTS(static_list, node, nnode, shr)) { + osvrf = static_vrf_lookup_by_name(shr->vrf_name); + nh_svrf = static_vrf_lookup_by_name(shr->nhvrf_name); + + if (osvrf != svrf && nh_svrf != svrf) + continue; + + if (osvrf->vrf->vrf_id == VRF_UNKNOWN + || nh_svrf->vrf->vrf_id == VRF_UNKNOWN) + continue; + + installed = static_route_leak( + NULL, osvrf, nh_svrf, shr->afi, shr->safi, NULL, + shr->dest_str, shr->mask_str, shr->src_str, + shr->gate_str, shr->ifname, shr->flag_str, shr->tag_str, + shr->distance_str, shr->label_str, shr->table_str); + + if (installed != CMD_SUCCESS) + zlog_debug( + "%s: Attempt to install %s as a route and it was rejected", + __PRETTY_FUNCTION__, shr->dest_str); + listnode_delete(static_list, shr); + static_list_delete(shr); + } +} + +/* Write static route configuration. */ +int static_config(struct vty *vty, struct static_vrf *svrf, afi_t afi, + safi_t safi, const char *cmd) +{ + struct static_hold_route *shr; + struct listnode *node; + char spacing[100]; + struct route_node *rn; + struct static_route *si; + struct route_table *stable; + char buf[SRCDEST2STR_BUFFER]; + int write = 0; + + stable = svrf->stable[afi][safi]; + if (stable == NULL) + return write; + + sprintf(spacing, "%s%s", (svrf->vrf->vrf_id == VRF_DEFAULT) ? "" : " ", + cmd); + + /* + * Static routes for vrfs not fully inited + */ + for (ALL_LIST_ELEMENTS_RO(static_list, node, shr)) { + if (shr->afi != afi || shr->safi != safi) + continue; + + if (strcmp(svrf->vrf->name, shr->vrf_name) != 0) + continue; + + char dest_str[PREFIX_STRLEN]; + + prefix2str(&shr->dest, dest_str, sizeof(dest_str)); + + vty_out(vty, "%s ", spacing); + if (shr->dest_str) + vty_out(vty, "%s ", dest_str); + if (shr->src_str) + vty_out(vty, "from %s ", shr->src_str); + if (shr->gate_str) + vty_out(vty, "%s ", shr->gate_str); + if (shr->ifname) + vty_out(vty, "%s ", shr->ifname); + if (shr->flag_str) + vty_out(vty, "%s ", shr->flag_str); + if (shr->tag_str) + vty_out(vty, "tag %s ", shr->tag_str); + if (shr->distance_str) + vty_out(vty, "%s ", shr->distance_str); + if (shr->label_str) + vty_out(vty, "label %s ", shr->label_str); + if (shr->table_str) + vty_out(vty, "table %s", shr->table_str); + if (strcmp(shr->vrf_name, shr->nhvrf_name) != 0) + vty_out(vty, "nexthop-vrf %s", shr->nhvrf_name); + vty_out(vty, "\n"); + } + + for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) + for (si = rn->info; si; si = si->next) { + vty_out(vty, "%s %s", spacing, + srcdest_rnode2str(rn, buf, sizeof(buf))); + + switch (si->type) { + case STATIC_IPV4_GATEWAY: + vty_out(vty, " %s", inet_ntoa(si->addr.ipv4)); + break; + case STATIC_IPV6_GATEWAY: + vty_out(vty, " %s", + inet_ntop(AF_INET6, &si->addr.ipv6, buf, + sizeof(buf))); + break; + case STATIC_IFNAME: + vty_out(vty, " %s", si->ifname); + break; + case STATIC_BLACKHOLE: + switch (si->bh_type) { + case STATIC_BLACKHOLE_DROP: + vty_out(vty, " blackhole"); + break; + case STATIC_BLACKHOLE_NULL: + vty_out(vty, " Null0"); + break; + case STATIC_BLACKHOLE_REJECT: + vty_out(vty, " reject"); + break; + } + break; + case STATIC_IPV4_GATEWAY_IFNAME: + vty_out(vty, " %s %s", + inet_ntop(AF_INET, &si->addr.ipv4, buf, + sizeof(buf)), + si->ifname); + break; + case STATIC_IPV6_GATEWAY_IFNAME: + vty_out(vty, " %s %s", + inet_ntop(AF_INET6, &si->addr.ipv6, buf, + sizeof(buf)), + si->ifname); + break; + } + + if (si->tag) + vty_out(vty, " tag %" ROUTE_TAG_PRI, si->tag); + + if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT) + vty_out(vty, " %d", si->distance); + + /* Label information */ + if (si->snh_label.num_labels) + vty_out(vty, " label %s", + mpls_label2str(si->snh_label.num_labels, + si->snh_label.label, buf, + sizeof(buf), 0)); + + if (si->nh_vrf_id != si->vrf_id) + vty_out(vty, " nexthop-vrf %s", si->nh_vrfname); + + /* + * table ID from VRF overrides configured + */ + if (si->table_id && + svrf->vrf->data.l.table_id == RT_TABLE_MAIN) + vty_out(vty, " table %u", si->table_id); + + vty_out(vty, "\n"); + + write = 1; + } + return write; +} + +/* Static unicast routes for multicast RPF lookup. */ +DEFPY (ip_mroute_dist, + ip_mroute_dist_cmd, + "[no] ip mroute A.B.C.D/M$prefix [(1-255)$distance]", + NO_STR + IP_STR + "Configure static unicast route into MRIB for multicast RPF lookup\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "Nexthop address\n" + "Nexthop interface name\n" + "Distance\n") +{ + return static_route(vty, AFI_IP, SAFI_MULTICAST, no, prefix_str, + NULL, NULL, gate_str, ifname, NULL, NULL, + distance_str, NULL, NULL, NULL); +} + +/* Static route configuration. */ +DEFPY(ip_route_blackhole, + ip_route_blackhole_cmd, + "[no] ip route\ + \ + $flag \ + [{ \ + tag (1-4294967295) \ + |(1-255)$distance \ + |vrf NAME \ + |label WORD \ + |table (1-4294967295) \ + }]", + NO_STR IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR + MPLS_LABEL_HELPSTR + "Table to configure\n" + "The table number to configure\n") +{ + if (table_str && !vrf_is_backend_netns()) { + vty_out(vty, + "%% table param only available when running on netns-based vrfs\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + return static_route(vty, AFI_IP, SAFI_UNICAST, no, prefix, + mask_str, NULL, NULL, NULL, flag, tag_str, + distance_str, vrf, label, table_str); +} + +DEFPY(ip_route_blackhole_vrf, + ip_route_blackhole_vrf_cmd, + "[no] ip route\ + \ + $flag \ + [{ \ + tag (1-4294967295) \ + |(1-255)$distance \ + |label WORD \ + |table (1-4294967295) \ + }]", + NO_STR IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n" + MPLS_LABEL_HELPSTR + "Table to configure\n" + "The table number to configure\n") +{ + VTY_DECLVAR_CONTEXT(vrf, vrf); + struct static_vrf *svrf = vrf->info; + + if (table_str && !vrf_is_backend_netns()) { + vty_out(vty, + "%% table param only available when running on netns-based vrfs\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + /* + * Coverity is complaining that prefix could + * be dereferenced, but we know that prefix will + * valid. Add an assert to make it happy + */ + assert(prefix); + return static_route_leak(vty, svrf, svrf, AFI_IP, SAFI_UNICAST, + no, prefix, mask_str, NULL, NULL, NULL, + flag, tag_str, distance_str, label, table_str); +} + +DEFPY(ip_route_address_interface, + ip_route_address_interface_cmd, + "[no] ip route\ + \ + A.B.C.D$gate \ + INTERFACE$ifname \ + [{ \ + tag (1-4294967295) \ + |(1-255)$distance \ + |vrf NAME \ + |label WORD \ + |table (1-4294967295) \ + |nexthop-vrf NAME \ + }]", + NO_STR IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name. Specify 'Null0' (case-insensitive) for a \ + null route.\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR + MPLS_LABEL_HELPSTR + "Table to configure\n" + "The table number to configure\n" + VRF_CMD_HELP_STR) +{ + struct static_vrf *svrf; + struct static_vrf *nh_svrf; + const char *flag = NULL; + + if (ifname && !strncasecmp(ifname, "Null0", 5)) { + flag = "Null0"; + ifname = NULL; + } + + svrf = static_vty_get_unknown_vrf(vty, vrf); + if (!svrf) { + vty_out(vty, "%% vrf %s is not defined\n", vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + if (table_str && !vrf_is_backend_netns()) { + vty_out(vty, + "%% table param only available when running on netns-based vrfs\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (nexthop_vrf) + nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf); + else + nh_svrf = svrf; + + if (!nh_svrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + return static_route_leak( + vty, svrf, nh_svrf, AFI_IP, SAFI_UNICAST, no, prefix, mask_str, + NULL, gate_str, ifname, flag, tag_str, distance_str, label, + table_str); +} + +DEFPY(ip_route_address_interface_vrf, + ip_route_address_interface_vrf_cmd, + "[no] ip route\ + \ + A.B.C.D$gate \ + INTERFACE$ifname \ + [{ \ + tag (1-4294967295) \ + |(1-255)$distance \ + |label WORD \ + |table (1-4294967295) \ + |nexthop-vrf NAME \ + }]", + NO_STR IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name. Specify 'Null0' (case-insensitive) for a \ + null route.\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n" + MPLS_LABEL_HELPSTR + "Table to configure\n" + "The table number to configure\n" + VRF_CMD_HELP_STR) +{ + VTY_DECLVAR_CONTEXT(vrf, vrf); + const char *flag = NULL; + struct static_vrf *svrf = vrf->info; + struct static_vrf *nh_svrf; + + if (table_str && !vrf_is_backend_netns()) { + vty_out(vty, + "%% table param only available when running on netns-based vrfs\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (ifname && !strncasecmp(ifname, "Null0", 5)) { + flag = "Null0"; + ifname = NULL; + } + + if (nexthop_vrf) + nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf); + else + nh_svrf = svrf; + + if (!nh_svrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + return static_route_leak( + vty, svrf, nh_svrf, AFI_IP, SAFI_UNICAST, no, prefix, mask_str, + NULL, gate_str, ifname, flag, tag_str, distance_str, label, + table_str); +} + +DEFPY(ip_route, + ip_route_cmd, + "[no] ip route\ + \ + \ + [{ \ + tag (1-4294967295) \ + |(1-255)$distance \ + |vrf NAME \ + |label WORD \ + |table (1-4294967295) \ + |nexthop-vrf NAME \ + }]", + NO_STR IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n" + VRF_CMD_HELP_STR + MPLS_LABEL_HELPSTR + "Table to configure\n" + "The table number to configure\n" + VRF_CMD_HELP_STR) +{ + struct static_vrf *svrf; + struct static_vrf *nh_svrf; + const char *flag = NULL; + + if (table_str && !vrf_is_backend_netns()) { + vty_out(vty, + "%% table param only available when running on netns-based vrfs\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (ifname && !strncasecmp(ifname, "Null0", 5)) { + flag = "Null0"; + ifname = NULL; + } + + svrf = static_vty_get_unknown_vrf(vty, vrf); + if (!svrf) { + vty_out(vty, "%% vrf %s is not defined\n", vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + if (nexthop_vrf) + nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf); + else + nh_svrf = svrf; + + if (!nh_svrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + return static_route_leak( + vty, svrf, nh_svrf, AFI_IP, SAFI_UNICAST, no, prefix, mask_str, + NULL, gate_str, ifname, flag, tag_str, distance_str, label, + table_str); +} + +DEFPY(ip_route_vrf, + ip_route_vrf_cmd, + "[no] ip route\ + \ + \ + [{ \ + tag (1-4294967295) \ + |(1-255)$distance \ + |label WORD \ + |table (1-4294967295) \ + |nexthop-vrf NAME \ + }]", + NO_STR IP_STR + "Establish static routes\n" + "IP destination prefix (e.g. 10.0.0.0/8)\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this route\n" + MPLS_LABEL_HELPSTR + "Table to configure\n" + "The table number to configure\n" + VRF_CMD_HELP_STR) +{ + VTY_DECLVAR_CONTEXT(vrf, vrf); + struct static_vrf *svrf = vrf->info; + struct static_vrf *nh_svrf; + const char *flag = NULL; + + if (table_str && !vrf_is_backend_netns()) { + vty_out(vty, + "%% table param only available when running on netns-based vrfs\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (ifname && !strncasecmp(ifname, "Null0", 5)) { + flag = "Null0"; + ifname = NULL; + } + + if (nexthop_vrf) + nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf); + else + nh_svrf = svrf; + + if (!nh_svrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + return static_route_leak( + vty, svrf, nh_svrf, AFI_IP, SAFI_UNICAST, no, prefix, mask_str, + NULL, gate_str, ifname, flag, tag_str, distance_str, label, + table_str); +} + +DEFPY(ipv6_route_blackhole, + ipv6_route_blackhole_cmd, + "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \ + $flag \ + [{ \ + tag (1-4294967295) \ + |(1-255)$distance \ + |vrf NAME \ + |label WORD \ + |table (1-4294967295) \ + }]", + NO_STR + IPV6_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 source-dest route\n" + "IPv6 source prefix\n" + "Null interface\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" + VRF_CMD_HELP_STR + MPLS_LABEL_HELPSTR + "Table to configure\n" + "The table number to configure\n") +{ + if (table_str && !vrf_is_backend_netns()) { + vty_out(vty, + "%% table param only available when running on netns-based vrfs\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + return static_route(vty, AFI_IP6, SAFI_UNICAST, no, prefix_str, + NULL, from_str, NULL, NULL, flag, tag_str, + distance_str, vrf, label, table_str); +} + +DEFPY(ipv6_route_blackhole_vrf, + ipv6_route_blackhole_vrf_cmd, + "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \ + $flag \ + [{ \ + tag (1-4294967295) \ + |(1-255)$distance \ + |label WORD \ + |table (1-4294967295) \ + }]", + NO_STR + IPV6_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 source-dest route\n" + "IPv6 source prefix\n" + "Null interface\n" + "Emit an ICMP unreachable when matched\n" + "Silently discard pkts when matched\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" + MPLS_LABEL_HELPSTR + "Table to configure\n" + "The table number to configure\n") +{ + VTY_DECLVAR_CONTEXT(vrf, vrf); + struct static_vrf *svrf = vrf->info; + + if (table_str && !vrf_is_backend_netns()) { + vty_out(vty, + "%% table param only available when running on netns-based vrfs\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + /* + * Coverity is complaining that prefix could + * be dereferenced, but we know that prefix will + * valid. Add an assert to make it happy + */ + assert(prefix); + return static_route_leak( + vty, svrf, svrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL, + from_str, NULL, NULL, flag, tag_str, distance_str, label, + table_str); +} + +DEFPY(ipv6_route_address_interface, + ipv6_route_address_interface_cmd, + "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \ + X:X::X:X$gate \ + INTERFACE$ifname \ + [{ \ + tag (1-4294967295) \ + |(1-255)$distance \ + |vrf NAME \ + |label WORD \ + |table (1-4294967295) \ + |nexthop-vrf NAME \ + }]", + NO_STR + IPV6_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 source-dest route\n" + "IPv6 source prefix\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" + VRF_CMD_HELP_STR + MPLS_LABEL_HELPSTR + "Table to configure\n" + "The table number to configure\n" + VRF_CMD_HELP_STR) +{ + struct static_vrf *svrf; + struct static_vrf *nh_svrf; + + if (table_str && !vrf_is_backend_netns()) { + vty_out(vty, + "%% table param only available when running on netns-based vrfs\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + svrf = static_vty_get_unknown_vrf(vty, vrf); + if (!svrf) { + vty_out(vty, "%% vrf %s is not defined\n", vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + if (nexthop_vrf) + nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf); + else + nh_svrf = svrf; + + if (!nh_svrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + return static_route_leak( + vty, svrf, nh_svrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL, + from_str, gate_str, ifname, NULL, tag_str, distance_str, label, + table_str); +} + +DEFPY(ipv6_route_address_interface_vrf, + ipv6_route_address_interface_vrf_cmd, + "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \ + X:X::X:X$gate \ + INTERFACE$ifname \ + [{ \ + tag (1-4294967295) \ + |(1-255)$distance \ + |label WORD \ + |table (1-4294967295) \ + |nexthop-vrf NAME \ + }]", + NO_STR + IPV6_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 source-dest route\n" + "IPv6 source prefix\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" + MPLS_LABEL_HELPSTR + "Table to configure\n" + "The table number to configure\n" + VRF_CMD_HELP_STR) +{ + VTY_DECLVAR_CONTEXT(vrf, vrf); + struct static_vrf *svrf = vrf->info; + struct static_vrf *nh_svrf; + + if (table_str && !vrf_is_backend_netns()) { + vty_out(vty, + "%% table param only available when running on netns-based vrfs\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (nexthop_vrf) + nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf); + else + nh_svrf = svrf; + + if (!nh_svrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + return static_route_leak( + vty, svrf, nh_svrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL, + from_str, gate_str, ifname, NULL, tag_str, distance_str, label, + table_str); +} + +DEFPY(ipv6_route, + ipv6_route_cmd, + "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \ + \ + [{ \ + tag (1-4294967295) \ + |(1-255)$distance \ + |vrf NAME \ + |label WORD \ + |table (1-4294967295) \ + |nexthop-vrf NAME \ + }]", + NO_STR + IPV6_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 source-dest route\n" + "IPv6 source prefix\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" + VRF_CMD_HELP_STR + MPLS_LABEL_HELPSTR + "Table to configure\n" + "The table number to configure\n" + VRF_CMD_HELP_STR) +{ + struct static_vrf *svrf; + struct static_vrf *nh_svrf; + + if (table_str && !vrf_is_backend_netns()) { + vty_out(vty, + "%% table param only available when running on netns-based vrfs\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + svrf = static_vty_get_unknown_vrf(vty, vrf); + if (!svrf) { + vty_out(vty, "%% vrf %s is not defined\n", vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + if (nexthop_vrf) + nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf); + else + nh_svrf = svrf; + + if (!nh_svrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + return static_route_leak( + vty, svrf, nh_svrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL, + from_str, gate_str, ifname, NULL, tag_str, distance_str, label, + table_str); +} + +DEFPY(ipv6_route_vrf, + ipv6_route_vrf_cmd, + "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \ + \ + [{ \ + tag (1-4294967295) \ + |(1-255)$distance \ + |label WORD \ + |table (1-4294967295) \ + |nexthop-vrf NAME \ + }]", + NO_STR + IPV6_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 source-dest route\n" + "IPv6 source prefix\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Set tag for this route\n" + "Tag value\n" + "Distance value for this prefix\n" + MPLS_LABEL_HELPSTR + "Table to configure\n" + "The table number to configure\n" + VRF_CMD_HELP_STR) +{ + VTY_DECLVAR_CONTEXT(vrf, vrf); + struct static_vrf *svrf = vrf->info; + struct static_vrf *nh_svrf; + + if (table_str && !vrf_is_backend_netns()) { + vty_out(vty, + "%% table param only available when running on netns-based vrfs\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (nexthop_vrf) + nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf); + else + nh_svrf = svrf; + + if (!nh_svrf) { + vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf); + return CMD_WARNING_CONFIG_FAILED; + } + + return static_route_leak( + vty, svrf, nh_svrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL, + from_str, gate_str, ifname, NULL, tag_str, distance_str, label, + table_str); +} + +void static_vty_init(void) +{ + install_element(CONFIG_NODE, &ip_mroute_dist_cmd); + + install_element(CONFIG_NODE, &ip_route_blackhole_cmd); + install_element(VRF_NODE, &ip_route_blackhole_vrf_cmd); + install_element(CONFIG_NODE, &ip_route_address_interface_cmd); + install_element(VRF_NODE, &ip_route_address_interface_vrf_cmd); + install_element(CONFIG_NODE, &ip_route_cmd); + install_element(VRF_NODE, &ip_route_vrf_cmd); + + install_element(CONFIG_NODE, &ipv6_route_blackhole_cmd); + install_element(VRF_NODE, &ipv6_route_blackhole_vrf_cmd); + install_element(CONFIG_NODE, &ipv6_route_address_interface_cmd); + install_element(VRF_NODE, &ipv6_route_address_interface_vrf_cmd); + install_element(CONFIG_NODE, &ipv6_route_cmd); + install_element(VRF_NODE, &ipv6_route_vrf_cmd); + + static_list = list_new(); + static_list->cmp = (int (*)(void *, void *))static_list_compare; + static_list->del = (void (*)(void *))static_list_delete; +} diff --git a/staticd/static_vty.h b/staticd/static_vty.h new file mode 100644 index 000000000..be7056a4d --- /dev/null +++ b/staticd/static_vty.h @@ -0,0 +1,29 @@ +/* + * STATICd - vty header + * Copyright (C) 2018 Cumulus Networks, Inc. + * Donald Sharp + * + * FRR 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, or (at your option) any + * later version. + * + * FRR 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 __STATIC_VTY_H__ +#define __STATIC_VTY_H__ + +void static_config_install_delayed_routes(struct static_vrf *svrf); + +int static_config(struct vty *vty, struct static_vrf *svrf, + afi_t afi, safi_t safi, const char *cmd); + +void static_vty_init(void); +#endif diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c new file mode 100644 index 000000000..3f7440dfa --- /dev/null +++ b/staticd/static_zebra.c @@ -0,0 +1,377 @@ +/* + * Zebra connect code. + * Copyright (C) 2018 Cumulus Networks, Inc. + * Donald Sharp + * + * FRR 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, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include + +#include "thread.h" +#include "command.h" +#include "network.h" +#include "prefix.h" +#include "routemap.h" +#include "table.h" +#include "srcdest_table.h" +#include "stream.h" +#include "memory.h" +#include "zclient.h" +#include "filter.h" +#include "plist.h" +#include "log.h" +#include "nexthop.h" +#include "nexthop_group.h" + +#include "static_vrf.h" +#include "static_routes.h" +#include "static_zebra.h" +#include "static_nht.h" +#include "static_vty.h" + +/* Zebra structure to hold current status. */ +struct zclient *zclient; + +static struct interface *zebra_interface_if_lookup(struct stream *s) +{ + char ifname_tmp[INTERFACE_NAMSIZ]; + + /* Read interface name. */ + stream_get(ifname_tmp, s, INTERFACE_NAMSIZ); + + /* And look it up. */ + return if_lookup_by_name(ifname_tmp, VRF_DEFAULT); +} + +/* Inteface addition message from zebra. */ +static int interface_add(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct interface *ifp; + + ifp = zebra_interface_add_read(zclient->ibuf, vrf_id); + + if (!ifp) + return 0; + + static_ifindex_update(ifp, true); + return 0; +} + +static int interface_delete(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct interface *ifp; + struct stream *s; + + s = zclient->ibuf; + /* zebra_interface_state_read () updates interface structure in iflist + */ + ifp = zebra_interface_state_read(s, vrf_id); + + if (ifp == NULL) + return 0; + + if_set_index(ifp, IFINDEX_INTERNAL); + + static_ifindex_update(ifp, false); + return 0; +} + +static int interface_address_add(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + zebra_interface_address_read(command, zclient->ibuf, vrf_id); + + return 0; +} + +static int interface_address_delete(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct connected *c; + + c = zebra_interface_address_read(command, zclient->ibuf, vrf_id); + + if (!c) + return 0; + + connected_free(c); + return 0; +} + +static int interface_state_up(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct interface *ifp; + + ifp = zebra_interface_if_lookup(zclient->ibuf); + + if (if_is_vrf(ifp)) { + struct static_vrf *svrf = static_vrf_lookup_by_id(vrf_id); + + static_fixup_vrf_ids(svrf); + static_config_install_delayed_routes(svrf); + } + + return 0; +} + +static int interface_state_down(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + zebra_interface_state_read(zclient->ibuf, vrf_id); + + return 0; +} + +static int route_notify_owner(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct prefix p; + enum zapi_route_notify_owner note; + uint32_t table_id; + char buf[PREFIX_STRLEN]; + + prefix2str(&p, buf, sizeof(buf)); + + if (!zapi_route_notify_decode(zclient->ibuf, &p, &table_id, ¬e)) + return -1; + + switch (note) { + case ZAPI_ROUTE_FAIL_INSTALL: + zlog_warn("%s: Route %s failed to install for table: %u", + __PRETTY_FUNCTION__, buf, table_id); + break; + case ZAPI_ROUTE_BETTER_ADMIN_WON: + zlog_warn("%s: Route %s over-ridden by better route for table: %u", + __PRETTY_FUNCTION__, buf, table_id); + break; + case ZAPI_ROUTE_INSTALLED: + break; + case ZAPI_ROUTE_REMOVED: + break; + case ZAPI_ROUTE_REMOVE_FAIL: + zlog_warn("%s: Route %s failure to remove for table: %u", + __PRETTY_FUNCTION__, buf, table_id); + break; + } + + return 0; +} +static void zebra_connected(struct zclient *zclient) +{ + zclient_send_reg_requests(zclient, VRF_DEFAULT); +} + + +static int static_zebra_nexthop_update(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct zapi_route nhr; + afi_t afi = AFI_IP; + + if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) { + zlog_warn("Failure to decode nexthop update message"); + return 1; + } + + if (nhr.prefix.family == AF_INET6) + afi = AFI_IP6; + + static_nht_update(&nhr.prefix, nhr.nexthop_num, afi, vrf_id); + return 1; +} + +static void static_zebra_capabilities(struct zclient_capabilities *cap) +{ + mpls_enabled = cap->mpls_enabled; +} + +void static_zebra_nht_register(struct static_route *si, bool reg) +{ + uint32_t cmd; + struct prefix p; + + cmd = (reg) ? + ZEBRA_NEXTHOP_REGISTER : ZEBRA_NEXTHOP_UNREGISTER; + + if (si->nh_registered && reg) + return; + + if (!si->nh_registered && !reg) + return; + + memset(&p, 0, sizeof(p)); + switch (si->type) { + case STATIC_IPV4_GATEWAY_IFNAME: + case STATIC_IFNAME: + case STATIC_BLACKHOLE: + case STATIC_IPV6_GATEWAY_IFNAME: + return; + case STATIC_IPV4_GATEWAY: + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + p.u.prefix4 = si->addr.ipv4; + break; + case STATIC_IPV6_GATEWAY: + p.family = AF_INET6; + p.prefixlen = IPV6_MAX_BITLEN; + p.u.prefix6 = si->addr.ipv6; + break; + } + + if (zclient_send_rnh(zclient, cmd, &p, false, si->nh_vrf_id) < 0) + zlog_warn("%s: Failure to send nexthop to zebra", + __PRETTY_FUNCTION__); + + si->nh_registered = reg; +} + +extern void static_zebra_route_add(struct route_node *rn, vrf_id_t vrf_id, + safi_t safi, bool install) +{ + struct static_route *si = rn->info; + const struct prefix *p, *src_pp; + struct zapi_nexthop *api_nh; + struct zapi_route api; + uint32_t nh_num = 0; + + p = src_pp = NULL; + srcdest_rnode_prefixes(rn, &p, &src_pp); + + memset(&api, 0, sizeof(api)); + api.vrf_id = vrf_id; + api.type = ZEBRA_ROUTE_STATIC; + api.safi = safi; + memcpy(&api.prefix, p, sizeof(api.prefix)); + + if (src_pp) { + SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX); + memcpy(&api.src_prefix, src_pp, sizeof(api.src_prefix)); + } + + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); + + for (/*loaded above*/; si; si = si->next) { + api_nh = &api.nexthops[nh_num]; + if (si->nh_vrf_id == VRF_UNKNOWN) + continue; + + /* + * If we create a ecmp static route the + * last distance and tag entered wins. Why because + * this cli choosen sucks + */ + if (si->distance) { + SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE); + api.distance = si->distance; + } + if (si->tag) { + SET_FLAG(api.message, ZAPI_MESSAGE_TAG); + api.tag = si->tag; + } + + api.tableid = si->table_id; + + api_nh->vrf_id = si->nh_vrf_id; + switch (si->type) { + case STATIC_IFNAME: + if (si->ifindex == IFINDEX_INTERNAL) + continue; + api_nh->ifindex = si->ifindex; + api_nh->type = NEXTHOP_TYPE_IFINDEX; + break; + case STATIC_IPV4_GATEWAY: + if (!si->nh_valid) + continue; + api_nh->type = NEXTHOP_TYPE_IPV4; + api_nh->gate = si->addr; + break; + case STATIC_IPV4_GATEWAY_IFNAME: + if (si->ifindex == IFINDEX_INTERNAL) + continue; + api_nh->ifindex = si->ifindex; + api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX; + api_nh->gate = si->addr; + break; + case STATIC_IPV6_GATEWAY: + if (!si->nh_valid) + continue; + api_nh->type = NEXTHOP_TYPE_IPV6; + api_nh->gate = si->addr; + break; + case STATIC_IPV6_GATEWAY_IFNAME: + if (si->ifindex == IFINDEX_INTERNAL) + continue; + api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX; + api_nh->ifindex = si->ifindex; + api_nh->gate = si->addr; + break; + case STATIC_BLACKHOLE: + api_nh->type = NEXTHOP_TYPE_BLACKHOLE; + switch (si->bh_type) { + case STATIC_BLACKHOLE_DROP: + case STATIC_BLACKHOLE_NULL: + api_nh->bh_type = BLACKHOLE_NULL; + break; + case STATIC_BLACKHOLE_REJECT: + api_nh->bh_type = BLACKHOLE_REJECT; + } + break; + } + + if (si->snh_label.num_labels) { + int i; + + SET_FLAG(api.message, ZAPI_MESSAGE_LABEL); + api_nh->label_num = si->snh_label.num_labels; + for (i = 0; i < api_nh->label_num; i++) + api_nh->labels[i] = si->snh_label.label[i]; + } + nh_num++; + } + + api.nexthop_num = nh_num; + + /* + * If we have been given an install but nothing is valid + * go ahead and delete the route for double plus fun + */ + if (!nh_num && install) + install = false; + + zclient_route_send(install ? + ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE, + zclient, &api); +} +void static_zebra_init(void) +{ + struct zclient_options opt = { .receive_notify = true }; + + zclient = zclient_new_notify(master, &opt); + + zclient_init(zclient, ZEBRA_ROUTE_STATIC, 0, &static_privs); + zclient->zebra_capabilities = static_zebra_capabilities; + zclient->zebra_connected = zebra_connected; + zclient->interface_add = interface_add; + zclient->interface_delete = interface_delete; + zclient->interface_up = interface_state_up; + zclient->interface_down = interface_state_down; + zclient->interface_address_add = interface_address_add; + zclient->interface_address_delete = interface_address_delete; + zclient->route_notify_owner = route_notify_owner; + zclient->nexthop_update = static_zebra_nexthop_update; +} diff --git a/staticd/static_zebra.h b/staticd/static_zebra.h new file mode 100644 index 000000000..b408bc63b --- /dev/null +++ b/staticd/static_zebra.h @@ -0,0 +1,30 @@ +/* + * Zebra connect library for staticd + * Copyright (C) 2018 Cumulus Networks, Inc. + * Donald Sharp + * + * FRR 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, or (at your option) any + * later version. + * + * FRR 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 __STATIC_ZEBRA_H__ +#define __STATIC_ZEBRA_H__ + +extern struct thread_master *master; + +extern void static_zebra_nht_register(struct static_route *si, bool reg); + +extern void static_zebra_route_add(struct route_node *rn, vrf_id_t vrf_id, + safi_t safi, bool install); +extern void static_zebra_init(void); +#endif diff --git a/staticd/staticd.conf.sample b/staticd/staticd.conf.sample new file mode 100644 index 000000000..bb1c2edca --- /dev/null +++ b/staticd/staticd.conf.sample @@ -0,0 +1,3 @@ +! +! +log stdout diff --git a/staticd/subdir.am b/staticd/subdir.am new file mode 100644 index 000000000..3b06a92e2 --- /dev/null +++ b/staticd/subdir.am @@ -0,0 +1,33 @@ +# +# staticd +# + +if STATICD +noinst_LIBRARIES += staticd/libstatic.a +sbin_PROGRAMS += staticd/staticd +dist_examples_DATA += staticd/staticd.conf.sample +endif + +staticd_libstatic_a_SOURCES = \ + staticd/static_memory.c \ + staticd/static_nht.c \ + staticd/static_routes.c \ + staticd/static_zebra.c \ + staticd/static_vrf.c \ + staticd/static_vty.c \ + # end + +noinst_HEADERS += \ + staticd/static_memory.h \ + staticd/static_nht.h \ + staticd/static_zebra.h \ + staticd/static_routes.h \ + staticd/static_vty.h \ + staticd/static_vrf.h \ + # end + +staticd/static_vty_clippy.c: $(CLIPPY_DEPS) +staticd/static_vty.$(OBJEXT): staticd/static_vty_clippy.c + +staticd_staticd_SOURCES = staticd/static_main.c +staticd_staticd_LDADD = staticd/libstatic.a lib/libfrr.la @LIBCAP@ diff --git a/vtysh/Makefile.am b/vtysh/Makefile.am index 5d6f890e9..6d0b4a8fd 100644 --- a/vtysh/Makefile.am +++ b/vtysh/Makefile.am @@ -146,6 +146,10 @@ vtysh_scan += $(top_srcdir)/pbrd/pbr_vty.c vtysh_scan += $(top_srcdir)/pbrd/pbr_debug.c endif +if STATICD +vtysh_scan += $(top_srcdir)/staticd/static_vty.c +endif + vtysh_cmd_FILES = $(vtysh_scan) \ $(top_srcdir)/lib/keychain.c $(top_srcdir)/lib/routemap.c \ $(top_srcdir)/lib/filter.c $(top_srcdir)/lib/plist.c \ diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index b56eaa899..e25a57692 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -133,6 +133,7 @@ struct vtysh_client vtysh_client[] = { {.fd = -1, .name = "sharpd", .flag = VTYSH_SHARPD, .next = NULL}, {.fd = -1, .name = "watchfrr", .flag = VTYSH_WATCHFRR, .next = NULL}, {.fd = -1, .name = "pbrd", .flag = VTYSH_PBRD, .next = NULL}, + {.fd = -1, .name = "staticd", .flag = VTYSH_STATICD, .next = NULL}, }; enum vtysh_write_integrated vtysh_write_integrated = diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index 6fa61dd88..e6ed5659c 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -39,6 +39,7 @@ DECLARE_MGROUP(MVTYSH) #define VTYSH_BABELD 0x1000 #define VTYSH_SHARPD 0x2000 #define VTYSH_PBRD 0x4000 +#define VTYSH_STATICD 0x8000 #define VTYSH_WAS_ACTIVE (-2) @@ -47,7 +48,7 @@ DECLARE_MGROUP(MVTYSH) /* watchfrr is not in ALL since library CLI functions should not be * run on it (logging & co. should stay in a fixed/frozen config, and * things like prefix lists are not even initialised) */ -#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD +#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD|VTYSH_STATICD #define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_SHARPD #define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_PBRD #define VTYSH_NS VTYSH_ZEBRA diff --git a/zebra/interface.c b/zebra/interface.c index 1067f9bdc..7fe7058de 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -577,7 +577,6 @@ void if_add_update(struct interface *ifp) "interface %s vrf %u index %d becomes active.", ifp->name, ifp->vrf_id, ifp->ifindex); - static_ifindex_update(ifp, true); } else { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("interface %s vrf %u index %d is added.", @@ -736,8 +735,6 @@ void if_delete_update(struct interface *ifp) zlog_debug("interface %s vrf %u index %d is now inactive.", ifp->name, ifp->vrf_id, ifp->ifindex); - static_ifindex_update(ifp, false); - /* Delete connected routes from the kernel. */ if_delete_connected(ifp); @@ -777,8 +774,6 @@ void if_handle_vrf_change(struct interface *ifp, vrf_id_t vrf_id) old_vrf_id = ifp->vrf_id; - static_ifindex_update(ifp, false); - /* Uninstall connected routes. */ if_uninstall_connected(ifp); @@ -803,8 +798,6 @@ void if_handle_vrf_change(struct interface *ifp, vrf_id_t vrf_id) if (if_is_operative(ifp)) if_install_connected(ifp); - static_ifindex_update(ifp, true); - /* Due to connected route change, schedule RIB processing for both old * and new VRF. */ @@ -934,12 +927,6 @@ void if_up(struct interface *ifp) /* Install connected routes to the kernel. */ if_install_connected(ifp); - /* Install any static routes using this vrf interface */ - if (IS_ZEBRA_IF_VRF(ifp)) { - static_fixup_vrf_ids(zvrf); - static_config_install_delayed_routes(zvrf); - } - if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug("%u: IF %s up, scheduling RIB processing", ifp->vrf_id, ifp->name); diff --git a/zebra/rib.h b/zebra/rib.h index 6509cdaba..439327aa4 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -291,8 +291,6 @@ extern int is_zebra_valid_kernel_table(uint32_t table_id); extern int is_zebra_main_routing_table(uint32_t table_id); extern int zebra_check_addr(const struct prefix *p); -extern void rib_addnode(struct route_node *rn, struct route_entry *re, - int process); extern void rib_delnode(struct route_node *rn, struct route_entry *re); extern void rib_install_kernel(struct route_node *rn, struct route_entry *re, struct route_entry *old); @@ -450,9 +448,6 @@ DECLARE_HOOK(rib_update, (struct route_node * rn, const char *reason), extern void zebra_vty_init(void); -extern int static_config(struct vty *vty, struct zebra_vrf *zvrf, afi_t afi, - safi_t safi, const char *cmd); -extern void static_config_install_delayed_routes(struct zebra_vrf *zvrf); extern pid_t pid; diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 71d48632c..33eebfe99 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2086,7 +2086,8 @@ static void rib_link(struct route_node *rn, struct route_entry *re, int process) rib_queue_add(rn); } -void rib_addnode(struct route_node *rn, struct route_entry *re, int process) +static void rib_addnode(struct route_node *rn, + struct route_entry *re, int process) { /* RE node has been un-removed before route-node is processed. * route_node must hence already be on the queue for processing.. @@ -2135,10 +2136,6 @@ void rib_unlink(struct route_node *rn, struct route_entry *re) if (dest->selected_fib == re) dest->selected_fib = NULL; - /* free RE and nexthops */ - if (re->type == ZEBRA_ROUTE_STATIC) - zebra_deregister_rnh_static_nexthops(re->ng.nexthop->vrf_id, - re->ng.nexthop, rn); nexthops_free(re->ng.nexthop); XFREE(MTYPE_RE, re); } diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index d482e0ab3..453f08a18 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -131,7 +131,6 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type) rnh = XCALLOC(MTYPE_RNH, sizeof(struct rnh)); rnh->client_list = list_new(); rnh->vrf_id = vrfid; - rnh->zebra_static_route_list = list_new(); rnh->zebra_pseudowire_list = list_new(); route_lock_node(rn); rn->info = rnh; @@ -167,7 +166,6 @@ void zebra_free_rnh(struct rnh *rnh) { rnh->flags |= ZEBRA_NHT_DELETED; list_delete_and_null(&rnh->client_list); - list_delete_and_null(&rnh->zebra_static_route_list); list_delete_and_null(&rnh->zebra_pseudowire_list); free_state(rnh->vrf_id, rnh->state, rnh->node); XFREE(MTYPE_RNH, rnh); @@ -218,82 +216,10 @@ void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client, } listnode_delete(rnh->client_list, client); if (list_isempty(rnh->client_list) - && list_isempty(rnh->zebra_static_route_list) && list_isempty(rnh->zebra_pseudowire_list)) zebra_delete_rnh(rnh, type); } -void zebra_register_rnh_static_nh(vrf_id_t vrf_id, struct prefix *nh, - struct route_node *static_rn) -{ - struct rnh *rnh; - - rnh = zebra_add_rnh(nh, vrf_id, RNH_NEXTHOP_TYPE); - if (rnh && !listnode_lookup(rnh->zebra_static_route_list, static_rn)) { - listnode_add(rnh->zebra_static_route_list, static_rn); - } -} - -void zebra_deregister_rnh_static_nh(vrf_id_t vrf_id, struct prefix *nh, - struct route_node *static_rn) -{ - struct rnh *rnh; - - rnh = zebra_lookup_rnh(nh, vrf_id, RNH_NEXTHOP_TYPE); - if (!rnh || (rnh->flags & ZEBRA_NHT_DELETED)) - return; - - listnode_delete(rnh->zebra_static_route_list, static_rn); - - if (list_isempty(rnh->client_list) - && list_isempty(rnh->zebra_static_route_list) - && list_isempty(rnh->zebra_pseudowire_list)) - zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE); -} - -void zebra_deregister_rnh_static_nexthops(vrf_id_t vrf_id, - struct nexthop *nexthop, - struct route_node *rn) -{ - struct nexthop *nh; - struct prefix nh_p; - - for (nh = nexthop; nh; nh = nh->next) { - switch (nh->type) { - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - nh_p.family = AF_INET; - nh_p.prefixlen = IPV4_MAX_BITLEN; - nh_p.u.prefix4 = nh->gate.ipv4; - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - nh_p.family = AF_INET6; - nh_p.prefixlen = IPV6_MAX_BITLEN; - nh_p.u.prefix6 = nh->gate.ipv6; - break; - /* - * Not sure what really to do here, we are not - * supposed to have either of these for NHT - * and the code has no way to know what prefix - * to use. So I'm going to just continue - * for the moment, which is preferable to - * what is currently happening which is a - * CRASH and BURN. - * Some simple testing shows that we - * are not leaving slag around for these - * skipped static routes. Since - * they don't appear to be installed - */ - case NEXTHOP_TYPE_IFINDEX: - case NEXTHOP_TYPE_BLACKHOLE: - continue; - break; - } - zebra_deregister_rnh_static_nh(vrf_id, &nh_p, rn); - } -} - /* XXX move this utility function elsewhere? */ static void addr2hostprefix(int af, const union g_addr *addr, struct prefix *prefix) @@ -342,7 +268,6 @@ void zebra_deregister_rnh_pseudowire(vrf_id_t vrf_id, struct zebra_pw *pw) pw->rnh = NULL; if (list_isempty(rnh->client_list) - && list_isempty(rnh->zebra_static_route_list) && list_isempty(rnh->zebra_pseudowire_list)) zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE); } @@ -575,115 +500,6 @@ static void zebra_rnh_process_pbr_tables(int family, } } -static void zebra_rnh_process_static_routes(vrf_id_t vrfid, int family, - struct route_node *nrn, - struct rnh *rnh, - struct route_node *prn, - struct route_entry *re) -{ - struct listnode *node; - int num_resolving_nh = 0; - struct route_node *static_rn; - struct route_entry *sre; - struct nexthop *nexthop; - char bufn[INET6_ADDRSTRLEN]; - char bufp[INET6_ADDRSTRLEN]; - char bufs[INET6_ADDRSTRLEN]; - - if (IS_ZEBRA_DEBUG_NHT) { - prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN); - if (prn) - prefix2str(&prn->p, bufp, INET6_ADDRSTRLEN); - } - - if (prn && re) { - /* Apply route-map for "static" to route resolving this - * nexthop to see if it is filtered or not. - */ - num_resolving_nh = zebra_rnh_apply_nht_rmap(family, prn, re, - ZEBRA_ROUTE_STATIC); - if (num_resolving_nh) - rnh->filtered[ZEBRA_ROUTE_STATIC] = 0; - else - rnh->filtered[ZEBRA_ROUTE_STATIC] = 1; - } else - rnh->filtered[ZEBRA_ROUTE_STATIC] = 0; - - /* Evaluate each static route associated with this nexthop. */ - for (ALL_LIST_ELEMENTS_RO(rnh->zebra_static_route_list, node, - static_rn)) { - RNODE_FOREACH_RE (static_rn, sre) { - if (sre->type != ZEBRA_ROUTE_STATIC) - continue; - - /* Set the filter flag for the correct nexthop - static - * route may - * be having multiple. We care here only about - * registered nexthops. - */ - for (nexthop = sre->ng.nexthop; nexthop; - nexthop = nexthop->next) { - switch (nexthop->type) { - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - if (nexthop->gate.ipv4.s_addr - == nrn->p.u.prefix4.s_addr) { - if (num_resolving_nh) - UNSET_FLAG( - nexthop->flags, - NEXTHOP_FLAG_FILTERED); - else - SET_FLAG( - nexthop->flags, - NEXTHOP_FLAG_FILTERED); - } - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - - if (memcmp(&nexthop->gate.ipv6, - &nrn->p.u.prefix6, 16) - == 0) { - if (num_resolving_nh) - UNSET_FLAG( - nexthop->flags, - NEXTHOP_FLAG_FILTERED); - else - SET_FLAG( - nexthop->flags, - NEXTHOP_FLAG_FILTERED); - } - break; - default: - break; - } - } - - if (IS_ZEBRA_DEBUG_NHT) { - prefix2str(&static_rn->p, bufs, - INET6_ADDRSTRLEN); - if (prn && re) - zlog_debug( - "%u:%s: NH change %s, scheduling static route %s", - vrfid, bufn, - num_resolving_nh - ? "" - : "(filtered by route-map)", - bufs); - else - zlog_debug( - "%u:%s: NH unreachable, scheduling static route %s", - vrfid, bufn, bufs); - } - - SET_FLAG(sre->status, ROUTE_ENTRY_CHANGED); - SET_FLAG(sre->status, ROUTE_ENTRY_NEXTHOPS_CHANGED); - } - - rib_queue_add(static_rn); - } -} - /* * Determine appropriate route (route entry) resolving a tracked * nexthop. @@ -809,10 +625,6 @@ static void zebra_rnh_eval_nexthop_entry(vrf_id_t vrfid, int family, int force, zebra_rnh_notify_protocol_clients(vrfid, family, nrn, rnh, prn, rnh->state); - /* Process static routes attached to this nexthop */ - zebra_rnh_process_static_routes(vrfid, family, nrn, rnh, prn, - rnh->state); - zebra_rnh_process_pbr_tables(family, nrn, rnh, prn, rnh->state); @@ -962,7 +774,6 @@ static void free_state(vrf_id_t vrf_id, struct route_entry *re, return; /* free RE and nexthops */ - zebra_deregister_rnh_static_nexthops(vrf_id, re->ng.nexthop, rn); nexthops_free(re->ng.nexthop); XFREE(MTYPE_RE, re); } @@ -1173,9 +984,6 @@ static void print_rnh(struct route_node *rn, struct vty *vty) vty_out(vty, " %s(fd %d)%s", zebra_route_string(client->proto), client->sock, rnh->filtered[client->proto] ? "(filtered)" : ""); - if (!list_isempty(rnh->zebra_static_route_list)) - vty_out(vty, " zebra%s", - rnh->filtered[ZEBRA_ROUTE_STATIC] ? "(filtered)" : ""); if (!list_isempty(rnh->zebra_pseudowire_list)) vty_out(vty, " zebra[pseudowires]"); vty_out(vty, "\n"); diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h index ea7d5545e..9e09a1bc6 100644 --- a/zebra/zebra_rnh.h +++ b/zebra/zebra_rnh.h @@ -39,14 +39,16 @@ struct rnh { struct route_entry *state; struct prefix resolved_route; struct list *client_list; - struct list - *zebra_static_route_list; /* static routes dependent on this NH - */ - struct list - *zebra_pseudowire_list; /* pseudowires dependent on this NH */ + + /* pseudowires dependent on this nh */ + struct list *zebra_pseudowire_list; + struct route_node *node; - int filtered[ZEBRA_ROUTE_MAX]; /* if this has been filtered for client - */ + + /* + * if this has been filtered for the client + */ + int filtered[ZEBRA_ROUTE_MAX]; }; typedef enum { RNH_NEXTHOP_TYPE, RNH_IMPORT_CHECK_TYPE } rnh_type_t; @@ -73,13 +75,6 @@ extern void zebra_free_rnh(struct rnh *rnh); extern void zebra_delete_rnh(struct rnh *rnh, rnh_type_t type); extern void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client, rnh_type_t type, vrf_id_t vrfid); -extern void zebra_register_rnh_static_nh(vrf_id_t, struct prefix *, - struct route_node *); -extern void zebra_deregister_rnh_static_nexthops(vrf_id_t, - struct nexthop *nexthop, - struct route_node *rn); -extern void zebra_deregister_rnh_static_nh(vrf_id_t, struct prefix *, - struct route_node *); extern void zebra_register_rnh_pseudowire(vrf_id_t, struct zebra_pw *); extern void zebra_deregister_rnh_pseudowire(vrf_id_t, struct zebra_pw *); extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client, diff --git a/zebra/zebra_static.c b/zebra/zebra_static.c index 76346f6b6..d6e07f125 100644 --- a/zebra/zebra_static.c +++ b/zebra/zebra_static.c @@ -20,833 +20,3 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include - -#include -#include -#include -#include - -#include "vty.h" -#include "zebra/debug.h" -#include "zebra/rib.h" -#include "zebra/zserv.h" -#include "zebra/zebra_vrf.h" -#include "zebra/zebra_static.h" -#include "zebra/zebra_rnh.h" -#include "zebra/redistribute.h" -#include "zebra/zebra_memory.h" - -/* Install static route into rib. */ -void static_install_route(afi_t afi, safi_t safi, const struct prefix *p, - const struct prefix_ipv6 *src_p, - struct static_route *si) -{ - struct route_entry *re; - struct route_node *rn; - struct route_table *table; - struct prefix nh_p; - struct nexthop *nexthop = NULL; - enum blackhole_type bh_type = 0; - struct vrf *nh_vrf; - - /* Lookup table. */ - table = zebra_vrf_table_with_table_id(afi, safi, - si->vrf_id, - si->table_id); - if (!table) - return; - - /* - * If a specific vrf is coming up and the nexthop vrf we are - * looking at using hasn't been brought up yet, just don't - * install the static route yet. - * When the nexthop vrf comes up we will get another call - * back to do the right thing. I'm putting this check - * here because we are calling static_install_route a bunch - * from a bunch of different callpaths. - */ - nh_vrf = vrf_lookup_by_id(si->nh_vrf_id); - if (!nh_vrf) - return; - - memset(&nh_p, 0, sizeof(nh_p)); - if (si->type == STATIC_BLACKHOLE) { - switch (si->bh_type) { - case STATIC_BLACKHOLE_DROP: - case STATIC_BLACKHOLE_NULL: - bh_type = BLACKHOLE_NULL; - break; - case STATIC_BLACKHOLE_REJECT: - bh_type = BLACKHOLE_REJECT; - break; - } - } - - /* Lookup existing route */ - rn = srcdest_rnode_get(table, p, src_p); - RNODE_FOREACH_RE (rn, re) { - if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) - continue; - - if (re->type == ZEBRA_ROUTE_STATIC - && re->distance == si->distance) - break; - } - - if (re) { - /* if tag value changed , update old value in RIB */ - if (re->tag != si->tag) - re->tag = si->tag; - - /* Same distance static route is there. Update it with new - nexthop. */ - route_unlock_node(rn); - switch (si->type) { - case STATIC_IPV4_GATEWAY: - nexthop = route_entry_nexthop_ipv4_add( - re, &si->addr.ipv4, NULL, si->nh_vrf_id); - nh_p.family = AF_INET; - nh_p.prefixlen = IPV4_MAX_BITLEN; - nh_p.u.prefix4 = si->addr.ipv4; - zebra_register_rnh_static_nh(si->nh_vrf_id, &nh_p, rn); - break; - case STATIC_IPV4_GATEWAY_IFNAME: - nexthop = route_entry_nexthop_ipv4_ifindex_add( - re, &si->addr.ipv4, NULL, si->ifindex, - si->nh_vrf_id); - break; - case STATIC_IFNAME: - nexthop = route_entry_nexthop_ifindex_add( - re, si->ifindex, si->nh_vrf_id); - break; - case STATIC_BLACKHOLE: - nexthop = - route_entry_nexthop_blackhole_add(re, bh_type); - break; - case STATIC_IPV6_GATEWAY: - nexthop = route_entry_nexthop_ipv6_add( - re, &si->addr.ipv6, si->nh_vrf_id); - nh_p.family = AF_INET6; - nh_p.prefixlen = IPV6_MAX_BITLEN; - nh_p.u.prefix6 = si->addr.ipv6; - zebra_register_rnh_static_nh(si->nh_vrf_id, &nh_p, rn); - break; - case STATIC_IPV6_GATEWAY_IFNAME: - nexthop = route_entry_nexthop_ipv6_ifindex_add( - re, &si->addr.ipv6, si->ifindex, si->nh_vrf_id); - break; - } - /* Update label(s), if present. */ - if (si->snh_label.num_labels) - nexthop_add_labels(nexthop, ZEBRA_LSP_STATIC, - si->snh_label.num_labels, - &si->snh_label.label[0]); - - if (IS_ZEBRA_DEBUG_RIB) { - char buf[INET6_ADDRSTRLEN]; - if (IS_ZEBRA_DEBUG_RIB) { - inet_ntop(p->family, &p->u.prefix, buf, - INET6_ADDRSTRLEN); - zlog_debug( - "%u:%s/%d: Modifying route rn %p, re %p (type %d)", - si->vrf_id, buf, p->prefixlen, rn, re, - re->type); - } - } - - re->uptime = time(NULL); - /* Schedule route for processing or invoke NHT, as appropriate. - */ - if (si->type == STATIC_IPV4_GATEWAY - || si->type == STATIC_IPV6_GATEWAY) - zebra_evaluate_rnh(si->nh_vrf_id, nh_p.family, 1, - RNH_NEXTHOP_TYPE, &nh_p); - else - rib_queue_add(rn); - } else { - /* This is new static route. */ - re = XCALLOC(MTYPE_RE, sizeof(struct route_entry)); - - re->type = ZEBRA_ROUTE_STATIC; - re->instance = 0; - re->distance = si->distance; - re->metric = 0; - re->mtu = 0; - re->vrf_id = si->vrf_id; - if (!vrf_is_backend_netns()) { - re->table = - (si->vrf_id != VRF_DEFAULT) - ? (zebra_vrf_lookup_by_id(si->vrf_id))->table_id - : zebrad.rtm_table_default; - } else { - struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(si->vrf_id); - - if (zvrf->table_id != RT_TABLE_MAIN || - zvrf->table_id != zebrad.rtm_table_default) - re->table = zvrf->table_id; - else - re->table = zebrad.rtm_table_default; - } - re->nexthop_num = 0; - re->tag = si->tag; - - switch (si->type) { - case STATIC_IPV4_GATEWAY: - nexthop = route_entry_nexthop_ipv4_add( - re, &si->addr.ipv4, NULL, si->nh_vrf_id); - nh_p.family = AF_INET; - nh_p.prefixlen = IPV4_MAX_BITLEN; - nh_p.u.prefix4 = si->addr.ipv4; - zebra_register_rnh_static_nh(si->nh_vrf_id, &nh_p, rn); - break; - case STATIC_IPV4_GATEWAY_IFNAME: - nexthop = route_entry_nexthop_ipv4_ifindex_add( - re, &si->addr.ipv4, NULL, si->ifindex, - si->nh_vrf_id); - break; - case STATIC_IFNAME: - nexthop = route_entry_nexthop_ifindex_add( - re, si->ifindex, si->nh_vrf_id); - break; - case STATIC_BLACKHOLE: - nexthop = - route_entry_nexthop_blackhole_add(re, bh_type); - break; - case STATIC_IPV6_GATEWAY: - nexthop = route_entry_nexthop_ipv6_add( - re, &si->addr.ipv6, si->nh_vrf_id); - nh_p.family = AF_INET6; - nh_p.prefixlen = IPV6_MAX_BITLEN; - nh_p.u.prefix6 = si->addr.ipv6; - zebra_register_rnh_static_nh(si->nh_vrf_id, &nh_p, rn); - break; - case STATIC_IPV6_GATEWAY_IFNAME: - nexthop = route_entry_nexthop_ipv6_ifindex_add( - re, &si->addr.ipv6, si->ifindex, si->nh_vrf_id); - break; - } - /* Update label(s), if present. */ - if (si->snh_label.num_labels) - nexthop_add_labels(nexthop, ZEBRA_LSP_STATIC, - si->snh_label.num_labels, - &si->snh_label.label[0]); - - if (IS_ZEBRA_DEBUG_RIB) { - char buf[INET6_ADDRSTRLEN]; - if (IS_ZEBRA_DEBUG_RIB) { - inet_ntop(p->family, &p->u.prefix, buf, - INET6_ADDRSTRLEN); - zlog_debug( - "%u:%s/%d: Inserting route rn %p, re %p (type %d)", - si->vrf_id, buf, p->prefixlen, rn, re, - re->type); - } - } - re->uptime = time(NULL); - /* Link this re to the tree. Schedule for processing or invoke - * NHT, - * as appropriate. - */ - if (si->type == STATIC_IPV4_GATEWAY - || si->type == STATIC_IPV6_GATEWAY) { - rib_addnode(rn, re, 0); - zebra_evaluate_rnh(si->nh_vrf_id, nh_p.family, 1, - RNH_NEXTHOP_TYPE, &nh_p); - } else - rib_addnode(rn, re, 1); - } -} - -/* this works correctly with IFNAME<>IFINDEX because a static route on a - * non-active interface will have IFINDEX_INTERNAL and thus compare false - */ -static int static_nexthop_same(struct nexthop *nexthop, struct static_route *si) -{ - if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE - && si->type == STATIC_BLACKHOLE) - return 1; - - if (nexthop->type == NEXTHOP_TYPE_IPV4 - && si->type == STATIC_IPV4_GATEWAY - && IPV4_ADDR_SAME(&nexthop->gate.ipv4, &si->addr.ipv4)) - return 1; - else if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX - && si->type == STATIC_IPV4_GATEWAY_IFNAME - && IPV4_ADDR_SAME(&nexthop->gate.ipv4, &si->addr.ipv4) - && nexthop->ifindex == si->ifindex) - return 1; - else if (nexthop->type == NEXTHOP_TYPE_IFINDEX - && si->type == STATIC_IFNAME - && nexthop->ifindex == si->ifindex) - return 1; - else if (nexthop->type == NEXTHOP_TYPE_IPV6 - && si->type == STATIC_IPV6_GATEWAY - && IPV6_ADDR_SAME(&nexthop->gate.ipv6, &si->addr.ipv6)) - return 1; - else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX - && si->type == STATIC_IPV6_GATEWAY_IFNAME - && IPV6_ADDR_SAME(&nexthop->gate.ipv6, &si->addr.ipv6) - && nexthop->ifindex == si->ifindex) - return 1; - - return 0; -} - -/* Uninstall static route from RIB. */ -void static_uninstall_route(afi_t afi, safi_t safi, const struct prefix *p, - const struct prefix_ipv6 *src_p, - struct static_route *si) -{ - struct route_node *rn; - struct route_entry *re; - struct nexthop *nexthop; - struct route_table *table; - struct prefix nh_p; - - /* Lookup table. */ - table = zebra_vrf_table_with_table_id(afi, safi, - si->vrf_id, - si->table_id); - if (!table) - return; - - /* Lookup existing route with type and distance. */ - rn = srcdest_rnode_lookup(table, p, src_p); - if (!rn) - return; - - RNODE_FOREACH_RE (rn, re) { - if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) - continue; - - if (re->type == ZEBRA_ROUTE_STATIC - && re->distance == si->distance && re->tag == si->tag) - break; - } - - if (!re) { - route_unlock_node(rn); - return; - } - - /* Lookup nexthop. */ - for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) - if (static_nexthop_same(nexthop, si)) - break; - - /* Can't find nexthop. */ - if (!nexthop) { - route_unlock_node(rn); - return; - } - - /* Check nexthop. */ - if (re->nexthop_num == 1) - rib_delnode(rn, re); - else { - /* Mark this nexthop as inactive and reinstall the route. Then, - * delete - * the nexthop. There is no need to re-evaluate the route for - * this - * scenario. - */ - if (IS_ZEBRA_DEBUG_RIB) { - char buf[INET6_ADDRSTRLEN]; - if (IS_ZEBRA_DEBUG_RIB) { - inet_ntop(p->family, &p->u.prefix, buf, - INET6_ADDRSTRLEN); - zlog_debug( - "%u:%s/%d: Modifying route rn %p, re %p (type %d)", - si->vrf_id, buf, p->prefixlen, rn, re, - re->type); - } - } - UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) { - rib_dest_t *dest = rib_dest_from_rnode(rn); - - /* If there are other active nexthops, do an update. */ - if (re->nexthop_active_num > 1) { - /* Update route in kernel if it's in fib */ - if (dest->selected_fib) - rib_install_kernel(rn, re, re); - /* Update redistribution if it's selected */ - if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) - redistribute_update( - p, (struct prefix *)src_p, re, - NULL); - } else { - /* Remove from redistribute if selected route - * becomes inactive */ - if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) - redistribute_delete( - p, (struct prefix *)src_p, re); - /* Remove from kernel if fib route becomes - * inactive */ - if (dest->selected_fib) - rib_uninstall_kernel(rn, re); - } - } - - if (afi == AFI_IP) { - /* Delete the nexthop and dereg from NHT */ - nh_p.family = AF_INET; - nh_p.prefixlen = IPV4_MAX_BITLEN; - nh_p.u.prefix4 = nexthop->gate.ipv4; - } else { - nh_p.family = AF_INET6; - nh_p.prefixlen = IPV6_MAX_BITLEN; - nh_p.u.prefix6 = nexthop->gate.ipv6; - } - route_entry_nexthop_delete(re, nexthop); - zebra_deregister_rnh_static_nh(si->nh_vrf_id, &nh_p, rn); - nexthop_free(nexthop); - } - /* Unlock node. */ - route_unlock_node(rn); -} - -int static_add_route(afi_t afi, safi_t safi, uint8_t type, struct prefix *p, - struct prefix_ipv6 *src_p, union g_addr *gate, - const char *ifname, enum static_blackhole_type bh_type, - route_tag_t tag, uint8_t distance, struct zebra_vrf *zvrf, - struct zebra_vrf *nh_zvrf, - struct static_nh_label *snh_label, - uint32_t table_id) -{ - struct route_node *rn; - struct static_route *si; - struct static_route *pp; - struct static_route *cp; - struct static_route *update = NULL; - struct route_table *stable = zvrf->stable[afi][safi]; - - if (!stable) - return -1; - - if (!gate && (type == STATIC_IPV4_GATEWAY - || type == STATIC_IPV4_GATEWAY_IFNAME - || type == STATIC_IPV6_GATEWAY - || type == STATIC_IPV6_GATEWAY_IFNAME)) - return -1; - - if (!ifname - && (type == STATIC_IFNAME || type == STATIC_IPV4_GATEWAY_IFNAME - || type == STATIC_IPV6_GATEWAY_IFNAME)) - return -1; - - /* Lookup static route prefix. */ - rn = srcdest_rnode_get(stable, p, src_p); - - /* Do nothing if there is a same static route. */ - for (si = rn->info; si; si = si->next) { - if (type == si->type - && (!gate - || ((afi == AFI_IP - && IPV4_ADDR_SAME(&gate->ipv4, &si->addr.ipv4)) - || (afi == AFI_IP6 - && IPV6_ADDR_SAME(gate, &si->addr.ipv6)))) - && (!strcmp(ifname ? ifname : "", si->ifname))) { - if ((distance == si->distance) && (tag == si->tag) - && !memcmp(&si->snh_label, snh_label, - sizeof(struct static_nh_label)) - && si->bh_type == bh_type) { - route_unlock_node(rn); - return 0; - } else - update = si; - } - } - - /* Distance or tag or label changed, delete existing first. */ - if (update) - static_delete_route(afi, safi, type, p, src_p, gate, ifname, - update->tag, update->distance, zvrf, - &update->snh_label, table_id); - - /* Make new static route structure. */ - si = XCALLOC(MTYPE_STATIC_ROUTE, sizeof(struct static_route)); - - si->type = type; - si->distance = distance; - si->bh_type = bh_type; - si->tag = tag; - si->vrf_id = zvrf_id(zvrf); - si->nh_vrf_id = zvrf_id(nh_zvrf); - strcpy(si->nh_vrfname, nh_zvrf->vrf->name); - si->table_id = table_id; - - if (ifname) - strlcpy(si->ifname, ifname, sizeof(si->ifname)); - si->ifindex = IFINDEX_INTERNAL; - - switch (type) { - case STATIC_IPV4_GATEWAY: - case STATIC_IPV4_GATEWAY_IFNAME: - si->addr.ipv4 = gate->ipv4; - break; - case STATIC_IPV6_GATEWAY: - case STATIC_IPV6_GATEWAY_IFNAME: - si->addr.ipv6 = gate->ipv6; - break; - case STATIC_IFNAME: - break; - } - - /* Save labels, if any. */ - memcpy(&si->snh_label, snh_label, sizeof(struct static_nh_label)); - - /* Add new static route information to the tree with sort by - distance value and gateway address. */ - for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next) { - if (si->distance < cp->distance) - break; - if (si->distance > cp->distance) - continue; - if (si->type == STATIC_IPV4_GATEWAY - && cp->type == STATIC_IPV4_GATEWAY) { - if (ntohl(si->addr.ipv4.s_addr) - < ntohl(cp->addr.ipv4.s_addr)) - break; - if (ntohl(si->addr.ipv4.s_addr) - > ntohl(cp->addr.ipv4.s_addr)) - continue; - } - } - - /* Make linked list. */ - if (pp) - pp->next = si; - else - rn->info = si; - if (cp) - cp->prev = si; - si->prev = pp; - si->next = cp; - - /* check whether interface exists in system & install if it does */ - if (!ifname) - static_install_route(afi, safi, p, src_p, si); - else { - struct interface *ifp; - - ifp = if_lookup_by_name(ifname, zvrf_id(nh_zvrf)); - if (ifp && ifp->ifindex != IFINDEX_INTERNAL) { - si->ifindex = ifp->ifindex; - static_install_route(afi, safi, p, src_p, si); - } else - zlog_warn("Static Route using %s interface not installed because the interface does not exist in specified vrf", - ifname); - } - - return 1; -} - -int static_delete_route(afi_t afi, safi_t safi, uint8_t type, struct prefix *p, - struct prefix_ipv6 *src_p, union g_addr *gate, - const char *ifname, route_tag_t tag, uint8_t distance, - struct zebra_vrf *zvrf, - struct static_nh_label *snh_label, - uint32_t table_id) -{ - struct route_node *rn; - struct static_route *si; - struct route_table *stable; - - /* Lookup table. */ - stable = zebra_vrf_static_table(afi, safi, zvrf); - if (!stable) - return -1; - - /* Lookup static route prefix. */ - rn = srcdest_rnode_lookup(stable, p, src_p); - if (!rn) - return 0; - - /* Find same static route is the tree */ - for (si = rn->info; si; si = si->next) - if (type == si->type - && (!gate - || ((afi == AFI_IP - && IPV4_ADDR_SAME(&gate->ipv4, &si->addr.ipv4)) - || (afi == AFI_IP6 - && IPV6_ADDR_SAME(gate, &si->addr.ipv6)))) - && (!strcmp(ifname ? ifname : "", si->ifname)) - && (!tag || (tag == si->tag)) - && (table_id == si->table_id) - && (!snh_label->num_labels - || !memcmp(&si->snh_label, snh_label, - sizeof(struct static_nh_label)))) - break; - - /* Can't find static route. */ - if (!si) { - route_unlock_node(rn); - return 0; - } - - /* Uninstall from rib. */ - if (!si->ifname[0] || si->ifindex != IFINDEX_INTERNAL) - static_uninstall_route(afi, safi, p, src_p, si); - - /* Unlink static route from linked list. */ - if (si->prev) - si->prev->next = si->next; - else - rn->info = si->next; - if (si->next) - si->next->prev = si->prev; - route_unlock_node(rn); - - /* Free static route configuration. */ - XFREE(MTYPE_STATIC_ROUTE, si); - - route_unlock_node(rn); - - return 1; -} - -static void static_ifindex_update_af(struct interface *ifp, bool up, afi_t afi, - safi_t safi) -{ - struct route_table *stable; - struct route_node *rn; - struct static_route *si; - const struct prefix *p, *src_pp; - struct prefix_ipv6 *src_p; - struct vrf *vrf; - - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - struct zebra_vrf *zvrf; - - zvrf = vrf->info; - - stable = zebra_vrf_static_table(afi, safi, zvrf); - if (!stable) - continue; - - for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) { - srcdest_rnode_prefixes(rn, &p, &src_pp); - src_p = (struct prefix_ipv6 *)src_pp; - - for (si = rn->info; si; si = si->next) { - if (!si->ifname[0]) - continue; - if (up) { - if (strcmp(si->ifname, ifp->name)) - continue; - si->ifindex = ifp->ifindex; - static_install_route(afi, safi, p, src_p, si); - } else { - if (si->ifindex != ifp->ifindex) - continue; - static_uninstall_route(afi, safi, p, src_p, si); - si->ifindex = IFINDEX_INTERNAL; - } - } - } - } -} - -/* - * This function looks at a zvrf's stable and notices if any of the - * nexthops we are using are part of the vrf coming up. - * If we are using them then cleanup the nexthop vrf id - * to be the new value and then re-installs them - * - * - * stable -> The table we are looking at. - * zvrf -> The newly changed vrf. - * afi -> The afi to look at - * safi -> the safi to look at - */ -static void static_fixup_vrf(struct zebra_vrf *zvrf, - struct route_table *stable, afi_t afi, safi_t safi) -{ - struct route_node *rn; - struct static_route *si; - struct interface *ifp; - - for (rn = route_top(stable); rn; rn = route_next(rn)) { - for (si = rn->info; si; si = si->next) { - if (strcmp(zvrf->vrf->name, si->nh_vrfname) != 0) - continue; - - si->nh_vrf_id = zvrf->vrf->vrf_id; - if (si->ifindex) { - ifp = if_lookup_by_name(si->ifname, - si->nh_vrf_id); - if (ifp) - si->ifindex = ifp->ifindex; - else - continue; - } - static_install_route(afi, safi, &rn->p, NULL, si); - } - } -} - -/* - * This function enables static routes in a zvrf as it - * is coming up. It sets the new vrf_id as appropriate. - * - * zvrf -> The zvrf that is being brought up and enabled by the kernel - * stable -> The stable we are looking at. - * afi -> the afi in question - * safi -> the safi in question - */ -static void static_enable_vrf(struct zebra_vrf *zvrf, - struct route_table *stable, - afi_t afi, safi_t safi) -{ - struct route_node *rn; - struct static_route *si; - struct interface *ifp; - struct vrf *vrf = zvrf->vrf; - - for (rn = route_top(stable); rn; rn = route_next(rn)) { - for (si = rn->info; si; si = si->next) { - si->vrf_id = vrf->vrf_id; - if (si->ifindex) { - ifp = if_lookup_by_name(si->ifname, - si->nh_vrf_id); - if (ifp) - si->ifindex = ifp->ifindex; - else - continue; - } - static_install_route(afi, safi, &rn->p, NULL, si); - } - } -} - -/* - * When a vrf is being enabled by the kernel, go through all the - * static routes in the system that use this vrf (both nexthops vrfs - * and the routes vrf ) - * - * enable_zvrf -> the vrf being enabled - */ -void static_fixup_vrf_ids(struct zebra_vrf *enable_zvrf) -{ - struct route_table *stable; - struct vrf *vrf; - afi_t afi; - safi_t safi; - - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - struct zebra_vrf *zvrf; - - zvrf = vrf->info; - /* Install any static routes configured for this VRF. */ - for (afi = AFI_IP; afi < AFI_MAX; afi++) { - for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { - stable = zvrf->stable[afi][safi]; - if (!stable) - continue; - - static_fixup_vrf(enable_zvrf, stable, - afi, safi); - - if (enable_zvrf == zvrf) - static_enable_vrf(zvrf, stable, - afi, safi); - } - } - } -} - -/* - * Look at the specified stable and if any of the routes in - * this table are using the zvrf as the nexthop, uninstall - * those routes. - * - * zvrf -> the vrf being disabled - * stable -> the table we need to look at. - * afi -> the afi in question - * safi -> the safi in question - */ -static void static_cleanup_vrf(struct zebra_vrf *zvrf, - struct route_table *stable, - afi_t afi, safi_t safi) -{ - struct route_node *rn; - struct static_route *si; - - for (rn = route_top(stable); rn; rn = route_next(rn)) { - for (si = rn->info; si; si = si->next) { - if (strcmp(zvrf->vrf->name, si->nh_vrfname) != 0) - continue; - - static_uninstall_route(afi, safi, &rn->p, NULL, si); - } - } -} - -/* - * Look at all static routes in this table and uninstall - * them. - * - * stable -> The table to uninstall from - * afi -> The afi in question - * safi -> the safi in question - */ -static void static_disable_vrf(struct route_table *stable, - afi_t afi, safi_t safi) -{ - struct route_node *rn; - struct static_route *si; - - for (rn = route_top(stable); rn; rn = route_next(rn)) { - for (si = rn->info; si; si = si->next) { - static_uninstall_route(afi, safi, &rn->p, NULL, si); - } - } -} - -/* - * When the disable_zvrf is shutdown by the kernel, we call - * this function and it cleans up all static routes using - * this vrf as a nexthop as well as all static routes - * in it's stables. - * - * disable_zvrf - The vrf being disabled - */ -void static_cleanup_vrf_ids(struct zebra_vrf *disable_zvrf) -{ - struct vrf *vrf; - afi_t afi; - safi_t safi; - - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - struct zebra_vrf *zvrf; - - zvrf = vrf->info; - - /* Uninstall any static routes configured for this VRF. */ - for (afi = AFI_IP; afi < AFI_MAX; afi++) { - for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { - struct route_table *stable; - - stable = zvrf->stable[afi][safi]; - if (!stable) - continue; - - static_cleanup_vrf(disable_zvrf, stable, - afi, safi); - - if (disable_zvrf == zvrf) - static_disable_vrf(stable, afi, safi); - } - } - } -} - -/* called from if_{add,delete}_update, i.e. when ifindex becomes [in]valid */ -void static_ifindex_update(struct interface *ifp, bool up) -{ - static_ifindex_update_af(ifp, up, AFI_IP, SAFI_UNICAST); - static_ifindex_update_af(ifp, up, AFI_IP, SAFI_MULTICAST); - static_ifindex_update_af(ifp, up, AFI_IP6, SAFI_UNICAST); - static_ifindex_update_af(ifp, up, AFI_IP6, SAFI_MULTICAST); -} diff --git a/zebra/zebra_static.h b/zebra/zebra_static.h index 0be434fff..4885b1b8f 100644 --- a/zebra/zebra_static.h +++ b/zebra/zebra_static.h @@ -22,93 +22,4 @@ #ifndef __ZEBRA_STATIC_H__ #define __ZEBRA_STATIC_H__ -#include "zebra/zebra_mpls.h" - -/* Static route label information */ -struct static_nh_label { - uint8_t num_labels; - uint8_t reserved[3]; - mpls_label_t label[MPLS_MAX_LABELS]; -}; - -enum static_blackhole_type { - STATIC_BLACKHOLE_DROP = 0, - STATIC_BLACKHOLE_NULL, - STATIC_BLACKHOLE_REJECT -}; - -typedef enum { - STATIC_IFNAME, - STATIC_IPV4_GATEWAY, - STATIC_IPV4_GATEWAY_IFNAME, - STATIC_BLACKHOLE, - STATIC_IPV6_GATEWAY, - STATIC_IPV6_GATEWAY_IFNAME, -} zebra_static_types; - -/* Static route information. */ -struct static_route { - /* For linked list. */ - struct static_route *prev; - struct static_route *next; - - /* VRF identifier. */ - vrf_id_t vrf_id; - vrf_id_t nh_vrf_id; - char nh_vrfname[VRF_NAMSIZ + 1]; - - /* Administrative distance. */ - uint8_t distance; - - /* Tag */ - route_tag_t tag; - - /* Flag for this static route's type. */ - zebra_static_types type; - - /* - * Nexthop value. - */ - enum static_blackhole_type bh_type; - union g_addr addr; - ifindex_t ifindex; - - char ifname[INTERFACE_NAMSIZ + 1]; - - /* Label information */ - struct static_nh_label snh_label; - - /* Table Information */ - uint32_t table_id; -}; - -extern void static_install_route(afi_t afi, safi_t safi, const struct prefix *p, - const struct prefix_ipv6 *src_p, - struct static_route *si); -extern void static_uninstall_route(afi_t afi, safi_t safi, - const struct prefix *p, - const struct prefix_ipv6 *src_p, - struct static_route *si); - -extern int static_add_route(afi_t, safi_t safi, uint8_t type, struct prefix *p, - struct prefix_ipv6 *src_p, union g_addr *gate, - const char *ifname, - enum static_blackhole_type bh_type, route_tag_t tag, - uint8_t distance, struct zebra_vrf *zvrf, - struct zebra_vrf *nh_zvrf, - struct static_nh_label *snh_label, - uint32_t table_id); - -extern int static_delete_route(afi_t, safi_t safi, uint8_t type, - struct prefix *p, struct prefix_ipv6 *src_p, - union g_addr *gate, const char *ifname, - route_tag_t tag, uint8_t distance, - struct zebra_vrf *zvrf, - struct static_nh_label *snh_label, - uint32_t table_id); - -extern void static_ifindex_update(struct interface *ifp, bool up); - -extern void static_cleanup_vrf_ids(struct zebra_vrf *zvrf); -extern void static_fixup_vrf_ids(struct zebra_vrf *zvrf); #endif diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 3c21c3c1e..607001fe2 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -155,8 +155,6 @@ static int zebra_vrf_disable(struct vrf *vrf) zlog_debug("VRF %s id %u is now inactive", zvrf_name(zvrf), zvrf_id(zvrf)); - static_cleanup_vrf_ids(zvrf); - /* Stop any VxLAN-EVPN processing. */ zebra_vxlan_vrf_disable(zvrf); @@ -268,9 +266,6 @@ static int zebra_vrf_delete(struct vrf *vrf) route_table_finish(table); XFREE(MTYPE_RIB_TABLE_INFO, table_info); } - - table = zvrf->stable[afi][safi]; - route_table_finish(table); } route_table_finish(zvrf->rnh_table[afi]); @@ -294,24 +289,6 @@ static int zebra_vrf_delete(struct vrf *vrf) */ int zebra_vrf_has_config(struct zebra_vrf *zvrf) { - afi_t afi; - safi_t safi; - struct route_table *stable; - - /* NOTE: This is a don't care for the default VRF, but we go through - * the motions to keep things consistent. - */ - /* Any static routes? */ - for (afi = AFI_IP; afi < AFI_MAX; afi++) { - for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { - stable = zvrf->stable[afi][safi]; - if (!stable) - continue; - if (route_table_count(stable)) - return 1; - } - } - /* EVPN L3-VNI? */ if (zvrf->l3vni) return 1; @@ -366,18 +343,6 @@ void zebra_rtable_node_cleanup(struct route_table *table, XFREE(MTYPE_RIB_DEST, node->info); } -static void zebra_stable_node_cleanup(struct route_table *table, - struct route_node *node) -{ - struct static_route *si, *next; - - if (node->info) - for (si = node->info; si; si = next) { - next = si->next; - XFREE(MTYPE_STATIC_ROUTE, si); - } -} - static void zebra_rnhtable_node_cleanup(struct route_table *table, struct route_node *node) { @@ -414,24 +379,9 @@ static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi, struct zebra_vrf *zebra_vrf_alloc(void) { struct zebra_vrf *zvrf; - afi_t afi; - safi_t safi; - struct route_table *table; zvrf = XCALLOC(MTYPE_ZEBRA_VRF, sizeof(struct zebra_vrf)); - /* Allocate table for static route configuration. */ - for (afi = AFI_IP; afi <= AFI_IP6; afi++) { - for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) { - if (afi == AFI_IP6) - table = srcdest_table_init(); - else - table = route_table_init(); - table->cleanup = zebra_stable_node_cleanup; - zvrf->stable[afi][safi] = table; - } - } - zebra_vxlan_init_tables(zvrf); zebra_mpls_init_tables(zvrf); zebra_pw_init(zvrf); @@ -475,19 +425,6 @@ struct route_table *zebra_vrf_table(afi_t afi, safi_t safi, vrf_id_t vrf_id) return zvrf->table[afi][safi]; } -/* Lookup the static routing table in a VRF. */ -struct route_table *zebra_vrf_static_table(afi_t afi, safi_t safi, - struct zebra_vrf *zvrf) -{ - if (!zvrf) - return NULL; - - if (afi >= AFI_MAX || safi >= SAFI_MAX) - return NULL; - - return zvrf->stable[afi][safi]; -} - struct route_table *zebra_vrf_other_route_table(afi_t afi, uint32_t table_id, vrf_id_t vrf_id) { @@ -545,10 +482,6 @@ static int vrf_config_write(struct vty *vty) } - static_config(vty, zvrf, AFI_IP, SAFI_UNICAST, "ip route"); - static_config(vty, zvrf, AFI_IP, SAFI_MULTICAST, "ip mroute"); - static_config(vty, zvrf, AFI_IP6, SAFI_UNICAST, "ipv6 route"); - if (zvrf_id(zvrf) != VRF_DEFAULT) vty_endframe(vty, " exit-vrf\n!\n"); } diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h index 5c5d2f522..b8664f4ec 100644 --- a/zebra/zebra_vrf.h +++ b/zebra/zebra_vrf.h @@ -53,9 +53,6 @@ struct zebra_vrf { /* Routing table. */ struct route_table *table[AFI_MAX][SAFI_MAX]; - /* Static route configuration. */ - struct route_table *stable[AFI_MAX][SAFI_MAX]; - /* Recursive Nexthop table */ struct route_table *rnh_table[AFI_MAX]; @@ -159,8 +156,7 @@ extern struct zebra_vrf *zebra_vrf_lookup_by_id(vrf_id_t vrf_id); extern struct zebra_vrf *zebra_vrf_lookup_by_name(const char *); extern struct zebra_vrf *zebra_vrf_alloc(void); extern struct route_table *zebra_vrf_table(afi_t, safi_t, vrf_id_t); -extern struct route_table *zebra_vrf_static_table(afi_t, safi_t, - struct zebra_vrf *zvrf); + extern struct route_table * zebra_vrf_other_route_table(afi_t afi, uint32_t table_id, vrf_id_t vrf_id); extern int zebra_vrf_has_config(struct zebra_vrf *zvrf); diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 4d71682f6..117ed3a95 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -78,572 +78,6 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty, /* VNI range as per RFC 7432 */ #define CMD_VNI_RANGE "(1-16777215)" -struct static_hold_route { - char *vrf_name; - char *nhvrf_name; - afi_t afi; - safi_t safi; - char *dest_str; - char *mask_str; - char *src_str; - char *gate_str; - char *ifname; - char *flag_str; - char *tag_str; - char *distance_str; - char *label_str; - char *table_str; - - /* processed & masked destination, used for config display */ - struct prefix dest; -}; - -static struct list *static_list; - -static int static_list_compare_helper(const char *s1, const char *s2) -{ - /* Are Both NULL */ - if (s1 == s2) - return 0; - - if (!s1 && s2) - return -1; - - if (s1 && !s2) - return 1; - - return strcmp(s1, s2); -} - -static void static_list_delete(struct static_hold_route *shr) -{ - if (shr->vrf_name) - XFREE(MTYPE_STATIC_ROUTE, shr->vrf_name); - if (shr->nhvrf_name) - XFREE(MTYPE_STATIC_ROUTE, shr->nhvrf_name); - if (shr->dest_str) - XFREE(MTYPE_STATIC_ROUTE, shr->dest_str); - if (shr->mask_str) - XFREE(MTYPE_STATIC_ROUTE, shr->mask_str); - if (shr->src_str) - XFREE(MTYPE_STATIC_ROUTE, shr->src_str); - if (shr->gate_str) - XFREE(MTYPE_STATIC_ROUTE, shr->gate_str); - if (shr->ifname) - XFREE(MTYPE_STATIC_ROUTE, shr->ifname); - if (shr->flag_str) - XFREE(MTYPE_STATIC_ROUTE, shr->flag_str); - if (shr->tag_str) - XFREE(MTYPE_STATIC_ROUTE, shr->tag_str); - if (shr->distance_str) - XFREE(MTYPE_STATIC_ROUTE, shr->distance_str); - if (shr->label_str) - XFREE(MTYPE_STATIC_ROUTE, shr->label_str); - - XFREE(MTYPE_STATIC_ROUTE, shr); -} - -static int static_list_compare(void *arg1, void *arg2) -{ - struct static_hold_route *shr1 = arg1; - struct static_hold_route *shr2 = arg2; - int ret; - - ret = strcmp(shr1->vrf_name, shr2->vrf_name); - if (ret) - return ret; - - ret = strcmp(shr1->nhvrf_name, shr2->nhvrf_name); - if (ret) - return ret; - - ret = shr1->afi - shr2->afi; - if (ret) - return ret; - - ret = shr1->safi - shr2->safi; - if (ret) - return ret; - - ret = prefix_cmp(&shr1->dest, &shr2->dest); - if (ret) - return ret; - - ret = static_list_compare_helper(shr1->src_str, shr2->src_str); - if (ret) - return ret; - - ret = static_list_compare_helper(shr1->gate_str, shr2->gate_str); - if (ret) - return ret; - - ret = static_list_compare_helper(shr1->ifname, shr2->ifname); - if (ret) - return ret; - - ret = static_list_compare_helper(shr1->flag_str, shr2->flag_str); - if (ret) - return ret; - - ret = static_list_compare_helper(shr1->tag_str, shr2->tag_str); - if (ret) - return ret; - - ret = static_list_compare_helper(shr1->distance_str, - shr2->distance_str); - if (ret) - return ret; - - ret = static_list_compare_helper(shr1->table_str, - shr2->table_str); - if (ret) - return ret; - - return static_list_compare_helper(shr1->label_str, shr2->label_str); -} - - -/* General function for static route. */ -static int zebra_static_route_holdem( - struct zebra_vrf *zvrf, struct zebra_vrf *nh_zvrf, afi_t afi, - safi_t safi, const char *negate, struct prefix *dest, - const char *dest_str, const char *mask_str, const char *src_str, - const char *gate_str, const char *ifname, const char *flag_str, - const char *tag_str, const char *distance_str, const char *label_str, - const char *table_str) -{ - struct static_hold_route *shr, *lookup; - struct listnode *node; - - zlog_warn("Static Route to %s not installed currently because dependent config not fully available", - dest_str); - - shr = XCALLOC(MTYPE_STATIC_ROUTE, sizeof(*shr)); - shr->vrf_name = XSTRDUP(MTYPE_STATIC_ROUTE, zvrf->vrf->name); - shr->nhvrf_name = XSTRDUP(MTYPE_STATIC_ROUTE, nh_zvrf->vrf->name); - shr->afi = afi; - shr->safi = safi; - if (dest) - prefix_copy(&shr->dest, dest); - if (dest_str) - shr->dest_str = XSTRDUP(MTYPE_STATIC_ROUTE, dest_str); - if (mask_str) - shr->mask_str = XSTRDUP(MTYPE_STATIC_ROUTE, mask_str); - if (src_str) - shr->src_str = XSTRDUP(MTYPE_STATIC_ROUTE, src_str); - if (gate_str) - shr->gate_str = XSTRDUP(MTYPE_STATIC_ROUTE, gate_str); - if (ifname) - shr->ifname = XSTRDUP(MTYPE_STATIC_ROUTE, ifname); - if (flag_str) - shr->flag_str = XSTRDUP(MTYPE_STATIC_ROUTE, flag_str); - if (tag_str) - shr->tag_str = XSTRDUP(MTYPE_STATIC_ROUTE, tag_str); - if (distance_str) - shr->distance_str = XSTRDUP(MTYPE_STATIC_ROUTE, distance_str); - if (label_str) - shr->label_str = XSTRDUP(MTYPE_STATIC_ROUTE, label_str); - if (table_str) - shr->table_str = XSTRDUP(MTYPE_STATIC_ROUTE, table_str); - - for (ALL_LIST_ELEMENTS_RO(static_list, node, lookup)) { - if (static_list_compare(shr, lookup) == 0) - break; - } - - if (lookup) { - if (negate) { - listnode_delete(static_list, lookup); - static_list_delete(shr); - static_list_delete(lookup); - - return CMD_SUCCESS; - } - - /* - * If a person enters the same line again - * we need to silently accept it - */ - goto shr_cleanup; - } - - if (!negate) { - listnode_add_sort(static_list, shr); - return CMD_SUCCESS; - } - -shr_cleanup: - XFREE(MTYPE_STATIC_ROUTE, shr->nhvrf_name); - XFREE(MTYPE_STATIC_ROUTE, shr->vrf_name); - XFREE(MTYPE_STATIC_ROUTE, shr); - - return CMD_SUCCESS; -} - -static int zebra_static_route_leak( - struct vty *vty, struct zebra_vrf *zvrf, struct zebra_vrf *nh_zvrf, - afi_t afi, safi_t safi, const char *negate, const char *dest_str, - const char *mask_str, const char *src_str, const char *gate_str, - const char *ifname, const char *flag_str, const char *tag_str, - const char *distance_str, const char *label_str, const char *table_str) -{ - int ret; - uint8_t distance; - struct prefix p, src; - struct prefix_ipv6 *src_p = NULL; - union g_addr gate; - union g_addr *gatep = NULL; - struct in_addr mask; - enum static_blackhole_type bh_type = 0; - route_tag_t tag = 0; - uint8_t type; - struct static_nh_label snh_label; - uint32_t table_id = 0; - - ret = str2prefix(dest_str, &p); - if (ret <= 0) { - if (vty) - vty_out(vty, "%% Malformed address\n"); - else - zlog_warn("%s: Malformed address: %s", - __PRETTY_FUNCTION__, dest_str); - return CMD_WARNING_CONFIG_FAILED; - } - - switch (afi) { - case AFI_IP: - /* Cisco like mask notation. */ - if (mask_str) { - ret = inet_aton(mask_str, &mask); - if (ret == 0) { - if (vty) - vty_out(vty, "%% Malformed address\n"); - else - zlog_warn("%s: Malformed address: %s", - __PRETTY_FUNCTION__, - mask_str); - return CMD_WARNING_CONFIG_FAILED; - } - p.prefixlen = ip_masklen(mask); - } - break; - case AFI_IP6: - /* srcdest routing */ - if (src_str) { - ret = str2prefix(src_str, &src); - if (ret <= 0 || src.family != AF_INET6) { - if (vty) - vty_out(vty, - "%% Malformed source address\n"); - else - zlog_warn( - "%s: Malformed Source address: %s", - __PRETTY_FUNCTION__, src_str); - return CMD_WARNING_CONFIG_FAILED; - } - src_p = (struct prefix_ipv6 *)&src; - } - break; - default: - break; - } - - /* Apply mask for given prefix. */ - apply_mask(&p); - - if (zvrf->vrf->vrf_id == VRF_UNKNOWN - || nh_zvrf->vrf->vrf_id == VRF_UNKNOWN) { - vrf_set_user_cfged(zvrf->vrf); - return zebra_static_route_holdem( - zvrf, nh_zvrf, afi, safi, negate, &p, dest_str, - mask_str, src_str, gate_str, ifname, flag_str, tag_str, - distance_str, label_str, table_str); - } - if (table_str) { - /* table configured. check consistent with vrf config - */ - if (zvrf->table_id != RT_TABLE_MAIN && - zvrf->table_id != zebrad.rtm_table_default) { - if (vty) - vty_out(vty, - "%% Table %s overlaps vrf table %u\n", - table_str, zvrf->table_id); - else - zlog_warn( - "%s: Table %s overlaps vrf table %u", - __PRETTY_FUNCTION__, - table_str, zvrf->table_id); - return CMD_WARNING_CONFIG_FAILED; - } - } - - /* Administrative distance. */ - if (distance_str) - distance = atoi(distance_str); - else - distance = ZEBRA_STATIC_DISTANCE_DEFAULT; - - /* tag */ - if (tag_str) - tag = strtoul(tag_str, NULL, 10); - - /* Labels */ - memset(&snh_label, 0, sizeof(struct static_nh_label)); - if (label_str) { - if (!mpls_enabled) { - if (vty) - vty_out(vty, - "%% MPLS not turned on in kernel, ignoring command\n"); - else - zlog_warn( - "%s: MPLS not turned on in kernel ignoring static route to %s", - __PRETTY_FUNCTION__, dest_str); - return CMD_WARNING_CONFIG_FAILED; - } - int rc = mpls_str2label(label_str, &snh_label.num_labels, - snh_label.label); - if (rc < 0) { - switch (rc) { - case -1: - if (vty) - vty_out(vty, "%% Malformed label(s)\n"); - else - zlog_warn( - "%s: Malformed labels specified for route %s", - __PRETTY_FUNCTION__, dest_str); - break; - case -2: - if (vty) - vty_out(vty, - "%% Cannot use reserved label(s) (%d-%d)\n", - MPLS_LABEL_RESERVED_MIN, - MPLS_LABEL_RESERVED_MAX); - else - zlog_warn( - "%s: Cannot use reserved labels (%d-%d) for %s", - __PRETTY_FUNCTION__, - MPLS_LABEL_RESERVED_MIN, - MPLS_LABEL_RESERVED_MAX, - dest_str); - break; - case -3: - if (vty) - vty_out(vty, - "%% Too many labels. Enter %d or fewer\n", - MPLS_MAX_LABELS); - else - zlog_warn( - "%s: Too many labels, Enter %d or fewer for %s", - __PRETTY_FUNCTION__, - MPLS_MAX_LABELS, dest_str); - break; - } - return CMD_WARNING_CONFIG_FAILED; - } - } - /* TableID */ - if (table_str) - table_id = atol(table_str); - - /* Null0 static route. */ - if (ifname != NULL) { - if (strncasecmp(ifname, "Null0", strlen(ifname)) == 0 - || strncasecmp(ifname, "reject", strlen(ifname)) == 0 - || strncasecmp(ifname, "blackhole", strlen(ifname)) == 0) { - if (vty) - vty_out(vty, - "%% Nexthop interface cannot be Null0, reject or blackhole\n"); - else - zlog_warn( - "%s: Nexthop interface cannot be Null0, reject or blackhole for %s", - __PRETTY_FUNCTION__, dest_str); - return CMD_WARNING_CONFIG_FAILED; - } - } - - /* Route flags */ - if (flag_str) { - switch (flag_str[0]) { - case 'r': - bh_type = STATIC_BLACKHOLE_REJECT; - break; - case 'b': - bh_type = STATIC_BLACKHOLE_DROP; - break; - case 'N': - bh_type = STATIC_BLACKHOLE_NULL; - break; - default: - if (vty) - vty_out(vty, "%% Malformed flag %s \n", - flag_str); - else - zlog_warn("%s: Malformed flag %s for %s", - __PRETTY_FUNCTION__, flag_str, - dest_str); - return CMD_WARNING_CONFIG_FAILED; - } - } - - if (gate_str) { - if (inet_pton(afi2family(afi), gate_str, &gate) != 1) { - if (vty) - vty_out(vty, - "%% Malformed nexthop address %s\n", - gate_str); - else - zlog_warn( - "%s: Malformed nexthop address %s for %s", - __PRETTY_FUNCTION__, gate_str, - dest_str); - return CMD_WARNING_CONFIG_FAILED; - } - gatep = &gate; - } - - if (gate_str == NULL && ifname == NULL) - type = STATIC_BLACKHOLE; - else if (gate_str && ifname) { - if (afi == AFI_IP) - type = STATIC_IPV4_GATEWAY_IFNAME; - else - type = STATIC_IPV6_GATEWAY_IFNAME; - } else if (ifname) - type = STATIC_IFNAME; - else { - if (afi == AFI_IP) - type = STATIC_IPV4_GATEWAY; - else - type = STATIC_IPV6_GATEWAY; - } - - if (!negate) { - static_add_route(afi, safi, type, &p, src_p, gatep, ifname, - bh_type, tag, distance, zvrf, nh_zvrf, - &snh_label, table_id); - /* Mark as having FRR configuration */ - vrf_set_user_cfged(zvrf->vrf); - } else { - static_delete_route(afi, safi, type, &p, src_p, gatep, ifname, - tag, distance, zvrf, &snh_label, table_id); - /* If no other FRR config for this VRF, mark accordingly. */ - if (!zebra_vrf_has_config(zvrf)) - vrf_reset_user_cfged(zvrf->vrf); - } - - return CMD_SUCCESS; -} - -static struct zebra_vrf *zebra_vty_get_unknown_vrf(struct vty *vty, - const char *vrf_name) -{ - struct zebra_vrf *zvrf; - struct vrf *vrf; - - zvrf = zebra_vrf_lookup_by_name(vrf_name); - - if (zvrf) - return zvrf; - - vrf = vrf_get(VRF_UNKNOWN, vrf_name); - if (!vrf) { - vty_out(vty, "%% Could not create vrf %s\n", vrf_name); - return NULL; - } - zvrf = vrf->info; - if (!zvrf) { - vty_out(vty, "%% Could not create vrf-info %s\n", - vrf_name); - return NULL; - } - /* Mark as having FRR configuration */ - vrf_set_user_cfged(vrf); - - return zvrf; -} - -static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi, - const char *negate, const char *dest_str, - const char *mask_str, const char *src_str, - const char *gate_str, const char *ifname, - const char *flag_str, const char *tag_str, - const char *distance_str, const char *vrf_name, - const char *label_str, const char *table_str) -{ - struct zebra_vrf *zvrf; - - /* VRF id */ - zvrf = zebra_vrf_lookup_by_name(vrf_name); - - /* When trying to delete, the VRF must exist. */ - if (negate && !zvrf) { - vty_out(vty, "%% vrf %s is not defined\n", vrf_name); - return CMD_WARNING_CONFIG_FAILED; - } - - /* When trying to create, create the VRF if it doesn't exist. - * Note: The VRF isn't active until we hear about it from the kernel. - */ - if (!zvrf) { - zvrf = zebra_vty_get_unknown_vrf(vty, vrf_name); - if (!zvrf) - return CMD_WARNING_CONFIG_FAILED; - } - return zebra_static_route_leak( - vty, zvrf, zvrf, afi, safi, negate, dest_str, mask_str, src_str, - gate_str, ifname, flag_str, tag_str, distance_str, label_str, - table_str); -} - -void static_config_install_delayed_routes(struct zebra_vrf *zvrf) -{ - struct listnode *node, *nnode; - struct static_hold_route *shr; - struct zebra_vrf *ozvrf, *nh_zvrf; - int installed; - - for (ALL_LIST_ELEMENTS(static_list, node, nnode, shr)) { - ozvrf = zebra_vrf_lookup_by_name(shr->vrf_name); - nh_zvrf = zebra_vrf_lookup_by_name(shr->nhvrf_name); - - if (ozvrf != zvrf && nh_zvrf != zvrf) - continue; - - if (ozvrf->vrf->vrf_id == VRF_UNKNOWN - || nh_zvrf->vrf->vrf_id == VRF_UNKNOWN) - continue; - - installed = zebra_static_route_leak( - NULL, ozvrf, nh_zvrf, shr->afi, shr->safi, NULL, - shr->dest_str, shr->mask_str, shr->src_str, - shr->gate_str, shr->ifname, shr->flag_str, shr->tag_str, - shr->distance_str, shr->label_str, shr->table_str); - - if (installed != CMD_SUCCESS) - zlog_debug( - "%s: Attempt to install %s as a route and it was rejected", - __PRETTY_FUNCTION__, shr->dest_str); - listnode_delete(static_list, shr); - static_list_delete(shr); - } -} -/* Static unicast routes for multicast RPF lookup. */ -DEFPY (ip_mroute_dist, - ip_mroute_dist_cmd, - "[no] ip mroute A.B.C.D/M$prefix [(1-255)$distance]", - NO_STR - IP_STR - "Configure static unicast route into MRIB for multicast RPF lookup\n" - "IP destination prefix (e.g. 10.0.0.0/8)\n" - "Nexthop address\n" - "Nexthop interface name\n" - "Distance\n") -{ - return zebra_static_route(vty, AFI_IP, SAFI_MULTICAST, no, prefix_str, - NULL, NULL, gate_str, ifname, NULL, NULL, - distance_str, NULL, NULL, NULL); -} - DEFUN (ip_multicast_mode, ip_multicast_mode_cmd, "ip multicast rpf-lookup-mode ", @@ -737,343 +171,6 @@ DEFUN (show_ip_rpf_addr, return CMD_SUCCESS; } -/* Static route configuration. */ -DEFPY(ip_route_blackhole, - ip_route_blackhole_cmd, - "[no] ip route\ - \ - $flag \ - [{ \ - tag (1-4294967295) \ - |(1-255)$distance \ - |vrf NAME \ - |label WORD \ - |table (1-4294967295) \ - }]", - NO_STR IP_STR - "Establish static routes\n" - "IP destination prefix (e.g. 10.0.0.0/8)\n" - "IP destination prefix\n" - "IP destination prefix mask\n" - "Emit an ICMP unreachable when matched\n" - "Silently discard pkts when matched\n" - "Set tag for this route\n" - "Tag value\n" - "Distance value for this route\n" - VRF_CMD_HELP_STR - MPLS_LABEL_HELPSTR - "Table to configure\n" - "The table number to configure\n") -{ - if (table_str && !vrf_is_backend_netns()) { - vty_out(vty, - "%% table param only available when running on netns-based vrfs\n"); - return CMD_WARNING_CONFIG_FAILED; - } - return zebra_static_route(vty, AFI_IP, SAFI_UNICAST, no, prefix, - mask_str, NULL, NULL, NULL, flag, tag_str, - distance_str, vrf, label, table_str); -} - -DEFPY(ip_route_blackhole_vrf, - ip_route_blackhole_vrf_cmd, - "[no] ip route\ - \ - $flag \ - [{ \ - tag (1-4294967295) \ - |(1-255)$distance \ - |label WORD \ - |table (1-4294967295) \ - }]", - NO_STR IP_STR - "Establish static routes\n" - "IP destination prefix (e.g. 10.0.0.0/8)\n" - "IP destination prefix\n" - "IP destination prefix mask\n" - "Emit an ICMP unreachable when matched\n" - "Silently discard pkts when matched\n" - "Set tag for this route\n" - "Tag value\n" - "Distance value for this route\n" - MPLS_LABEL_HELPSTR - "Table to configure\n" - "The table number to configure\n") -{ - VTY_DECLVAR_CONTEXT(vrf, vrf); - struct zebra_vrf *zvrf = vrf->info; - - if (table_str && !vrf_is_backend_netns()) { - vty_out(vty, - "%% table param only available when running on netns-based vrfs\n"); - return CMD_WARNING_CONFIG_FAILED; - } - /* - * Coverity is complaining that prefix could - * be dereferenced, but we know that prefix will - * valid. Add an assert to make it happy - */ - assert(prefix); - return zebra_static_route_leak(vty, zvrf, zvrf, AFI_IP, SAFI_UNICAST, - no, prefix, mask_str, NULL, NULL, NULL, - flag, tag_str, distance_str, label, table_str); -} - -DEFPY(ip_route_address_interface, - ip_route_address_interface_cmd, - "[no] ip route\ - \ - A.B.C.D$gate \ - INTERFACE$ifname \ - [{ \ - tag (1-4294967295) \ - |(1-255)$distance \ - |vrf NAME \ - |label WORD \ - |table (1-4294967295) \ - |nexthop-vrf NAME \ - }]", - NO_STR IP_STR - "Establish static routes\n" - "IP destination prefix (e.g. 10.0.0.0/8)\n" - "IP destination prefix\n" - "IP destination prefix mask\n" - "IP gateway address\n" - "IP gateway interface name. Specify 'Null0' (case-insensitive) for a \ - null route.\n" - "Set tag for this route\n" - "Tag value\n" - "Distance value for this route\n" - VRF_CMD_HELP_STR - MPLS_LABEL_HELPSTR - "Table to configure\n" - "The table number to configure\n" - VRF_CMD_HELP_STR) -{ - struct zebra_vrf *zvrf; - struct zebra_vrf *nh_zvrf; - - const char *flag = NULL; - if (ifname && !strncasecmp(ifname, "Null0", 5)) { - flag = "Null0"; - ifname = NULL; - } - - zvrf = zebra_vty_get_unknown_vrf(vty, vrf); - if (!zvrf) { - vty_out(vty, "%% vrf %s is not defined\n", vrf); - return CMD_WARNING_CONFIG_FAILED; - } - - if (table_str && !vrf_is_backend_netns()) { - vty_out(vty, - "%% table param only available when running on netns-based vrfs\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (nexthop_vrf) - nh_zvrf = zebra_vty_get_unknown_vrf(vty, nexthop_vrf); - else - nh_zvrf = zvrf; - - if (!nh_zvrf) { - vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf); - return CMD_WARNING_CONFIG_FAILED; - } - - return zebra_static_route_leak( - vty, zvrf, nh_zvrf, AFI_IP, SAFI_UNICAST, no, prefix, mask_str, - NULL, gate_str, ifname, flag, tag_str, distance_str, label, - table_str); -} - -DEFPY(ip_route_address_interface_vrf, - ip_route_address_interface_vrf_cmd, - "[no] ip route\ - \ - A.B.C.D$gate \ - INTERFACE$ifname \ - [{ \ - tag (1-4294967295) \ - |(1-255)$distance \ - |label WORD \ - |table (1-4294967295) \ - |nexthop-vrf NAME \ - }]", - NO_STR IP_STR - "Establish static routes\n" - "IP destination prefix (e.g. 10.0.0.0/8)\n" - "IP destination prefix\n" - "IP destination prefix mask\n" - "IP gateway address\n" - "IP gateway interface name. Specify 'Null0' (case-insensitive) for a \ - null route.\n" - "Set tag for this route\n" - "Tag value\n" - "Distance value for this route\n" - MPLS_LABEL_HELPSTR - "Table to configure\n" - "The table number to configure\n" - VRF_CMD_HELP_STR) -{ - VTY_DECLVAR_CONTEXT(vrf, vrf); - const char *flag = NULL; - struct zebra_vrf *zvrf = vrf->info; - struct zebra_vrf *nh_zvrf; - - if (table_str && !vrf_is_backend_netns()) { - vty_out(vty, - "%% table param only available when running on netns-based vrfs\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (ifname && !strncasecmp(ifname, "Null0", 5)) { - flag = "Null0"; - ifname = NULL; - } - - if (nexthop_vrf) - nh_zvrf = zebra_vty_get_unknown_vrf(vty, nexthop_vrf); - else - nh_zvrf = zvrf; - - if (!nh_zvrf) { - vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf); - return CMD_WARNING_CONFIG_FAILED; - } - - return zebra_static_route_leak( - vty, zvrf, nh_zvrf, AFI_IP, SAFI_UNICAST, no, prefix, mask_str, - NULL, gate_str, ifname, flag, tag_str, distance_str, label, - table_str); -} - -DEFPY(ip_route, - ip_route_cmd, - "[no] ip route\ - \ - \ - [{ \ - tag (1-4294967295) \ - |(1-255)$distance \ - |vrf NAME \ - |label WORD \ - |table (1-4294967295) \ - |nexthop-vrf NAME \ - }]", - NO_STR IP_STR - "Establish static routes\n" - "IP destination prefix (e.g. 10.0.0.0/8)\n" - "IP destination prefix\n" - "IP destination prefix mask\n" - "IP gateway address\n" - "IP gateway interface name\n" - "Set tag for this route\n" - "Tag value\n" - "Distance value for this route\n" - VRF_CMD_HELP_STR - MPLS_LABEL_HELPSTR - "Table to configure\n" - "The table number to configure\n" - VRF_CMD_HELP_STR) -{ - struct zebra_vrf *zvrf; - struct zebra_vrf *nh_zvrf; - const char *flag = NULL; - - if (table_str && !vrf_is_backend_netns()) { - vty_out(vty, - "%% table param only available when running on netns-based vrfs\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (ifname && !strncasecmp(ifname, "Null0", 5)) { - flag = "Null0"; - ifname = NULL; - } - - zvrf = zebra_vty_get_unknown_vrf(vty, vrf); - if (!zvrf) { - vty_out(vty, "%% vrf %s is not defined\n", vrf); - return CMD_WARNING_CONFIG_FAILED; - } - - if (nexthop_vrf) - nh_zvrf = zebra_vty_get_unknown_vrf(vty, nexthop_vrf); - else - nh_zvrf = zvrf; - - if (!nh_zvrf) { - vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf); - return CMD_WARNING_CONFIG_FAILED; - } - - - return zebra_static_route_leak( - vty, zvrf, nh_zvrf, AFI_IP, SAFI_UNICAST, no, prefix, mask_str, - NULL, gate_str, ifname, flag, tag_str, distance_str, label, - table_str); -} - -DEFPY(ip_route_vrf, - ip_route_vrf_cmd, - "[no] ip route\ - \ - \ - [{ \ - tag (1-4294967295) \ - |(1-255)$distance \ - |label WORD \ - |table (1-4294967295) \ - |nexthop-vrf NAME \ - }]", - NO_STR IP_STR - "Establish static routes\n" - "IP destination prefix (e.g. 10.0.0.0/8)\n" - "IP destination prefix\n" - "IP destination prefix mask\n" - "IP gateway address\n" - "IP gateway interface name\n" - "Set tag for this route\n" - "Tag value\n" - "Distance value for this route\n" - MPLS_LABEL_HELPSTR - "Table to configure\n" - "The table number to configure\n" - VRF_CMD_HELP_STR) -{ - VTY_DECLVAR_CONTEXT(vrf, vrf); - struct zebra_vrf *zvrf = vrf->info; - struct zebra_vrf *nh_zvrf; - const char *flag = NULL; - - if (table_str && !vrf_is_backend_netns()) { - vty_out(vty, - "%% table param only available when running on netns-based vrfs\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (ifname && !strncasecmp(ifname, "Null0", 5)) { - flag = "Null0"; - ifname = NULL; - } - - if (nexthop_vrf) - nh_zvrf = zebra_vty_get_unknown_vrf(vty, nexthop_vrf); - else - nh_zvrf = zvrf; - - if (!nh_zvrf) { - vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf); - return CMD_WARNING_CONFIG_FAILED; - } - - return zebra_static_route_leak( - vty, zvrf, nh_zvrf, AFI_IP, SAFI_UNICAST, no, prefix, mask_str, - NULL, gate_str, ifname, flag, tag_str, distance_str, label, - table_str); -} - /* New RIB. Detailed information for IPv4 route. */ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, int mcast) @@ -2331,449 +1428,6 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty, vty_out(vty, "\n"); } -/* Write static route configuration. */ -int static_config(struct vty *vty, struct zebra_vrf *zvrf, afi_t afi, - safi_t safi, const char *cmd) -{ - struct static_hold_route *shr; - struct listnode *node; - char spacing[100]; - struct route_node *rn; - struct static_route *si; - struct route_table *stable; - char buf[SRCDEST2STR_BUFFER]; - int write = 0; - - if ((stable = zvrf->stable[afi][safi]) == NULL) - return write; - - sprintf(spacing, "%s%s", (zvrf->vrf->vrf_id == VRF_DEFAULT) ? "" : " ", - cmd); - - /* - * Static routes for vrfs not fully inited - */ - for (ALL_LIST_ELEMENTS_RO(static_list, node, shr)) { - if (shr->afi != afi || shr->safi != safi) - continue; - - if (strcmp(zvrf->vrf->name, shr->vrf_name) != 0) - continue; - - char dest_str[PREFIX_STRLEN]; - - prefix2str(&shr->dest, dest_str, sizeof(dest_str)); - - vty_out(vty, "%s ", spacing); - if (shr->dest_str) - vty_out(vty, "%s ", dest_str); - if (shr->src_str) - vty_out(vty, "from %s ", shr->src_str); - if (shr->gate_str) - vty_out(vty, "%s ", shr->gate_str); - if (shr->ifname) - vty_out(vty, "%s ", shr->ifname); - if (shr->flag_str) - vty_out(vty, "%s ", shr->flag_str); - if (shr->tag_str) - vty_out(vty, "tag %s ", shr->tag_str); - if (shr->distance_str) - vty_out(vty, "%s ", shr->distance_str); - if (shr->label_str) - vty_out(vty, "label %s ", shr->label_str); - if (shr->table_str) - vty_out(vty, "table %s ", shr->table_str); - if (strcmp(shr->vrf_name, shr->nhvrf_name) != 0) - vty_out(vty, "nexthop-vrf %s", shr->nhvrf_name); - vty_out(vty, "\n"); - } - - for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) - for (si = rn->info; si; si = si->next) { - vty_out(vty, "%s %s", spacing, - srcdest_rnode2str(rn, buf, sizeof buf)); - - switch (si->type) { - case STATIC_IPV4_GATEWAY: - vty_out(vty, " %s", inet_ntoa(si->addr.ipv4)); - break; - case STATIC_IPV6_GATEWAY: - vty_out(vty, " %s", - inet_ntop(AF_INET6, &si->addr.ipv6, buf, - sizeof buf)); - break; - case STATIC_IFNAME: - vty_out(vty, " %s", si->ifname); - break; - case STATIC_BLACKHOLE: - switch (si->bh_type) { - case STATIC_BLACKHOLE_DROP: - vty_out(vty, " blackhole"); - break; - case STATIC_BLACKHOLE_NULL: - vty_out(vty, " Null0"); - break; - case STATIC_BLACKHOLE_REJECT: - vty_out(vty, " reject"); - break; - } - break; - case STATIC_IPV4_GATEWAY_IFNAME: - vty_out(vty, " %s %s", - inet_ntop(AF_INET, &si->addr.ipv4, buf, - sizeof buf), - si->ifname); - break; - case STATIC_IPV6_GATEWAY_IFNAME: - vty_out(vty, " %s %s", - inet_ntop(AF_INET6, &si->addr.ipv6, buf, - sizeof buf), - si->ifname); - break; - } - - if (si->tag) - vty_out(vty, " tag %" ROUTE_TAG_PRI, si->tag); - - if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT) - vty_out(vty, " %d", si->distance); - - /* Label information */ - if (si->snh_label.num_labels) - vty_out(vty, " label %s", - mpls_label2str(si->snh_label.num_labels, - si->snh_label.label, buf, - sizeof buf, 0)); - - if (si->nh_vrf_id != si->vrf_id) { - vty_out(vty, " nexthop-vrf %s", si->nh_vrfname); - } - - /* table ID from VRF overrides configured - */ - if (si->table_id && zvrf->table_id == RT_TABLE_MAIN) - vty_out(vty, " table %u", si->table_id); - - vty_out(vty, "\n"); - - write = 1; - } - return write; -} - -DEFPY(ipv6_route_blackhole, - ipv6_route_blackhole_cmd, - "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \ - $flag \ - [{ \ - tag (1-4294967295) \ - |(1-255)$distance \ - |vrf NAME \ - |label WORD \ - |table (1-4294967295) \ - }]", - NO_STR - IPV6_STR - "Establish static routes\n" - "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" - "IPv6 source-dest route\n" - "IPv6 source prefix\n" - "Null interface\n" - "Emit an ICMP unreachable when matched\n" - "Silently discard pkts when matched\n" - "Set tag for this route\n" - "Tag value\n" - "Distance value for this prefix\n" - VRF_CMD_HELP_STR - MPLS_LABEL_HELPSTR - "Table to configure\n" - "The table number to configure\n") -{ - if (table_str && !vrf_is_backend_netns()) { - vty_out(vty, - "%% table param only available when running on netns-based vrfs\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - return zebra_static_route(vty, AFI_IP6, SAFI_UNICAST, no, prefix_str, - NULL, from_str, NULL, NULL, flag, tag_str, - distance_str, vrf, label, table_str); -} - -DEFPY(ipv6_route_blackhole_vrf, - ipv6_route_blackhole_vrf_cmd, - "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \ - $flag \ - [{ \ - tag (1-4294967295) \ - |(1-255)$distance \ - |label WORD \ - |table (1-4294967295) \ - }]", - NO_STR - IPV6_STR - "Establish static routes\n" - "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" - "IPv6 source-dest route\n" - "IPv6 source prefix\n" - "Null interface\n" - "Emit an ICMP unreachable when matched\n" - "Silently discard pkts when matched\n" - "Set tag for this route\n" - "Tag value\n" - "Distance value for this prefix\n" - MPLS_LABEL_HELPSTR - "Table to configure\n" - "The table number to configure\n") -{ - VTY_DECLVAR_CONTEXT(vrf, vrf); - struct zebra_vrf *zvrf = vrf->info; - - if (table_str && !vrf_is_backend_netns()) { - vty_out(vty, - "%% table param only available when running on netns-based vrfs\n"); - return CMD_WARNING_CONFIG_FAILED; - } - /* - * Coverity is complaining that prefix could - * be dereferenced, but we know that prefix will - * valid. Add an assert to make it happy - */ - assert(prefix); - return zebra_static_route_leak( - vty, zvrf, zvrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL, - from_str, NULL, NULL, flag, tag_str, distance_str, label, - table_str); -} - -DEFPY(ipv6_route_address_interface, - ipv6_route_address_interface_cmd, - "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \ - X:X::X:X$gate \ - INTERFACE$ifname \ - [{ \ - tag (1-4294967295) \ - |(1-255)$distance \ - |vrf NAME \ - |label WORD \ - |table (1-4294967295) \ - |nexthop-vrf NAME \ - }]", - NO_STR - IPV6_STR - "Establish static routes\n" - "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" - "IPv6 source-dest route\n" - "IPv6 source prefix\n" - "IPv6 gateway address\n" - "IPv6 gateway interface name\n" - "Set tag for this route\n" - "Tag value\n" - "Distance value for this prefix\n" - VRF_CMD_HELP_STR - MPLS_LABEL_HELPSTR - "Table to configure\n" - "The table number to configure\n" - VRF_CMD_HELP_STR) -{ - struct zebra_vrf *zvrf; - struct zebra_vrf *nh_zvrf; - - if (table_str && !vrf_is_backend_netns()) { - vty_out(vty, - "%% table param only available when running on netns-based vrfs\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - zvrf = zebra_vty_get_unknown_vrf(vty, vrf); - if (!zvrf) { - vty_out(vty, "%% vrf %s is not defined\n", vrf); - return CMD_WARNING_CONFIG_FAILED; - } - - if (nexthop_vrf) - nh_zvrf = zebra_vty_get_unknown_vrf(vty, nexthop_vrf); - else - nh_zvrf = zvrf; - - if (!nh_zvrf) { - vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf); - return CMD_WARNING_CONFIG_FAILED; - } - - return zebra_static_route_leak( - vty, zvrf, nh_zvrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL, - from_str, gate_str, ifname, NULL, tag_str, distance_str, label, - table_str); -} - -DEFPY(ipv6_route_address_interface_vrf, - ipv6_route_address_interface_vrf_cmd, - "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \ - X:X::X:X$gate \ - INTERFACE$ifname \ - [{ \ - tag (1-4294967295) \ - |(1-255)$distance \ - |label WORD \ - |table (1-4294967295) \ - |nexthop-vrf NAME \ - }]", - NO_STR - IPV6_STR - "Establish static routes\n" - "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" - "IPv6 source-dest route\n" - "IPv6 source prefix\n" - "IPv6 gateway address\n" - "IPv6 gateway interface name\n" - "Set tag for this route\n" - "Tag value\n" - "Distance value for this prefix\n" - MPLS_LABEL_HELPSTR - "Table to configure\n" - "The table number to configure\n" - VRF_CMD_HELP_STR) -{ - VTY_DECLVAR_CONTEXT(vrf, vrf); - struct zebra_vrf *zvrf = vrf->info; - struct zebra_vrf *nh_zvrf; - - if (table_str && !vrf_is_backend_netns()) { - vty_out(vty, - "%% table param only available when running on netns-based vrfs\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (nexthop_vrf) - nh_zvrf = zebra_vty_get_unknown_vrf(vty, nexthop_vrf); - else - nh_zvrf = zvrf; - - if (!nh_zvrf) { - vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf); - return CMD_WARNING_CONFIG_FAILED; - } - - return zebra_static_route_leak( - vty, zvrf, nh_zvrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL, - from_str, gate_str, ifname, NULL, tag_str, distance_str, label, - table_str); -} - -DEFPY(ipv6_route, - ipv6_route_cmd, - "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \ - \ - [{ \ - tag (1-4294967295) \ - |(1-255)$distance \ - |vrf NAME \ - |label WORD \ - |table (1-4294967295) \ - |nexthop-vrf NAME \ - }]", - NO_STR - IPV6_STR - "Establish static routes\n" - "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" - "IPv6 source-dest route\n" - "IPv6 source prefix\n" - "IPv6 gateway address\n" - "IPv6 gateway interface name\n" - "Set tag for this route\n" - "Tag value\n" - "Distance value for this prefix\n" - VRF_CMD_HELP_STR - MPLS_LABEL_HELPSTR - "Table to configure\n" - "The table number to configure\n" - VRF_CMD_HELP_STR) -{ - struct zebra_vrf *zvrf; - struct zebra_vrf *nh_zvrf; - - if (table_str && !vrf_is_backend_netns()) { - vty_out(vty, - "%% table param only available when running on netns-based vrfs\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - zvrf = zebra_vty_get_unknown_vrf(vty, vrf); - if (!zvrf) { - vty_out(vty, "%% vrf %s is not defined\n", vrf); - return CMD_WARNING_CONFIG_FAILED; - } - - if (nexthop_vrf) - nh_zvrf = zebra_vty_get_unknown_vrf(vty, nexthop_vrf); - else - nh_zvrf = zvrf; - - if (!nh_zvrf) { - vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf); - return CMD_WARNING_CONFIG_FAILED; - } - - return zebra_static_route_leak( - vty, zvrf, nh_zvrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL, - from_str, gate_str, ifname, NULL, tag_str, distance_str, label, - table_str); -} - -DEFPY(ipv6_route_vrf, - ipv6_route_vrf_cmd, - "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \ - \ - [{ \ - tag (1-4294967295) \ - |(1-255)$distance \ - |label WORD \ - |table (1-4294967295) \ - |nexthop-vrf NAME \ - }]", - NO_STR - IPV6_STR - "Establish static routes\n" - "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" - "IPv6 source-dest route\n" - "IPv6 source prefix\n" - "IPv6 gateway address\n" - "IPv6 gateway interface name\n" - "Set tag for this route\n" - "Tag value\n" - "Distance value for this prefix\n" - MPLS_LABEL_HELPSTR - "Table to configure\n" - "The table number to configure\n" - VRF_CMD_HELP_STR) -{ - VTY_DECLVAR_CONTEXT(vrf, vrf); - struct zebra_vrf *zvrf = vrf->info; - struct zebra_vrf *nh_zvrf; - - if (table_str && !vrf_is_backend_netns()) { - vty_out(vty, - "%% table param only available when running on netns-based vrfs\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (nexthop_vrf) - nh_zvrf = zebra_vty_get_unknown_vrf(vty, nexthop_vrf); - else - nh_zvrf = zvrf; - - if (!nh_zvrf) { - vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf); - return CMD_WARNING_CONFIG_FAILED; - } - - return zebra_static_route_leak( - vty, zvrf, nh_zvrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL, - from_str, gate_str, ifname, NULL, tag_str, distance_str, label, - table_str); -} - /* * Show IPv6 mroute command.Used to dump * the Multicast routing table. @@ -3932,16 +2586,9 @@ void zebra_vty_init(void) install_element(CONFIG_NODE, &allow_external_route_update_cmd); install_element(CONFIG_NODE, &no_allow_external_route_update_cmd); - install_element(CONFIG_NODE, &ip_mroute_dist_cmd); + install_element(CONFIG_NODE, &ip_multicast_mode_cmd); install_element(CONFIG_NODE, &no_ip_multicast_mode_cmd); - install_element(CONFIG_NODE, &ip_route_blackhole_cmd); - install_element(CONFIG_NODE, - &ip_route_address_interface_cmd); - install_element(CONFIG_NODE, &ip_route_cmd); - install_element(VRF_NODE, &ip_route_blackhole_vrf_cmd); - install_element(VRF_NODE, &ip_route_address_interface_vrf_cmd); - install_element(VRF_NODE, &ip_route_vrf_cmd); install_element(CONFIG_NODE, &ip_zebra_import_table_distance_cmd); install_element(CONFIG_NODE, &no_ip_zebra_import_table_cmd); @@ -3966,15 +2613,6 @@ void zebra_vty_init(void) install_element(VIEW_NODE, &show_ip_rpf_cmd); install_element(VIEW_NODE, &show_ip_rpf_addr_cmd); - install_element(CONFIG_NODE, - &ipv6_route_blackhole_cmd); - install_element(CONFIG_NODE, - &ipv6_route_address_interface_cmd); - install_element(CONFIG_NODE, &ipv6_route_cmd); - install_element(VRF_NODE, &ipv6_route_blackhole_vrf_cmd); - install_element(VRF_NODE, - &ipv6_route_address_interface_vrf_cmd); - install_element(VRF_NODE, &ipv6_route_vrf_cmd); install_element(CONFIG_NODE, &ip_nht_default_route_cmd); install_element(CONFIG_NODE, &no_ip_nht_default_route_cmd); install_element(CONFIG_NODE, &ipv6_nht_default_route_cmd); @@ -4011,7 +2649,5 @@ void zebra_vty_init(void) install_element(VRF_NODE, &vrf_vni_mapping_cmd); install_element(VRF_NODE, &no_vrf_vni_mapping_cmd); - static_list = list_new(); - static_list->cmp = (int (*)(void *, void *))static_list_compare; - static_list->del = (void (*)(void *))static_list_delete; + } -- 2.39.5