mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-13 21:10:28 +00:00
zebra: rework recursive route resolution
Change the datastructure for recursive routes. This brings the following benefits: By using struct nexthop also to store nexthops obtained by recursive resolution, we can get rid of quite a bit of code duplication in the fib management. (rt_netlink, rt_socket, ...) With the new datastructure we can make use of all available paths when recursive routes are resolved with multipath routes. Signed-off-by: Christian Franke <chris@opensourcerouting.org> Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
This commit is contained in:
parent
bfac8dcd2f
commit
fa713d9ee5
1
tests/.gitignore
vendored
1
tests/.gitignore
vendored
@ -31,4 +31,5 @@ testmemory
|
|||||||
testprivs
|
testprivs
|
||||||
testsig
|
testsig
|
||||||
teststream
|
teststream
|
||||||
|
testnexthopiter
|
||||||
site.exp
|
site.exp
|
||||||
|
@ -25,7 +25,7 @@ TESTS_BGPD =
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
check_PROGRAMS = testsig testbuffer testmemory heavy heavywq heavythread \
|
check_PROGRAMS = testsig testbuffer testmemory heavy heavywq heavythread \
|
||||||
testprivs teststream testchecksum tabletest \
|
testprivs teststream testchecksum tabletest testnexthopiter \
|
||||||
$(TESTS_BGPD)
|
$(TESTS_BGPD)
|
||||||
|
|
||||||
testsig_SOURCES = test-sig.c
|
testsig_SOURCES = test-sig.c
|
||||||
@ -43,6 +43,7 @@ testbgpmpattr_SOURCES = bgp_mp_attr_test.c
|
|||||||
testchecksum_SOURCES = test-checksum.c
|
testchecksum_SOURCES = test-checksum.c
|
||||||
testbgpmpath_SOURCES = bgp_mpath_test.c
|
testbgpmpath_SOURCES = bgp_mpath_test.c
|
||||||
tabletest_SOURCES = table_test.c
|
tabletest_SOURCES = table_test.c
|
||||||
|
testnexthopiter_SOURCES = test-nexthop-iter.c prng.c
|
||||||
|
|
||||||
testsig_LDADD = ../lib/libzebra.la @LIBCAP@
|
testsig_LDADD = ../lib/libzebra.la @LIBCAP@
|
||||||
testbuffer_LDADD = ../lib/libzebra.la @LIBCAP@
|
testbuffer_LDADD = ../lib/libzebra.la @LIBCAP@
|
||||||
@ -59,3 +60,4 @@ testbgpmpattr_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm
|
|||||||
testchecksum_LDADD = ../lib/libzebra.la @LIBCAP@
|
testchecksum_LDADD = ../lib/libzebra.la @LIBCAP@
|
||||||
testbgpmpath_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm
|
testbgpmpath_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm
|
||||||
tabletest_LDADD = ../lib/libzebra.la @LIBCAP@ -lm
|
tabletest_LDADD = ../lib/libzebra.la @LIBCAP@ -lm
|
||||||
|
testnexthopiter_LDADD = ../lib/libzebra.la @LIBCAP@
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
tabletest.exp
|
tabletest.exp \
|
||||||
|
testnexthopiter.exp
|
||||||
|
8
tests/libzebra.tests/testnexthopiter.exp
Normal file
8
tests/libzebra.tests/testnexthopiter.exp
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
set timeout 10
|
||||||
|
set testprefix "testnexthopiter "
|
||||||
|
set aborted 0
|
||||||
|
|
||||||
|
spawn "./testnexthopiter"
|
||||||
|
|
||||||
|
onesimple "simple" "Simple test passed."
|
||||||
|
onesimple "prng" "PRNG test passed."
|
82
tests/prng.c
Normal file
82
tests/prng.c
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* Very simple prng to allow for randomized tests with reproducable
|
||||||
|
* results.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 by Open Source Routing.
|
||||||
|
* Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
*
|
||||||
|
* This file is part of Quagga
|
||||||
|
*
|
||||||
|
* Quagga 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.
|
||||||
|
*
|
||||||
|
* Quagga 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 Quagga; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "prng.h"
|
||||||
|
|
||||||
|
struct prng
|
||||||
|
{
|
||||||
|
unsigned long long state1;
|
||||||
|
unsigned long long state2;
|
||||||
|
};
|
||||||
|
|
||||||
|
static char
|
||||||
|
prng_bit(struct prng *prng)
|
||||||
|
{
|
||||||
|
prng->state1 *= 2416;
|
||||||
|
prng->state1 += 374441;
|
||||||
|
prng->state1 %= 1771875;
|
||||||
|
|
||||||
|
if (prng->state1 % 2)
|
||||||
|
{
|
||||||
|
prng->state2 *= 84589;
|
||||||
|
prng->state2 += 45989;
|
||||||
|
prng->state2 %= 217728;
|
||||||
|
}
|
||||||
|
|
||||||
|
return prng->state2 % 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct prng*
|
||||||
|
prng_new(unsigned long long seed)
|
||||||
|
{
|
||||||
|
struct prng *rv = calloc(sizeof(*rv), 1);
|
||||||
|
assert(rv);
|
||||||
|
|
||||||
|
rv->state1 = rv->state2 = seed;
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
prng_rand(struct prng *prng)
|
||||||
|
{
|
||||||
|
unsigned int i, rv = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 32; i++)
|
||||||
|
{
|
||||||
|
rv |= prng_bit(prng);
|
||||||
|
rv <<= 1;
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
prng_free(struct prng *prng)
|
||||||
|
{
|
||||||
|
free(prng);
|
||||||
|
}
|
34
tests/prng.h
Normal file
34
tests/prng.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Very simple prng to allow for randomized tests with reproducable
|
||||||
|
* results.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 by Open Source Routing.
|
||||||
|
* Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
*
|
||||||
|
* This file is part of Quagga
|
||||||
|
*
|
||||||
|
* Quagga 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.
|
||||||
|
*
|
||||||
|
* Quagga 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 Quagga; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
#ifndef _PRNG_H
|
||||||
|
#define _PRNG_H
|
||||||
|
|
||||||
|
struct prng;
|
||||||
|
|
||||||
|
struct prng* prng_new(unsigned long long seed);
|
||||||
|
unsigned int prng_rand(struct prng*);
|
||||||
|
void prng_free(struct prng *);
|
||||||
|
|
||||||
|
#endif
|
291
tests/test-nexthop-iter.c
Normal file
291
tests/test-nexthop-iter.c
Normal file
@ -0,0 +1,291 @@
|
|||||||
|
/*
|
||||||
|
* Recursive Nexthop Iterator test.
|
||||||
|
* This tests the ALL_NEXTHOPS_RO macro.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 by Open Source Routing.
|
||||||
|
* Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
*
|
||||||
|
* This file is part of Quagga
|
||||||
|
*
|
||||||
|
* Quagga 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.
|
||||||
|
*
|
||||||
|
* Quagga 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 Quagga; see the file COPYING. If not, write to the Free
|
||||||
|
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zebra.h>
|
||||||
|
#include "zebra/rib.h"
|
||||||
|
#include "prng.h"
|
||||||
|
|
||||||
|
struct thread_master *master;
|
||||||
|
static int verbose;
|
||||||
|
|
||||||
|
static void
|
||||||
|
str_append(char **buf, const char *repr)
|
||||||
|
{
|
||||||
|
if (*buf)
|
||||||
|
{
|
||||||
|
*buf = realloc(*buf, strlen(*buf) + strlen(repr) + 1);
|
||||||
|
assert(*buf);
|
||||||
|
strncpy((*buf) + strlen(*buf), repr, strlen(repr) + 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*buf = strdup(repr);
|
||||||
|
assert(*buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
str_appendf(char **buf, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
int rv;
|
||||||
|
char *pbuf;
|
||||||
|
|
||||||
|
va_start(ap, format);
|
||||||
|
rv = vasprintf(&pbuf, format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
assert(rv >= 0);
|
||||||
|
|
||||||
|
str_append(buf, pbuf);
|
||||||
|
free(pbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This structure contains a nexthop chain
|
||||||
|
* and its expected representation */
|
||||||
|
struct nexthop_chain
|
||||||
|
{
|
||||||
|
/* Head of the chain */
|
||||||
|
struct nexthop *head;
|
||||||
|
/* Last nexthop in top chain */
|
||||||
|
struct nexthop *current_top;
|
||||||
|
/* Last nexthop in current recursive chain */
|
||||||
|
struct nexthop *current_recursive;
|
||||||
|
/* Expected string representation. */
|
||||||
|
char *repr;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct nexthop_chain*
|
||||||
|
nexthop_chain_new(void)
|
||||||
|
{
|
||||||
|
struct nexthop_chain *rv;
|
||||||
|
|
||||||
|
rv = calloc(sizeof(*rv), 1);
|
||||||
|
assert(rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nexthop_chain_add_top(struct nexthop_chain *nc)
|
||||||
|
{
|
||||||
|
struct nexthop *nh;
|
||||||
|
|
||||||
|
nh = calloc(sizeof(*nh), 1);
|
||||||
|
assert(nh);
|
||||||
|
|
||||||
|
if (nc->head)
|
||||||
|
{
|
||||||
|
nc->current_top->next = nh;
|
||||||
|
nh->prev = nc->current_top;
|
||||||
|
nc->current_top = nh;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nc->head = nc->current_top = nh;
|
||||||
|
}
|
||||||
|
nc->current_recursive = NULL;
|
||||||
|
str_appendf(&nc->repr, "%p\n", nh);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nexthop_chain_add_recursive(struct nexthop_chain *nc)
|
||||||
|
{
|
||||||
|
struct nexthop *nh;
|
||||||
|
|
||||||
|
nh = calloc(sizeof(*nh), 1);
|
||||||
|
assert(nh);
|
||||||
|
|
||||||
|
assert(nc->current_top);
|
||||||
|
if (nc->current_recursive)
|
||||||
|
{
|
||||||
|
nc->current_recursive->next = nh;
|
||||||
|
nh->prev = nc->current_recursive;
|
||||||
|
nc->current_recursive = nh;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SET_FLAG(nc->current_top->flags, NEXTHOP_FLAG_RECURSIVE);
|
||||||
|
nc->current_top->resolved = nh;
|
||||||
|
nc->current_recursive = nh;
|
||||||
|
}
|
||||||
|
str_appendf(&nc->repr, " %p\n", nh);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nexthop_chain_clear(struct nexthop_chain *nc)
|
||||||
|
{
|
||||||
|
struct nexthop *tcur, *tnext;
|
||||||
|
|
||||||
|
for (tcur = nc->head; tcur; tcur = tnext)
|
||||||
|
{
|
||||||
|
tnext = tcur->next;
|
||||||
|
if (CHECK_FLAG(tcur->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||||
|
{
|
||||||
|
struct nexthop *rcur, *rnext;
|
||||||
|
for (rcur = tcur->resolved; rcur; rcur = rnext)
|
||||||
|
{
|
||||||
|
rnext = rcur->next;
|
||||||
|
free(rcur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(tcur);
|
||||||
|
}
|
||||||
|
nc->head = nc->current_top = nc->current_recursive = NULL;
|
||||||
|
free(nc->repr);
|
||||||
|
nc->repr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nexthop_chain_free(struct nexthop_chain *nc)
|
||||||
|
{
|
||||||
|
if (!nc)
|
||||||
|
return;
|
||||||
|
nexthop_chain_clear(nc);
|
||||||
|
free(nc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function builds a string representation of
|
||||||
|
* the nexthop chain using the ALL_NEXTHOPS_RO macro.
|
||||||
|
* It verifies that the ALL_NEXTHOPS_RO macro iterated
|
||||||
|
* correctly over the nexthop chain by comparing the
|
||||||
|
* generated representation with the expected representation.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
nexthop_chain_verify_iter(struct nexthop_chain *nc)
|
||||||
|
{
|
||||||
|
struct nexthop *nh, *tnh;
|
||||||
|
int recursing;
|
||||||
|
char *repr = NULL;
|
||||||
|
|
||||||
|
for (ALL_NEXTHOPS_RO(nc->head, nh, tnh, recursing))
|
||||||
|
{
|
||||||
|
if (recursing)
|
||||||
|
str_appendf(&repr, " %p\n", nh);
|
||||||
|
else
|
||||||
|
str_appendf(&repr, "%p\n", nh);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (repr && verbose)
|
||||||
|
printf("===\n%s", repr);
|
||||||
|
assert((!repr && !nc->repr) || (repr && nc->repr && !strcmp(repr, nc->repr)));
|
||||||
|
free(repr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This test run builds a simple nexthop chain
|
||||||
|
* with some recursive nexthops and verifies that
|
||||||
|
* the iterator works correctly in each stage along
|
||||||
|
* the way.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
test_run_first(void)
|
||||||
|
{
|
||||||
|
struct nexthop_chain *nc;
|
||||||
|
|
||||||
|
nc = nexthop_chain_new();
|
||||||
|
nexthop_chain_verify_iter(nc);
|
||||||
|
|
||||||
|
nexthop_chain_add_top(nc);
|
||||||
|
nexthop_chain_verify_iter(nc);
|
||||||
|
|
||||||
|
nexthop_chain_add_top(nc);
|
||||||
|
nexthop_chain_verify_iter(nc);
|
||||||
|
|
||||||
|
nexthop_chain_add_recursive(nc);
|
||||||
|
nexthop_chain_verify_iter(nc);
|
||||||
|
|
||||||
|
nexthop_chain_add_recursive(nc);
|
||||||
|
nexthop_chain_verify_iter(nc);
|
||||||
|
|
||||||
|
nexthop_chain_add_top(nc);
|
||||||
|
nexthop_chain_verify_iter(nc);
|
||||||
|
|
||||||
|
nexthop_chain_add_top(nc);
|
||||||
|
nexthop_chain_verify_iter(nc);
|
||||||
|
|
||||||
|
nexthop_chain_add_top(nc);
|
||||||
|
nexthop_chain_verify_iter(nc);
|
||||||
|
|
||||||
|
nexthop_chain_add_recursive(nc);
|
||||||
|
nexthop_chain_verify_iter(nc);
|
||||||
|
|
||||||
|
nexthop_chain_add_recursive(nc);
|
||||||
|
nexthop_chain_verify_iter(nc);
|
||||||
|
|
||||||
|
nexthop_chain_add_recursive(nc);
|
||||||
|
nexthop_chain_verify_iter(nc);
|
||||||
|
|
||||||
|
nexthop_chain_free(nc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This test run builds numerous random
|
||||||
|
* nexthop chain configurations and verifies
|
||||||
|
* that the iterator correctly progresses
|
||||||
|
* through each. */
|
||||||
|
static void
|
||||||
|
test_run_prng(void)
|
||||||
|
{
|
||||||
|
struct nexthop_chain *nc;
|
||||||
|
struct prng *prng;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
nc = nexthop_chain_new();
|
||||||
|
prng = prng_new(0);
|
||||||
|
|
||||||
|
for (i = 0; i < 1000000; i++)
|
||||||
|
{
|
||||||
|
switch (prng_rand(prng) % 10)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
nexthop_chain_clear(nc);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
nexthop_chain_add_top(nc);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
case 7:
|
||||||
|
case 8:
|
||||||
|
case 9:
|
||||||
|
if (nc->current_top)
|
||||||
|
nexthop_chain_add_recursive(nc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
nexthop_chain_verify_iter(nc);
|
||||||
|
}
|
||||||
|
nexthop_chain_free(nc);
|
||||||
|
prng_free(prng);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if (argc >= 2 && !strcmp("-v", argv[1]))
|
||||||
|
verbose = 1;
|
||||||
|
test_run_first();
|
||||||
|
printf("Simple test passed.\n");
|
||||||
|
test_run_prng();
|
||||||
|
printf("PRNG test passed.\n");
|
||||||
|
}
|
62
zebra/rib.h
62
zebra/rib.h
@ -254,16 +254,65 @@ struct nexthop
|
|||||||
#define NEXTHOP_FLAG_FIB (1 << 1) /* FIB nexthop. */
|
#define NEXTHOP_FLAG_FIB (1 << 1) /* FIB nexthop. */
|
||||||
#define NEXTHOP_FLAG_RECURSIVE (1 << 2) /* Recursive nexthop. */
|
#define NEXTHOP_FLAG_RECURSIVE (1 << 2) /* Recursive nexthop. */
|
||||||
|
|
||||||
/* Nexthop address or interface name. */
|
/* Nexthop address */
|
||||||
union g_addr gate;
|
union g_addr gate;
|
||||||
|
|
||||||
/* Recursive lookup nexthop. */
|
|
||||||
u_char rtype;
|
|
||||||
unsigned int rifindex;
|
|
||||||
union g_addr rgate;
|
|
||||||
union g_addr src;
|
union g_addr src;
|
||||||
|
|
||||||
|
/* Nexthops obtained by recursive resolution.
|
||||||
|
*
|
||||||
|
* If the nexthop struct needs to be resolved recursively,
|
||||||
|
* NEXTHOP_FLAG_RECURSIVE will be set in flags and the nexthops
|
||||||
|
* obtained by recursive resolution will be added to `resolved'.
|
||||||
|
* Only one level of recursive resolution is currently supported. */
|
||||||
|
struct nexthop *resolved;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* The following for loop allows to iterate over the nexthop
|
||||||
|
* structure of routes.
|
||||||
|
*
|
||||||
|
* We have to maintain quite a bit of state:
|
||||||
|
*
|
||||||
|
* nexthop: The pointer to the current nexthop, either in the
|
||||||
|
* top-level chain or in the resolved chain of ni.
|
||||||
|
* tnexthop: The pointer to the current nexthop in the top-level
|
||||||
|
* nexthop chain.
|
||||||
|
* recursing: Information if nh currently is in the top-level chain
|
||||||
|
* (0) or in a resolved chain (1).
|
||||||
|
*
|
||||||
|
* Initialization: Set `nexthop' and `tnexthop' to the head of the
|
||||||
|
* top-level chain. As nexthop is in the top level chain, set recursing
|
||||||
|
* to 0.
|
||||||
|
*
|
||||||
|
* Iteration check: Check that the `nexthop' pointer is not NULL.
|
||||||
|
*
|
||||||
|
* Iteration step: This is the tricky part. Check if `nexthop' has
|
||||||
|
* NEXTHOP_FLAG_RECURSIVE set. If yes, this implies that `nexthop' is in
|
||||||
|
* the top level chain and has at least one nexthop attached to
|
||||||
|
* `nexthop->resolved'. As we want to descend into `nexthop->resolved',
|
||||||
|
* set `recursing' to 1 and set `nexthop' to `nexthop->resolved'.
|
||||||
|
* `tnexthop' is left alone in that case so we can remember which nexthop
|
||||||
|
* in the top level chain we are currently handling.
|
||||||
|
*
|
||||||
|
* If NEXTHOP_FLAG_RECURSIVE is not set, `nexthop' will progress in its
|
||||||
|
* current chain. If we are recursing, `nexthop' will be set to
|
||||||
|
* `nexthop->next' and `tnexthop' will be left alone. If we are not
|
||||||
|
* recursing, both `tnexthop' and `nexthop' will be set to `nexthop->next'
|
||||||
|
* as we are progressing in the top level chain.
|
||||||
|
* If we encounter `nexthop->next == NULL', we will clear the `recursing'
|
||||||
|
* flag as we arived either at the end of the resolved chain or at the end
|
||||||
|
* of the top level chain. In both cases, we set `tnexthop' and `nexthop'
|
||||||
|
* to `tnexthop->next', progressing to the next position in the top-level
|
||||||
|
* chain and possibly to its end marked by NULL.
|
||||||
|
*/
|
||||||
|
#define ALL_NEXTHOPS_RO(head, nexthop, tnexthop, recursing) \
|
||||||
|
(tnexthop) = (nexthop) = (head), (recursing) = 0; \
|
||||||
|
(nexthop); \
|
||||||
|
(nexthop) = CHECK_FLAG((nexthop)->flags, NEXTHOP_FLAG_RECURSIVE) \
|
||||||
|
? (((recursing) = 1), (nexthop)->resolved) \
|
||||||
|
: ((nexthop)->next ? ((recursing) ? (nexthop)->next \
|
||||||
|
: ((tnexthop) = (nexthop)->next)) \
|
||||||
|
: (((recursing) = 0),((tnexthop) = (tnexthop)->next)))
|
||||||
|
|
||||||
/* Routing table instance. */
|
/* Routing table instance. */
|
||||||
struct vrf
|
struct vrf
|
||||||
{
|
{
|
||||||
@ -333,6 +382,7 @@ extern struct nexthop *nexthop_ipv4_ifindex_add (struct rib *,
|
|||||||
struct in_addr *,
|
struct in_addr *,
|
||||||
struct in_addr *,
|
struct in_addr *,
|
||||||
unsigned int);
|
unsigned int);
|
||||||
|
extern int nexthop_has_fib_child(struct nexthop *);
|
||||||
extern void rib_lookup_and_dump (struct prefix_ipv4 *);
|
extern void rib_lookup_and_dump (struct prefix_ipv4 *);
|
||||||
extern void rib_lookup_and_pushup (struct prefix_ipv4 *);
|
extern void rib_lookup_and_pushup (struct prefix_ipv4 *);
|
||||||
extern void rib_dump (const char *, const struct prefix_ipv4 *, const struct rib *);
|
extern void rib_dump (const char *, const struct prefix_ipv4 *, const struct rib *);
|
||||||
|
122
zebra/rt_ioctl.c
122
zebra/rt_ioctl.c
@ -169,7 +169,8 @@ kernel_ioctl_ipv4 (u_long cmd, struct prefix *p, struct rib *rib, int family)
|
|||||||
int sock;
|
int sock;
|
||||||
struct rtentry rtentry;
|
struct rtentry rtentry;
|
||||||
struct sockaddr_in sin_dest, sin_mask, sin_gate;
|
struct sockaddr_in sin_dest, sin_mask, sin_gate;
|
||||||
struct nexthop *nexthop;
|
struct nexthop *nexthop, *tnexthop;
|
||||||
|
int recursing;
|
||||||
int nexthop_num = 0;
|
int nexthop_num = 0;
|
||||||
struct interface *ifp;
|
struct interface *ifp;
|
||||||
|
|
||||||
@ -188,65 +189,49 @@ kernel_ioctl_ipv4 (u_long cmd, struct prefix *p, struct rib *rib, int family)
|
|||||||
SET_FLAG (rtentry.rt_flags, RTF_REJECT);
|
SET_FLAG (rtentry.rt_flags, RTF_REJECT);
|
||||||
|
|
||||||
if (cmd == SIOCADDRT)
|
if (cmd == SIOCADDRT)
|
||||||
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
|
for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
|
||||||
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
|
{
|
||||||
|
/* We shouldn't encounter recursive nexthops on discard routes,
|
||||||
|
* but it is probably better to handle that case correctly anyway.
|
||||||
|
*/
|
||||||
|
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||||
|
continue;
|
||||||
|
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
|
||||||
|
}
|
||||||
goto skip;
|
goto skip;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset (&sin_gate, 0, sizeof (struct sockaddr_in));
|
memset (&sin_gate, 0, sizeof (struct sockaddr_in));
|
||||||
|
|
||||||
/* Make gateway. */
|
/* Make gateway. */
|
||||||
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
|
for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
|
||||||
{
|
{
|
||||||
|
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||||
|
continue;
|
||||||
|
|
||||||
if ((cmd == SIOCADDRT
|
if ((cmd == SIOCADDRT
|
||||||
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|
||||||
|| (cmd == SIOCDELRT
|
|| (cmd == SIOCDELRT
|
||||||
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
|
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
|
||||||
{
|
{
|
||||||
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
|
||||||
|
nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
|
||||||
{
|
{
|
||||||
if (nexthop->rtype == NEXTHOP_TYPE_IPV4 ||
|
sin_gate.sin_family = AF_INET;
|
||||||
nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
|
|
||||||
{
|
|
||||||
sin_gate.sin_family = AF_INET;
|
|
||||||
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
|
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
|
||||||
sin_gate.sin_len = sizeof (struct sockaddr_in);
|
sin_gate.sin_len = sizeof (struct sockaddr_in);
|
||||||
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
|
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
|
||||||
sin_gate.sin_addr = nexthop->rgate.ipv4;
|
sin_gate.sin_addr = nexthop->gate.ipv4;
|
||||||
rtentry.rt_flags |= RTF_GATEWAY;
|
rtentry.rt_flags |= RTF_GATEWAY;
|
||||||
}
|
|
||||||
if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
|
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IFNAME)
|
|
||||||
{
|
|
||||||
ifp = if_lookup_by_index (nexthop->rifindex);
|
|
||||||
if (ifp)
|
|
||||||
rtentry.rt_dev = ifp->name;
|
|
||||||
else
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
if (nexthop->type == NEXTHOP_TYPE_IFINDEX
|
||||||
|
|| nexthop->type == NEXTHOP_TYPE_IFNAME)
|
||||||
{
|
{
|
||||||
if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
|
ifp = if_lookup_by_index (nexthop->ifindex);
|
||||||
nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
|
if (ifp)
|
||||||
{
|
rtentry.rt_dev = ifp->name;
|
||||||
sin_gate.sin_family = AF_INET;
|
else
|
||||||
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
|
return -1;
|
||||||
sin_gate.sin_len = sizeof (struct sockaddr_in);
|
|
||||||
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
|
|
||||||
sin_gate.sin_addr = nexthop->gate.ipv4;
|
|
||||||
rtentry.rt_flags |= RTF_GATEWAY;
|
|
||||||
}
|
|
||||||
if (nexthop->type == NEXTHOP_TYPE_IFINDEX
|
|
||||||
|| nexthop->type == NEXTHOP_TYPE_IFNAME)
|
|
||||||
{
|
|
||||||
ifp = if_lookup_by_index (nexthop->ifindex);
|
|
||||||
if (ifp)
|
|
||||||
rtentry.rt_dev = ifp->name;
|
|
||||||
else
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmd == SIOCADDRT)
|
if (cmd == SIOCADDRT)
|
||||||
@ -430,7 +415,8 @@ kernel_ioctl_ipv6_multipath (u_long cmd, struct prefix *p, struct rib *rib,
|
|||||||
int ret;
|
int ret;
|
||||||
int sock;
|
int sock;
|
||||||
struct in6_rtmsg rtm;
|
struct in6_rtmsg rtm;
|
||||||
struct nexthop *nexthop;
|
struct nexthop *nexthop, *tnexthop;
|
||||||
|
int recursing;
|
||||||
int nexthop_num = 0;
|
int nexthop_num = 0;
|
||||||
|
|
||||||
memset (&rtm, 0, sizeof (struct in6_rtmsg));
|
memset (&rtm, 0, sizeof (struct in6_rtmsg));
|
||||||
@ -456,48 +442,30 @@ kernel_ioctl_ipv6_multipath (u_long cmd, struct prefix *p, struct rib *rib,
|
|||||||
/* rtm.rtmsg_flags |= RTF_DYNAMIC; */
|
/* rtm.rtmsg_flags |= RTF_DYNAMIC; */
|
||||||
|
|
||||||
/* Make gateway. */
|
/* Make gateway. */
|
||||||
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
|
for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
|
||||||
{
|
{
|
||||||
|
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||||
|
continue;
|
||||||
|
|
||||||
if ((cmd == SIOCADDRT
|
if ((cmd == SIOCADDRT
|
||||||
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|
||||||
|| (cmd == SIOCDELRT
|
|| (cmd == SIOCDELRT
|
||||||
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
|
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
|
||||||
{
|
{
|
||||||
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
if (nexthop->type == NEXTHOP_TYPE_IPV6
|
||||||
|
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
|
||||||
|
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
|
||||||
{
|
{
|
||||||
if (nexthop->rtype == NEXTHOP_TYPE_IPV6
|
memcpy (&rtm.rtmsg_gateway, &nexthop->gate.ipv6,
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
|
sizeof (struct in6_addr));
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
|
|
||||||
{
|
|
||||||
memcpy (&rtm.rtmsg_gateway, &nexthop->rgate.ipv6,
|
|
||||||
sizeof (struct in6_addr));
|
|
||||||
}
|
|
||||||
if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
|
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IFNAME
|
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
|
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
|
|
||||||
rtm.rtmsg_ifindex = nexthop->rifindex;
|
|
||||||
else
|
|
||||||
rtm.rtmsg_ifindex = 0;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
if (nexthop->type == NEXTHOP_TYPE_IFINDEX
|
||||||
|
|| nexthop->type == NEXTHOP_TYPE_IFNAME
|
||||||
|
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
|
||||||
|
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
|
||||||
|
rtm.rtmsg_ifindex = nexthop->ifindex;
|
||||||
else
|
else
|
||||||
{
|
rtm.rtmsg_ifindex = 0;
|
||||||
if (nexthop->type == NEXTHOP_TYPE_IPV6
|
|
||||||
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
|
|
||||||
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
|
|
||||||
{
|
|
||||||
memcpy (&rtm.rtmsg_gateway, &nexthop->gate.ipv6,
|
|
||||||
sizeof (struct in6_addr));
|
|
||||||
}
|
|
||||||
if (nexthop->type == NEXTHOP_TYPE_IFINDEX
|
|
||||||
|| nexthop->type == NEXTHOP_TYPE_IFNAME
|
|
||||||
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
|
|
||||||
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
|
|
||||||
rtm.rtmsg_ifindex = nexthop->ifindex;
|
|
||||||
else
|
|
||||||
rtm.rtmsg_ifindex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cmd == SIOCADDRT)
|
if (cmd == SIOCADDRT)
|
||||||
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
|
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
|
||||||
|
@ -1426,6 +1426,207 @@ netlink_route (int cmd, int family, void *dest, int length, void *gate,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This function takes a nexthop as argument and adds
|
||||||
|
* the appropriate netlink attributes to an existing
|
||||||
|
* netlink message.
|
||||||
|
*
|
||||||
|
* @param routedesc: Human readable description of route type
|
||||||
|
* (direct/recursive, single-/multipath)
|
||||||
|
* @param bytelen: Length of addresses in bytes.
|
||||||
|
* @param nexthop: Nexthop information
|
||||||
|
* @param nlmsg: nlmsghdr structure to fill in.
|
||||||
|
* @param req_size: The size allocated for the message.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
_netlink_route_build_singlepath(
|
||||||
|
const char *routedesc,
|
||||||
|
int bytelen,
|
||||||
|
struct nexthop *nexthop,
|
||||||
|
struct nlmsghdr *nlmsg,
|
||||||
|
size_t req_size)
|
||||||
|
{
|
||||||
|
if (nexthop->type == NEXTHOP_TYPE_IPV4
|
||||||
|
|| nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
|
||||||
|
{
|
||||||
|
addattr_l (nlmsg, req_size, RTA_GATEWAY,
|
||||||
|
&nexthop->gate.ipv4, bytelen);
|
||||||
|
if (nexthop->src.ipv4.s_addr)
|
||||||
|
addattr_l (nlmsg, req_size, RTA_PREFSRC,
|
||||||
|
&nexthop->src.ipv4, bytelen);
|
||||||
|
|
||||||
|
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||||
|
zlog_debug("netlink_route_multipath() (%s): "
|
||||||
|
"nexthop via %s if %u",
|
||||||
|
routedesc,
|
||||||
|
inet_ntoa (nexthop->gate.ipv4),
|
||||||
|
nexthop->ifindex);
|
||||||
|
}
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
if (nexthop->type == NEXTHOP_TYPE_IPV6
|
||||||
|
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
|
||||||
|
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
|
||||||
|
{
|
||||||
|
addattr_l (nlmsg, req_size, RTA_GATEWAY,
|
||||||
|
&nexthop->gate.ipv6, bytelen);
|
||||||
|
|
||||||
|
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||||
|
zlog_debug("netlink_route_multipath() (%s): "
|
||||||
|
"nexthop via %s if %u",
|
||||||
|
routedesc,
|
||||||
|
inet6_ntoa (nexthop->gate.ipv6),
|
||||||
|
nexthop->ifindex);
|
||||||
|
}
|
||||||
|
#endif /* HAVE_IPV6 */
|
||||||
|
if (nexthop->type == NEXTHOP_TYPE_IFINDEX
|
||||||
|
|| nexthop->type == NEXTHOP_TYPE_IFNAME
|
||||||
|
|| nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
|
||||||
|
{
|
||||||
|
addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex);
|
||||||
|
|
||||||
|
if (nexthop->src.ipv4.s_addr)
|
||||||
|
addattr_l (nlmsg, req_size, RTA_PREFSRC,
|
||||||
|
&nexthop->src.ipv4, bytelen);
|
||||||
|
|
||||||
|
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||||
|
zlog_debug("netlink_route_multipath() (%s): "
|
||||||
|
"nexthop via if %u", routedesc, nexthop->ifindex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
|
||||||
|
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
|
||||||
|
{
|
||||||
|
addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex);
|
||||||
|
|
||||||
|
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||||
|
zlog_debug("netlink_route_multipath() (%s): "
|
||||||
|
"nexthop via if %u", routedesc, nexthop->ifindex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function takes a nexthop as argument and
|
||||||
|
* appends to the given rtattr/rtnexthop pair the
|
||||||
|
* representation of the nexthop. If the nexthop
|
||||||
|
* defines a preferred source, the src parameter
|
||||||
|
* will be modified to point to that src, otherwise
|
||||||
|
* it will be kept unmodified.
|
||||||
|
*
|
||||||
|
* @param routedesc: Human readable description of route type
|
||||||
|
* (direct/recursive, single-/multipath)
|
||||||
|
* @param bytelen: Length of addresses in bytes.
|
||||||
|
* @param nexthop: Nexthop information
|
||||||
|
* @param rta: rtnetlink attribute structure
|
||||||
|
* @param rtnh: pointer to an rtnetlink nexthop structure
|
||||||
|
* @param src: pointer pointing to a location where
|
||||||
|
* the prefsrc should be stored.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
_netlink_route_build_multipath(
|
||||||
|
const char *routedesc,
|
||||||
|
int bytelen,
|
||||||
|
struct nexthop *nexthop,
|
||||||
|
struct rtattr *rta,
|
||||||
|
struct rtnexthop *rtnh,
|
||||||
|
union g_addr **src
|
||||||
|
)
|
||||||
|
{
|
||||||
|
rtnh->rtnh_len = sizeof (*rtnh);
|
||||||
|
rtnh->rtnh_flags = 0;
|
||||||
|
rtnh->rtnh_hops = 0;
|
||||||
|
rta->rta_len += rtnh->rtnh_len;
|
||||||
|
|
||||||
|
if (nexthop->type == NEXTHOP_TYPE_IPV4
|
||||||
|
|| nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
|
||||||
|
{
|
||||||
|
rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
|
||||||
|
&nexthop->gate.ipv4, bytelen);
|
||||||
|
rtnh->rtnh_len += sizeof (struct rtattr) + 4;
|
||||||
|
|
||||||
|
if (nexthop->src.ipv4.s_addr)
|
||||||
|
*src = &nexthop->src;
|
||||||
|
|
||||||
|
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||||
|
zlog_debug("netlink_route_multipath() (%s): "
|
||||||
|
"nexthop via %s if %u",
|
||||||
|
routedesc,
|
||||||
|
inet_ntoa (nexthop->gate.ipv4),
|
||||||
|
nexthop->ifindex);
|
||||||
|
}
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
if (nexthop->type == NEXTHOP_TYPE_IPV6
|
||||||
|
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
|
||||||
|
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
|
||||||
|
{
|
||||||
|
rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
|
||||||
|
&nexthop->gate.ipv6, bytelen);
|
||||||
|
|
||||||
|
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||||
|
zlog_debug("netlink_route_multipath() (%s): "
|
||||||
|
"nexthop via %s if %u",
|
||||||
|
routedesc,
|
||||||
|
inet6_ntoa (nexthop->gate.ipv6),
|
||||||
|
nexthop->ifindex);
|
||||||
|
}
|
||||||
|
#endif /* HAVE_IPV6 */
|
||||||
|
/* ifindex */
|
||||||
|
if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
|
||||||
|
|| nexthop->type == NEXTHOP_TYPE_IFINDEX
|
||||||
|
|| nexthop->type == NEXTHOP_TYPE_IFNAME)
|
||||||
|
{
|
||||||
|
rtnh->rtnh_ifindex = nexthop->ifindex;
|
||||||
|
if (nexthop->src.ipv4.s_addr)
|
||||||
|
*src = &nexthop->src;
|
||||||
|
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||||
|
zlog_debug("netlink_route_multipath() (%s): "
|
||||||
|
"nexthop via if %u", routedesc, nexthop->ifindex);
|
||||||
|
}
|
||||||
|
else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
|
||||||
|
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
|
||||||
|
{
|
||||||
|
rtnh->rtnh_ifindex = nexthop->ifindex;
|
||||||
|
|
||||||
|
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||||
|
zlog_debug("netlink_route_multipath() (%s): "
|
||||||
|
"nexthop via if %u", routedesc, nexthop->ifindex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rtnh->rtnh_ifindex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Log debug information for netlink_route_multipath
|
||||||
|
* if debug logging is enabled.
|
||||||
|
*
|
||||||
|
* @param cmd: Netlink command which is to be processed
|
||||||
|
* @param p: Prefix for which the change is due
|
||||||
|
* @param nexthop: Nexthop which is currently processed
|
||||||
|
* @param routedesc: Semantic annotation for nexthop
|
||||||
|
* (recursive, multipath, etc.)
|
||||||
|
* @param family: Address family which the change concerns
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
_netlink_route_debug(
|
||||||
|
int cmd,
|
||||||
|
struct prefix *p,
|
||||||
|
struct nexthop *nexthop,
|
||||||
|
const char *routedesc,
|
||||||
|
int family)
|
||||||
|
{
|
||||||
|
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||||
|
{
|
||||||
|
zlog_debug ("netlink_route_multipath() (%s): %s %s/%d type %s",
|
||||||
|
routedesc,
|
||||||
|
lookup (nlmsg_str, cmd),
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
(family == AF_INET) ? inet_ntoa (p->u.prefix4) :
|
||||||
|
inet6_ntoa (p->u.prefix6),
|
||||||
|
#else
|
||||||
|
inet_ntoa (p->u.prefix4),
|
||||||
|
#endif /* HAVE_IPV6 */
|
||||||
|
p->prefixlen, nexthop_type_to_str (nexthop->type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Routing table change via netlink interface. */
|
/* Routing table change via netlink interface. */
|
||||||
static int
|
static int
|
||||||
netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
|
netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
|
||||||
@ -1433,9 +1634,11 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
|
|||||||
{
|
{
|
||||||
int bytelen;
|
int bytelen;
|
||||||
struct sockaddr_nl snl;
|
struct sockaddr_nl snl;
|
||||||
struct nexthop *nexthop = NULL;
|
struct nexthop *nexthop = NULL, *tnexthop;
|
||||||
int nexthop_num = 0;
|
int recursing;
|
||||||
|
int nexthop_num;
|
||||||
int discard;
|
int discard;
|
||||||
|
const char *routedesc;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
@ -1485,159 +1688,52 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
|
|||||||
if (discard)
|
if (discard)
|
||||||
{
|
{
|
||||||
if (cmd == RTM_NEWROUTE)
|
if (cmd == RTM_NEWROUTE)
|
||||||
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
|
for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
|
||||||
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
|
{
|
||||||
|
/* We shouldn't encounter recursive nexthops on discard routes,
|
||||||
|
* but it is probably better to handle that case correctly anyway.
|
||||||
|
*/
|
||||||
|
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||||
|
continue;
|
||||||
|
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
|
||||||
|
}
|
||||||
goto skip;
|
goto skip;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Multipath case. */
|
/* Count overall nexthops so we can decide whether to use singlepath
|
||||||
if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
|
* or multipath case. */
|
||||||
|
nexthop_num = 0;
|
||||||
|
for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
|
||||||
{
|
{
|
||||||
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
|
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||||
|
continue;
|
||||||
|
if (cmd == RTM_NEWROUTE && !CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|
||||||
|
continue;
|
||||||
|
if (cmd == RTM_DELROUTE && !CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
nexthop_num++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Singlepath case. */
|
||||||
|
if (nexthop_num == 1 || MULTIPATH_NUM == 1)
|
||||||
|
{
|
||||||
|
nexthop_num = 0;
|
||||||
|
for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
|
||||||
{
|
{
|
||||||
|
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||||
|
continue;
|
||||||
|
|
||||||
if ((cmd == RTM_NEWROUTE
|
if ((cmd == RTM_NEWROUTE
|
||||||
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|
||||||
|| (cmd == RTM_DELROUTE
|
|| (cmd == RTM_DELROUTE
|
||||||
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
|
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
|
||||||
{
|
{
|
||||||
|
routedesc = recursing ? "recursive, 1 hop" : "single hop";
|
||||||
|
|
||||||
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
_netlink_route_debug(cmd, p, nexthop, routedesc, family);
|
||||||
{
|
_netlink_route_build_singlepath(routedesc, bytelen,
|
||||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
nexthop, &req.n, sizeof req);
|
||||||
{
|
|
||||||
zlog_debug
|
|
||||||
("netlink_route_multipath() (recursive, 1 hop): "
|
|
||||||
"%s %s/%d, type %s", lookup (nlmsg_str, cmd),
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
(family == AF_INET) ? inet_ntoa (p->u.prefix4) :
|
|
||||||
inet6_ntoa (p->u.prefix6),
|
|
||||||
#else
|
|
||||||
inet_ntoa (p->u.prefix4),
|
|
||||||
#endif /* HAVE_IPV6 */
|
|
||||||
|
|
||||||
p->prefixlen, nexthop_type_to_str (nexthop->rtype));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nexthop->rtype == NEXTHOP_TYPE_IPV4
|
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
|
|
||||||
{
|
|
||||||
addattr_l (&req.n, sizeof req, RTA_GATEWAY,
|
|
||||||
&nexthop->rgate.ipv4, bytelen);
|
|
||||||
if (nexthop->src.ipv4.s_addr)
|
|
||||||
addattr_l(&req.n, sizeof req, RTA_PREFSRC,
|
|
||||||
&nexthop->src.ipv4, bytelen);
|
|
||||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
|
||||||
zlog_debug("netlink_route_multipath() (recursive, "
|
|
||||||
"1 hop): nexthop via %s if %u",
|
|
||||||
inet_ntoa (nexthop->rgate.ipv4),
|
|
||||||
nexthop->rifindex);
|
|
||||||
}
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
if (nexthop->rtype == NEXTHOP_TYPE_IPV6
|
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
|
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
|
|
||||||
{
|
|
||||||
addattr_l (&req.n, sizeof req, RTA_GATEWAY,
|
|
||||||
&nexthop->rgate.ipv6, bytelen);
|
|
||||||
|
|
||||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
|
||||||
zlog_debug("netlink_route_multipath() (recursive, "
|
|
||||||
"1 hop): nexthop via %s if %u",
|
|
||||||
inet6_ntoa (nexthop->rgate.ipv6),
|
|
||||||
nexthop->rifindex);
|
|
||||||
}
|
|
||||||
#endif /* HAVE_IPV6 */
|
|
||||||
if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
|
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IFNAME
|
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
|
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
|
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
|
|
||||||
{
|
|
||||||
addattr32 (&req.n, sizeof req, RTA_OIF,
|
|
||||||
nexthop->rifindex);
|
|
||||||
if ((nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
|
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IFINDEX)
|
|
||||||
&& nexthop->src.ipv4.s_addr)
|
|
||||||
addattr_l (&req.n, sizeof req, RTA_PREFSRC,
|
|
||||||
&nexthop->src.ipv4, bytelen);
|
|
||||||
|
|
||||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
|
||||||
zlog_debug("netlink_route_multipath() (recursive, "
|
|
||||||
"1 hop): nexthop via if %u",
|
|
||||||
nexthop->rifindex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
|
||||||
{
|
|
||||||
zlog_debug
|
|
||||||
("netlink_route_multipath() (single hop): "
|
|
||||||
"%s %s/%d, type %s", lookup (nlmsg_str, cmd),
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
(family == AF_INET) ? inet_ntoa (p->u.prefix4) :
|
|
||||||
inet6_ntoa (p->u.prefix6),
|
|
||||||
#else
|
|
||||||
inet_ntoa (p->u.prefix4),
|
|
||||||
#endif /* HAVE_IPV6 */
|
|
||||||
p->prefixlen, nexthop_type_to_str (nexthop->type));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nexthop->type == NEXTHOP_TYPE_IPV4
|
|
||||||
|| nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
|
|
||||||
{
|
|
||||||
addattr_l (&req.n, sizeof req, RTA_GATEWAY,
|
|
||||||
&nexthop->gate.ipv4, bytelen);
|
|
||||||
if (nexthop->src.ipv4.s_addr)
|
|
||||||
addattr_l (&req.n, sizeof req, RTA_PREFSRC,
|
|
||||||
&nexthop->src.ipv4, bytelen);
|
|
||||||
|
|
||||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
|
||||||
zlog_debug("netlink_route_multipath() (single hop): "
|
|
||||||
"nexthop via %s if %u",
|
|
||||||
inet_ntoa (nexthop->gate.ipv4),
|
|
||||||
nexthop->ifindex);
|
|
||||||
}
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
if (nexthop->type == NEXTHOP_TYPE_IPV6
|
|
||||||
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
|
|
||||||
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
|
|
||||||
{
|
|
||||||
addattr_l (&req.n, sizeof req, RTA_GATEWAY,
|
|
||||||
&nexthop->gate.ipv6, bytelen);
|
|
||||||
|
|
||||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
|
||||||
zlog_debug("netlink_route_multipath() (single hop): "
|
|
||||||
"nexthop via %s if %u",
|
|
||||||
inet6_ntoa (nexthop->gate.ipv6),
|
|
||||||
nexthop->ifindex);
|
|
||||||
}
|
|
||||||
#endif /* HAVE_IPV6 */
|
|
||||||
if (nexthop->type == NEXTHOP_TYPE_IFINDEX
|
|
||||||
|| nexthop->type == NEXTHOP_TYPE_IFNAME
|
|
||||||
|| nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
|
|
||||||
{
|
|
||||||
addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
|
|
||||||
|
|
||||||
if (nexthop->src.ipv4.s_addr)
|
|
||||||
addattr_l (&req.n, sizeof req, RTA_PREFSRC,
|
|
||||||
&nexthop->src.ipv4, bytelen);
|
|
||||||
|
|
||||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
|
||||||
zlog_debug("netlink_route_multipath() (single hop): "
|
|
||||||
"nexthop via if %u", nexthop->ifindex);
|
|
||||||
}
|
|
||||||
else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
|
|
||||||
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
|
|
||||||
{
|
|
||||||
addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
|
|
||||||
|
|
||||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
|
||||||
zlog_debug("netlink_route_multipath() (single hop): "
|
|
||||||
"nexthop via if %u", nexthop->ifindex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cmd == RTM_NEWROUTE)
|
if (cmd == RTM_NEWROUTE)
|
||||||
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
|
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
|
||||||
@ -1659,168 +1755,26 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
|
|||||||
rtnh = RTA_DATA (rta);
|
rtnh = RTA_DATA (rta);
|
||||||
|
|
||||||
nexthop_num = 0;
|
nexthop_num = 0;
|
||||||
for (nexthop = rib->nexthop;
|
for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
|
||||||
nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
|
|
||||||
nexthop = nexthop->next)
|
|
||||||
{
|
{
|
||||||
|
if (MULTIPATH_NUM != 0 && nexthop_num >= MULTIPATH_NUM)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||||
|
continue;
|
||||||
|
|
||||||
if ((cmd == RTM_NEWROUTE
|
if ((cmd == RTM_NEWROUTE
|
||||||
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|
||||||
|| (cmd == RTM_DELROUTE
|
|| (cmd == RTM_DELROUTE
|
||||||
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
|
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
|
||||||
{
|
{
|
||||||
|
routedesc = recursing ? "recursive, multihop" : "multihop";
|
||||||
nexthop_num++;
|
nexthop_num++;
|
||||||
|
|
||||||
rtnh->rtnh_len = sizeof (*rtnh);
|
_netlink_route_debug(cmd, p, nexthop,
|
||||||
rtnh->rtnh_flags = 0;
|
routedesc, family);
|
||||||
rtnh->rtnh_hops = 0;
|
_netlink_route_build_multipath(routedesc, bytelen,
|
||||||
rta->rta_len += rtnh->rtnh_len;
|
nexthop, rta, rtnh, &src);
|
||||||
|
|
||||||
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
|
||||||
{
|
|
||||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
|
||||||
{
|
|
||||||
zlog_debug ("netlink_route_multipath() "
|
|
||||||
"(recursive, multihop): %s %s/%d type %s",
|
|
||||||
lookup (nlmsg_str, cmd),
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
(family == AF_INET) ? inet_ntoa (p->u.prefix4) :
|
|
||||||
inet6_ntoa (p->u.prefix6),
|
|
||||||
#else
|
|
||||||
inet_ntoa (p->u.prefix4),
|
|
||||||
#endif /* HAVE_IPV6 */
|
|
||||||
p->prefixlen, nexthop_type_to_str (nexthop->rtype));
|
|
||||||
}
|
|
||||||
if (nexthop->rtype == NEXTHOP_TYPE_IPV4
|
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
|
|
||||||
{
|
|
||||||
rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
|
|
||||||
&nexthop->rgate.ipv4, bytelen);
|
|
||||||
rtnh->rtnh_len += sizeof (struct rtattr) + 4;
|
|
||||||
|
|
||||||
if (nexthop->src.ipv4.s_addr)
|
|
||||||
src = &nexthop->src;
|
|
||||||
|
|
||||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
|
||||||
zlog_debug("netlink_route_multipath() (recursive, "
|
|
||||||
"multihop): nexthop via %s if %u",
|
|
||||||
inet_ntoa (nexthop->rgate.ipv4),
|
|
||||||
nexthop->rifindex);
|
|
||||||
}
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
if (nexthop->rtype == NEXTHOP_TYPE_IPV6
|
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
|
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
|
|
||||||
{
|
|
||||||
rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
|
|
||||||
&nexthop->rgate.ipv6, bytelen);
|
|
||||||
|
|
||||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
|
||||||
zlog_debug("netlink_route_multipath() (recursive, "
|
|
||||||
"multihop): nexthop via %s if %u",
|
|
||||||
inet6_ntoa (nexthop->rgate.ipv6),
|
|
||||||
nexthop->rifindex);
|
|
||||||
}
|
|
||||||
#endif /* HAVE_IPV6 */
|
|
||||||
/* ifindex */
|
|
||||||
if (nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
|
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IFINDEX
|
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IFNAME)
|
|
||||||
{
|
|
||||||
rtnh->rtnh_ifindex = nexthop->rifindex;
|
|
||||||
if (nexthop->src.ipv4.s_addr)
|
|
||||||
src = &nexthop->src;
|
|
||||||
|
|
||||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
|
||||||
zlog_debug("netlink_route_multipath() (recursive, "
|
|
||||||
"multihop): nexthop via if %u",
|
|
||||||
nexthop->rifindex);
|
|
||||||
}
|
|
||||||
else if (nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
|
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
|
|
||||||
{
|
|
||||||
rtnh->rtnh_ifindex = nexthop->rifindex;
|
|
||||||
|
|
||||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
|
||||||
zlog_debug("netlink_route_multipath() (recursive, "
|
|
||||||
"multihop): nexthop via if %u",
|
|
||||||
nexthop->rifindex);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rtnh->rtnh_ifindex = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
|
||||||
{
|
|
||||||
zlog_debug ("netlink_route_multipath() (multihop): "
|
|
||||||
"%s %s/%d, type %s", lookup (nlmsg_str, cmd),
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
(family == AF_INET) ? inet_ntoa (p->u.prefix4) :
|
|
||||||
inet6_ntoa (p->u.prefix6),
|
|
||||||
#else
|
|
||||||
inet_ntoa (p->u.prefix4),
|
|
||||||
#endif /* HAVE_IPV6 */
|
|
||||||
p->prefixlen, nexthop_type_to_str (nexthop->type));
|
|
||||||
}
|
|
||||||
if (nexthop->type == NEXTHOP_TYPE_IPV4
|
|
||||||
|| nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
|
|
||||||
{
|
|
||||||
rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
|
|
||||||
&nexthop->gate.ipv4, bytelen);
|
|
||||||
rtnh->rtnh_len += sizeof (struct rtattr) + 4;
|
|
||||||
|
|
||||||
if (nexthop->src.ipv4.s_addr)
|
|
||||||
src = &nexthop->src;
|
|
||||||
|
|
||||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
|
||||||
zlog_debug("netlink_route_multipath() (multihop): "
|
|
||||||
"nexthop via %s if %u",
|
|
||||||
inet_ntoa (nexthop->gate.ipv4),
|
|
||||||
nexthop->ifindex);
|
|
||||||
}
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
if (nexthop->type == NEXTHOP_TYPE_IPV6
|
|
||||||
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
|
|
||||||
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
|
|
||||||
{
|
|
||||||
rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
|
|
||||||
&nexthop->gate.ipv6, bytelen);
|
|
||||||
|
|
||||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
|
||||||
zlog_debug("netlink_route_multipath() (multihop): "
|
|
||||||
"nexthop via %s if %u",
|
|
||||||
inet6_ntoa (nexthop->gate.ipv6),
|
|
||||||
nexthop->ifindex);
|
|
||||||
}
|
|
||||||
#endif /* HAVE_IPV6 */
|
|
||||||
/* ifindex */
|
|
||||||
if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
|
|
||||||
|| nexthop->type == NEXTHOP_TYPE_IFINDEX
|
|
||||||
|| nexthop->type == NEXTHOP_TYPE_IFNAME)
|
|
||||||
{
|
|
||||||
rtnh->rtnh_ifindex = nexthop->ifindex;
|
|
||||||
if (nexthop->src.ipv4.s_addr)
|
|
||||||
src = &nexthop->src;
|
|
||||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
|
||||||
zlog_debug("netlink_route_multipath() (multihop): "
|
|
||||||
"nexthop via if %u", nexthop->ifindex);
|
|
||||||
}
|
|
||||||
else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
|
|
||||||
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
|
|
||||||
{
|
|
||||||
rtnh->rtnh_ifindex = nexthop->ifindex;
|
|
||||||
|
|
||||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
|
||||||
zlog_debug("netlink_route_multipath() (multihop): "
|
|
||||||
"nexthop via if %u", nexthop->ifindex);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rtnh->rtnh_ifindex = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rtnh = RTNH_NEXT (rtnh);
|
rtnh = RTNH_NEXT (rtnh);
|
||||||
|
|
||||||
if (cmd == RTM_NEWROUTE)
|
if (cmd == RTM_NEWROUTE)
|
||||||
|
@ -71,7 +71,8 @@ kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family)
|
|||||||
{
|
{
|
||||||
struct sockaddr_in *mask = NULL;
|
struct sockaddr_in *mask = NULL;
|
||||||
struct sockaddr_in sin_dest, sin_mask, sin_gate;
|
struct sockaddr_in sin_dest, sin_mask, sin_gate;
|
||||||
struct nexthop *nexthop;
|
struct nexthop *nexthop, *tnexthop;
|
||||||
|
int recursing;
|
||||||
int nexthop_num = 0;
|
int nexthop_num = 0;
|
||||||
unsigned int ifindex = 0;
|
unsigned int ifindex = 0;
|
||||||
int gate = 0;
|
int gate = 0;
|
||||||
@ -96,8 +97,11 @@ kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family)
|
|||||||
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
|
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
|
||||||
|
|
||||||
/* Make gateway. */
|
/* Make gateway. */
|
||||||
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
|
for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
|
||||||
{
|
{
|
||||||
|
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||||
|
continue;
|
||||||
|
|
||||||
gate = 0;
|
gate = 0;
|
||||||
char gate_buf[INET_ADDRSTRLEN] = "NULL";
|
char gate_buf[INET_ADDRSTRLEN] = "NULL";
|
||||||
|
|
||||||
@ -112,38 +116,22 @@ kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family)
|
|||||||
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
|
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
|
||||||
))
|
))
|
||||||
{
|
{
|
||||||
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
|
||||||
|
nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
|
||||||
{
|
{
|
||||||
if (nexthop->rtype == NEXTHOP_TYPE_IPV4 ||
|
sin_gate.sin_addr = nexthop->gate.ipv4;
|
||||||
nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
|
gate = 1;
|
||||||
{
|
|
||||||
sin_gate.sin_addr = nexthop->rgate.ipv4;
|
|
||||||
gate = 1;
|
|
||||||
}
|
|
||||||
if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
|
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IFNAME
|
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
|
|
||||||
ifindex = nexthop->rifindex;
|
|
||||||
}
|
}
|
||||||
else
|
if (nexthop->type == NEXTHOP_TYPE_IFINDEX
|
||||||
|
|| nexthop->type == NEXTHOP_TYPE_IFNAME
|
||||||
|
|| nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
|
||||||
|
ifindex = nexthop->ifindex;
|
||||||
|
if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE)
|
||||||
{
|
{
|
||||||
if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
|
struct in_addr loopback;
|
||||||
nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
|
loopback.s_addr = htonl (INADDR_LOOPBACK);
|
||||||
{
|
sin_gate.sin_addr = loopback;
|
||||||
sin_gate.sin_addr = nexthop->gate.ipv4;
|
gate = 1;
|
||||||
gate = 1;
|
|
||||||
}
|
|
||||||
if (nexthop->type == NEXTHOP_TYPE_IFINDEX
|
|
||||||
|| nexthop->type == NEXTHOP_TYPE_IFNAME
|
|
||||||
|| nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
|
|
||||||
ifindex = nexthop->ifindex;
|
|
||||||
if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE)
|
|
||||||
{
|
|
||||||
struct in_addr loopback;
|
|
||||||
loopback.s_addr = htonl (INADDR_LOOPBACK);
|
|
||||||
sin_gate.sin_addr = loopback;
|
|
||||||
gate = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gate && p->prefixlen == 32)
|
if (gate && p->prefixlen == 32)
|
||||||
@ -219,7 +207,7 @@ kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family)
|
|||||||
if (IS_ZEBRA_DEBUG_RIB)
|
if (IS_ZEBRA_DEBUG_RIB)
|
||||||
zlog_debug ("%s: odd command %s for flags %d",
|
zlog_debug ("%s: odd command %s for flags %d",
|
||||||
__func__, lookup (rtm_type_str, cmd), nexthop->flags);
|
__func__, lookup (rtm_type_str, cmd), nexthop->flags);
|
||||||
} /* for (nexthop = ... */
|
} /* for (ALL_NEXTHOPS_RO(...))*/
|
||||||
|
|
||||||
/* If there was no useful nexthop, then complain. */
|
/* If there was no useful nexthop, then complain. */
|
||||||
if (nexthop_num == 0 && IS_ZEBRA_DEBUG_KERNEL)
|
if (nexthop_num == 0 && IS_ZEBRA_DEBUG_KERNEL)
|
||||||
@ -354,7 +342,8 @@ kernel_rtm_ipv6_multipath (int cmd, struct prefix *p, struct rib *rib,
|
|||||||
{
|
{
|
||||||
struct sockaddr_in6 *mask;
|
struct sockaddr_in6 *mask;
|
||||||
struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
|
struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
|
||||||
struct nexthop *nexthop;
|
struct nexthop *nexthop, *tnexthop;
|
||||||
|
int recursing;
|
||||||
int nexthop_num = 0;
|
int nexthop_num = 0;
|
||||||
unsigned int ifindex = 0;
|
unsigned int ifindex = 0;
|
||||||
int gate = 0;
|
int gate = 0;
|
||||||
@ -376,8 +365,11 @@ kernel_rtm_ipv6_multipath (int cmd, struct prefix *p, struct rib *rib,
|
|||||||
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
|
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
|
||||||
|
|
||||||
/* Make gateway. */
|
/* Make gateway. */
|
||||||
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
|
for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
|
||||||
{
|
{
|
||||||
|
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||||
|
continue;
|
||||||
|
|
||||||
gate = 0;
|
gate = 0;
|
||||||
|
|
||||||
if ((cmd == RTM_ADD
|
if ((cmd == RTM_ADD
|
||||||
@ -388,36 +380,18 @@ kernel_rtm_ipv6_multipath (int cmd, struct prefix *p, struct rib *rib,
|
|||||||
#endif
|
#endif
|
||||||
))
|
))
|
||||||
{
|
{
|
||||||
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
if (nexthop->type == NEXTHOP_TYPE_IPV6
|
||||||
|
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
|
||||||
|
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
|
||||||
{
|
{
|
||||||
if (nexthop->rtype == NEXTHOP_TYPE_IPV6
|
sin_gate.sin6_addr = nexthop->gate.ipv6;
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
|
gate = 1;
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
|
|
||||||
{
|
|
||||||
sin_gate.sin6_addr = nexthop->rgate.ipv6;
|
|
||||||
gate = 1;
|
|
||||||
}
|
|
||||||
if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
|
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IFNAME
|
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
|
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
|
|
||||||
ifindex = nexthop->rifindex;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (nexthop->type == NEXTHOP_TYPE_IPV6
|
|
||||||
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
|
|
||||||
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
|
|
||||||
{
|
|
||||||
sin_gate.sin6_addr = nexthop->gate.ipv6;
|
|
||||||
gate = 1;
|
|
||||||
}
|
|
||||||
if (nexthop->type == NEXTHOP_TYPE_IFINDEX
|
|
||||||
|| nexthop->type == NEXTHOP_TYPE_IFNAME
|
|
||||||
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
|
|
||||||
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
|
|
||||||
ifindex = nexthop->ifindex;
|
|
||||||
}
|
}
|
||||||
|
if (nexthop->type == NEXTHOP_TYPE_IFINDEX
|
||||||
|
|| nexthop->type == NEXTHOP_TYPE_IFNAME
|
||||||
|
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
|
||||||
|
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
|
||||||
|
ifindex = nexthop->ifindex;
|
||||||
|
|
||||||
if (cmd == RTM_ADD)
|
if (cmd == RTM_ADD)
|
||||||
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
|
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
|
||||||
|
@ -152,7 +152,8 @@ typedef struct netlink_route_info_t_
|
|||||||
* Returns TRUE if a nexthop was added, FALSE otherwise.
|
* Returns TRUE if a nexthop was added, FALSE otherwise.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
netlink_route_info_add_nh (netlink_route_info_t *ri, struct nexthop *nexthop)
|
netlink_route_info_add_nh (netlink_route_info_t *ri, struct nexthop *nexthop,
|
||||||
|
int recursive)
|
||||||
{
|
{
|
||||||
netlink_nh_info_t nhi;
|
netlink_nh_info_t nhi;
|
||||||
union g_addr *src;
|
union g_addr *src;
|
||||||
@ -163,40 +164,7 @@ netlink_route_info_add_nh (netlink_route_info_t *ri, struct nexthop *nexthop)
|
|||||||
if (ri->num_nhs >= (int) ZEBRA_NUM_OF (ri->nhs))
|
if (ri->num_nhs >= (int) ZEBRA_NUM_OF (ri->nhs))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
nhi.recursive = recursive;
|
||||||
{
|
|
||||||
nhi.recursive = 1;
|
|
||||||
nhi.type = nexthop->rtype;
|
|
||||||
nhi.if_index = nexthop->rifindex;
|
|
||||||
|
|
||||||
if (nexthop->rtype == NEXTHOP_TYPE_IPV4
|
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
|
|
||||||
{
|
|
||||||
nhi.gateway = &nexthop->rgate;
|
|
||||||
if (nexthop->src.ipv4.s_addr)
|
|
||||||
src = &nexthop->src;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
if (nexthop->rtype == NEXTHOP_TYPE_IPV6
|
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
|
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
|
|
||||||
{
|
|
||||||
nhi.gateway = &nexthop->rgate;
|
|
||||||
}
|
|
||||||
#endif /* HAVE_IPV6 */
|
|
||||||
|
|
||||||
if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
|
|
||||||
|| nexthop->rtype == NEXTHOP_TYPE_IFNAME)
|
|
||||||
{
|
|
||||||
if (nexthop->src.ipv4.s_addr)
|
|
||||||
src = &nexthop->src;
|
|
||||||
}
|
|
||||||
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
nhi.recursive = 0;
|
|
||||||
nhi.type = nexthop->type;
|
nhi.type = nexthop->type;
|
||||||
nhi.if_index = nexthop->ifindex;
|
nhi.if_index = nexthop->ifindex;
|
||||||
|
|
||||||
@ -224,11 +192,6 @@ netlink_route_info_add_nh (netlink_route_info_t *ri, struct nexthop *nexthop)
|
|||||||
src = &nexthop->src;
|
src = &nexthop->src;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Fall through...
|
|
||||||
*/
|
|
||||||
|
|
||||||
done:
|
|
||||||
if (!nhi.gateway && nhi.if_index == 0)
|
if (!nhi.gateway && nhi.if_index == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -272,7 +235,8 @@ static int
|
|||||||
netlink_route_info_fill (netlink_route_info_t *ri, int cmd,
|
netlink_route_info_fill (netlink_route_info_t *ri, int cmd,
|
||||||
rib_dest_t *dest, struct rib *rib)
|
rib_dest_t *dest, struct rib *rib)
|
||||||
{
|
{
|
||||||
struct nexthop *nexthop = NULL;
|
struct nexthop *nexthop, *tnexthop;
|
||||||
|
int recursing;
|
||||||
int discard;
|
int discard;
|
||||||
|
|
||||||
memset (ri, 0, sizeof (*ri));
|
memset (ri, 0, sizeof (*ri));
|
||||||
@ -321,35 +285,20 @@ netlink_route_info_fill (netlink_route_info_t *ri, int cmd,
|
|||||||
goto skip;
|
goto skip;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Multipath case. */
|
for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
|
||||||
if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
|
|
||||||
{
|
{
|
||||||
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
|
if (MULTIPATH_NUM != 0 && ri->num_nhs >= MULTIPATH_NUM)
|
||||||
{
|
break;
|
||||||
|
|
||||||
if ((cmd == RTM_NEWROUTE
|
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||||
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|
continue;
|
||||||
|| (cmd == RTM_DELROUTE
|
|
||||||
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
|
if ((cmd == RTM_NEWROUTE
|
||||||
{
|
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|
||||||
netlink_route_info_add_nh (ri, nexthop);
|
|| (cmd == RTM_DELROUTE
|
||||||
break;
|
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (nexthop = rib->nexthop;
|
|
||||||
nexthop && (MULTIPATH_NUM == 0 || ri->num_nhs < MULTIPATH_NUM);
|
|
||||||
nexthop = nexthop->next)
|
|
||||||
{
|
{
|
||||||
if ((cmd == RTM_NEWROUTE
|
netlink_route_info_add_nh (ri, nexthop, recursing);
|
||||||
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|
|
||||||
|| (cmd == RTM_DELROUTE
|
|
||||||
&& CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
|
|
||||||
{
|
|
||||||
netlink_route_info_add_nh (ri, nexthop);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,20 +202,26 @@ nexthop_type_to_str (enum nexthop_types_t nh_type)
|
|||||||
return desc[nh_type];
|
return desc[nh_type];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add nexthop to the end of the list. */
|
/* Add nexthop to the end of a nexthop list. */
|
||||||
static void
|
static void
|
||||||
nexthop_add (struct rib *rib, struct nexthop *nexthop)
|
_nexthop_add (struct nexthop **target, struct nexthop *nexthop)
|
||||||
{
|
{
|
||||||
struct nexthop *last;
|
struct nexthop *last;
|
||||||
|
|
||||||
for (last = rib->nexthop; last && last->next; last = last->next)
|
for (last = *target; last && last->next; last = last->next)
|
||||||
;
|
;
|
||||||
if (last)
|
if (last)
|
||||||
last->next = nexthop;
|
last->next = nexthop;
|
||||||
else
|
else
|
||||||
rib->nexthop = nexthop;
|
*target = nexthop;
|
||||||
nexthop->prev = last;
|
nexthop->prev = last;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add nexthop to the end of a rib node's nexthop list */
|
||||||
|
static void
|
||||||
|
nexthop_add (struct rib *rib, struct nexthop *nexthop)
|
||||||
|
{
|
||||||
|
_nexthop_add(&rib->nexthop, nexthop);
|
||||||
rib->nexthop_num++;
|
rib->nexthop_num++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,15 +238,32 @@ nexthop_delete (struct rib *rib, struct nexthop *nexthop)
|
|||||||
rib->nexthop_num--;
|
rib->nexthop_num--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void nexthops_free(struct nexthop *nexthop);
|
||||||
|
|
||||||
/* Free nexthop. */
|
/* Free nexthop. */
|
||||||
static void
|
static void
|
||||||
nexthop_free (struct nexthop *nexthop)
|
nexthop_free (struct nexthop *nexthop)
|
||||||
{
|
{
|
||||||
if (nexthop->ifname)
|
if (nexthop->ifname)
|
||||||
XFREE (0, nexthop->ifname);
|
XFREE (0, nexthop->ifname);
|
||||||
|
if (nexthop->resolved)
|
||||||
|
nexthops_free(nexthop->resolved);
|
||||||
XFREE (MTYPE_NEXTHOP, nexthop);
|
XFREE (MTYPE_NEXTHOP, nexthop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Frees a list of nexthops */
|
||||||
|
static void
|
||||||
|
nexthops_free (struct nexthop *nexthop)
|
||||||
|
{
|
||||||
|
struct nexthop *nh, *next;
|
||||||
|
|
||||||
|
for (nh = nexthop; nh; nh = next)
|
||||||
|
{
|
||||||
|
next = nh->next;
|
||||||
|
nexthop_free (nh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct nexthop *
|
struct nexthop *
|
||||||
nexthop_ifindex_add (struct rib *rib, unsigned int ifindex)
|
nexthop_ifindex_add (struct rib *rib, unsigned int ifindex)
|
||||||
{
|
{
|
||||||
@ -365,6 +388,24 @@ nexthop_blackhole_add (struct rib *rib)
|
|||||||
return nexthop;
|
return nexthop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This method checks whether a recursive nexthop has at
|
||||||
|
* least one resolved nexthop in the fib.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
nexthop_has_fib_child(struct nexthop *nexthop)
|
||||||
|
{
|
||||||
|
struct nexthop *nh;
|
||||||
|
|
||||||
|
if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (nh = nexthop->resolved; nh; nh = nh->next)
|
||||||
|
if (CHECK_FLAG (nh->flags, NEXTHOP_FLAG_FIB))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* If force flag is not set, do not modify falgs at all for uninstall
|
/* If force flag is not set, do not modify falgs at all for uninstall
|
||||||
the route from FIB. */
|
the route from FIB. */
|
||||||
static int
|
static int
|
||||||
@ -375,13 +416,19 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
|
|||||||
struct route_table *table;
|
struct route_table *table;
|
||||||
struct route_node *rn;
|
struct route_node *rn;
|
||||||
struct rib *match;
|
struct rib *match;
|
||||||
|
int resolved;
|
||||||
struct nexthop *newhop;
|
struct nexthop *newhop;
|
||||||
|
struct nexthop *resolved_hop;
|
||||||
|
|
||||||
if (nexthop->type == NEXTHOP_TYPE_IPV4)
|
if (nexthop->type == NEXTHOP_TYPE_IPV4)
|
||||||
nexthop->ifindex = 0;
|
nexthop->ifindex = 0;
|
||||||
|
|
||||||
if (set)
|
if (set)
|
||||||
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
|
{
|
||||||
|
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
|
||||||
|
nexthops_free(nexthop->resolved);
|
||||||
|
nexthop->resolved = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Make lookup prefix. */
|
/* Make lookup prefix. */
|
||||||
memset (&p, 0, sizeof (struct prefix_ipv4));
|
memset (&p, 0, sizeof (struct prefix_ipv4));
|
||||||
@ -436,6 +483,7 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
|
|||||||
}
|
}
|
||||||
else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL))
|
else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL))
|
||||||
{
|
{
|
||||||
|
resolved = 0;
|
||||||
for (newhop = match->nexthop; newhop; newhop = newhop->next)
|
for (newhop = match->nexthop; newhop; newhop = newhop->next)
|
||||||
if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)
|
if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)
|
||||||
&& ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE))
|
&& ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||||
@ -443,18 +491,25 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
|
|||||||
if (set)
|
if (set)
|
||||||
{
|
{
|
||||||
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
|
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
|
||||||
nexthop->rtype = newhop->type;
|
|
||||||
|
resolved_hop = XCALLOC(MTYPE_NEXTHOP, sizeof (struct nexthop));
|
||||||
|
SET_FLAG (resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
|
||||||
|
|
||||||
|
resolved_hop->type = newhop->type;
|
||||||
if (newhop->type == NEXTHOP_TYPE_IPV4 ||
|
if (newhop->type == NEXTHOP_TYPE_IPV4 ||
|
||||||
newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
|
newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
|
||||||
nexthop->rgate.ipv4 = newhop->gate.ipv4;
|
resolved_hop->gate.ipv4 = newhop->gate.ipv4;
|
||||||
|
|
||||||
if (newhop->type == NEXTHOP_TYPE_IFINDEX
|
if (newhop->type == NEXTHOP_TYPE_IFINDEX
|
||||||
|| newhop->type == NEXTHOP_TYPE_IFNAME
|
|| newhop->type == NEXTHOP_TYPE_IFNAME
|
||||||
|| newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
|
|| newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
|
||||||
nexthop->rifindex = newhop->ifindex;
|
resolved_hop->ifindex = newhop->ifindex;
|
||||||
|
|
||||||
|
_nexthop_add(&nexthop->resolved, resolved_hop);
|
||||||
}
|
}
|
||||||
return 1;
|
resolved = 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return resolved;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -476,13 +531,19 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set,
|
|||||||
struct route_table *table;
|
struct route_table *table;
|
||||||
struct route_node *rn;
|
struct route_node *rn;
|
||||||
struct rib *match;
|
struct rib *match;
|
||||||
|
int resolved;
|
||||||
struct nexthop *newhop;
|
struct nexthop *newhop;
|
||||||
|
struct nexthop *resolved_hop;
|
||||||
|
|
||||||
if (nexthop->type == NEXTHOP_TYPE_IPV6)
|
if (nexthop->type == NEXTHOP_TYPE_IPV6)
|
||||||
nexthop->ifindex = 0;
|
nexthop->ifindex = 0;
|
||||||
|
|
||||||
if (set)
|
if (set)
|
||||||
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
|
{
|
||||||
|
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
|
||||||
|
nexthops_free(nexthop->resolved);
|
||||||
|
nexthop->resolved = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Make lookup prefix. */
|
/* Make lookup prefix. */
|
||||||
memset (&p, 0, sizeof (struct prefix_ipv6));
|
memset (&p, 0, sizeof (struct prefix_ipv6));
|
||||||
@ -538,6 +599,7 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set,
|
|||||||
}
|
}
|
||||||
else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL))
|
else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL))
|
||||||
{
|
{
|
||||||
|
resolved = 0;
|
||||||
for (newhop = match->nexthop; newhop; newhop = newhop->next)
|
for (newhop = match->nexthop; newhop; newhop = newhop->next)
|
||||||
if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)
|
if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)
|
||||||
&& ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE))
|
&& ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||||
@ -545,20 +607,27 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set,
|
|||||||
if (set)
|
if (set)
|
||||||
{
|
{
|
||||||
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
|
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
|
||||||
nexthop->rtype = newhop->type;
|
|
||||||
|
resolved_hop = XCALLOC(MTYPE_NEXTHOP, sizeof (struct nexthop));
|
||||||
|
SET_FLAG (resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
|
||||||
|
|
||||||
|
resolved_hop->type = newhop->type;
|
||||||
if (newhop->type == NEXTHOP_TYPE_IPV6
|
if (newhop->type == NEXTHOP_TYPE_IPV6
|
||||||
|| newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX
|
|| newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX
|
||||||
|| newhop->type == NEXTHOP_TYPE_IPV6_IFNAME)
|
|| newhop->type == NEXTHOP_TYPE_IPV6_IFNAME)
|
||||||
nexthop->rgate.ipv6 = newhop->gate.ipv6;
|
resolved_hop->gate.ipv6 = newhop->gate.ipv6;
|
||||||
|
|
||||||
if (newhop->type == NEXTHOP_TYPE_IFINDEX
|
if (newhop->type == NEXTHOP_TYPE_IFINDEX
|
||||||
|| newhop->type == NEXTHOP_TYPE_IFNAME
|
|| newhop->type == NEXTHOP_TYPE_IFNAME
|
||||||
|| newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX
|
|| newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX
|
||||||
|| newhop->type == NEXTHOP_TYPE_IPV6_IFNAME)
|
|| newhop->type == NEXTHOP_TYPE_IPV6_IFNAME)
|
||||||
nexthop->rifindex = newhop->ifindex;
|
resolved_hop->ifindex = newhop->ifindex;
|
||||||
|
|
||||||
|
_nexthop_add(&nexthop->resolved, resolved_hop);
|
||||||
}
|
}
|
||||||
return 1;
|
resolved = 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return resolved;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -577,7 +646,8 @@ rib_match_ipv4 (struct in_addr addr)
|
|||||||
struct route_table *table;
|
struct route_table *table;
|
||||||
struct route_node *rn;
|
struct route_node *rn;
|
||||||
struct rib *match;
|
struct rib *match;
|
||||||
struct nexthop *newhop;
|
struct nexthop *newhop, *tnewhop;
|
||||||
|
int recursing;
|
||||||
|
|
||||||
/* Lookup table. */
|
/* Lookup table. */
|
||||||
table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
|
table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
|
||||||
@ -622,7 +692,7 @@ rib_match_ipv4 (struct in_addr addr)
|
|||||||
return match;
|
return match;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (newhop = match->nexthop; newhop; newhop = newhop->next)
|
for (ALL_NEXTHOPS_RO(match->nexthop, newhop, tnewhop, recursing))
|
||||||
if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB))
|
if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB))
|
||||||
return match;
|
return match;
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -638,7 +708,8 @@ rib_lookup_ipv4 (struct prefix_ipv4 *p)
|
|||||||
struct route_table *table;
|
struct route_table *table;
|
||||||
struct route_node *rn;
|
struct route_node *rn;
|
||||||
struct rib *match;
|
struct rib *match;
|
||||||
struct nexthop *nexthop;
|
struct nexthop *nexthop, *tnexthop;
|
||||||
|
int recursing;
|
||||||
|
|
||||||
/* Lookup table. */
|
/* Lookup table. */
|
||||||
table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
|
table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
|
||||||
@ -668,7 +739,7 @@ rib_lookup_ipv4 (struct prefix_ipv4 *p)
|
|||||||
if (match->type == ZEBRA_ROUTE_CONNECT)
|
if (match->type == ZEBRA_ROUTE_CONNECT)
|
||||||
return match;
|
return match;
|
||||||
|
|
||||||
for (nexthop = match->nexthop; nexthop; nexthop = nexthop->next)
|
for (ALL_NEXTHOPS_RO(match->nexthop, nexthop, tnexthop, recursing))
|
||||||
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
|
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
|
||||||
return match;
|
return match;
|
||||||
|
|
||||||
@ -693,7 +764,9 @@ rib_lookup_ipv4_route (struct prefix_ipv4 *p, union sockunion * qgate)
|
|||||||
struct route_table *table;
|
struct route_table *table;
|
||||||
struct route_node *rn;
|
struct route_node *rn;
|
||||||
struct rib *match;
|
struct rib *match;
|
||||||
struct nexthop *nexthop;
|
struct nexthop *nexthop, *tnexthop;
|
||||||
|
int recursing;
|
||||||
|
int nexthops_active;
|
||||||
|
|
||||||
/* Lookup table. */
|
/* Lookup table. */
|
||||||
table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
|
table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
|
||||||
@ -727,26 +800,25 @@ rib_lookup_ipv4_route (struct prefix_ipv4 *p, union sockunion * qgate)
|
|||||||
return ZEBRA_RIB_FOUND_CONNECTED;
|
return ZEBRA_RIB_FOUND_CONNECTED;
|
||||||
|
|
||||||
/* Ok, we have a cood candidate, let's check it's nexthop list... */
|
/* Ok, we have a cood candidate, let's check it's nexthop list... */
|
||||||
for (nexthop = match->nexthop; nexthop; nexthop = nexthop->next)
|
nexthops_active = 0;
|
||||||
|
for (ALL_NEXTHOPS_RO(match->nexthop, nexthop, tnexthop, recursing))
|
||||||
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
|
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
|
||||||
{
|
|
||||||
/* We are happy with either direct or recursive hexthop */
|
|
||||||
if (nexthop->gate.ipv4.s_addr == sockunion2ip (qgate) ||
|
|
||||||
nexthop->rgate.ipv4.s_addr == sockunion2ip (qgate))
|
|
||||||
return ZEBRA_RIB_FOUND_EXACT;
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
|
nexthops_active = 1;
|
||||||
|
if (nexthop->gate.ipv4.s_addr == sockunion2ip (qgate))
|
||||||
|
return ZEBRA_RIB_FOUND_EXACT;
|
||||||
if (IS_ZEBRA_DEBUG_RIB)
|
if (IS_ZEBRA_DEBUG_RIB)
|
||||||
{
|
{
|
||||||
char gate_buf[INET_ADDRSTRLEN], rgate_buf[INET_ADDRSTRLEN], qgate_buf[INET_ADDRSTRLEN];
|
char gate_buf[INET_ADDRSTRLEN], qgate_buf[INET_ADDRSTRLEN];
|
||||||
inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, gate_buf, INET_ADDRSTRLEN);
|
inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, gate_buf, INET_ADDRSTRLEN);
|
||||||
inet_ntop (AF_INET, &nexthop->rgate.ipv4.s_addr, rgate_buf, INET_ADDRSTRLEN);
|
inet_ntop (AF_INET, &sockunion2ip(qgate), qgate_buf, INET_ADDRSTRLEN);
|
||||||
inet_ntop (AF_INET, &sockunion2ip (qgate), qgate_buf, INET_ADDRSTRLEN);
|
zlog_debug ("%s: qgate == %s, %s == %s", __func__,
|
||||||
zlog_debug ("%s: qgate == %s, gate == %s, rgate == %s", __func__, qgate_buf, gate_buf, rgate_buf);
|
qgate_buf, recursing ? "rgate" : "gate", gate_buf);
|
||||||
}
|
}
|
||||||
return ZEBRA_RIB_FOUND_NOGATE;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if (nexthops_active)
|
||||||
|
return ZEBRA_RIB_FOUND_NOGATE;
|
||||||
|
|
||||||
return ZEBRA_RIB_NOTFOUND;
|
return ZEBRA_RIB_NOTFOUND;
|
||||||
}
|
}
|
||||||
@ -759,7 +831,8 @@ rib_match_ipv6 (struct in6_addr *addr)
|
|||||||
struct route_table *table;
|
struct route_table *table;
|
||||||
struct route_node *rn;
|
struct route_node *rn;
|
||||||
struct rib *match;
|
struct rib *match;
|
||||||
struct nexthop *newhop;
|
struct nexthop *newhop, *tnewhop;
|
||||||
|
int recursing;
|
||||||
|
|
||||||
/* Lookup table. */
|
/* Lookup table. */
|
||||||
table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
|
table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
|
||||||
@ -804,7 +877,7 @@ rib_match_ipv6 (struct in6_addr *addr)
|
|||||||
return match;
|
return match;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (newhop = match->nexthop; newhop; newhop = newhop->next)
|
for (ALL_NEXTHOPS_RO(match->nexthop, newhop, tnewhop, recursing))
|
||||||
if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB))
|
if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB))
|
||||||
return match;
|
return match;
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -966,7 +1039,8 @@ static void
|
|||||||
rib_install_kernel (struct route_node *rn, struct rib *rib)
|
rib_install_kernel (struct route_node *rn, struct rib *rib)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct nexthop *nexthop;
|
struct nexthop *nexthop, *tnexthop;
|
||||||
|
int recursing;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure we update the FPM any time we send new information to
|
* Make sure we update the FPM any time we send new information to
|
||||||
@ -988,7 +1062,7 @@ rib_install_kernel (struct route_node *rn, struct rib *rib)
|
|||||||
/* This condition is never met, if we are using rt_socket.c */
|
/* This condition is never met, if we are using rt_socket.c */
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
|
for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
|
||||||
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
|
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -998,7 +1072,8 @@ static int
|
|||||||
rib_uninstall_kernel (struct route_node *rn, struct rib *rib)
|
rib_uninstall_kernel (struct route_node *rn, struct rib *rib)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct nexthop *nexthop;
|
struct nexthop *nexthop, *tnexthop;
|
||||||
|
int recursing;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure we update the FPM any time we send new information to
|
* Make sure we update the FPM any time we send new information to
|
||||||
@ -1018,7 +1093,7 @@ rib_uninstall_kernel (struct route_node *rn, struct rib *rib)
|
|||||||
#endif /* HAVE_IPV6 */
|
#endif /* HAVE_IPV6 */
|
||||||
}
|
}
|
||||||
|
|
||||||
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
|
for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
|
||||||
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
|
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -1114,7 +1189,8 @@ rib_process (struct route_node *rn)
|
|||||||
struct rib *select = NULL;
|
struct rib *select = NULL;
|
||||||
struct rib *del = NULL;
|
struct rib *del = NULL;
|
||||||
int installed = 0;
|
int installed = 0;
|
||||||
struct nexthop *nexthop = NULL;
|
struct nexthop *nexthop = NULL, *tnexthop;
|
||||||
|
int recursing;
|
||||||
char buf[INET6_ADDRSTRLEN];
|
char buf[INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
assert (rn);
|
assert (rn);
|
||||||
@ -1237,7 +1313,7 @@ rib_process (struct route_node *rn)
|
|||||||
This makes sure the routes are IN the kernel.
|
This makes sure the routes are IN the kernel.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (nexthop = select->nexthop; nexthop; nexthop = nexthop->next)
|
for (ALL_NEXTHOPS_RO(select->nexthop, nexthop, tnexthop, recursing))
|
||||||
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
|
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
|
||||||
{
|
{
|
||||||
installed = 1;
|
installed = 1;
|
||||||
@ -1626,7 +1702,6 @@ rib_addnode (struct route_node *rn, struct rib *rib)
|
|||||||
static void
|
static void
|
||||||
rib_unlink (struct route_node *rn, struct rib *rib)
|
rib_unlink (struct route_node *rn, struct rib *rib)
|
||||||
{
|
{
|
||||||
struct nexthop *nexthop, *next;
|
|
||||||
char buf[INET6_ADDRSTRLEN];
|
char buf[INET6_ADDRSTRLEN];
|
||||||
rib_dest_t *dest;
|
rib_dest_t *dest;
|
||||||
|
|
||||||
@ -1652,11 +1727,7 @@ rib_unlink (struct route_node *rn, struct rib *rib)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* free RIB and nexthops */
|
/* free RIB and nexthops */
|
||||||
for (nexthop = rib->nexthop; nexthop; nexthop = next)
|
nexthops_free(rib->nexthop);
|
||||||
{
|
|
||||||
next = nexthop->next;
|
|
||||||
nexthop_free (nexthop);
|
|
||||||
}
|
|
||||||
XFREE (MTYPE_RIB, rib);
|
XFREE (MTYPE_RIB, rib);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1786,11 +1857,12 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p,
|
|||||||
|
|
||||||
void rib_dump (const char * func, const struct prefix_ipv4 * p, const struct rib * rib)
|
void rib_dump (const char * func, const struct prefix_ipv4 * p, const struct rib * rib)
|
||||||
{
|
{
|
||||||
char straddr1[INET_ADDRSTRLEN], straddr2[INET_ADDRSTRLEN];
|
char straddr[INET_ADDRSTRLEN];
|
||||||
struct nexthop *nexthop;
|
struct nexthop *nexthop, *tnexthop;
|
||||||
|
int recursing;
|
||||||
|
|
||||||
inet_ntop (AF_INET, &p->prefix, straddr1, INET_ADDRSTRLEN);
|
inet_ntop (AF_INET, &p->prefix, straddr, INET_ADDRSTRLEN);
|
||||||
zlog_debug ("%s: dumping RIB entry %p for %s/%d", func, rib, straddr1, p->prefixlen);
|
zlog_debug ("%s: dumping RIB entry %p for %s/%d", func, rib, straddr, p->prefixlen);
|
||||||
zlog_debug
|
zlog_debug
|
||||||
(
|
(
|
||||||
"%s: refcnt == %lu, uptime == %lu, type == %u, table == %d",
|
"%s: refcnt == %lu, uptime == %lu, type == %u, table == %d",
|
||||||
@ -1817,21 +1889,20 @@ void rib_dump (const char * func, const struct prefix_ipv4 * p, const struct rib
|
|||||||
rib->nexthop_active_num,
|
rib->nexthop_active_num,
|
||||||
rib->nexthop_fib_num
|
rib->nexthop_fib_num
|
||||||
);
|
);
|
||||||
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
|
for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
|
||||||
{
|
{
|
||||||
inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, straddr1, INET_ADDRSTRLEN);
|
inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, straddr, INET_ADDRSTRLEN);
|
||||||
inet_ntop (AF_INET, &nexthop->rgate.ipv4.s_addr, straddr2, INET_ADDRSTRLEN);
|
zlog_debug
|
||||||
zlog_debug
|
(
|
||||||
(
|
"%s: %s %s with flags %s%s%s",
|
||||||
"%s: NH %s (%s) with flags %s%s%s",
|
func,
|
||||||
func,
|
(recursing ? " NH" : "NH"),
|
||||||
straddr1,
|
straddr,
|
||||||
straddr2,
|
(CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE) ? "ACTIVE " : ""),
|
||||||
(CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE) ? "ACTIVE " : ""),
|
(CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? "FIB " : ""),
|
||||||
(CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? "FIB " : ""),
|
(CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE) ? "RECURSIVE" : "")
|
||||||
(CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE) ? "RECURSIVE" : "")
|
);
|
||||||
);
|
}
|
||||||
}
|
|
||||||
zlog_debug ("%s: dump complete", func);
|
zlog_debug ("%s: dump complete", func);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2018,7 +2089,8 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p,
|
|||||||
struct rib *rib;
|
struct rib *rib;
|
||||||
struct rib *fib = NULL;
|
struct rib *fib = NULL;
|
||||||
struct rib *same = NULL;
|
struct rib *same = NULL;
|
||||||
struct nexthop *nexthop;
|
struct nexthop *nexthop, *tnexthop;
|
||||||
|
int recursing;
|
||||||
char buf1[INET_ADDRSTRLEN];
|
char buf1[INET_ADDRSTRLEN];
|
||||||
char buf2[INET_ADDRSTRLEN];
|
char buf2[INET_ADDRSTRLEN];
|
||||||
|
|
||||||
@ -2085,16 +2157,23 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Make sure that the route found has the same gateway. */
|
/* Make sure that the route found has the same gateway. */
|
||||||
else if (gate == NULL ||
|
else
|
||||||
((nexthop = rib->nexthop) &&
|
|
||||||
(IPV4_ADDR_SAME (&nexthop->gate.ipv4, gate) ||
|
|
||||||
IPV4_ADDR_SAME (&nexthop->rgate.ipv4, gate))))
|
|
||||||
{
|
{
|
||||||
same = rib;
|
if (gate == NULL)
|
||||||
break;
|
{
|
||||||
}
|
same = rib;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
|
||||||
|
if (IPV4_ADDR_SAME (&nexthop->gate.ipv4, gate))
|
||||||
|
{
|
||||||
|
same = rib;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (same)
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If same type of route can't be found and this message is from
|
/* If same type of route can't be found and this message is from
|
||||||
kernel. */
|
kernel. */
|
||||||
if (! same)
|
if (! same)
|
||||||
@ -2576,7 +2655,8 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
|
|||||||
struct rib *rib;
|
struct rib *rib;
|
||||||
struct rib *fib = NULL;
|
struct rib *fib = NULL;
|
||||||
struct rib *same = NULL;
|
struct rib *same = NULL;
|
||||||
struct nexthop *nexthop;
|
struct nexthop *nexthop, *tnexthop;
|
||||||
|
int recursing;
|
||||||
char buf1[INET6_ADDRSTRLEN];
|
char buf1[INET6_ADDRSTRLEN];
|
||||||
char buf2[INET6_ADDRSTRLEN];
|
char buf2[INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
@ -2636,14 +2716,22 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Make sure that the route found has the same gateway. */
|
/* Make sure that the route found has the same gateway. */
|
||||||
else if (gate == NULL ||
|
else
|
||||||
((nexthop = rib->nexthop) &&
|
{
|
||||||
(IPV6_ADDR_SAME (&nexthop->gate.ipv6, gate) ||
|
if (gate == NULL)
|
||||||
IPV6_ADDR_SAME (&nexthop->rgate.ipv6, gate))))
|
{
|
||||||
{
|
same = rib;
|
||||||
same = rib;
|
break;
|
||||||
break;
|
}
|
||||||
}
|
for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
|
||||||
|
if (IPV6_ADDR_SAME (&nexthop->gate.ipv6, gate))
|
||||||
|
{
|
||||||
|
same = rib;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (same)
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If same type of route can't be found and this message is from
|
/* If same type of route can't be found and this message is from
|
||||||
|
@ -422,14 +422,10 @@ route_match_ip_next_hop (void *rule, struct prefix *prefix,
|
|||||||
switch (nexthop->type) {
|
switch (nexthop->type) {
|
||||||
case NEXTHOP_TYPE_IFINDEX:
|
case NEXTHOP_TYPE_IFINDEX:
|
||||||
case NEXTHOP_TYPE_IFNAME:
|
case NEXTHOP_TYPE_IFNAME:
|
||||||
|
/* Interface routes can't match ip next-hop */
|
||||||
|
return RMAP_NOMATCH;
|
||||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||||
case NEXTHOP_TYPE_IPV4_IFNAME:
|
case NEXTHOP_TYPE_IPV4_IFNAME:
|
||||||
if (nexthop->rtype != NEXTHOP_TYPE_IPV4)
|
|
||||||
return RMAP_NOMATCH;
|
|
||||||
p.family = AF_INET;
|
|
||||||
p.prefix = nexthop->rgate.ipv4;
|
|
||||||
p.prefixlen = IPV4_MAX_BITLEN;
|
|
||||||
break;
|
|
||||||
case NEXTHOP_TYPE_IPV4:
|
case NEXTHOP_TYPE_IPV4:
|
||||||
p.family = AF_INET;
|
p.family = AF_INET;
|
||||||
p.prefix = nexthop->gate.ipv4;
|
p.prefix = nexthop->gate.ipv4;
|
||||||
@ -488,14 +484,10 @@ route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix,
|
|||||||
switch (nexthop->type) {
|
switch (nexthop->type) {
|
||||||
case NEXTHOP_TYPE_IFINDEX:
|
case NEXTHOP_TYPE_IFINDEX:
|
||||||
case NEXTHOP_TYPE_IFNAME:
|
case NEXTHOP_TYPE_IFNAME:
|
||||||
|
/* Interface routes can't match ip next-hop */
|
||||||
|
return RMAP_NOMATCH;
|
||||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||||
case NEXTHOP_TYPE_IPV4_IFNAME:
|
case NEXTHOP_TYPE_IPV4_IFNAME:
|
||||||
if (nexthop->rtype != NEXTHOP_TYPE_IPV4)
|
|
||||||
return RMAP_NOMATCH;
|
|
||||||
p.family = AF_INET;
|
|
||||||
p.prefix = nexthop->rgate.ipv4;
|
|
||||||
p.prefixlen = IPV4_MAX_BITLEN;
|
|
||||||
break;
|
|
||||||
case NEXTHOP_TYPE_IPV4:
|
case NEXTHOP_TYPE_IPV4:
|
||||||
p.family = AF_INET;
|
p.family = AF_INET;
|
||||||
p.prefix = nexthop->gate.ipv4;
|
p.prefix = nexthop->gate.ipv4;
|
||||||
|
@ -533,7 +533,8 @@ static void
|
|||||||
vty_show_ip_route_detail (struct vty *vty, struct route_node *rn)
|
vty_show_ip_route_detail (struct vty *vty, struct route_node *rn)
|
||||||
{
|
{
|
||||||
struct rib *rib;
|
struct rib *rib;
|
||||||
struct nexthop *nexthop;
|
struct nexthop *nexthop, *tnexthop;
|
||||||
|
int recursing;
|
||||||
|
|
||||||
RNODE_FOREACH_RIB (rn, rib)
|
RNODE_FOREACH_RIB (rn, rib)
|
||||||
{
|
{
|
||||||
@ -582,12 +583,13 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn)
|
|||||||
vty_out (vty, " ago%s", VTY_NEWLINE);
|
vty_out (vty, " ago%s", VTY_NEWLINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
|
for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
|
||||||
{
|
{
|
||||||
char addrstr[32];
|
char addrstr[32];
|
||||||
|
|
||||||
vty_out (vty, " %c",
|
vty_out (vty, " %c%s",
|
||||||
CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ');
|
CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ',
|
||||||
|
recursing ? " " : "");
|
||||||
|
|
||||||
switch (nexthop->type)
|
switch (nexthop->type)
|
||||||
{
|
{
|
||||||
@ -614,28 +616,8 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn)
|
|||||||
vty_out (vty, " inactive");
|
vty_out (vty, " inactive");
|
||||||
|
|
||||||
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||||
{
|
vty_out (vty, " (recursive)");
|
||||||
vty_out (vty, " (recursive");
|
|
||||||
|
|
||||||
switch (nexthop->rtype)
|
|
||||||
{
|
|
||||||
case NEXTHOP_TYPE_IPV4:
|
|
||||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
|
||||||
vty_out (vty, " via %s", inet_ntoa (nexthop->rgate.ipv4));
|
|
||||||
if (nexthop->rifindex)
|
|
||||||
vty_out (vty, ", %s", ifindex2ifname (nexthop->rifindex));
|
|
||||||
vty_out (vty, ")");
|
|
||||||
|
|
||||||
break;
|
|
||||||
case NEXTHOP_TYPE_IFINDEX:
|
|
||||||
case NEXTHOP_TYPE_IFNAME:
|
|
||||||
vty_out (vty, " is directly connected, %s)",
|
|
||||||
ifindex2ifname (nexthop->rifindex));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch (nexthop->type)
|
switch (nexthop->type)
|
||||||
{
|
{
|
||||||
case NEXTHOP_TYPE_IPV4:
|
case NEXTHOP_TYPE_IPV4:
|
||||||
@ -672,12 +654,13 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn)
|
|||||||
static void
|
static void
|
||||||
vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib)
|
vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib)
|
||||||
{
|
{
|
||||||
struct nexthop *nexthop;
|
struct nexthop *nexthop, *tnexthop;
|
||||||
|
int recursing;
|
||||||
int len = 0;
|
int len = 0;
|
||||||
char buf[BUFSIZ];
|
char buf[BUFSIZ];
|
||||||
|
|
||||||
/* Nexthop information. */
|
/* Nexthop information. */
|
||||||
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
|
for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
|
||||||
{
|
{
|
||||||
if (nexthop == rib->nexthop)
|
if (nexthop == rib->nexthop)
|
||||||
{
|
{
|
||||||
@ -701,7 +684,7 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib)
|
|||||||
vty_out (vty, " %c%*c",
|
vty_out (vty, " %c%*c",
|
||||||
CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
|
CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
|
||||||
? '*' : ' ',
|
? '*' : ' ',
|
||||||
len - 3, ' ');
|
len - 3 + (2 * recursing), ' ');
|
||||||
|
|
||||||
switch (nexthop->type)
|
switch (nexthop->type)
|
||||||
{
|
{
|
||||||
@ -728,27 +711,8 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib)
|
|||||||
vty_out (vty, " inactive");
|
vty_out (vty, " inactive");
|
||||||
|
|
||||||
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||||
{
|
vty_out (vty, " (recursive)");
|
||||||
vty_out (vty, " (recursive");
|
|
||||||
|
|
||||||
switch (nexthop->rtype)
|
|
||||||
{
|
|
||||||
case NEXTHOP_TYPE_IPV4:
|
|
||||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
|
||||||
vty_out (vty, " via %s", inet_ntoa (nexthop->rgate.ipv4));
|
|
||||||
if (nexthop->rifindex)
|
|
||||||
vty_out (vty, ", %s", ifindex2ifname (nexthop->rifindex));
|
|
||||||
vty_out (vty, ")");
|
|
||||||
break;
|
|
||||||
case NEXTHOP_TYPE_IFINDEX:
|
|
||||||
case NEXTHOP_TYPE_IFNAME:
|
|
||||||
vty_out (vty, " is directly connected, %s)",
|
|
||||||
ifindex2ifname (nexthop->rifindex));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch (nexthop->type)
|
switch (nexthop->type)
|
||||||
{
|
{
|
||||||
case NEXTHOP_TYPE_IPV4:
|
case NEXTHOP_TYPE_IPV4:
|
||||||
@ -1058,7 +1022,8 @@ vty_show_ip_route_summary (struct vty *vty, struct route_table *table)
|
|||||||
{
|
{
|
||||||
rib_cnt[ZEBRA_ROUTE_TOTAL]++;
|
rib_cnt[ZEBRA_ROUTE_TOTAL]++;
|
||||||
rib_cnt[rib->type]++;
|
rib_cnt[rib->type]++;
|
||||||
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
|
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
|
||||||
|
|| nexthop_has_fib_child(nexthop))
|
||||||
{
|
{
|
||||||
fib_cnt[ZEBRA_ROUTE_TOTAL]++;
|
fib_cnt[ZEBRA_ROUTE_TOTAL]++;
|
||||||
fib_cnt[rib->type]++;
|
fib_cnt[rib->type]++;
|
||||||
@ -1067,7 +1032,8 @@ vty_show_ip_route_summary (struct vty *vty, struct route_table *table)
|
|||||||
CHECK_FLAG (rib->flags, ZEBRA_FLAG_IBGP))
|
CHECK_FLAG (rib->flags, ZEBRA_FLAG_IBGP))
|
||||||
{
|
{
|
||||||
rib_cnt[ZEBRA_ROUTE_IBGP]++;
|
rib_cnt[ZEBRA_ROUTE_IBGP]++;
|
||||||
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
|
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
|
||||||
|
|| nexthop_has_fib_child(nexthop))
|
||||||
fib_cnt[ZEBRA_ROUTE_IBGP]++;
|
fib_cnt[ZEBRA_ROUTE_IBGP]++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1550,7 +1516,8 @@ static void
|
|||||||
vty_show_ipv6_route_detail (struct vty *vty, struct route_node *rn)
|
vty_show_ipv6_route_detail (struct vty *vty, struct route_node *rn)
|
||||||
{
|
{
|
||||||
struct rib *rib;
|
struct rib *rib;
|
||||||
struct nexthop *nexthop;
|
struct nexthop *nexthop, *tnexthop;
|
||||||
|
int recursing;
|
||||||
char buf[BUFSIZ];
|
char buf[BUFSIZ];
|
||||||
|
|
||||||
RNODE_FOREACH_RIB (rn, rib)
|
RNODE_FOREACH_RIB (rn, rib)
|
||||||
@ -1601,10 +1568,11 @@ vty_show_ipv6_route_detail (struct vty *vty, struct route_node *rn)
|
|||||||
vty_out (vty, " ago%s", VTY_NEWLINE);
|
vty_out (vty, " ago%s", VTY_NEWLINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
|
for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
|
||||||
{
|
{
|
||||||
vty_out (vty, " %c",
|
vty_out (vty, " %c%s",
|
||||||
CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ');
|
CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ',
|
||||||
|
recursing ? " " : "");
|
||||||
|
|
||||||
switch (nexthop->type)
|
switch (nexthop->type)
|
||||||
{
|
{
|
||||||
@ -1633,29 +1601,8 @@ vty_show_ipv6_route_detail (struct vty *vty, struct route_node *rn)
|
|||||||
vty_out (vty, " inactive");
|
vty_out (vty, " inactive");
|
||||||
|
|
||||||
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||||
{
|
vty_out (vty, " (recursive)");
|
||||||
vty_out (vty, " (recursive");
|
|
||||||
|
|
||||||
switch (nexthop->rtype)
|
|
||||||
{
|
|
||||||
case NEXTHOP_TYPE_IPV6:
|
|
||||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
|
||||||
case NEXTHOP_TYPE_IPV6_IFNAME:
|
|
||||||
vty_out (vty, " via %s)",
|
|
||||||
inet_ntop (AF_INET6, &nexthop->rgate.ipv6,
|
|
||||||
buf, BUFSIZ));
|
|
||||||
if (nexthop->rifindex)
|
|
||||||
vty_out (vty, ", %s", ifindex2ifname (nexthop->rifindex));
|
|
||||||
break;
|
|
||||||
case NEXTHOP_TYPE_IFINDEX:
|
|
||||||
case NEXTHOP_TYPE_IFNAME:
|
|
||||||
vty_out (vty, " is directly connected, %s)",
|
|
||||||
ifindex2ifname (nexthop->rifindex));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
vty_out (vty, "%s", VTY_NEWLINE);
|
vty_out (vty, "%s", VTY_NEWLINE);
|
||||||
}
|
}
|
||||||
vty_out (vty, "%s", VTY_NEWLINE);
|
vty_out (vty, "%s", VTY_NEWLINE);
|
||||||
@ -1666,12 +1613,13 @@ static void
|
|||||||
vty_show_ipv6_route (struct vty *vty, struct route_node *rn,
|
vty_show_ipv6_route (struct vty *vty, struct route_node *rn,
|
||||||
struct rib *rib)
|
struct rib *rib)
|
||||||
{
|
{
|
||||||
struct nexthop *nexthop;
|
struct nexthop *nexthop, *tnexthop;
|
||||||
|
int recursing;
|
||||||
int len = 0;
|
int len = 0;
|
||||||
char buf[BUFSIZ];
|
char buf[BUFSIZ];
|
||||||
|
|
||||||
/* Nexthop information. */
|
/* Nexthop information. */
|
||||||
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
|
for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
|
||||||
{
|
{
|
||||||
if (nexthop == rib->nexthop)
|
if (nexthop == rib->nexthop)
|
||||||
{
|
{
|
||||||
@ -1695,7 +1643,7 @@ vty_show_ipv6_route (struct vty *vty, struct route_node *rn,
|
|||||||
vty_out (vty, " %c%*c",
|
vty_out (vty, " %c%*c",
|
||||||
CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
|
CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
|
||||||
? '*' : ' ',
|
? '*' : ' ',
|
||||||
len - 3, ' ');
|
len - 3 + (2 * recursing), ' ');
|
||||||
|
|
||||||
switch (nexthop->type)
|
switch (nexthop->type)
|
||||||
{
|
{
|
||||||
@ -1724,29 +1672,7 @@ vty_show_ipv6_route (struct vty *vty, struct route_node *rn,
|
|||||||
vty_out (vty, " inactive");
|
vty_out (vty, " inactive");
|
||||||
|
|
||||||
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||||
{
|
vty_out (vty, " (recursive)");
|
||||||
vty_out (vty, " (recursive");
|
|
||||||
|
|
||||||
switch (nexthop->rtype)
|
|
||||||
{
|
|
||||||
case NEXTHOP_TYPE_IPV6:
|
|
||||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
|
||||||
case NEXTHOP_TYPE_IPV6_IFNAME:
|
|
||||||
vty_out (vty, " via %s)",
|
|
||||||
inet_ntop (AF_INET6, &nexthop->rgate.ipv6,
|
|
||||||
buf, BUFSIZ));
|
|
||||||
if (nexthop->rifindex)
|
|
||||||
vty_out (vty, ", %s", ifindex2ifname (nexthop->rifindex));
|
|
||||||
break;
|
|
||||||
case NEXTHOP_TYPE_IFINDEX:
|
|
||||||
case NEXTHOP_TYPE_IFNAME:
|
|
||||||
vty_out (vty, " is directly connected, %s)",
|
|
||||||
ifindex2ifname (nexthop->rifindex));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE))
|
if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE))
|
||||||
vty_out (vty, ", bh");
|
vty_out (vty, ", bh");
|
||||||
|
@ -389,7 +389,8 @@ zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p,
|
|||||||
|
|
||||||
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
|
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
|
||||||
{
|
{
|
||||||
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
|
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)
|
||||||
|
|| nexthop_has_fib_child(nexthop))
|
||||||
{
|
{
|
||||||
SET_FLAG (zapi_flags, ZAPI_MESSAGE_NEXTHOP);
|
SET_FLAG (zapi_flags, ZAPI_MESSAGE_NEXTHOP);
|
||||||
SET_FLAG (zapi_flags, ZAPI_MESSAGE_IFINDEX);
|
SET_FLAG (zapi_flags, ZAPI_MESSAGE_IFINDEX);
|
||||||
@ -488,6 +489,9 @@ zsend_ipv6_nexthop_lookup (struct zserv *client, struct in6_addr *addr)
|
|||||||
num = 0;
|
num = 0;
|
||||||
nump = stream_get_endp(s);
|
nump = stream_get_endp(s);
|
||||||
stream_putc (s, 0);
|
stream_putc (s, 0);
|
||||||
|
/* Only non-recursive routes are elegible to resolve nexthop we
|
||||||
|
* are looking up. Therefore, we will just iterate over the top
|
||||||
|
* chain of nexthops. */
|
||||||
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
|
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
|
||||||
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
|
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
|
||||||
{
|
{
|
||||||
@ -554,6 +558,9 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr)
|
|||||||
num = 0;
|
num = 0;
|
||||||
nump = stream_get_endp(s);
|
nump = stream_get_endp(s);
|
||||||
stream_putc (s, 0);
|
stream_putc (s, 0);
|
||||||
|
/* Only non-recursive routes are elegible to resolve the nexthop we
|
||||||
|
* are looking up. Therefore, we will just iterate over the top
|
||||||
|
* chain of nexthops. */
|
||||||
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
|
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
|
||||||
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
|
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
|
||||||
{
|
{
|
||||||
@ -619,7 +626,8 @@ zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p)
|
|||||||
nump = stream_get_endp(s);
|
nump = stream_get_endp(s);
|
||||||
stream_putc (s, 0);
|
stream_putc (s, 0);
|
||||||
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
|
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
|
||||||
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
|
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)
|
||||||
|
|| nexthop_has_fib_child(nexthop))
|
||||||
{
|
{
|
||||||
stream_putc (s, nexthop->type);
|
stream_putc (s, nexthop->type);
|
||||||
switch (nexthop->type)
|
switch (nexthop->type)
|
||||||
|
Loading…
Reference in New Issue
Block a user