mirror of
https://github.com/FRRouting/frr.git
synced 2025-04-30 13:37:17 +02:00

CI tests are showing cases where staticd is connecting to zebra after config is read in and the nexthops are never being registered w/ zebra: 2025/03/11 15:39:44 STATIC: [T83RR-8SM5G] staticd 10.4-dev starting: vty@2616 2025/03/11 15:39:45 STATIC: [GH3PB-C7X4Y] Static Route to 13.13.13.13/32 not installed currently because dependent config not fully available 2025/03/11 15:39:45 STATIC: [RHJK1-M5FAR] static_zebra_nht_register: Failure to send nexthop 1.1.1.2/32 for 11.11.11.11/32 to zebra 2025/03/11 15:39:45 STATIC: [M7Q4P-46WDR] vty[14]@> enable Zebra shows connection time as: 2025/03/11 15:39:45.933343 ZEBRA: [V98V0-MTWPF] client 5 says hello and bids fair to announce only static routes vrf=0 As a result staticd never installs the route because it has no nexthop tracking to say that the route could be installed. Modify staticd on startup to go through it's nexthops and dump them to zebra to allow the staticd state machine to get to work. Signed-off-by: Donald Sharp <sharpd@nvidia.com>
666 lines
16 KiB
C
666 lines
16 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* STATICd - route code
|
|
* Copyright (C) 2018 Cumulus Networks, Inc.
|
|
* Donald Sharp
|
|
*/
|
|
#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 "printfrr.h"
|
|
|
|
#include "static_vrf.h"
|
|
#include "static_routes.h"
|
|
#include "static_zebra.h"
|
|
#include "static_debug.h"
|
|
|
|
DEFINE_MGROUP(STATIC, "staticd");
|
|
|
|
DEFINE_MTYPE_STATIC(STATIC, STATIC_ROUTE, "Static Route Info");
|
|
DEFINE_MTYPE_STATIC(STATIC, STATIC_PATH, "Static Path");
|
|
DEFINE_MTYPE_STATIC(STATIC, STATIC_NEXTHOP, "Static Nexthop");
|
|
|
|
void zebra_stable_node_cleanup(struct route_table *table,
|
|
struct route_node *node)
|
|
{
|
|
struct static_nexthop *nh;
|
|
struct static_path *pn;
|
|
struct static_route_info *si;
|
|
|
|
si = node->info;
|
|
|
|
if (si) {
|
|
frr_each_safe(static_path_list, &si->path_list, pn) {
|
|
frr_each_safe(static_nexthop_list, &pn->nexthop_list,
|
|
nh) {
|
|
static_nexthop_list_del(&pn->nexthop_list, nh);
|
|
XFREE(MTYPE_STATIC_NEXTHOP, nh);
|
|
}
|
|
static_path_list_del(&si->path_list, pn);
|
|
XFREE(MTYPE_STATIC_PATH, pn);
|
|
}
|
|
XFREE(MTYPE_STATIC_ROUTE, node->info);
|
|
}
|
|
}
|
|
|
|
/* Install static path into rib. */
|
|
void static_install_path(struct static_path *pn)
|
|
{
|
|
struct static_nexthop *nh;
|
|
|
|
frr_each (static_nexthop_list, &pn->nexthop_list, nh)
|
|
static_zebra_nht_register(nh, true);
|
|
|
|
if (static_nexthop_list_count(&pn->nexthop_list))
|
|
static_zebra_route_add(pn, true);
|
|
}
|
|
|
|
/* Uninstall static path from RIB. */
|
|
static void static_uninstall_path(struct static_path *pn)
|
|
{
|
|
if (static_nexthop_list_count(&pn->nexthop_list))
|
|
static_zebra_route_add(pn, true);
|
|
else
|
|
static_zebra_route_add(pn, false);
|
|
}
|
|
|
|
struct route_node *static_add_route(afi_t afi, safi_t safi, struct prefix *p,
|
|
struct prefix_ipv6 *src_p,
|
|
struct static_vrf *svrf)
|
|
{
|
|
struct route_node *rn;
|
|
struct static_route_info *si;
|
|
struct route_table *stable = svrf->stable[afi][safi];
|
|
|
|
assert(stable);
|
|
|
|
/* Lookup static route prefix. */
|
|
rn = srcdest_rnode_get(stable, p, src_p);
|
|
|
|
si = XCALLOC(MTYPE_STATIC_ROUTE, sizeof(struct static_route_info));
|
|
|
|
si->svrf = svrf;
|
|
si->safi = safi;
|
|
static_path_list_init(&(si->path_list));
|
|
|
|
rn->info = si;
|
|
|
|
return rn;
|
|
}
|
|
|
|
void static_del_route(struct route_node *rn)
|
|
{
|
|
struct static_path *pn;
|
|
struct static_route_info *si;
|
|
|
|
si = rn->info;
|
|
|
|
frr_each_safe(static_path_list, &si->path_list, pn) {
|
|
static_del_path(pn);
|
|
}
|
|
|
|
XFREE(MTYPE_STATIC_ROUTE, rn->info);
|
|
route_unlock_node(rn);
|
|
}
|
|
|
|
bool static_add_nexthop_validate(const char *nh_vrf_name,
|
|
enum static_nh_type type,
|
|
struct ipaddr *ipaddr)
|
|
{
|
|
struct vrf *vrf;
|
|
|
|
vrf = vrf_lookup_by_name(nh_vrf_name);
|
|
if (!vrf)
|
|
return true;
|
|
|
|
switch (type) {
|
|
case STATIC_IPV4_GATEWAY:
|
|
case STATIC_IPV4_GATEWAY_IFNAME:
|
|
if (if_address_is_local(&ipaddr->ipaddr_v4, AF_INET,
|
|
vrf->vrf_id))
|
|
return false;
|
|
break;
|
|
case STATIC_IPV6_GATEWAY:
|
|
case STATIC_IPV6_GATEWAY_IFNAME:
|
|
if (if_address_is_local(&ipaddr->ipaddr_v6, AF_INET6,
|
|
vrf->vrf_id))
|
|
return false;
|
|
break;
|
|
case STATIC_IFNAME:
|
|
case STATIC_BLACKHOLE:
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
struct static_path *static_add_path(struct route_node *rn, uint32_t table_id,
|
|
uint8_t distance)
|
|
{
|
|
struct static_path *pn;
|
|
struct static_route_info *si;
|
|
|
|
route_lock_node(rn);
|
|
|
|
/* Make new static route structure. */
|
|
pn = XCALLOC(MTYPE_STATIC_PATH, sizeof(struct static_path));
|
|
|
|
pn->rn = rn;
|
|
pn->distance = distance;
|
|
pn->table_id = table_id;
|
|
static_nexthop_list_init(&(pn->nexthop_list));
|
|
|
|
si = rn->info;
|
|
static_path_list_add_head(&(si->path_list), pn);
|
|
|
|
return pn;
|
|
}
|
|
|
|
void static_del_path(struct static_path *pn)
|
|
{
|
|
struct route_node *rn = pn->rn;
|
|
struct static_route_info *si;
|
|
struct static_nexthop *nh;
|
|
|
|
si = rn->info;
|
|
|
|
static_path_list_del(&si->path_list, pn);
|
|
|
|
frr_each_safe(static_nexthop_list, &pn->nexthop_list, nh) {
|
|
static_delete_nexthop(nh);
|
|
}
|
|
|
|
route_unlock_node(rn);
|
|
|
|
XFREE(MTYPE_STATIC_PATH, pn);
|
|
}
|
|
|
|
struct static_nexthop *
|
|
static_add_nexthop(struct static_path *pn, enum static_nh_type type,
|
|
struct ipaddr *ipaddr, const char *ifname,
|
|
const char *nh_vrfname, uint32_t color)
|
|
{
|
|
struct route_node *rn = pn->rn;
|
|
struct static_nexthop *nh;
|
|
struct vrf *nh_vrf;
|
|
struct interface *ifp;
|
|
struct static_nexthop *cp;
|
|
|
|
route_lock_node(rn);
|
|
|
|
nh_vrf = vrf_lookup_by_name(nh_vrfname);
|
|
|
|
/* Make new static route structure. */
|
|
nh = XCALLOC(MTYPE_STATIC_NEXTHOP, sizeof(struct static_nexthop));
|
|
|
|
/* Copy back pointers. */
|
|
nh->rn = rn;
|
|
nh->pn = pn;
|
|
|
|
nh->type = type;
|
|
nh->color = color;
|
|
|
|
if (nh->type == STATIC_BLACKHOLE)
|
|
nh->bh_type = STATIC_BLACKHOLE_NULL;
|
|
|
|
nh->nh_vrf_id = nh_vrf ? nh_vrf->vrf_id : VRF_UNKNOWN;
|
|
strlcpy(nh->nh_vrfname, nh_vrfname, sizeof(nh->nh_vrfname));
|
|
|
|
if (ifname)
|
|
strlcpy(nh->ifname, ifname, sizeof(nh->ifname));
|
|
nh->ifindex = IFINDEX_INTERNAL;
|
|
|
|
switch (type) {
|
|
case STATIC_IPV4_GATEWAY:
|
|
case STATIC_IPV4_GATEWAY_IFNAME:
|
|
nh->addr.ipv4 = ipaddr->ipaddr_v4;
|
|
break;
|
|
case STATIC_IPV6_GATEWAY:
|
|
case STATIC_IPV6_GATEWAY_IFNAME:
|
|
nh->addr.ipv6 = ipaddr->ipaddr_v6;
|
|
break;
|
|
case STATIC_IFNAME:
|
|
case STATIC_BLACKHOLE:
|
|
break;
|
|
}
|
|
/*
|
|
* Add new static route information to the tree with sort by
|
|
* gateway address.
|
|
*/
|
|
frr_each(static_nexthop_list, &pn->nexthop_list, cp) {
|
|
if (nh->type == STATIC_IPV4_GATEWAY
|
|
&& cp->type == STATIC_IPV4_GATEWAY) {
|
|
if (ntohl(nh->addr.ipv4.s_addr)
|
|
< ntohl(cp->addr.ipv4.s_addr))
|
|
break;
|
|
if (ntohl(nh->addr.ipv4.s_addr)
|
|
> ntohl(cp->addr.ipv4.s_addr))
|
|
continue;
|
|
}
|
|
}
|
|
static_nexthop_list_add_after(&(pn->nexthop_list), cp, nh);
|
|
|
|
if (nh->nh_vrf_id == VRF_UNKNOWN) {
|
|
zlog_warn(
|
|
"Static Route to %pFX not installed currently because dependent config not fully available",
|
|
&rn->p);
|
|
return nh;
|
|
}
|
|
|
|
/* check whether interface exists in system & install if it does */
|
|
switch (nh->type) {
|
|
case STATIC_IPV4_GATEWAY:
|
|
case STATIC_IPV6_GATEWAY:
|
|
case STATIC_BLACKHOLE:
|
|
break;
|
|
case STATIC_IPV4_GATEWAY_IFNAME:
|
|
case STATIC_IPV6_GATEWAY_IFNAME:
|
|
case STATIC_IFNAME:
|
|
ifp = if_lookup_by_name(ifname, nh->nh_vrf_id);
|
|
if (ifp && ifp->ifindex != IFINDEX_INTERNAL)
|
|
nh->ifindex = ifp->ifindex;
|
|
else
|
|
zlog_warn(
|
|
"Static Route using %s interface not installed because the interface does not exist in specified vrf",
|
|
ifname);
|
|
break;
|
|
}
|
|
|
|
return nh;
|
|
}
|
|
|
|
void static_install_nexthop(struct static_nexthop *nh)
|
|
{
|
|
struct static_path *pn = nh->pn;
|
|
struct route_node *rn = pn->rn;
|
|
struct interface *ifp;
|
|
|
|
if (nh->nh_vrf_id == VRF_UNKNOWN) {
|
|
char nexthop_str[NEXTHOP_STR];
|
|
|
|
static_get_nh_str(nh, nexthop_str, sizeof(nexthop_str));
|
|
DEBUGD(&static_dbg_route,
|
|
"Static Route %pFX not installed for %s vrf %s is unknown",
|
|
&rn->p, nexthop_str, nh->nh_vrfname);
|
|
return;
|
|
}
|
|
|
|
/* check whether interface exists in system & install if it does */
|
|
switch (nh->type) {
|
|
case STATIC_IPV4_GATEWAY:
|
|
case STATIC_IPV6_GATEWAY:
|
|
static_zebra_nht_register(nh, true);
|
|
break;
|
|
case STATIC_IPV4_GATEWAY_IFNAME:
|
|
case STATIC_IPV6_GATEWAY_IFNAME:
|
|
static_zebra_nht_register(nh, true);
|
|
break;
|
|
case STATIC_BLACKHOLE:
|
|
static_install_path(pn);
|
|
break;
|
|
case STATIC_IFNAME:
|
|
ifp = if_lookup_by_name(nh->ifname, nh->nh_vrf_id);
|
|
if (ifp && ifp->ifindex != IFINDEX_INTERNAL)
|
|
static_install_path(pn);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
void static_uninstall_nexthop(struct static_nexthop *nh)
|
|
{
|
|
struct static_path *pn = nh->pn;
|
|
|
|
if (nh->nh_vrf_id == VRF_UNKNOWN)
|
|
return;
|
|
|
|
static_zebra_nht_register(nh, false);
|
|
static_uninstall_path(pn);
|
|
}
|
|
|
|
void static_delete_nexthop(struct static_nexthop *nh)
|
|
{
|
|
struct static_path *pn = nh->pn;
|
|
struct route_node *rn = pn->rn;
|
|
|
|
static_nexthop_list_del(&(pn->nexthop_list), nh);
|
|
/* Remove BFD session/configuration if any. */
|
|
bfd_sess_free(&nh->bsp);
|
|
|
|
static_uninstall_nexthop(nh);
|
|
|
|
route_unlock_node(rn);
|
|
/* Free static route configuration. */
|
|
XFREE(MTYPE_STATIC_NEXTHOP, nh);
|
|
}
|
|
|
|
static void static_ifindex_update_nh(struct interface *ifp, bool up,
|
|
struct route_node *rn,
|
|
struct static_path *pn,
|
|
struct static_nexthop *nh,
|
|
struct static_vrf *svrf, safi_t safi)
|
|
{
|
|
if (!nh->ifname[0])
|
|
return;
|
|
if (up) {
|
|
if (strcmp(nh->ifname, ifp->name))
|
|
return;
|
|
if (nh->nh_vrf_id != ifp->vrf->vrf_id)
|
|
return;
|
|
nh->ifindex = ifp->ifindex;
|
|
} else {
|
|
if (nh->ifindex != ifp->ifindex)
|
|
return;
|
|
if (nh->nh_vrf_id != ifp->vrf->vrf_id)
|
|
return;
|
|
nh->ifindex = IFINDEX_INTERNAL;
|
|
}
|
|
|
|
/* Remove previously configured route if any. */
|
|
static_uninstall_path(pn);
|
|
static_install_path(pn);
|
|
}
|
|
|
|
void static_install_nexthops_on_startup(void)
|
|
{
|
|
struct route_table *stable;
|
|
struct route_node *rn;
|
|
struct static_nexthop *nh;
|
|
struct static_path *pn;
|
|
struct static_vrf *svrf;
|
|
struct static_route_info *si;
|
|
afi_t afi;
|
|
safi_t safi;
|
|
|
|
RB_FOREACH (svrf, svrf_name_head, &svrfs) {
|
|
FOREACH_AFI_SAFI (afi, safi) {
|
|
stable = static_vrf_static_table(afi, safi, svrf);
|
|
if (!stable)
|
|
continue;
|
|
for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) {
|
|
si = static_route_info_from_rnode(rn);
|
|
if (!si)
|
|
continue;
|
|
frr_each (static_path_list, &si->path_list, pn) {
|
|
frr_each (static_nexthop_list, &pn->nexthop_list, nh) {
|
|
static_zebra_nht_register(nh, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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_nexthop *nh;
|
|
struct static_path *pn;
|
|
struct static_vrf *svrf;
|
|
struct static_route_info *si;
|
|
|
|
RB_FOREACH (svrf, svrf_name_head, &svrfs) {
|
|
stable = static_vrf_static_table(afi, safi, svrf);
|
|
if (!stable)
|
|
continue;
|
|
for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) {
|
|
si = static_route_info_from_rnode(rn);
|
|
if (!si)
|
|
continue;
|
|
frr_each(static_path_list, &si->path_list, pn) {
|
|
frr_each(static_nexthop_list,
|
|
&pn->nexthop_list, nh) {
|
|
static_ifindex_update_nh(ifp, up, rn,
|
|
pn, nh, svrf,
|
|
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 vrf *vrf, struct route_table *stable,
|
|
afi_t afi, safi_t safi)
|
|
{
|
|
struct route_node *rn;
|
|
struct static_nexthop *nh;
|
|
struct interface *ifp;
|
|
struct static_path *pn;
|
|
struct static_route_info *si;
|
|
|
|
for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) {
|
|
si = static_route_info_from_rnode(rn);
|
|
if (!si)
|
|
continue;
|
|
frr_each(static_path_list, &si->path_list, pn) {
|
|
frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
|
|
if (strcmp(vrf->name, nh->nh_vrfname) != 0)
|
|
continue;
|
|
|
|
nh->nh_vrf_id = vrf->vrf_id;
|
|
if (nh->ifname[0]) {
|
|
ifp = if_lookup_by_name(nh->ifname,
|
|
nh->nh_vrf_id);
|
|
if (ifp)
|
|
nh->ifindex = ifp->ifindex;
|
|
else
|
|
continue;
|
|
}
|
|
|
|
static_install_nexthop(nh);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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 route_table *stable, afi_t afi, safi_t safi)
|
|
{
|
|
struct route_node *rn;
|
|
struct static_path *pn;
|
|
struct static_route_info *si;
|
|
|
|
for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) {
|
|
si = static_route_info_from_rnode(rn);
|
|
if (!si)
|
|
continue;
|
|
frr_each(static_path_list, &si->path_list, pn)
|
|
static_install_path(pn);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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 vrf *vrf)
|
|
{
|
|
struct route_table *stable;
|
|
struct static_vrf *svrf, *enable_svrf;
|
|
afi_t afi;
|
|
safi_t safi;
|
|
|
|
enable_svrf = vrf->info;
|
|
|
|
RB_FOREACH (svrf, svrf_name_head, &svrfs) {
|
|
/* Install any static routes configured for this VRF. */
|
|
FOREACH_AFI_SAFI (afi, safi) {
|
|
stable = svrf->stable[afi][safi];
|
|
if (!stable)
|
|
continue;
|
|
|
|
static_fixup_vrf(vrf, stable, afi, safi);
|
|
|
|
if (enable_svrf == svrf)
|
|
static_enable_vrf(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 vrf *vrf, struct route_table *stable,
|
|
afi_t afi, safi_t safi)
|
|
{
|
|
struct route_node *rn;
|
|
struct static_nexthop *nh;
|
|
struct static_path *pn;
|
|
struct static_route_info *si;
|
|
|
|
for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) {
|
|
si = static_route_info_from_rnode(rn);
|
|
if (!si)
|
|
continue;
|
|
frr_each(static_path_list, &si->path_list, pn) {
|
|
frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
|
|
if (strcmp(vrf->name, nh->nh_vrfname) != 0)
|
|
continue;
|
|
|
|
static_uninstall_nexthop(nh);
|
|
|
|
nh->nh_vrf_id = VRF_UNKNOWN;
|
|
nh->ifindex = IFINDEX_INTERNAL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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_path *pn;
|
|
struct static_route_info *si;
|
|
|
|
for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) {
|
|
si = static_route_info_from_rnode(rn);
|
|
if (!si)
|
|
continue;
|
|
frr_each(static_path_list, &si->path_list, pn)
|
|
static_uninstall_path(pn);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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 vrf *vrf)
|
|
{
|
|
struct route_table *stable;
|
|
struct static_vrf *svrf, *disable_svrf;
|
|
afi_t afi;
|
|
safi_t safi;
|
|
|
|
disable_svrf = vrf->info;
|
|
|
|
RB_FOREACH (svrf, svrf_name_head, &svrfs) {
|
|
/* Uninstall any static routes configured for this VRF. */
|
|
FOREACH_AFI_SAFI (afi, safi) {
|
|
stable = svrf->stable[afi][safi];
|
|
if (!stable)
|
|
continue;
|
|
|
|
static_cleanup_vrf(vrf, 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);
|
|
}
|
|
|
|
struct stable_info *static_get_stable_info(struct route_node *rn)
|
|
{
|
|
struct route_table *table;
|
|
|
|
table = srcdest_rnode_table(rn);
|
|
return table->info;
|
|
}
|
|
|
|
void static_get_nh_str(struct static_nexthop *nh, char *nexthop, size_t size)
|
|
{
|
|
switch (nh->type) {
|
|
case STATIC_IFNAME:
|
|
snprintfrr(nexthop, size, "ifindex : %s", nh->ifname);
|
|
break;
|
|
case STATIC_IPV4_GATEWAY:
|
|
snprintfrr(nexthop, size, "ip4 : %pI4", &nh->addr.ipv4);
|
|
break;
|
|
case STATIC_IPV4_GATEWAY_IFNAME:
|
|
snprintfrr(nexthop, size, "ip4-ifindex : %pI4 : %s",
|
|
&nh->addr.ipv4, nh->ifname);
|
|
break;
|
|
case STATIC_BLACKHOLE:
|
|
snprintfrr(nexthop, size, "blackhole : %d", nh->bh_type);
|
|
break;
|
|
case STATIC_IPV6_GATEWAY:
|
|
snprintfrr(nexthop, size, "ip6 : %pI6", &nh->addr.ipv6);
|
|
break;
|
|
case STATIC_IPV6_GATEWAY_IFNAME:
|
|
snprintfrr(nexthop, size, "ip6-ifindex : %pI6 : %s",
|
|
&nh->addr.ipv6, nh->ifname);
|
|
break;
|
|
};
|
|
}
|