mirror of
https://github.com/FRRouting/frr.git
synced 2025-04-30 13:37:17 +02:00
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 <sharpd@cumulusnetworks.com>
This commit is contained in:
parent
f23cbcda59
commit
7e24fdf333
|
@ -55,6 +55,7 @@ include eigrpd/subdir.am
|
||||||
include sharpd/subdir.am
|
include sharpd/subdir.am
|
||||||
include pimd/subdir.am
|
include pimd/subdir.am
|
||||||
include pbrd/subdir.am
|
include pbrd/subdir.am
|
||||||
|
include staticd/subdir.am
|
||||||
|
|
||||||
SUBDIRS = . @LIBRFP@ @RFPTEST@ \
|
SUBDIRS = . @LIBRFP@ @RFPTEST@ \
|
||||||
@BGPD@ \
|
@BGPD@ \
|
||||||
|
|
|
@ -1409,6 +1409,7 @@ AM_CONDITIONAL(ISISD, test "${enable_isisd}" != "no")
|
||||||
AM_CONDITIONAL(PIMD, test "${enable_pimd}" != "no")
|
AM_CONDITIONAL(PIMD, test "${enable_pimd}" != "no")
|
||||||
AM_CONDITIONAL(PBRD, test "${enable_pbrd}" != "no")
|
AM_CONDITIONAL(PBRD, test "${enable_pbrd}" != "no")
|
||||||
AM_CONDITIONAL(SHARPD, test "${enable_sharpd}" = "yes")
|
AM_CONDITIONAL(SHARPD, test "${enable_sharpd}" = "yes")
|
||||||
|
AM_CONDITIONAL(STATICD, test "${enable_staticd}" != "no")
|
||||||
|
|
||||||
if test "${enable_bgp_announce}" = "no";then
|
if test "${enable_bgp_announce}" = "no";then
|
||||||
AC_DEFINE(DISABLE_BGP_ANNOUNCE,1,Disable BGP installation to zebra)
|
AC_DEFINE(DISABLE_BGP_ANNOUNCE,1,Disable BGP installation to zebra)
|
||||||
|
|
2
staticd/.gitignore
vendored
Normal file
2
staticd/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
libstatic.a
|
||||||
|
staticd
|
10
staticd/Makefile
Normal file
10
staticd/Makefile
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
all: ALWAYS
|
||||||
|
@$(MAKE) -s -C .. staticd/staticd
|
||||||
|
%: ALWAYS
|
||||||
|
@$(MAKE) -s -C .. staticd/$@
|
||||||
|
|
||||||
|
Makefile:
|
||||||
|
#nothing
|
||||||
|
ALWAYS:
|
||||||
|
.PHONY: ALWAYS makefiles
|
||||||
|
.SUFFIXES:
|
145
staticd/static_main.c
Normal file
145
staticd/static_main.c
Normal file
|
@ -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 <zebra.h>
|
||||||
|
|
||||||
|
#include <lib/version.h>
|
||||||
|
#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;
|
||||||
|
}
|
28
staticd/static_memory.c
Normal file
28
staticd/static_memory.c
Normal file
|
@ -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 <zebra.h>
|
||||||
|
|
||||||
|
#include <memory.h>
|
||||||
|
|
||||||
|
#include "staticd/static_memory.h"
|
||||||
|
|
||||||
|
DEFINE_MGROUP(STATIC, "staticd")
|
||||||
|
|
||||||
|
DEFINE_MTYPE(STATIC, STATIC_ROUTE, "Static Route");
|
28
staticd/static_memory.h
Normal file
28
staticd/static_memory.h
Normal file
|
@ -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
|
75
staticd/static_nht.c
Normal file
75
staticd/static_nht.c
Normal file
|
@ -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 <zebra.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
}
|
25
staticd/static_nht.h
Normal file
25
staticd/static_nht.h
Normal file
|
@ -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
|
513
staticd/static_routes.c
Normal file
513
staticd/static_routes.c
Normal file
|
@ -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 <zebra.h>
|
||||||
|
|
||||||
|
#include <lib/nexthop.h>
|
||||||
|
#include <lib/memory.h>
|
||||||
|
#include <lib/srcdest_table.h>
|
||||||
|
#include <lib/if.h>
|
||||||
|
#include <lib/vty.h>
|
||||||
|
#include <lib/vrf.h>
|
||||||
|
#include <lib/memory.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
110
staticd/static_routes.h
Normal file
110
staticd/static_routes.h
Normal file
|
@ -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
|
196
staticd/static_vrf.c
Normal file
196
staticd/static_vrf.c
Normal file
|
@ -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 <zebra.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
38
staticd/static_vrf.h
Normal file
38
staticd/static_vrf.h
Normal file
|
@ -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
|
1414
staticd/static_vty.c
Normal file
1414
staticd/static_vty.c
Normal file
File diff suppressed because it is too large
Load diff
29
staticd/static_vty.h
Normal file
29
staticd/static_vty.h
Normal file
|
@ -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
|
377
staticd/static_zebra.c
Normal file
377
staticd/static_zebra.c
Normal file
|
@ -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 <zebra.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
30
staticd/static_zebra.h
Normal file
30
staticd/static_zebra.h
Normal file
|
@ -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
|
3
staticd/staticd.conf.sample
Normal file
3
staticd/staticd.conf.sample
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
!
|
||||||
|
!
|
||||||
|
log stdout
|
33
staticd/subdir.am
Normal file
33
staticd/subdir.am
Normal file
|
@ -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@
|
|
@ -146,6 +146,10 @@ vtysh_scan += $(top_srcdir)/pbrd/pbr_vty.c
|
||||||
vtysh_scan += $(top_srcdir)/pbrd/pbr_debug.c
|
vtysh_scan += $(top_srcdir)/pbrd/pbr_debug.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if STATICD
|
||||||
|
vtysh_scan += $(top_srcdir)/staticd/static_vty.c
|
||||||
|
endif
|
||||||
|
|
||||||
vtysh_cmd_FILES = $(vtysh_scan) \
|
vtysh_cmd_FILES = $(vtysh_scan) \
|
||||||
$(top_srcdir)/lib/keychain.c $(top_srcdir)/lib/routemap.c \
|
$(top_srcdir)/lib/keychain.c $(top_srcdir)/lib/routemap.c \
|
||||||
$(top_srcdir)/lib/filter.c $(top_srcdir)/lib/plist.c \
|
$(top_srcdir)/lib/filter.c $(top_srcdir)/lib/plist.c \
|
||||||
|
|
|
@ -133,6 +133,7 @@ struct vtysh_client vtysh_client[] = {
|
||||||
{.fd = -1, .name = "sharpd", .flag = VTYSH_SHARPD, .next = NULL},
|
{.fd = -1, .name = "sharpd", .flag = VTYSH_SHARPD, .next = NULL},
|
||||||
{.fd = -1, .name = "watchfrr", .flag = VTYSH_WATCHFRR, .next = NULL},
|
{.fd = -1, .name = "watchfrr", .flag = VTYSH_WATCHFRR, .next = NULL},
|
||||||
{.fd = -1, .name = "pbrd", .flag = VTYSH_PBRD, .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 =
|
enum vtysh_write_integrated vtysh_write_integrated =
|
||||||
|
|
|
@ -39,6 +39,7 @@ DECLARE_MGROUP(MVTYSH)
|
||||||
#define VTYSH_BABELD 0x1000
|
#define VTYSH_BABELD 0x1000
|
||||||
#define VTYSH_SHARPD 0x2000
|
#define VTYSH_SHARPD 0x2000
|
||||||
#define VTYSH_PBRD 0x4000
|
#define VTYSH_PBRD 0x4000
|
||||||
|
#define VTYSH_STATICD 0x8000
|
||||||
|
|
||||||
#define VTYSH_WAS_ACTIVE (-2)
|
#define VTYSH_WAS_ACTIVE (-2)
|
||||||
|
|
||||||
|
@ -47,7 +48,7 @@ DECLARE_MGROUP(MVTYSH)
|
||||||
/* watchfrr is not in ALL since library CLI functions should not be
|
/* 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
|
* run on it (logging & co. should stay in a fixed/frozen config, and
|
||||||
* things like prefix lists are not even initialised) */
|
* 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_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_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
|
#define VTYSH_NS VTYSH_ZEBRA
|
||||||
|
|
|
@ -577,7 +577,6 @@ void if_add_update(struct interface *ifp)
|
||||||
"interface %s vrf %u index %d becomes active.",
|
"interface %s vrf %u index %d becomes active.",
|
||||||
ifp->name, ifp->vrf_id, ifp->ifindex);
|
ifp->name, ifp->vrf_id, ifp->ifindex);
|
||||||
|
|
||||||
static_ifindex_update(ifp, true);
|
|
||||||
} else {
|
} else {
|
||||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||||
zlog_debug("interface %s vrf %u index %d is added.",
|
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.",
|
zlog_debug("interface %s vrf %u index %d is now inactive.",
|
||||||
ifp->name, ifp->vrf_id, ifp->ifindex);
|
ifp->name, ifp->vrf_id, ifp->ifindex);
|
||||||
|
|
||||||
static_ifindex_update(ifp, false);
|
|
||||||
|
|
||||||
/* Delete connected routes from the kernel. */
|
/* Delete connected routes from the kernel. */
|
||||||
if_delete_connected(ifp);
|
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;
|
old_vrf_id = ifp->vrf_id;
|
||||||
|
|
||||||
static_ifindex_update(ifp, false);
|
|
||||||
|
|
||||||
/* Uninstall connected routes. */
|
/* Uninstall connected routes. */
|
||||||
if_uninstall_connected(ifp);
|
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 (if_is_operative(ifp))
|
||||||
if_install_connected(ifp);
|
if_install_connected(ifp);
|
||||||
|
|
||||||
static_ifindex_update(ifp, true);
|
|
||||||
|
|
||||||
/* Due to connected route change, schedule RIB processing for both old
|
/* Due to connected route change, schedule RIB processing for both old
|
||||||
* and new VRF.
|
* and new VRF.
|
||||||
*/
|
*/
|
||||||
|
@ -934,12 +927,6 @@ void if_up(struct interface *ifp)
|
||||||
/* Install connected routes to the kernel. */
|
/* Install connected routes to the kernel. */
|
||||||
if_install_connected(ifp);
|
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)
|
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
|
||||||
zlog_debug("%u: IF %s up, scheduling RIB processing",
|
zlog_debug("%u: IF %s up, scheduling RIB processing",
|
||||||
ifp->vrf_id, ifp->name);
|
ifp->vrf_id, ifp->name);
|
||||||
|
|
|
@ -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 is_zebra_main_routing_table(uint32_t table_id);
|
||||||
extern int zebra_check_addr(const struct prefix *p);
|
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_delnode(struct route_node *rn, struct route_entry *re);
|
||||||
extern void rib_install_kernel(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);
|
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 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;
|
extern pid_t pid;
|
||||||
|
|
||||||
|
|
|
@ -2086,7 +2086,8 @@ static void rib_link(struct route_node *rn, struct route_entry *re, int process)
|
||||||
rib_queue_add(rn);
|
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.
|
/* RE node has been un-removed before route-node is processed.
|
||||||
* route_node must hence already be on the queue for processing..
|
* 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)
|
if (dest->selected_fib == re)
|
||||||
dest->selected_fib = NULL;
|
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);
|
nexthops_free(re->ng.nexthop);
|
||||||
XFREE(MTYPE_RE, re);
|
XFREE(MTYPE_RE, re);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 = XCALLOC(MTYPE_RNH, sizeof(struct rnh));
|
||||||
rnh->client_list = list_new();
|
rnh->client_list = list_new();
|
||||||
rnh->vrf_id = vrfid;
|
rnh->vrf_id = vrfid;
|
||||||
rnh->zebra_static_route_list = list_new();
|
|
||||||
rnh->zebra_pseudowire_list = list_new();
|
rnh->zebra_pseudowire_list = list_new();
|
||||||
route_lock_node(rn);
|
route_lock_node(rn);
|
||||||
rn->info = rnh;
|
rn->info = rnh;
|
||||||
|
@ -167,7 +166,6 @@ void zebra_free_rnh(struct rnh *rnh)
|
||||||
{
|
{
|
||||||
rnh->flags |= ZEBRA_NHT_DELETED;
|
rnh->flags |= ZEBRA_NHT_DELETED;
|
||||||
list_delete_and_null(&rnh->client_list);
|
list_delete_and_null(&rnh->client_list);
|
||||||
list_delete_and_null(&rnh->zebra_static_route_list);
|
|
||||||
list_delete_and_null(&rnh->zebra_pseudowire_list);
|
list_delete_and_null(&rnh->zebra_pseudowire_list);
|
||||||
free_state(rnh->vrf_id, rnh->state, rnh->node);
|
free_state(rnh->vrf_id, rnh->state, rnh->node);
|
||||||
XFREE(MTYPE_RNH, rnh);
|
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);
|
listnode_delete(rnh->client_list, client);
|
||||||
if (list_isempty(rnh->client_list)
|
if (list_isempty(rnh->client_list)
|
||||||
&& list_isempty(rnh->zebra_static_route_list)
|
|
||||||
&& list_isempty(rnh->zebra_pseudowire_list))
|
&& list_isempty(rnh->zebra_pseudowire_list))
|
||||||
zebra_delete_rnh(rnh, type);
|
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? */
|
/* XXX move this utility function elsewhere? */
|
||||||
static void addr2hostprefix(int af, const union g_addr *addr,
|
static void addr2hostprefix(int af, const union g_addr *addr,
|
||||||
struct prefix *prefix)
|
struct prefix *prefix)
|
||||||
|
@ -342,7 +268,6 @@ void zebra_deregister_rnh_pseudowire(vrf_id_t vrf_id, struct zebra_pw *pw)
|
||||||
pw->rnh = NULL;
|
pw->rnh = NULL;
|
||||||
|
|
||||||
if (list_isempty(rnh->client_list)
|
if (list_isempty(rnh->client_list)
|
||||||
&& list_isempty(rnh->zebra_static_route_list)
|
|
||||||
&& list_isempty(rnh->zebra_pseudowire_list))
|
&& list_isempty(rnh->zebra_pseudowire_list))
|
||||||
zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE);
|
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
|
* Determine appropriate route (route entry) resolving a tracked
|
||||||
* nexthop.
|
* 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,
|
zebra_rnh_notify_protocol_clients(vrfid, family, nrn, rnh, prn,
|
||||||
rnh->state);
|
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,
|
zebra_rnh_process_pbr_tables(family, nrn, rnh, prn,
|
||||||
rnh->state);
|
rnh->state);
|
||||||
|
|
||||||
|
@ -962,7 +774,6 @@ static void free_state(vrf_id_t vrf_id, struct route_entry *re,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* free RE and nexthops */
|
/* free RE and nexthops */
|
||||||
zebra_deregister_rnh_static_nexthops(vrf_id, re->ng.nexthop, rn);
|
|
||||||
nexthops_free(re->ng.nexthop);
|
nexthops_free(re->ng.nexthop);
|
||||||
XFREE(MTYPE_RE, re);
|
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),
|
vty_out(vty, " %s(fd %d)%s", zebra_route_string(client->proto),
|
||||||
client->sock,
|
client->sock,
|
||||||
rnh->filtered[client->proto] ? "(filtered)" : "");
|
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))
|
if (!list_isempty(rnh->zebra_pseudowire_list))
|
||||||
vty_out(vty, " zebra[pseudowires]");
|
vty_out(vty, " zebra[pseudowires]");
|
||||||
vty_out(vty, "\n");
|
vty_out(vty, "\n");
|
||||||
|
|
|
@ -39,14 +39,16 @@ struct rnh {
|
||||||
struct route_entry *state;
|
struct route_entry *state;
|
||||||
struct prefix resolved_route;
|
struct prefix resolved_route;
|
||||||
struct list *client_list;
|
struct list *client_list;
|
||||||
struct list
|
|
||||||
*zebra_static_route_list; /* static routes dependent on this NH
|
/* pseudowires dependent on this nh */
|
||||||
*/
|
struct list *zebra_pseudowire_list;
|
||||||
struct list
|
|
||||||
*zebra_pseudowire_list; /* pseudowires dependent on this NH */
|
|
||||||
struct route_node *node;
|
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;
|
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_delete_rnh(struct rnh *rnh, rnh_type_t type);
|
||||||
extern void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client,
|
extern void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client,
|
||||||
rnh_type_t type, vrf_id_t vrfid);
|
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_register_rnh_pseudowire(vrf_id_t, struct zebra_pw *);
|
||||||
extern void zebra_deregister_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,
|
extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client,
|
||||||
|
|
|
@ -20,833 +20,3 @@
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
#include <zebra.h>
|
#include <zebra.h>
|
||||||
|
|
||||||
#include <lib/nexthop.h>
|
|
||||||
#include <lib/memory.h>
|
|
||||||
#include <lib/srcdest_table.h>
|
|
||||||
#include <lib/if.h>
|
|
||||||
|
|
||||||
#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);
|
|
||||||
}
|
|
||||||
|
|
|
@ -22,93 +22,4 @@
|
||||||
#ifndef __ZEBRA_STATIC_H__
|
#ifndef __ZEBRA_STATIC_H__
|
||||||
#define __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
|
#endif
|
||||||
|
|
|
@ -155,8 +155,6 @@ static int zebra_vrf_disable(struct vrf *vrf)
|
||||||
zlog_debug("VRF %s id %u is now inactive", zvrf_name(zvrf),
|
zlog_debug("VRF %s id %u is now inactive", zvrf_name(zvrf),
|
||||||
zvrf_id(zvrf));
|
zvrf_id(zvrf));
|
||||||
|
|
||||||
static_cleanup_vrf_ids(zvrf);
|
|
||||||
|
|
||||||
/* Stop any VxLAN-EVPN processing. */
|
/* Stop any VxLAN-EVPN processing. */
|
||||||
zebra_vxlan_vrf_disable(zvrf);
|
zebra_vxlan_vrf_disable(zvrf);
|
||||||
|
|
||||||
|
@ -268,9 +266,6 @@ static int zebra_vrf_delete(struct vrf *vrf)
|
||||||
route_table_finish(table);
|
route_table_finish(table);
|
||||||
XFREE(MTYPE_RIB_TABLE_INFO, table_info);
|
XFREE(MTYPE_RIB_TABLE_INFO, table_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
table = zvrf->stable[afi][safi];
|
|
||||||
route_table_finish(table);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
route_table_finish(zvrf->rnh_table[afi]);
|
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)
|
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? */
|
/* EVPN L3-VNI? */
|
||||||
if (zvrf->l3vni)
|
if (zvrf->l3vni)
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -366,18 +343,6 @@ void zebra_rtable_node_cleanup(struct route_table *table,
|
||||||
XFREE(MTYPE_RIB_DEST, node->info);
|
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,
|
static void zebra_rnhtable_node_cleanup(struct route_table *table,
|
||||||
struct route_node *node)
|
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 *zebra_vrf_alloc(void)
|
||||||
{
|
{
|
||||||
struct zebra_vrf *zvrf;
|
struct zebra_vrf *zvrf;
|
||||||
afi_t afi;
|
|
||||||
safi_t safi;
|
|
||||||
struct route_table *table;
|
|
||||||
|
|
||||||
zvrf = XCALLOC(MTYPE_ZEBRA_VRF, sizeof(struct zebra_vrf));
|
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_vxlan_init_tables(zvrf);
|
||||||
zebra_mpls_init_tables(zvrf);
|
zebra_mpls_init_tables(zvrf);
|
||||||
zebra_pw_init(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];
|
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,
|
struct route_table *zebra_vrf_other_route_table(afi_t afi, uint32_t table_id,
|
||||||
vrf_id_t vrf_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)
|
if (zvrf_id(zvrf) != VRF_DEFAULT)
|
||||||
vty_endframe(vty, " exit-vrf\n!\n");
|
vty_endframe(vty, " exit-vrf\n!\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,9 +53,6 @@ struct zebra_vrf {
|
||||||
/* Routing table. */
|
/* Routing table. */
|
||||||
struct route_table *table[AFI_MAX][SAFI_MAX];
|
struct route_table *table[AFI_MAX][SAFI_MAX];
|
||||||
|
|
||||||
/* Static route configuration. */
|
|
||||||
struct route_table *stable[AFI_MAX][SAFI_MAX];
|
|
||||||
|
|
||||||
/* Recursive Nexthop table */
|
/* Recursive Nexthop table */
|
||||||
struct route_table *rnh_table[AFI_MAX];
|
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_lookup_by_name(const char *);
|
||||||
extern struct zebra_vrf *zebra_vrf_alloc(void);
|
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_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 *
|
extern struct route_table *
|
||||||
zebra_vrf_other_route_table(afi_t afi, uint32_t table_id, vrf_id_t vrf_id);
|
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);
|
extern int zebra_vrf_has_config(struct zebra_vrf *zvrf);
|
||||||
|
|
1368
zebra/zebra_vty.c
1368
zebra/zebra_vty.c
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue